diff --git a/plugins/plugin-webpack/README.md b/plugins/plugin-webpack/README.md index 502ee297b6..015847ef61 100644 --- a/plugins/plugin-webpack/README.md +++ b/plugins/plugin-webpack/README.md @@ -27,6 +27,7 @@ npm install --save-dev @snowpack/plugin-webpack - `outputPattern: {css: string, js: string, assets: string}` - Set the URL for your final bundled files. This is where they will be written to disk in the `build/` directory. See Webpack's [`output.filename`](https://webpack.js.org/configuration/output/#outputfilename) documentation for examples of valid values. - `extendConfig: (config: WebpackConfig) => WebpackConfig` - extend your webpack config, see below. - `manifest: boolean | string` - Enable generating a manifest file. The default value is `false`, the default file name is `./asset-manifest.json` if setting manifest to `true`. The relative path is resolved from the output directory. +- `htmlMinifierOptions: boolean | object` - [See below](#minify-html). #### Extending The Default Webpack Config @@ -50,3 +51,34 @@ module.exports = { ], }; ``` + +#### Minify HTML + +With `htmlMinifierOptions` you can either disable the minification entirely or provide your own [options](https://github.com/kangax/html-minifier#options-quick-reference). + +```js +// snowpack.config.js +module.exports = { + plugins: [ + [ + "@snowpack/plugin-webpack", + { + htmlMinifierOptions: false // disabled entirely, + }, + ], + ], +}; +``` + +The default options are: + +```js +{ + collapseWhitespace: true, + removeComments: true, + removeEmptyAttributes: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, +} +``` diff --git a/plugins/plugin-webpack/package.json b/plugins/plugin-webpack/package.json index 56804d6c4a..3bd00e8d78 100644 --- a/plugins/plugin-webpack/package.json +++ b/plugins/plugin-webpack/package.json @@ -13,6 +13,7 @@ "css-loader": "^3.5.3", "file-loader": "^6.0.0", "glob": "^7.1.6", + "html-minifier": "^4.0.0", "jsdom": "^16.2.2", "mini-css-extract-plugin": "^0.9.0", "optimize-css-assets-webpack-plugin": "^5.0.3", diff --git a/plugins/plugin-webpack/plugin.js b/plugins/plugin-webpack/plugin.js index e15b32f4cf..5f1af6be11 100644 --- a/plugins/plugin-webpack/plugin.js +++ b/plugins/plugin-webpack/plugin.js @@ -11,6 +11,7 @@ const ManifestPlugin = require('webpack-manifest-plugin'); const jsdom = require("jsdom"); const { JSDOM } = jsdom; const cwd = process.cwd(); +const minify = require('html-minifier').minify; function insertBefore(newNode, existingNode) { existingNode.parentNode.insertBefore(newNode, existingNode); @@ -51,7 +52,13 @@ function parseHTMLFiles({ buildDirectory }) { return { doms, jsEntries }; } -function emitHTMLFiles({ doms, jsEntries, stats, baseUrl, buildDirectory }) { +function emitHTMLFiles({ + doms, + jsEntries, + stats, baseUrl, + buildDirectory, + htmlMinifierOptions, +}) { const entrypoints = stats.toJson({ assets: false, hash: true }).entrypoints; //Now that webpack is done, modify the html files to point to the newly compiled resources @@ -87,7 +94,11 @@ function emitHTMLFiles({ doms, jsEntries, stats, baseUrl, buildDirectory }) { //And write our modified html files out to the destination for (const [htmlFile, dom] of Object.entries(doms)) { - fs.writeFileSync(path.join(buildDirectory, htmlFile), dom.serialize()); + const html = htmlMinifierOptions + ? minify(dom.serialize(), htmlMinifierOptions) + : dom.serialize(); + + fs.writeFileSync(path.join(buildDirectory, htmlFile), html); } } @@ -161,7 +172,20 @@ module.exports = function plugin(config, args) { if (!cssOutputPattern.endsWith(".css")) { throw new Error("Output Pattern for CSS must end in .css"); } - + + // Default options for HTMLMinifier + // https://github.com/kangax/html-minifier#options-quick-reference + const defaultHtmlMinifierOptions = { + collapseWhitespace: true, + removeComments: true, + removeEmptyAttributes: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, + }; + + const htmlMinifierOptions = args.htmlMinifierOptions === false ? false : Object.assign({}, defaultHtmlMinifierOptions, args.htmlMinifierOptions) + const manifest = typeof args.manifest === 'string' ? args.manifest @@ -355,7 +379,14 @@ module.exports = function plugin(config, args) { ); } - emitHTMLFiles({ doms, jsEntries, stats, baseUrl, buildDirectory }); + emitHTMLFiles({ + doms, + jsEntries, + stats, + baseUrl, + buildDirectory, + htmlMinifierOptions, + }); }, }; };