Skip to content

Commit dc22555

Browse files
committed
dev utils
1 parent 2adb576 commit dc22555

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const HtmlWebpackPlugin = require('html-webpack-plugin');
5+
const fs = require('fs-extra');
6+
7+
const ID = 'html-webpack-esmodules-plugin';
8+
9+
const safariFix = `(function(){var d=document;var c=d.createElement('script');if(!('noModule' in c)&&'onbeforeload' in c){var s=!1;d.addEventListener('beforeload',function(e){if(e.target===c){s=!0}else if(!e.target.hasAttribute('nomodule')||!s){return}e.preventDefault()},!0);c.type='module';c.src='.';d.head.appendChild(c);c.remove()}}())`;
10+
11+
class HtmlWebpackEsmodulesPlugin {
12+
constructor() {}
13+
14+
apply(compiler) {
15+
compiler.hooks.compilation.tap(ID, compilation => {
16+
HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(
17+
ID,
18+
({ plugin, bodyTags: body }, cb) => {
19+
const targetDir = compiler.options.output.path;
20+
// get stats, write to disk
21+
const htmlName = path.basename(plugin.options.filename);
22+
// Watch out for output files in sub directories
23+
const htmlPath = path.dirname(plugin.options.filename);
24+
const tempFilename = path.join(
25+
targetDir,
26+
htmlPath,
27+
`assets-${htmlName}.json`
28+
);
29+
30+
if (!fs.existsSync(tempFilename)) {
31+
fs.mkdirpSync(path.dirname(tempFilename));
32+
const newBody = body.filter(
33+
a => a.tagName === 'script' && a.attributes
34+
);
35+
newBody.forEach(a => (a.attributes.nomodule = ''));
36+
fs.writeFileSync(tempFilename, JSON.stringify(newBody));
37+
return cb();
38+
}
39+
40+
const legacyAssets = JSON.parse(
41+
fs.readFileSync(tempFilename, 'utf-8')
42+
);
43+
// TODO: to discuss, an improvement would be to
44+
// Inject these into the head tag together with the
45+
// Safari script.
46+
body.forEach(tag => {
47+
if (tag.tagName === 'script' && tag.attributes) {
48+
tag.attributes.type = 'module';
49+
}
50+
});
51+
52+
body.push({
53+
tagName: 'script',
54+
closeTag: true,
55+
innerHTML: safariFix,
56+
});
57+
58+
body.push(...legacyAssets);
59+
fs.removeSync(tempFilename);
60+
cb();
61+
}
62+
);
63+
64+
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tap(ID, data => {
65+
data.html = data.html.replace(/\snomodule="">/g, ' nomodule>');
66+
});
67+
});
68+
}
69+
}
70+
71+
module.exports = HtmlWebpackEsmodulesPlugin;

packages/react-dev-utils/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"getCSSModuleLocalIdent.js",
2727
"getProcessForPort.js",
2828
"globby.js",
29+
"htmlEsmodulesPlugin.js",
2930
"ignoredFiles.js",
3031
"immer.js",
3132
"InlineChunkHtmlPlugin.js",

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const getClientEnvironment = require('./env');
3131
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
3232
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
3333
const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
34+
// const HtmlWebpackEsmodulesPlugin = require('react-dev-utils/html-webpack-esmodules-plugin');
3435
// @remove-on-eject-begin
3536
const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier');
3637
// @remove-on-eject-end

0 commit comments

Comments
 (0)