makeRefreshRuntimeModule.js
3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
const { getRefreshGlobalScope } = require('../globals');
const getRefreshGlobal = require('./getRefreshGlobal');
/**
* Makes a runtime module to intercept module execution for React Refresh.
* @param {import('webpack')} webpack The Webpack exports.
* @returns {ReactRefreshRuntimeModule} The runtime module class.
*/
function makeRefreshRuntimeModule(webpack) {
return class ReactRefreshRuntimeModule extends webpack.RuntimeModule {
constructor() {
// Second argument is the `stage` for this runtime module -
// we'll use the same stage as Webpack's HMR runtime module for safety.
super('react refresh', webpack.RuntimeModule.STAGE_BASIC);
}
/**
* @returns {string} runtime code
*/
generate() {
const { runtimeTemplate } = this.compilation;
const refreshGlobal = getRefreshGlobalScope(webpack.RuntimeGlobals);
return webpack.Template.asString([
`${webpack.RuntimeGlobals.interceptModuleExecution}.push(${runtimeTemplate.basicFunction(
'options',
[
`${
runtimeTemplate.supportsConst() ? 'const' : 'var'
} originalFactory = options.factory;`,
`options.factory = function (moduleObject, moduleExports, webpackRequire) {`,
webpack.Template.indent([
`${refreshGlobal}.setup(options.id);`,
'try {',
webpack.Template.indent(
'originalFactory.call(this, moduleObject, moduleExports, webpackRequire);'
),
'} finally {',
webpack.Template.indent([
`if (typeof Promise !== 'undefined' && moduleObject.exports instanceof Promise) {`,
webpack.Template.indent([
// The exports of the module are re-assigned -
// this ensures anything coming after us would wait for `cleanup` to fire.
// This is particularly important because `cleanup` restores the refresh global,
// maintaining consistency for mutable variables like `moduleId`.
// This `.then` clause is a ponyfill of the `Promise.finally` API -
// it is only part of the spec after ES2018,
// but Webpack's top level await implementation support engines down to ES2015.
'options.module.exports = options.module.exports.then(',
webpack.Template.indent([
`${runtimeTemplate.basicFunction('result', [
`${refreshGlobal}.cleanup(options.id);`,
'return result;',
])},`,
runtimeTemplate.basicFunction('reason', [
`${refreshGlobal}.cleanup(options.id);`,
'return Promise.reject(reason);',
]),
]),
`);`,
]),
'} else {',
webpack.Template.indent(`${refreshGlobal}.cleanup(options.id)`),
'}',
]),
'}',
]),
`};`,
]
)})`,
'',
getRefreshGlobal(webpack.Template, webpack.RuntimeGlobals, runtimeTemplate),
]);
}
};
}
module.exports = makeRefreshRuntimeModule;