Permalink
Cannot retrieve contributors at this time
| /* | |
| * Copyright (c) 2016-2020 Martin Donath <martin.donath@squidfunk.com> | |
| * | |
| * 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. | |
| */ | |
| import * as CopyPlugin from "copy-webpack-plugin" | |
| import * as EventHooksPlugin from "event-hooks-webpack-plugin" | |
| import * as fs from "fs" | |
| import { minify as minhtml } from "html-minifier" | |
| import IgnoreEmitPlugin from "ignore-emit-webpack-plugin" | |
| import ImageminPlugin from "imagemin-webpack-plugin" | |
| import MiniCssExtractPlugin = require("mini-css-extract-plugin") | |
| import * as path from "path" | |
| import { toPairs } from "ramda" | |
| import { minify as minjs } from "terser" | |
| import { TsconfigPathsPlugin } from "tsconfig-paths-webpack-plugin" | |
| import { Configuration } from "webpack" | |
| import * as AssetsManifestPlugin from "webpack-assets-manifest" | |
| /* ---------------------------------------------------------------------------- | |
| * Helper functions | |
| * ------------------------------------------------------------------------- */ | |
| /** | |
| * Webpack base configuration | |
| * | |
| * @param args - Command-line arguments | |
| * | |
| * @return Webpack configuration | |
| */ | |
| function config(args: Configuration): Configuration { | |
| const assets = {} | |
| return { | |
| mode: args.mode, | |
| /* Loaders */ | |
| module: { | |
| rules: [ | |
| /* TypeScript */ | |
| { | |
| test: /\.tsx?$/, | |
| use: [ | |
| { | |
| loader: "ts-loader", | |
| options: { | |
| experimentalWatchApi: true, | |
| transpileOnly: true, | |
| compilerOptions: { | |
| importHelpers: true, | |
| module: "esnext", | |
| target: "es2015" | |
| } | |
| } | |
| } | |
| ], | |
| exclude: /\/node_modules\// | |
| }, | |
| /* SASS stylesheets */ | |
| { | |
| test: /\.scss$/, | |
| use: [ | |
| MiniCssExtractPlugin.loader, | |
| { | |
| loader: "css-loader", | |
| options: { | |
| url: false, | |
| sourceMap: true | |
| } | |
| }, | |
| { | |
| loader: "postcss-loader", | |
| options: { | |
| 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 | |
| } | |
| }, | |
| { | |
| loader: "sass-loader", | |
| options: { | |
| implementation: require("sass"), | |
| sassOptions: { | |
| includePaths: [ | |
| "node_modules/modularscale-sass/stylesheets", | |
| "node_modules/material-design-color", | |
| "node_modules/material-shadows" | |
| ] | |
| }, | |
| sourceMap: true | |
| } | |
| } | |
| ] | |
| }, | |
| /* Search */ | |
| { | |
| test: require.resolve("lunr"), | |
| loader: "expose-loader", | |
| options: { | |
| exposes: ["lunr"] | |
| } | |
| } | |
| ] | |
| }, | |
| /* Module resolver */ | |
| resolve: { | |
| mainFields: ["es2015", "module", "main"], | |
| modules: [ | |
| __dirname, | |
| path.resolve(__dirname, "node_modules") | |
| ], | |
| extensions: [".ts", ".tsx", ".js", ".json"], | |
| plugins: [ | |
| new TsconfigPathsPlugin() | |
| ] | |
| }, | |
| /* Plugins */ | |
| plugins: [ | |
| new IgnoreEmitPlugin(/\/stylesheets\/.*?\.js/), | |
| new AssetsManifestPlugin({ | |
| output: "assets/manifest.json", | |
| assets | |
| }) | |
| ], | |
| /* Source maps */ | |
| devtool: args.mode === "production" ? "source-map" : "eval", | |
| /* Filter false positives and omit verbosity */ | |
| stats: { | |
| entrypoints: false, | |
| excludeAssets: [ | |
| /\.(icons)/, | |
| /\/(images|lunr)\//, | |
| /\.(html|py|yml)$/ | |
| ], | |
| warningsFilter: [ | |
| /export '.[^']+' was not found in/ | |
| ] | |
| } | |
| } | |
| } | |
| /* ---------------------------------------------------------------------------- | |
| * Configuration | |
| * ------------------------------------------------------------------------- */ | |
| /** | |
| * Webpack configuration | |
| * | |
| * @param env - Webpack environment arguments | |
| * @param args - Command-line arguments | |
| * | |
| * @return Webpack configurations | |
| */ | |
| 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/overrides": "src/assets/stylesheets/overrides.scss", | |
| "assets/stylesheets/palette": "src/assets/stylesheets/palette.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` | |
| }), | |
| /* Improve performance by skipping dependencies in watch mode */ | |
| ...args.watch ? [] : [ | |
| /* 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: [ | |
| { 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 | |
| })) | |
| }), | |
| /* 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 */ | |
| 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" | |
| /* 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 | |
| }) | |
| /* Remove empty lines without collapsing everything */ | |
| .replace(/^\s*[\r\n]/gm, "") | |
| /* Write theme version into template */ | |
| .replace("$md-name$", metadata.name) | |
| .replace("$md-version$", metadata.version) | |
| } | |
| } | |
| ].map(pattern => ({ | |
| context: "src", | |
| ...pattern | |
| })) | |
| }), | |
| /* Hooks */ | |
| new EventHooksPlugin({ | |
| afterEmit: () => { | |
| /* 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]) => { | |
| return content.replace(new RegExp(from, "g"), to) | |
| }, fs.readFileSync(file, "utf8")) | |
| /* Save template with replaced assets */ | |
| fs.writeFileSync(file, template, "utf8") | |
| } | |
| } | |
| } | |
| }), | |
| /* Minify SVGs */ | |
| new ImageminPlugin({ | |
| svgo: { | |
| plugins: [ | |
| { removeDimensions: true }, | |
| { removeViewBox: false } | |
| ] | |
| } | |
| }) | |
| ], | |
| /* Optimizations */ | |
| optimization: { | |
| splitChunks: { | |
| cacheGroups: { | |
| vendor: { | |
| test: /[\\/]node_modules[\\/]/, | |
| name: "assets/javascripts/vendor", | |
| chunks: "all" | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| /* Search worker */ | |
| { | |
| ...base, | |
| entry: { | |
| "assets/javascripts/worker/search": | |
| "src/assets/javascripts/integrations/search/worker/main" | |
| }, | |
| output: { | |
| path: path.resolve(__dirname, "material"), | |
| filename: `[name]${hash}.js`, | |
| hashDigestLength: 8, | |
| libraryTarget: "var" | |
| } | |
| } | |
| ] | |
| } |