Skip to content

Commit e88809f

Browse files
authored
Inline the webpack runtime chunk (facebook#5058)
1 parent 78f0a96 commit e88809f

File tree

4 files changed

+97
-2
lines changed

4 files changed

+97
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
'use strict';
9+
10+
class InlineChunkHtmlPlugin {
11+
constructor(htmlWebpackPlugin, tests) {
12+
this.htmlWebpackPlugin = htmlWebpackPlugin;
13+
this.tests = tests;
14+
}
15+
16+
getInlinedTag(publicPath, assets, tag) {
17+
if (tag.tagName !== 'script' || !(tag.attributes && tag.attributes.src)) {
18+
return tag;
19+
}
20+
const scriptName = tag.attributes.src.replace(publicPath, '');
21+
if (!this.tests.some(test => scriptName.match(test))) {
22+
return tag;
23+
}
24+
const asset = assets[scriptName];
25+
if (asset == null) {
26+
return tag;
27+
}
28+
return { tagName: 'script', innerHTML: asset.source(), closeTag: true };
29+
}
30+
31+
apply(compiler) {
32+
let publicPath = compiler.options.output.publicPath;
33+
if (!publicPath.endsWith('/')) {
34+
publicPath += '/';
35+
}
36+
37+
compiler.hooks.compilation.tap('InlineChunkHtmlPlugin', compilation => {
38+
const tagFunction = tag =>
39+
this.getInlinedTag(publicPath, compilation.assets, tag);
40+
41+
const hooks = this.htmlWebpackPlugin.getHooks(compilation);
42+
hooks.alterAssetTagGroups.tap('InlineChunkHtmlPlugin', assets => {
43+
assets.headTags = assets.headTags.map(tagFunction);
44+
assets.bodyTags = assets.bodyTags.map(tagFunction);
45+
});
46+
hooks.afterEmit.tap('InlineChunkHtmlPlugin', () => {
47+
Object.keys(compilation.assets).forEach(assetName => {
48+
if (this.tests.some(test => assetName.match(test))) {
49+
delete compilation.assets[assetName];
50+
}
51+
});
52+
});
53+
});
54+
}
55+
}
56+
57+
module.exports = InlineChunkHtmlPlugin;

packages/react-dev-utils/README.md

+35-2
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ If you don’t use Create React App, or if you [ejected](https://github.com/face
1818

1919
There is no single entry point. You can only import individual top-level modules.
2020

21-
#### `new InterpolateHtmlPlugin(replacements: {[key:string]: string})`
21+
#### `new InterpolateHtmlPlugin(htmlWebpackPlugin: HtmlWebpackPlugin, replacements: {[key:string]: string})`
2222

2323
This Webpack plugin lets us interpolate custom variables into `index.html`.<br>
2424
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).
2525

2626
```js
2727
var path = require('path');
28-
var HtmlWebpackPlugin = require('html-dev-plugin');
28+
var HtmlWebpackPlugin = require('html-webpack-plugin');
2929
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
3030

3131
// Webpack config
@@ -56,6 +56,39 @@ module.exports = {
5656
};
5757
```
5858

59+
#### `new InlineChunkHtmlPlugin(htmlWebpackPlugin: HtmlWebpackPlugin, tests: Regex[])`
60+
61+
This Webpack plugin inlines script chunks into `index.html`.<br>
62+
It works in tandem with [HtmlWebpackPlugin](https://github.com/ampedandwired/html-webpack-plugin) 4.x.
63+
64+
```js
65+
var path = require('path');
66+
var HtmlWebpackPlugin = require('html-webpack-plugin');
67+
var InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
68+
69+
// Webpack config
70+
var publicUrl = '/my-custom-url';
71+
72+
module.exports = {
73+
output: {
74+
// ...
75+
publicPath: publicUrl + '/',
76+
},
77+
// ...
78+
plugins: [
79+
// Generates an `index.html` file with the <script> injected.
80+
new HtmlWebpackPlugin({
81+
inject: true,
82+
template: path.resolve('public/index.html'),
83+
}),
84+
// Inlines chunks with `runtime` in the name
85+
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime/]),
86+
// ...
87+
],
88+
// ...
89+
};
90+
```
91+
5992
#### `new ModuleScopePlugin(appSrc: string | string[], allowedFiles?: string[])`
6093

6194
This Webpack plugin ensures that relative imports from app's source directories don't reach outside of it.

packages/react-dev-utils/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"getCSSModuleLocalIdent.js",
2525
"getProcessForPort.js",
2626
"ignoredFiles.js",
27+
"InlineChunkHtmlPlugin.js",
2728
"inquirer.js",
2829
"InterpolateHtmlPlugin.js",
2930
"launchEditor.js",

packages/react-scripts/config/webpack.config.prod.js

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const autoprefixer = require('autoprefixer');
1212
const path = require('path');
1313
const webpack = require('webpack');
1414
const HtmlWebpackPlugin = require('html-webpack-plugin');
15+
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
1516
const TerserPlugin = require('terser-webpack-plugin');
1617
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
1718
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
@@ -433,6 +434,9 @@ module.exports = {
433434
minifyURLs: true,
434435
},
435436
}),
437+
// Inlines the webpack runtime script. This script is too small to warrant
438+
// a network request.
439+
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
436440
// Makes some environment variables available in index.html.
437441
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
438442
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">

0 commit comments

Comments
 (0)