diff --git a/.eslintignore b/.eslintignore index ea9b8e84..ea0974bf 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,3 +2,4 @@ lib/ coverage/ build/ dist/ +example/polyfill/polyfill.js diff --git a/README.md b/README.md index 2b0a3908..4645c051 100644 --- a/README.md +++ b/README.md @@ -136,14 +136,20 @@ Type: `string`, default: `js` Can be set to `css` to create a `link`-tag instead of a `script`-tag. -## Examples +#### `attributes` -### Add a DLL file from `webpack.DllPlugin` +Type: `object`, default: `{}` -Note: Remember to build the DLL file in a separate build. +Extra attributes to be added to the generated tag. Useful to for instance add +`nomodule` to a polyfill script. The `attributes` object uses the key as the +name of the attribute, and the value as the value of it. If value is simply +`true` no value will be added. -See [example](example/dll/) for an example of how to set it up. You can run it -by cloning this repo, running `yarn` followed by `yarn run example`. +An example of this is included in the repository. + +Currently only supports script tags. + +## Examples When adding assets, it's added to the start of the array, so when `html-webpack-plugin` injects the assets, it's before other assets. If you @@ -151,6 +157,13 @@ depend on some order for the assets beyond that, and ordering the plugins doesn't cut it, you'll have to create a custom template and add the tags yourself. +### Add a DLL file from `webpack.DllPlugin` + +Note: Remember to build the DLL file in a separate build. + +See [example](example/dll/) for an example of how to set it up. You can run it +by cloning this repo, running `yarn` followed by `yarn run example`. + #### Webpack config ```js @@ -201,6 +214,38 @@ const webpackConfig = { }; ``` +### Add a polyfill file you have locally + +See [example](example/polyfill/) for an example of how to use it. You can run it +by cloning this repo, running `yarn` followed by `yarn run example`. + +#### Webpack config + +```js +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const AddAssetHtmlPlugin = require('../../'); + +const webpackConfig = { + entry: 'entry.js', + devtool: '#source-map', + mode: 'development', + output: { + path: 'dist', + filename: 'index_bundle.js', + }, + plugins: [ + new HtmlWebpackPlugin(), + new AddAssetHtmlPlugin({ + filepath: path.resolve(__dirname, './polyfill.js'), + attributes: { + nomodule: true, + }, + }), + ], +}; +``` + [npm-url]: https://npmjs.org/package/add-asset-html-webpack-plugin [npm-image]: https://img.shields.io/npm/v/add-asset-html-webpack-plugin.svg [travis-url]: https://travis-ci.org/SimenB/add-asset-html-webpack-plugin diff --git a/example/polyfill/entry.js b/example/polyfill/entry.js new file mode 100644 index 00000000..b403638c --- /dev/null +++ b/example/polyfill/entry.js @@ -0,0 +1 @@ +[].someWeirdFunction(); diff --git a/example/polyfill/polyfill.js b/example/polyfill/polyfill.js new file mode 100644 index 00000000..73e669f2 --- /dev/null +++ b/example/polyfill/polyfill.js @@ -0,0 +1,5 @@ +// this file is a fake polyfill file + +Array.prototype.someWeirdFunction = function() { + console.log('hello!'); +}; diff --git a/example/polyfill/webpack.config.js b/example/polyfill/webpack.config.js new file mode 100644 index 00000000..299b816b --- /dev/null +++ b/example/polyfill/webpack.config.js @@ -0,0 +1,24 @@ +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const AddAssetHtmlPlugin = require('../../'); + +module.exports = { + // Normally CWD + context: __dirname, + entry: path.join(__dirname, 'entry.js'), + devtool: '#source-map', + mode: 'development', + output: { + path: path.join(__dirname, 'dist'), + filename: 'index_bundle.js', + }, + plugins: [ + new HtmlWebpackPlugin(), + new AddAssetHtmlPlugin({ + filepath: path.resolve(__dirname, './polyfill.js'), + attributes: { + nomodule: true, + }, + }), + ], +}; diff --git a/package.json b/package.json index bf449a3a..739ebe79 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,9 @@ "postbuild": "prettier lib/* --write", "cover": "jest --coverage", "preexample": "npm run clean && npm run build", - "example": "npm run example:dll", + "example": "npm run example:dll && npm run example:polyfill", "example:dll": "webpack --config example/dll/webpack.config.dll.js && webpack --config example/dll/webpack.config.js", + "example:polyfill": "webpack --config example/polyfill/webpack.config.js", "lint": "eslint .", "update-license": "licensor --width 72", "build-and-update-license": "npm run build && npm run update-license", diff --git a/src/index.js b/src/index.js index bce824d6..1680e230 100644 --- a/src/index.js +++ b/src/index.js @@ -12,25 +12,44 @@ import { export default class AddAssetHtmlPlugin { constructor(assets = []) { - this.assets = Array.isArray(assets) - ? assets.slice().reverse() - : [assets].filter(Boolean); + this.assets = Array.isArray(assets) ? assets.slice().reverse() : [assets]; + this.addedAssets = []; } /* istanbul ignore next: this would be integration tests */ apply(compiler) { compiler.hooks.compilation.tap('AddAssetHtmlPlugin', compilation => { - let hook; + let beforeGenerationHook; + let alterAssetTagsHook; if (HtmlWebpackPlugin.version === 4) { - hook = HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration; + const hooks = HtmlWebpackPlugin.getHooks(compilation); + + beforeGenerationHook = hooks.beforeAssetTagGeneration; + alterAssetTagsHook = hooks.alterAssetTags; } else { - hook = compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration; + const { hooks } = compilation; + + beforeGenerationHook = hooks.htmlWebpackPluginBeforeHtmlGeneration; + alterAssetTagsHook = hooks.htmlWebpackPluginAlterAssetTags; } - hook.tapPromise('AddAssetHtmlPlugin', htmlPluginData => + beforeGenerationHook.tapPromise('AddAssetHtmlPlugin', htmlPluginData => this.addAllAssetsToCompilation(compilation, htmlPluginData), ); + + alterAssetTagsHook.tap('AddAssetHtmlPlugin', htmlPluginData => { + const { assetTags } = htmlPluginData; + if (assetTags) { + this.alterAssetsAttributes(assetTags); + } else { + this.alterAssetsAttributes({ + scripts: htmlPluginData.body + .concat(htmlPluginData.head) + .filter(({ tagName }) => tagName === 'script'), + }); + } + }); }); } @@ -42,7 +61,19 @@ export default class AddAssetHtmlPlugin { return htmlPluginData; } - // eslint-disable-next-line class-methods-use-this + alterAssetsAttributes(assetTags) { + this.assets + .filter( + asset => asset.attributes && Object.keys(asset.attributes).length > 0, + ) + .forEach(asset => { + assetTags.scripts + .map(({ attributes }) => attributes) + .filter(attrs => this.addedAssets.includes(attrs.src)) + .forEach(attrs => Object.assign(attrs, asset.attributes)); + }); + } + async addFileToAssets( compilation, htmlPluginData, @@ -96,6 +127,8 @@ export default class AddAssetHtmlPlugin { resolveOutput(compilation, addedFilename, outputPath); + this.addedAssets.push(resolvedPath); + if (includeRelatedFiles) { const relatedFiles = await globby(`${filepath}.*`); await Promise.all( diff --git a/test.js b/test.js index 5388e942..305a7456 100644 --- a/test.js +++ b/test.js @@ -241,6 +241,40 @@ test('filter option should include some files with string option', async () => { expect(pluginData.assets).toMatchSnapshot(); }); +test('filter option should include some files with string option', async () => { + const pluginData = { + scripts: [ + { + tagName: 'script', + voidTag: false, + attributes: { src: 'polyfill.js' }, + }, + { + tagName: 'script', + voidTag: false, + attributes: { src: 'index_bundle.js' }, + }, + ], + styles: [], + meta: [], + }; + const plugin = new AddAssetHtmlPlugin({ + filepath: path.join(__dirname, 'my-file.js'), + files: 'index.*', + attributes: { nomodule: true }, + }); + + plugin.addedAssets.push('polyfill.js'); + + await plugin.alterAssetsAttributes(pluginData); + + expect(pluginData.scripts).toContainEqual({ + tagName: 'script', + voidTag: false, + attributes: { src: 'polyfill.js', nomodule: true }, + }); +}); + test('use globby to find multi file', async () => { const assets = [{ filepath: './src/*.js' }]; const ret = await handleUrl(assets);