From 4f7064ee56fe710e8f416018956647a72c270fb1 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Sun, 3 Jan 2021 14:28:38 +0100 Subject: [PATCH] fix: inject javascripts in the tag for inject:true and scriptLoading:'defer' --- .travis.yml | 8 ++++---- README.md | 2 +- index.js | 8 +++++++- package.json | 2 +- spec/basic.spec.js | 23 +++++++++++++++++++++++ 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index e603d050..e7aa5da5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,15 +5,15 @@ node_js: - 6.9 env: - WEBPACK_CORE=4 - - WEBPACK_CORE=next + - WEBPACK_CORE=5 jobs: exclude: - node_js: 6.9 - env: WEBPACK_CORE=next + env: WEBPACK_CORE=5 before_install: - stty columns 120 install: - - travis_retry npm install --ignore-scripts - - travis_retry npm install "webpack@$WEBPACK_CORE" --ignore-scripts + - travis_retry npm install --ignore-scripts --force --legacy-peer-deps + - travis_retry npm install "webpack@$WEBPACK_CORE" --ignore-scripts --force --legacy-peer-deps script: - travis_retry npm test diff --git a/README.md b/README.md index 1a32a57e..a9076b54 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ Allowed values are as follows: |**`template`**|`{String}`|``|`webpack` relative or absolute path to the template. By default it will use `src/index.ejs` if it exists. Please see the [docs](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md) for details| |**`templateContent`**|`{string\|Function\|false}`|false| Can be used instead of `template` to provide an inline template - please read the [Writing Your Own Templates](https://github.com/jantimon/html-webpack-plugin#writing-your-own-templates) section | |**`templateParameters`**|`{Boolean\|Object\|Function}`| `false`| Allows to overwrite the parameters used in the template - see [example](https://github.com/jantimon/html-webpack-plugin/tree/master/examples/template-parameters) | -|**`inject`**|`{Boolean\|String}`|`true`|`true \|\| 'head' \|\| 'body' \|\| false` Inject all assets into the given `template` or `templateContent`. When passing `true` or `'body'` all javascript resources will be placed at the bottom of the body element. `'head'` will place the scripts in the head element - see the [inject:false example](https://github.com/jantimon/html-webpack-plugin/tree/master/examples/custom-insertion-position)| +|**`inject`**|`{Boolean\|String}`|`true`|`true \|\| 'head' \|\| 'body' \|\| false` Inject all assets into the given `template` or `templateContent`. When passing `'body'` all javascript resources will be placed at the bottom of the body element. `'head'` will place the scripts in the head element. Passing `true` will add it to the head/body depending on the `scriptLoading` option. Passing `false` will disable automatic injections. - see the [inject:false example](https://github.com/jantimon/html-webpack-plugin/tree/master/examples/custom-insertion-position)| |**`publicPath`**|`{String\|'auto'}`|`'auto'`|The publicPath used for script and link tags| |**`scriptLoading`**|`{'blocking'\|'defer'}`|`'blocking'`| Modern browsers support non blocking javascript loading (`'defer'`) to improve the page startup performance. | |**`favicon`**|`{String}`|``|Adds the given favicon path to the output HTML| diff --git a/index.js b/index.js index 42fc28e5..79e1c7b9 100644 --- a/index.js +++ b/index.js @@ -23,6 +23,7 @@ const { createHtmlTagObject, htmlTagObjectToString, HtmlTagArray } = require('./ const prettyError = require('./lib/errors.js'); const chunkSorter = require('./lib/chunksorter.js'); const getHtmlWebpackPluginHooks = require('./lib/hooks.js').getHtmlWebpackPluginHooks; +const { assert } = require('console'); const fsStatAsync = promisify(fs.stat); const fsReadFileAsync = promisify(fs.readFile); @@ -65,6 +66,10 @@ class HtmlWebpackPlugin { /** @type {ProcessedHtmlWebpackOptions} */ this.options = Object.assign(defaultOptions, userOptions); + // Assert correct option spelling + assert(this.options.scriptLoading === 'defer' || this.options.scriptLoading === 'blocking', 'scriptLoading needs to be set to "defer" or "blocking'); + assert(this.options.inject === true || this.options.inject === false || this.options.inject === 'head' || this.options.inject === 'body', 'inject needs to be set to true, false, "head" or "body'); + // Default metaOptions if no template is provided if (!userOptions.template && this.options.templateContent === false && this.options.meta) { const defaultMeta = { @@ -209,7 +214,8 @@ class HtmlWebpackPlugin { })) .then(({ assetTags }) => { // Inject scripts to body unless it set explicitly to head - const scriptTarget = self.options.inject === 'head' ? 'head' : 'body'; + const scriptTarget = self.options.inject === 'head' || + (self.options.inject !== 'body' && self.options.scriptLoading === 'defer') ? 'head' : 'body'; // Group assets to `head` and `body` tag arrays const assetGroups = this.generateAssetGroups(assetTags, scriptTarget); // Allow third-party-plugin authors to reorder and change the assetTags once they are grouped diff --git a/package.json b/package.json index 74547e24..29d7dfb9 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@types/webpack": "^4.41.8", "html-minifier-terser": "^5.0.1", "loader-utils": "^1.2.3", - "lodash": "^4.17.15", + "lodash": "^4.17.20", "pretty-error": "^2.1.1", "tapable": "^1.1.3", "util.promisify": "1.0.0" diff --git a/spec/basic.spec.js b/spec/basic.spec.js index c4692e6b..b4e03f40 100644 --- a/spec/basic.spec.js +++ b/spec/basic.spec.js @@ -2343,6 +2343,29 @@ describe('HtmlWebpackPlugin', () => { }, [//], null, done); }); + it('should add the javascript assets to the head for inject:true with scriptLoading:defer', done => { + testHtmlPlugin({ + mode: 'production', + entry: path.join(__dirname, 'fixtures/theme.js'), + output: { + path: OUTPUT_DIR, + filename: 'index_bundle.js' + }, + module: { + rules: [ + { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] } + ] + }, + plugins: [ + new MiniCssExtractPlugin({ filename: 'styles.css' }), + new HtmlWebpackPlugin({ + scriptLoading: 'defer', + inject: true + }) + ] + }, [''], null, done); + }); + it('should allow to use headTags and bodyTags directly in string literals', done => { testHtmlPlugin({ mode: 'production',