From 7c70ed2462f586cfa039eedb5fce043734b5fe2a Mon Sep 17 00:00:00 2001 From: biodiscus Date: Tue, 5 Sep 2023 23:22:46 +0200 Subject: [PATCH] release v2.11.0 - feat: add support for `webpack-subresource-integrity` plugin to include the subresource integrity hash - feat: add the `integrity` option to enable/disable the support for `webpack-subresource-integrity` plugin - test: add tests for integrity - dosc: update readme --- CHANGELOG.md | 7 +- README.md | 115 +- examples/handlebars-layout/package.json | 2 +- .../src/views/helpers/block.js | 12 +- .../src/views/pages/about/index.hbs | 8 +- .../src/views/pages/home/index.hbs | 8 +- .../src/views/partials/layout.hbs | 10 +- examples/handlebars-layout/webpack.config.js | 2 +- examples/handlebars/src/views/pages/home.hbs | 6 +- examples/integrity/README.md | 26 + examples/integrity/package-lock.json | 6606 +++++++++++++++++ examples/integrity/package.json | 24 + examples/integrity/src/images/favicon.ico | Bin 0 -> 959 bytes examples/integrity/src/images/picture.png | Bin 0 -> 2743 bytes examples/integrity/src/index.html | 14 + examples/integrity/src/js/main.js | 1 + examples/integrity/src/scss/styles.scss | 7 + examples/integrity/webpack.config.js | 61 + package-lock.json | 49 +- package.json | 12 +- .../Handlebars/helpers/block/block.js | 10 +- src/Loader/Template.js | 12 +- src/Plugin/AssetCompiler.js | 11 + src/Plugin/Collection.js | 6 +- src/Plugin/Extras/Integrity.js | 100 + src/Plugin/Options.js | 13 +- .../expected/style.bundle.css | 0 .../src/style.css | 0 .../webpack.config.js | 0 .../entry-js-css/expected/index.1fe197ae.css | 3 + .../entry-js-css/expected/index.5317c1f6.js | 1 + test/cases/entry-js-css/src/main.js | 1 + test/cases/entry-js-css/src/styles.css | 3 + test/cases/entry-js-css/webpack.config.js | 37 + .../expected/index.html | 11 + .../expected/main.bundle.js | 1 + .../expected/src_chunk_js.js | 1 + .../integrity-dynamic-chunks/src/chunk.js | 1 + .../integrity-dynamic-chunks/src/index.html | 11 + .../integrity-dynamic-chunks/src/main.js | 41 + .../webpack.config.js | 48 + .../expected/index.html | 14 + .../expected/js/107.bundle.js | 1 + .../expected/js/192.bundle.js | 1 + .../expected/js/450.bundle.js | 1 + .../expected/js/671.bundle.js | 1 + .../expected/js/app.bundle.js | 1 + .../expected/js/runtime.bundle.js | 1 + .../integrity-split-chunks/src/index.html | 9 + .../integrity-split-chunks/src/js/app.js | 2 + .../integrity-split-chunks/src/js/lib.js | 16 + .../integrity-split-chunks/src/js/main-a.js | 11 + .../integrity-split-chunks/src/js/main-b.js | 10 + .../integrity-split-chunks/webpack.config.js | 46 + .../expected/assets/css/style.bundle.css | 3 + .../expected/assets/css/vendor.bundle.css | 3 + .../expected/assets/img/image.697ef306.png | Bin 0 -> 1250 bytes .../expected/assets/js/main.bundle.js | 1 + .../expected/assets/js/no-integrity.bundle.js | 1 + .../expected/assets/js/vendor.bundle.js | 1 + test/cases/integrity/expected/index.html | 31 + test/cases/integrity/src/image.png | Bin 0 -> 1250 bytes test/cases/integrity/src/index.html | 31 + test/cases/integrity/src/main.js | 1 + test/cases/integrity/src/no-integrity.js | 1 + test/cases/integrity/src/style.css | 3 + test/cases/integrity/src/vendor.css | 3 + test/cases/integrity/src/vendor.js | 1 + test/cases/integrity/webpack.config.js | 49 + .../expected/about.html | 2 + .../src/views/pages/about/index.hbs | 2 + .../webpack.config.js | 6 +- test/integration.test.js | 13 +- test/unit.test.js | 1 + types.d.ts | 1 + 75 files changed, 7475 insertions(+), 74 deletions(-) create mode 100644 examples/integrity/README.md create mode 100644 examples/integrity/package-lock.json create mode 100644 examples/integrity/package.json create mode 100644 examples/integrity/src/images/favicon.ico create mode 100644 examples/integrity/src/images/picture.png create mode 100644 examples/integrity/src/index.html create mode 100644 examples/integrity/src/js/main.js create mode 100644 examples/integrity/src/scss/styles.scss create mode 100644 examples/integrity/webpack.config.js create mode 100644 src/Plugin/Extras/Integrity.js rename test/cases/{extract-css-from-entry => entry-css-single}/expected/style.bundle.css (100%) rename test/cases/{extract-css-from-entry => entry-css-single}/src/style.css (100%) rename test/cases/{extract-css-from-entry => entry-css-single}/webpack.config.js (100%) create mode 100644 test/cases/entry-js-css/expected/index.1fe197ae.css create mode 100644 test/cases/entry-js-css/expected/index.5317c1f6.js create mode 100644 test/cases/entry-js-css/src/main.js create mode 100644 test/cases/entry-js-css/src/styles.css create mode 100644 test/cases/entry-js-css/webpack.config.js create mode 100644 test/cases/integrity-dynamic-chunks/expected/index.html create mode 100644 test/cases/integrity-dynamic-chunks/expected/main.bundle.js create mode 100644 test/cases/integrity-dynamic-chunks/expected/src_chunk_js.js create mode 100644 test/cases/integrity-dynamic-chunks/src/chunk.js create mode 100644 test/cases/integrity-dynamic-chunks/src/index.html create mode 100644 test/cases/integrity-dynamic-chunks/src/main.js create mode 100644 test/cases/integrity-dynamic-chunks/webpack.config.js create mode 100644 test/cases/integrity-split-chunks/expected/index.html create mode 100644 test/cases/integrity-split-chunks/expected/js/107.bundle.js create mode 100644 test/cases/integrity-split-chunks/expected/js/192.bundle.js create mode 100644 test/cases/integrity-split-chunks/expected/js/450.bundle.js create mode 100644 test/cases/integrity-split-chunks/expected/js/671.bundle.js create mode 100644 test/cases/integrity-split-chunks/expected/js/app.bundle.js create mode 100644 test/cases/integrity-split-chunks/expected/js/runtime.bundle.js create mode 100644 test/cases/integrity-split-chunks/src/index.html create mode 100644 test/cases/integrity-split-chunks/src/js/app.js create mode 100644 test/cases/integrity-split-chunks/src/js/lib.js create mode 100644 test/cases/integrity-split-chunks/src/js/main-a.js create mode 100644 test/cases/integrity-split-chunks/src/js/main-b.js create mode 100644 test/cases/integrity-split-chunks/webpack.config.js create mode 100644 test/cases/integrity/expected/assets/css/style.bundle.css create mode 100644 test/cases/integrity/expected/assets/css/vendor.bundle.css create mode 100644 test/cases/integrity/expected/assets/img/image.697ef306.png create mode 100644 test/cases/integrity/expected/assets/js/main.bundle.js create mode 100644 test/cases/integrity/expected/assets/js/no-integrity.bundle.js create mode 100644 test/cases/integrity/expected/assets/js/vendor.bundle.js create mode 100644 test/cases/integrity/expected/index.html create mode 100644 test/cases/integrity/src/image.png create mode 100644 test/cases/integrity/src/index.html create mode 100644 test/cases/integrity/src/main.js create mode 100644 test/cases/integrity/src/no-integrity.js create mode 100644 test/cases/integrity/src/style.css create mode 100644 test/cases/integrity/src/vendor.css create mode 100644 test/cases/integrity/src/vendor.js create mode 100644 test/cases/integrity/webpack.config.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d7a5447..8cceaa7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log +## 2.11.0 (2023-09-05) + +- feat: add support for the `webpack-subresource-integrity` plugin to include the [subresource integrity hash](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) +- feat: add the `integrity` option to enable/disable the support for `webpack-subresource-integrity` plugin + ## 2.10.1 (2023-09-02) - fix: avoid generation of empty css files when source styles are imported in TS file @@ -16,7 +21,7 @@ You can try it, but if that doesn't work, just use the default `cache.type` as `memory`. - feat: remove the `json5` dependency, take only the parser code from this package, remove unused code from it and optimize it for use with the plugin - fix: resolve output asset filenames without the needless index `.1`, like `index.1.js`, when used the same base filename for template and js files. - For example, if source files with the same base name `src/index.html` and `src/index.js` were used, then `dist/index.html` and `dist/index.1.js` were created, + For example, if the source files with the same base name `src/index.html` and `src/index.js` were used, then `dist/index.html` and `dist/index.1.js` were created, because the entry name used for compilation must be unique. This case is fixed. - test: add tests for features and fixes - test: remove unused code in test suits diff --git a/README.md b/README.md index 9f05bcda..7bfb28a8 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ > _HTML as an entry point works in both Vite and Parcel, and now also in Webpack._ +This plugin is a simple all-in-one solution for generating HTML containing JS, CSS, images, fonts and other resources, from their source files. The plugin allows to use any [template](#template-engine) file as [entry point](#option-entry). In an HTML template can be referenced any source files, similar to how it works in [Vite](https://vitejs.dev/guide/#index-html-and-project-root) or [Parcel](https://parceljs.org/). @@ -216,6 +217,7 @@ See [boilerplate](https://github.com/webdiscus/webpack-html-scss-boilerplate) - [preload](#option-preload) (inject preload link tags) - [minify](#option-minify) and [minifyOptions](#option-minify-options) (minification of generated HTML) - [extractComments](#option-extract-comments) + - [integrity](#option-integrity) (enable [subresource integrity hash](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)) - [verbose](#option-verbose) - [watchFiles](#option-watch-files) - [hotUpdate](#option-hot-update) @@ -266,6 +268,7 @@ See [boilerplate](https://github.com/webdiscus/webpack-html-scss-boilerplate) - Tailwind CSS with Webpack [View in browser](https://stackblitz.com/edit/webpack-webpack-js-org-auem8r?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/tailwindcss/) - Handlebars with Webpack [View in browser](https://stackblitz.com/edit/webpack-webpack-js-org-mxbx4t?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/handlebars/) - Extend Handlebars layout with blocks [View in browser](https://stackblitz.com/edit/webpack-webpack-js-org-bjtjvc?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/handlebars-layout/) + - Auto generate integrity hash for `link` and `script` tags [View in browser](https://stackblitz.com/edit/webpack-integrity-hvnfmg?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/integrity/) @@ -277,19 +280,20 @@ See [boilerplate](https://github.com/webdiscus/webpack-html-scss-boilerplate) - importing style files in JavaScript - resolves source asset files in HTML attributes and in the CSS `url()` - generated HTML contains output filenames -- support the module types `asset/resource` `asset/inline` `asset` `asset/source` ([\*](#note-asset-source)) +- supports the module types `asset/resource` `asset/inline` `asset` `asset/source` ([\*](#note-asset-source)) - `inline CSS` in HTML - `inline JavaScript` in HTML - `inline image` as `base64 encoded` data-URL for PNG, JPG, etc. in HTML and CSS - `inline SVG` as SVG tag in HTML - `inline SVG` as `utf-8` data-URL in CSS - auto generation of `` to preload assets -- support the `auto` publicPath +- supports the `auto` publicPath - enable/disable [extraction of comments](#option-extract-comments) to `*.LICENSE.txt` file - supports template engines such as [Eta](https://eta.js.org), [EJS](https://ejs.co), [Handlebars](https://handlebarsjs.com), [Nunjucks](https://mozilla.github.io/nunjucks/), [LiquidJS](https://github.com/harttle/liquidjs) and others -- support for both `async` and `sync` preprocessor +- supports both `async` and `sync` preprocessor - auto processing many HTML templates using the [entry path](#option-entry-path), add/delete/rename w/o restarting - dynamically loading template variables using the [data](#loader-option-data) option, change data w/o restarting +- supports [webpack-subresource-integrity](https://www.npmjs.com/package/webpack-subresource-integrity) and include the [integrity hash](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) to `link` and `script` tags - [minification](#option-minify) of generated HTML @@ -385,7 +389,7 @@ module.exports = { entry: { // define templates here index: { - // => dist/index.html (key is output filename w/o '.html') + // => dist/index.html import: 'src/views/home.html', // template file data: { title: 'Homepage', name: 'Heisenberg' }, // pass variables into template }, @@ -1456,7 +1460,7 @@ The generated HTML contains the preload tags exactly in the order of `preload` o ### `minify` -Type: `Object|string|boolean` Default: `false` +Type: `'auto'|boolean|Object` Default: `false` For minification generated HTML is used the [html-minifier-terser](https://github.com/terser/html-minifier-terser) with the following `default options`: @@ -1508,6 +1512,91 @@ But if you want to extract files like `*.LICENSE.txt`, set this option to `true` #### [↑ back to contents](#contents) + + +### `integrity` + +Type: `'auto'|boolean` Default: `'auto'` + +Possible values: + +- `auto` - enable in `production` mode, disable in `development` mode +- `true` - enable +- `false` - disable + +The `html-bundler-webpack-plugin` automatically supports the [webpack-subresource-integrity](https://www.npmjs.com/package/webpack-subresource-integrity) plugin +if it is installed. +To include the [subresource integrity hash](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) +in `link` and `script` tags, you need to install the `webpack-subresource-integrity` plugin: + +``` +npm install -D webpack-subresource-integrity +``` + +Add this plugin in the Webpack config: + +```js +const { SubresourceIntegrityPlugin } = require('webpack-subresource-integrity'); +const HtmlBundlerPlugin = require('html-bundler-webpack-plugin'); + +module.exports = { + output: { + // the following setting is required for SRI to work: + crossOriginLoading: 'anonymous', + }, + plugins: [ + new HtmlBundlerPlugin({ + entry: { + index: 'src/views/index.html', // template where are included link and script tags + }, + integrity: 'auto', // can be omitted, because the default value is 'auto' + }), + new SubresourceIntegrityPlugin(), + ], +}; +``` + +The source HTML template _src/views/index.html_: + +```html + + + + + + + + +

Hello World!

+ + +``` + +The generated HTML contains the integrity hashs: + +```html + + + + + + + +

Hello World!

+ + +``` + +#### [↑ back to contents](#contents) + ### `watchFiles` @@ -1601,7 +1690,7 @@ If you already have a js file in html, this setting should be `false` as Webpack ### `verbose` -Type: `string|boolean` Default: `false` +Type: `'auto'|boolean` Default: `false` The verbose option allows displaying in the console the processing information about extracted resources. All resources are grouped by their issuers. @@ -3221,7 +3310,7 @@ The template _index.html_ where is loaded the source style: Demo - + @@ -3749,10 +3838,10 @@ _src/views/pages/home/index.html_ ```html {% extends "src/views/layouts/default.html" %} {% block styles %} - + {% endblock %} {% block scripts %} - + {% endblock %} {% block content %}

{{ filmTitle }}

@@ -4128,9 +4217,9 @@ If you want save module styles separate from your styles, then load them in a te Home - + - + @@ -4163,7 +4252,7 @@ There is a template used the `main.js` _./src/views/index.html_: ```html - + @@ -4247,8 +4336,6 @@ dist/js/app-5fa74877.1aceb2db.js ## Sponsors -Support this project by becoming a sponsor! - Thank you to our sponsors! | Sponsors | | diff --git a/examples/handlebars-layout/package.json b/examples/handlebars-layout/package.json index aee8b453..7da4967a 100644 --- a/examples/handlebars-layout/package.json +++ b/examples/handlebars-layout/package.json @@ -15,7 +15,7 @@ "devDependencies": { "css-loader": "^6.8.1", "handlebars": "^4.7.8", - "html-bundler-webpack-plugin": "^2.10.0", + "html-bundler-webpack-plugin": "^2.10.1", "sass": "^1.64.2", "sass-loader": "^13.3.2", "webpack": "^5.88.2", diff --git a/examples/handlebars-layout/src/views/helpers/block.js b/examples/handlebars-layout/src/views/helpers/block.js index 1feb52bd..92491817 100644 --- a/examples/handlebars-layout/src/views/helpers/block.js +++ b/examples/handlebars-layout/src/views/helpers/block.js @@ -1,7 +1,5 @@ 'use strict'; -const Handlebars = require('handlebars'); - /** @typedef {import('handlebars').HelperOptions} HelperOptions */ /** @@ -17,13 +15,7 @@ const Handlebars = require('handlebars'); * @return {string} */ module.exports = function (name, options) { - const context = this; - let partial = context._blocks[name] || options.fn; - - if (typeof partial === 'string') { - partial = Handlebars.compile(partial); - context._blocks[name] = partial; - } + const partial = this._blocks[name] || options.fn; - return partial(context, { data: options.hash }); + return partial(this, { data: options.hash }); }; diff --git a/examples/handlebars-layout/src/views/pages/about/index.hbs b/examples/handlebars-layout/src/views/pages/about/index.hbs index 70e0c486..def5fdb4 100644 --- a/examples/handlebars-layout/src/views/pages/about/index.hbs +++ b/examples/handlebars-layout/src/views/pages/about/index.hbs @@ -1,16 +1,16 @@ {{assign title='About' header='About'}} - +{{! define the block with page-specific scripts }} {{#partial 'scripts'}} {{/partial}} - +{{! define the block with page-specific styles }} {{#partial 'styles'}} {{/partial}} - +{{! define block content: include the `home/content.hbs` partial }} {{#partial 'content'}} {{> about/content}} {{/partial}} @@ -19,5 +19,5 @@

About custom block

{{/partial}} - +{{! extends the layout template with blocks defined above }} {{> layout}} diff --git a/examples/handlebars-layout/src/views/pages/home/index.hbs b/examples/handlebars-layout/src/views/pages/home/index.hbs index 97b182c6..432b992f 100644 --- a/examples/handlebars-layout/src/views/pages/home/index.hbs +++ b/examples/handlebars-layout/src/views/pages/home/index.hbs @@ -1,19 +1,19 @@ {{assign title='Homepage' header='Home'}} - +{{! define the block with page-specific scripts }} {{#partial 'scripts'}} {{/partial}} - +{{! define the block with page-specific styles }} {{#partial 'styles'}} {{/partial}} - +{{! define the block content: include the `home/content.hbs` partial }} {{#partial 'content'}} {{> home/content}} {{/partial}} - +{{! extends the layout template with blocks defined above }} {{> layout}} diff --git a/examples/handlebars-layout/src/views/partials/layout.hbs b/examples/handlebars-layout/src/views/partials/layout.hbs index edeea833..3c4d0b43 100644 --- a/examples/handlebars-layout/src/views/partials/layout.hbs +++ b/examples/handlebars-layout/src/views/partials/layout.hbs @@ -2,14 +2,14 @@ {{ title }} - + {{! reference to source image }} - + {{! common used source styles and scripts }} - + {{! blocks for page-specific styles and scripts }} {{#block 'styles'}}{{/block}} {{#block 'scripts'}}{{/block}} @@ -22,11 +22,11 @@
- + {{! output content block defined in a parent template }} {{#block 'content'}}{{/block}}
- + {{! if the block is not defined in a parent template, then output default content }} {{#block 'custom_block'}}

default block content

{{/block}} {{> footer }} diff --git a/examples/handlebars-layout/webpack.config.js b/examples/handlebars-layout/webpack.config.js index 55658b3e..fe29a917 100644 --- a/examples/handlebars-layout/webpack.config.js +++ b/examples/handlebars-layout/webpack.config.js @@ -34,7 +34,7 @@ module.exports = { preprocessor: 'handlebars', // define handlebars options preprocessorOptions: { - //helpers: [path.join(__dirname, 'src/views/helpers')], + //helpers: [path.join(__dirname, 'src/views/helpers')], // enable to use own helpers partials: ['src/views/pages/', 'src/views/partials/'], }, js: { diff --git a/examples/handlebars/src/views/pages/home.hbs b/examples/handlebars/src/views/pages/home.hbs index 7bc700ed..fc3b6f0a 100644 --- a/examples/handlebars/src/views/pages/home.hbs +++ b/examples/handlebars/src/views/pages/home.hbs @@ -2,9 +2,9 @@ {{ title }} - + {{! reference to source image }} - + {{! references to source style and script }} @@ -14,7 +14,7 @@

Handlebars

- + {{! using of the arraySize helper }}
{{ arraySize persons }} persons: