1
0
mirror of https://github.com/squidfunk/mkdocs-material.git synced 2024-12-03 19:47:22 +01:00
mkdocs-material/webpack.config.ts

467 lines
14 KiB
TypeScript
Raw Normal View History

2019-09-29 00:30:56 +02:00
/*
2021-02-14 16:54:27 +01:00
* Copyright (c) 2016-2021 Martin Donath <martin.donath@squidfunk.com>
2019-09-29 00:30:56 +02:00
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
Squashed commit of the following: commit 9b5b80380fc81f5a68828e22754f0e7d53b0dea0 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Feb 7 16:25:06 2021 +0100 Refactored more stuff commit 5a2108254f1222db7de08690e13c24e972ea19c0 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Feb 7 13:48:16 2021 +0100 Refactored more stuff commit b3a112f4bddefebcf9dbd1d0ffe240d86fc9aa08 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Feb 7 12:02:42 2021 +0100 Refactored more stuff commit bff323b6b81571021c0ac9be6f637de7728447a5 Author: squidfunk <martin.donath@squidfunk.com> Date: Sat Feb 6 18:14:52 2021 +0100 Refactored search result list commit 27b7e7e2da3b725797ad769e4411260ffd35b9f8 Author: squidfunk <martin.donath@squidfunk.com> Date: Sat Feb 6 17:12:36 2021 +0100 Refactored more components commit 3747e5ba6d084ed513a2659f48f161449b760076 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Jan 24 18:56:26 2021 +0100 Implemented new architecture for several components commit ea2851ab0f27113b080c2539a94a88dc0332be84 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Jan 24 14:53:42 2021 +0100 Removed unnecessary height declaration for sidebars commit 3c3f83ab4ef392dbabf1a11afba2556e529b1674 Merge: 91d239d8 13024179 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Jan 24 13:04:49 2021 +0100 Merge branch 'master' into refactor/observable-architecture commit 91d239d86649b9571b376011669bc73a7865b186 Author: squidfunk <martin.donath@squidfunk.com> Date: Sat Jan 9 13:11:04 2021 +0100 Started refactoring observable architecture
2021-02-07 16:27:51 +01:00
import CopyPlugin from "copy-webpack-plugin"
import EventHooksPlugin from "event-hooks-webpack-plugin"
2020-02-10 18:32:28 +01:00
import * as fs from "fs"
import { minify as minhtml } from "html-minifier"
import IgnoreEmitPlugin from "ignore-emit-webpack-plugin"
2020-04-27 14:04:56 +02:00
import ImageminPlugin from "imagemin-webpack-plugin"
import MiniCssExtractPlugin = require("mini-css-extract-plugin")
2019-09-29 00:30:56 +02:00
import * as path from "path"
2020-02-10 18:32:28 +01:00
import { toPairs } from "ramda"
import glob from "tiny-glob"
import { minify as minjs } from "terser"
2019-12-18 16:38:36 +01:00
import { TsconfigPathsPlugin } from "tsconfig-paths-webpack-plugin"
import { Configuration } from "webpack"
Squashed commit of the following: commit 9b5b80380fc81f5a68828e22754f0e7d53b0dea0 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Feb 7 16:25:06 2021 +0100 Refactored more stuff commit 5a2108254f1222db7de08690e13c24e972ea19c0 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Feb 7 13:48:16 2021 +0100 Refactored more stuff commit b3a112f4bddefebcf9dbd1d0ffe240d86fc9aa08 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Feb 7 12:02:42 2021 +0100 Refactored more stuff commit bff323b6b81571021c0ac9be6f637de7728447a5 Author: squidfunk <martin.donath@squidfunk.com> Date: Sat Feb 6 18:14:52 2021 +0100 Refactored search result list commit 27b7e7e2da3b725797ad769e4411260ffd35b9f8 Author: squidfunk <martin.donath@squidfunk.com> Date: Sat Feb 6 17:12:36 2021 +0100 Refactored more components commit 3747e5ba6d084ed513a2659f48f161449b760076 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Jan 24 18:56:26 2021 +0100 Implemented new architecture for several components commit ea2851ab0f27113b080c2539a94a88dc0332be84 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Jan 24 14:53:42 2021 +0100 Removed unnecessary height declaration for sidebars commit 3c3f83ab4ef392dbabf1a11afba2556e529b1674 Merge: 91d239d8 13024179 Author: squidfunk <martin.donath@squidfunk.com> Date: Sun Jan 24 13:04:49 2021 +0100 Merge branch 'master' into refactor/observable-architecture commit 91d239d86649b9571b376011669bc73a7865b186 Author: squidfunk <martin.donath@squidfunk.com> Date: Sat Jan 9 13:11:04 2021 +0100 Started refactoring observable architecture
2021-02-07 16:27:51 +01:00
import AssetsManifestPlugin from "webpack-assets-manifest"
2019-09-29 00:30:56 +02:00
/* ----------------------------------------------------------------------------
* Helper functions
2019-09-29 00:30:56 +02:00
* ------------------------------------------------------------------------- */
/**
* Webpack base configuration
2019-09-29 00:30:56 +02:00
*
* @param args - Command-line arguments
*
2021-02-07 17:43:13 +01:00
* @returns Webpack configuration
2019-09-29 00:30:56 +02:00
*/
function config(args: Configuration): Configuration {
2020-02-10 18:32:28 +01:00
const assets = {}
2019-09-29 00:30:56 +02:00
return {
mode: args.mode,
/* Loaders */
module: {
rules: [
/* TypeScript */
{
test: /\.tsx?$/,
use: [
{
loader: "ts-loader",
options: {
2020-02-10 18:32:28 +01:00
experimentalWatchApi: true,
2019-09-29 00:30:56 +02:00
transpileOnly: true,
compilerOptions: {
importHelpers: true,
module: "esnext",
target: "es2015"
2019-09-29 00:30:56 +02:00
}
}
}
],
exclude: /\/node_modules\//
},
2020-02-10 18:32:28 +01:00
/* SASS stylesheets */
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
2020-02-10 18:32:28 +01:00
{
loader: "css-loader",
options: {
2020-02-11 11:02:46 +01:00
url: false,
sourceMap: true
2020-02-10 18:32:28 +01:00
}
},
{
loader: "postcss-loader",
options: {
2020-09-19 15:31:55 +02:00
postcssOptions: {
plugins: [
["autoprefixer"],
["postcss-inline-svg", {
paths: [
path.resolve(__dirname, "node_modules")
],
encode: false
}],
["postcss-svgo", {
plugins: [
{ removeDimensions: true },
{ removeViewBox: false }
],
encode: false
}]
]
},
sourceMap: true
2020-02-10 18:32:28 +01:00
}
},
{
loader: "sass-loader",
options: {
implementation: require("sass"),
sassOptions: {
includePaths: [
"src/assets/stylesheets",
2020-02-10 18:32:28 +01:00
"node_modules/modularscale-sass/stylesheets",
"node_modules/material-design-color",
"node_modules/material-shadows"
]
},
sourceMap: true
2020-02-10 18:32:28 +01:00
}
}
]
},
/* Search */
{
test: require.resolve("lunr"),
loader: "expose-loader",
options: {
exposes: ["lunr"]
}
2019-09-29 00:30:56 +02:00
}
]
},
/* Module resolver */
resolve: {
mainFields: ["es2015", "module", "main"],
2019-09-29 00:30:56 +02:00
modules: [
__dirname,
path.resolve(__dirname, "node_modules")
],
extensions: [".scss", ".ts", ".tsx", ".js", ".json"],
2019-12-18 16:38:36 +01:00
plugins: [
new TsconfigPathsPlugin()
]
2019-09-29 00:30:56 +02:00
},
2020-02-10 18:32:28 +01:00
/* Plugins */
plugins: [
new IgnoreEmitPlugin(/\/stylesheets\/.*?\.js/),
2020-02-10 18:32:28 +01:00
new AssetsManifestPlugin({
output: "assets/manifest.json",
assets
2020-02-10 18:32:28 +01:00
})
],
2019-12-17 10:01:46 +01:00
/* Source maps */
devtool: args.mode === "production" ? "source-map" : "eval",
2019-12-22 16:52:28 +01:00
2020-02-11 17:14:28 +01:00
/* Filter false positives and omit verbosity */
2019-12-22 16:52:28 +01:00
stats: {
2020-02-11 17:14:28 +01:00
entrypoints: false,
excludeAssets: [
/\.(icons)/,
/\/(images|lunr)\//,
/\.(html|py|yml)$/
],
2019-12-22 16:52:28 +01:00
warningsFilter: [
/export '.[^']+' was not found in/
2019-12-22 16:52:28 +01:00
]
}
2019-09-29 00:30:56 +02:00
}
}
/* ----------------------------------------------------------------------------
* Configuration
* ------------------------------------------------------------------------- */
/**
* Webpack configuration
*
* @param env - Webpack environment arguments
* @param args - Command-line arguments
*
2021-02-07 17:43:13 +01:00
* @returns Webpack configurations
*/
2020-02-10 18:32:28 +01:00
export default (_env: never, args: Configuration): Configuration[] => {
const hash = args.mode === "production" ? ".[chunkhash].min" : ""
const base = config(args)
return [
/* Application */
{
...base,
entry: {
"assets/javascripts/bundle": "src/assets/javascripts",
"assets/stylesheets/main": "src/assets/stylesheets/main.scss",
"assets/stylesheets/palette": "src/assets/stylesheets/palette.scss"
2020-02-10 18:32:28 +01:00
},
output: {
path: path.resolve(__dirname, "material"),
filename: `[name]${hash}.js`,
hashDigestLength: 8,
libraryTarget: "window"
},
/* Plugins */
2020-02-10 18:32:28 +01:00
plugins: [
2020-11-24 18:49:17 +01:00
...base.plugins || [],
2020-02-10 18:32:28 +01:00
/* Stylesheets */
new MiniCssExtractPlugin({
filename: `[name]${hash}.css`
}),
2020-06-21 11:23:05 +02:00
/* Improve performance by skipping dependencies in watch mode */
...args.watch ? [] : [
2020-02-10 18:32:28 +01:00
/* FontAwesome icons */
new CopyPlugin({
patterns: [
{ to: ".icons/fontawesome", from: "**/*.svg" },
{ to: ".icons/fontawesome", from: "../LICENSE.txt" }
].map(pattern => ({
context: "node_modules/@fortawesome/fontawesome-free/svgs",
...pattern
}))
}),
/* Material Design icons */
new CopyPlugin({
patterns: [
2020-07-24 12:29:33 +02:00
{ to: ".icons/material", from: "*.svg" },
{ to: ".icons/material", from: "../LICENSE" }
].map(pattern => ({
context: "node_modules/@mdi/svg/svg",
...pattern
}))
}),
/* GitHub octicons */
new CopyPlugin({
patterns: [
{ to: ".icons/octicons", from: "*.svg" },
{ to: ".icons/octicons", from: "../../LICENSE" }
].map(pattern => ({
context: "node_modules/@primer/octicons/build/svg",
...pattern
}))
2020-06-21 11:23:05 +02:00
}),
/* Search stemmers and segmenters */
new CopyPlugin({
patterns: [
{ to: "assets/javascripts/lunr", from: "min/*.js" },
{
to: "assets/javascripts/lunr/tinyseg.min.js",
from: "tinyseg.js",
transform: (content: Buffer) => minjs(`${content}`).code!
}
].map(pattern => ({
context: "node_modules/lunr-languages",
...pattern
}))
}),
/* Assets and configuration */
new CopyPlugin({
patterns: [
{ from: ".icons/*.svg" },
{ from: "assets/images/*" },
{ from: "**/*.{py,yml}" }
].map(pattern => ({
context: "src",
...pattern
}))
})
],
/* Template files */
2020-05-29 13:51:25 +02:00
new CopyPlugin({
patterns: [
{
from: "**/*.html",
transform: (content: Buffer) => {
const metadata = require("./package.json")
const banner =
"{#-\n" +
" This file was automatically generated - do not edit\n" +
"-#}\n"
2020-04-08 16:25:25 +02:00
2020-05-29 13:51:25 +02:00
/* Normalize line feeds and minify HTML */
const html = content.toString().replace(/\r\n/gm, "\n")
return banner + minhtml(html, {
collapseBooleanAttributes: true,
includeAutoGeneratedTags: false,
minifyCSS: true,
minifyJS: true,
removeComments: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true
})
2020-02-10 18:32:28 +01:00
2020-05-29 13:51:25 +02:00
/* Remove empty lines without collapsing everything */
.replace(/^\s*[\r\n]/gm, "")
2020-02-10 18:32:28 +01:00
2020-05-29 13:51:25 +02:00
/* Write theme version into template */
.replace("$md-name$", metadata.name)
.replace("$md-version$", metadata.version)
}
2020-02-10 18:32:28 +01:00
}
2020-05-29 13:51:25 +02:00
].map(pattern => ({
context: "src",
...pattern
}))
2020-02-10 18:32:28 +01:00
}),
/* Hooks */
2020-02-10 18:32:28 +01:00
new EventHooksPlugin({
2021-02-06 12:35:19 +01:00
afterEmit: async () => {
2020-02-10 18:32:28 +01:00
/* Replace asset URLs in templates */
if (args.mode === "production") {
const manifest = require("./material/assets/manifest.json")
for (const file of [
"material/base.html",
"material/overrides/main.html"
]) {
const template = toPairs<string>(manifest)
.reduce((content, [from, to]) => (
content.replace(new RegExp(
`('|")${from}\\1`, "g"),
`$1${to}$1`
)
), fs.readFileSync(file, "utf8"))
/* Save template with replaced assets */
fs.writeFileSync(file, template, "utf8")
}
2021-02-06 12:35:19 +01:00
2021-02-15 16:58:04 +01:00
/* Icon indexes */
const icons: Record<string, string> = {}
const emojis: Record<string, string> = {}
2021-02-15 15:57:44 +01:00
/* Build search index for bundled icons */
for (const file of await glob("**/*.svg", {
cwd: "material/.icons"
})) {
const name = file.replace(/\.svg$/, "").replace(/\//g, "-")
icons[name] = file
}
/* Build search index for emojis (based on Twemoji) */
const [database] = await glob("venv/**/twemoji_db.py")
if (typeof database !== "undefined") {
const contents = fs.readFileSync(database, "utf8")
const [, content] = contents.match(/^emoji = ({.*})$.alias/ms)!
for (const [name, data] of toPairs(JSON.parse(content))) {
emojis[name.replace(/(^:|:$)/g, "")] = `${data.unicode}.svg`
}
}
fs.writeFileSync(
"material/overrides/assets/javascripts/icon_search_index.json",
JSON.stringify({
icons: {
base: "https://raw.githubusercontent.com/squidfunk/mkdocs-material/master/material/.icons/",
data: icons
},
emojis: {
base: "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/",
data: emojis
}
})
)
}
2020-02-10 18:32:28 +01:00
}
2020-04-27 14:04:56 +02:00
}),
/* Minify SVGs */
new ImageminPlugin({
svgo: {
plugins: [
{ removeDimensions: true },
{ removeViewBox: false }
]
}
2020-02-10 18:32:28 +01:00
})
],
/* Optimizations */
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
2021-02-14 16:19:03 +01:00
test: /\/node_modules\//,
name: "assets/javascripts/vendor",
chunks: "all"
}
}
}
}
2020-02-10 18:32:28 +01:00
},
/* Search worker */
{
...base,
entry: {
"assets/javascripts/worker/search":
2020-03-27 15:29:17 +01:00
"src/assets/javascripts/integrations/search/worker/main"
2020-02-10 18:32:28 +01:00
},
output: {
path: path.resolve(__dirname, "material"),
filename: `[name]${hash}.js`,
hashDigestLength: 8,
libraryTarget: "var"
}
},
/* Overrides */
{
...base,
entry: {
"overrides/assets/javascripts/bundle": "src/overrides/assets/javascripts",
"overrides/assets/stylesheets/main": "src/overrides/assets/stylesheets/main.scss"
},
output: {
path: path.resolve(__dirname, "material"),
filename: `[name]${hash}.js`,
hashDigestLength: 8,
libraryTarget: "window"
},
/* Plugins */
plugins: [
...base.plugins || [],
/* Stylesheets */
new MiniCssExtractPlugin({
filename: `[name]${hash}.css`
2021-02-14 16:19:03 +01:00
})
],
/* Optimizations */
optimization: {
2021-02-14 16:19:03 +01:00
// minimize: false,
// splitChunks: {
// cacheGroups: {
// vendor: {
// test: /\/node_modules\//,
// name: "overrides/assets/javascripts/vendor",
// chunks: "all"
// }
// }
// }
}
}
2020-02-10 18:32:28 +01:00
]
}