From 6b87c916de5365f5528e999d4ff84398ffb5a9b3 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Fri, 21 Sep 2018 12:19:14 -0400 Subject: [PATCH] Inline the webpack runtime chunk --- .../react-dev-utils/InlineChunkHtmlPlugin.js | 57 +++++++++++++++++++ packages/react-dev-utils/README.md | 37 +++++++++++- packages/react-dev-utils/package.json | 1 + .../config/webpack.config.prod.js | 4 ++ 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 packages/react-dev-utils/InlineChunkHtmlPlugin.js diff --git a/packages/react-dev-utils/InlineChunkHtmlPlugin.js b/packages/react-dev-utils/InlineChunkHtmlPlugin.js new file mode 100644 index 00000000000..8f0cd45c717 --- /dev/null +++ b/packages/react-dev-utils/InlineChunkHtmlPlugin.js @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +class InlineChunkHtmlPlugin { + constructor(htmlWebpackPlugin, tests) { + this.htmlWebpackPlugin = htmlWebpackPlugin; + this.tests = tests; + } + + getInlinedTag(publicPath, assets, tag) { + if (tag.tagName !== 'script' || !(tag.attributes && tag.attributes.src)) { + return tag; + } + const scriptName = tag.attributes.src.replace(publicPath, ''); + if (!this.tests.some(test => scriptName.match(test))) { + return tag; + } + const asset = assets[scriptName]; + if (asset == null) { + return tag; + } + return { tagName: 'script', innerHTML: asset.source(), closeTag: true }; + } + + apply(compiler) { + let publicPath = compiler.options.output.publicPath; + if (!publicPath.endsWith('/')) { + publicPath += '/'; + } + + compiler.hooks.compilation.tap('InlineChunkHtmlPlugin', compilation => { + const tagFunction = tag => + this.getInlinedTag(publicPath, compilation.assets, tag); + + const hooks = this.htmlWebpackPlugin.getHooks(compilation); + hooks.alterAssetTagGroups.tap('InlineChunkHtmlPlugin', assets => { + assets.headTags = assets.headTags.map(tagFunction); + assets.bodyTags = assets.bodyTags.map(tagFunction); + }); + hooks.afterEmit.tap('InlineChunkHtmlPlugin', () => { + Object.keys(compilation.assets).forEach(assetName => { + if (this.tests.some(test => assetName.match(test))) { + delete compilation.assets[assetName]; + } + }); + }); + }); + } +} + +module.exports = InlineChunkHtmlPlugin; diff --git a/packages/react-dev-utils/README.md b/packages/react-dev-utils/README.md index 53c73bfc502..d615f66b5cf 100644 --- a/packages/react-dev-utils/README.md +++ b/packages/react-dev-utils/README.md @@ -18,14 +18,14 @@ If you don’t use Create React App, or if you [ejected](https://github.com/face There is no single entry point. You can only import individual top-level modules. -#### `new InterpolateHtmlPlugin(replacements: {[key:string]: string})` +#### `new InterpolateHtmlPlugin(htmlWebpackPlugin: HtmlWebpackPlugin, replacements: {[key:string]: string})` This Webpack plugin lets us interpolate custom variables into `index.html`.
It works in tandem with [HtmlWebpackPlugin](https://github.com/ampedandwired/html-webpack-plugin) 2.x via its [events](https://github.com/ampedandwired/html-webpack-plugin#events). ```js var path = require('path'); -var HtmlWebpackPlugin = require('html-dev-plugin'); +var HtmlWebpackPlugin = require('html-webpack-plugin'); var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); // Webpack config @@ -56,6 +56,39 @@ module.exports = { }; ``` +#### `new InlineChunkHtmlPlugin(htmlWebpackPlugin: HtmlWebpackPlugin, tests: Regex[])` + +This Webpack plugin inlines script chunks into `index.html`.
+It works in tandem with [HtmlWebpackPlugin](https://github.com/ampedandwired/html-webpack-plugin) 4.x. + +```js +var path = require('path'); +var HtmlWebpackPlugin = require('html-webpack-plugin'); +var InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); + +// Webpack config +var publicUrl = '/my-custom-url'; + +module.exports = { + output: { + // ... + publicPath: publicUrl + '/', + }, + // ... + plugins: [ + // Generates an `index.html` file with the