From d65b37d2c588047e0d81a38f4645fcdb3ead0b9e Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Tue, 28 Aug 2018 14:42:08 +0200 Subject: [PATCH] fix: Prevent chunks from beeing added multiple times --- README.md | 4 +- .../dist/webpack-4/entryC.html | 9 +++ examples/chunk-optimization/webpack.config.js | 3 + examples/inline/template.pug | 4 +- index.js | 61 +++++++++++-------- lib/hooks.js | 4 +- spec/basic.spec.js | 2 +- spec/fixtures/template.pug | 2 +- spec/fixtures/test.html | 2 +- spec/fixtures/webpackconfig.html | 2 +- typings.d.ts | 4 +- 11 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 examples/chunk-optimization/dist/webpack-4/entryC.html diff --git a/README.md b/README.md index 230c9e71..10c08040 100644 --- a/README.md +++ b/README.md @@ -301,8 +301,8 @@ about which values are passed. AsyncSeriesWaterfallHook<{ assets: { publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array<{string}>, + css: Array<{string}>, favicon?: string | undefined, manifest?: string | undefined }, diff --git a/examples/chunk-optimization/dist/webpack-4/entryC.html b/examples/chunk-optimization/dist/webpack-4/entryC.html new file mode 100644 index 00000000..6f986f9a --- /dev/null +++ b/examples/chunk-optimization/dist/webpack-4/entryC.html @@ -0,0 +1,9 @@ + + + + + Webpack App + + + + \ No newline at end of file diff --git a/examples/chunk-optimization/webpack.config.js b/examples/chunk-optimization/webpack.config.js index 837d1a7a..37c02387 100755 --- a/examples/chunk-optimization/webpack.config.js +++ b/examples/chunk-optimization/webpack.config.js @@ -47,6 +47,9 @@ module.exports = { new HtmlWebpackPlugin({ filename: 'entryB.html', chunks: ['entryB'] + }), + new HtmlWebpackPlugin({ + filename: 'entryC.html' }) ] }; diff --git a/examples/inline/template.pug b/examples/inline/template.pug index 83a8e9b0..b4337d6a 100644 --- a/examples/inline/template.pug +++ b/examples/inline/template.pug @@ -5,6 +5,6 @@ html title #{htmlWebpackPlugin.options.title} body each cssFile in htmlWebpackPlugin.files.css - style !{compilation.assets[cssFile.path.substr(htmlWebpackPlugin.files.publicPath.length)].source()} + style !{compilation.assets[cssFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()} each jsFile in htmlWebpackPlugin.files.js - script !{compilation.assets[jsFile.path.substr(htmlWebpackPlugin.files.publicPath.length)].source()} + script !{compilation.assets[jsFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()} diff --git a/index.js b/index.js index e479d480..baacb1ae 100644 --- a/index.js +++ b/index.js @@ -327,8 +327,8 @@ class HtmlWebpackPlugin { * @param {WebpackCompilation} compilation * @param {{ publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array, + css: Array, manifest?: string, favicon?: string }} assets @@ -357,8 +357,8 @@ class HtmlWebpackPlugin { * @param {(templatePArameters) => string | Promise} templateFunction * @param {{ publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array, + css: Array, manifest?: string, favicon?: string }} assets @@ -488,14 +488,14 @@ class HtmlWebpackPlugin { * * @param {{ publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array, + css: Array, manifest?: string, favicon?: string }} assets */ isHotUpdateCompilation (assets) { - return assets.js.length && assets.js.every(({entryName}) => /\.hot-update\.js$/.test(entryName)); + return assets.js.length && assets.js.every((assetPath) => /\.hot-update\.js$/.test(assetPath)); } /** @@ -505,8 +505,8 @@ class HtmlWebpackPlugin { * @param {string[]} entryNames * @returns {{ publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array, + css: Array, manifest?: string, favicon?: string }} @@ -533,8 +533,8 @@ class HtmlWebpackPlugin { /** * @type {{ publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array, + css: Array, manifest?: string, favicon?: string }} @@ -558,6 +558,7 @@ class HtmlWebpackPlugin { } // Extract paths to .js and .css files from the current compilation + const entryPointPublicPathMap = {}; const extensionRegexp = /\.(css|js)(\?|$)/; for (let i = 0; i < entryNames.length; i++) { const entryName = entryNames[i]; @@ -573,18 +574,21 @@ class HtmlWebpackPlugin { : entryPointPublicPath; }); - entryPointPublicPaths.forEach((entryPointPublicPaths) => { - const extMatch = extensionRegexp.exec(entryPointPublicPaths); + entryPointPublicPaths.forEach((entryPointPublicPath) => { + const extMatch = extensionRegexp.exec(entryPointPublicPath); // Skip if the public path is not a .css or .js file if (!extMatch) { return; } + // Skip if this file is already known + // (e.g. because of common chunk optimizations) + if (entryPointPublicPathMap[entryPointPublicPath]) { + return; + } + entryPointPublicPathMap[entryPointPublicPath] = true; // ext will contain .js or .css const ext = extMatch[1]; - assets[ext].push({ - entryName: entryName, - path: entryPointPublicPaths - }); + assets[ext].push(entryPointPublicPath); }); } return assets; @@ -650,32 +654,30 @@ class HtmlWebpackPlugin { /** * Generate all tags script for the given file paths - * @param {Array<{ entryName: string; path: string; }>} jsAssets + * @param {Array} jsAssets * @returns {Array} */ generatedScriptTags (jsAssets) { return jsAssets.map(scriptAsset => ({ tagName: 'script', voidTag: false, - entry: scriptAsset.entryName, attributes: { - src: scriptAsset.path + src: scriptAsset } })); } /** * Generate all style tags for the given file paths - * @param {Array<{ entryName: string; path: string; }>} cssAssets + * @param {Array} cssAssets * @returns {Array} */ generateStyleTags (cssAssets) { return cssAssets.map(styleAsset => ({ tagName: 'link', voidTag: true, - entry: styleAsset.entryName, attributes: { - href: styleAsset.path, + href: styleAsset, rel: 'stylesheet' } })); @@ -879,8 +881,8 @@ class HtmlWebpackPlugin { * @param {WebpackCompilation} compilation * @param {{ publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array, + css: Array, manifest?: string, favicon?: string }} assets @@ -892,6 +894,13 @@ class HtmlWebpackPlugin { * @returns {HtmlWebpackPluginTemplateParameter} */ function templateParametersGenerator (compilation, assets, assetTags, options) { + const xhtml = options.xhtml; + assetTags.headTags.toString = function () { + return this.map((assetTagObject) => htmlTagObjectToString(assetTagObject, xhtml)).join(''); + }; + assetTags.bodyTags.toString = function () { + return this.map((assetTagObject) => htmlTagObjectToString(assetTagObject, xhtml)).join(''); + }; return { compilation: compilation, webpackConfig: compilation.options, @@ -912,7 +921,7 @@ HtmlWebpackPlugin.version = 4; /** * A static helper to get the hooks for this plugin * - * Usage: HtmlWebpackPlugin.getHook(compilation, 'HookName').tap('YourPluginName', () => { ... }); + * Usage: HtmlWebpackPlugin.getHooks(compilation).HOOK_NAME.tapAsync('YourPluginName', () => { ... }); */ HtmlWebpackPlugin.getHooks = getHtmlWebpackPluginHooks; HtmlWebpackPlugin.createHtmlTagObject = createHtmlTagObject; diff --git a/lib/hooks.js b/lib/hooks.js index 3a762e50..a3c5c837 100644 --- a/lib/hooks.js +++ b/lib/hooks.js @@ -20,8 +20,8 @@ const AsyncSeriesWaterfallHook = require('tapable').AsyncSeriesWaterfallHook; AsyncSeriesWaterfallHook<{ assets: { publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array, + css: Array, favicon?: string | undefined, manifest?: string | undefined }, diff --git a/spec/basic.spec.js b/spec/basic.spec.js index 9f910673..e27e86e8 100644 --- a/spec/basic.spec.js +++ b/spec/basic.spec.js @@ -1243,7 +1243,7 @@ describe('HtmlWebpackPlugin', () => { compiler.plugin('compilation', compilation => { HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync('HtmlWebpackPluginTest', (object, callback) => { eventFired = true; - object.assets.js.push({path: 'funky-script.js'}); + object.assets.js.push('funky-script.js'); callback(); }); }); diff --git a/spec/fixtures/template.pug b/spec/fixtures/template.pug index d4febba0..1d303ae6 100644 --- a/spec/fixtures/template.pug +++ b/spec/fixtures/template.pug @@ -6,4 +6,4 @@ html body p Some unique text each jsFile in htmlWebpackPlugin.files.js - script(src!=jsFile.path) + script(src!=jsFile) diff --git a/spec/fixtures/test.html b/spec/fixtures/test.html index 2064a5b7..3f4fd9a9 100644 --- a/spec/fixtures/test.html +++ b/spec/fixtures/test.html @@ -6,6 +6,6 @@

Some unique text

- + diff --git a/spec/fixtures/webpackconfig.html b/spec/fixtures/webpackconfig.html index a7f47f3f..ff80a2cd 100644 --- a/spec/fixtures/webpackconfig.html +++ b/spec/fixtures/webpackconfig.html @@ -6,6 +6,6 @@

Public path is <%= webpackConfig.output.publicPath %>

- diff --git a/typings.d.ts b/typings.d.ts index 8b3f7ce4..df4833d6 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -128,8 +128,8 @@ interface HtmlWebpackPluginTemplateParameter { }, files: { publicPath: string, - js: Array<{entryName: string, path: string}>, - css: Array<{entryName: string, path: string}>, + js: Array, + css: Array, manifest?: string, favicon?: string },