-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
86 lines (75 loc) · 3.57 KB
/
index.js
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
78
79
80
81
82
83
84
85
86
const validateOptions = require('schema-utils');
const schema = require('./schema.json');
/*
Plugin modified from:
https://gist.github.com/devonChurch/c8f43d0270fc71168cdf23765043f679#file-webpack.config-js
https://gist.github.com/ScriptedAlchemy/60d0c49ce049184f6ce3e86ca351fdca
*/
/**
* Change `publicPath` at run time rather than build time for dynamic module federated containers.
* This allows builds to be environment agnostic and have `publicPath` update via the supplied run-time configuration.
* @class
*/
class DynamicContainerPathPlugin {
/**
* @param {options.iffe} immediatelyInvokedFunctionExpression - An immediately invoked function expression to get `publicPath` at runtime.
* @param {options.entry} thisApplicationsMainEntryPoint - The entry point name of the application.
*/
constructor(options) {
// validate options being passed through the plugin
validateOptions(schema, options, 'DynamicContainerPathPlugin');
// supply the custom function used to generate public path dynamically
this.options = options;
}
getInternalPublicPathVariable(module) {
/*
Strip out 'publicPath's' value '/' using webpack's internal global variable set
at build time ('__webpack_require__.p')
Note: we cannot simply declare '__webpack_require__.p' because it will not have
the appropriate context, but we can tap into 'PublicPathRuntimeModule' hooks to get it
'getGeneratedCode()'
https://github.com/webpack/webpack/blob/afc9b2fcf9bef0831640b3ebb02b73068ba18e17/types.d.ts#L8989
https://github.com/webpack/webpack/blob/af52c8f0457b1055098d6b7b545b257404d06c93/lib/RuntimeModule.js#L171-L178
*/
const [publicPath] = module.getGeneratedCode().split('=');
return [publicPath];
}
setNewPublicPathValueFromRuntime(module, publicPath, chunk) {
/*
By default, 'module._cachedGeneratedCode' is equal to '__webpack_require__.p = "/";' at build time
Now, we set 'publicPath's' internal variable '__webpack_require__.p' from 'getInternalPublicPathVariable'
equal to an anonymous function that will dynamically set the 'host' 'publicPath' at runtime
*/
module._cachedGeneratedCode = `${publicPath}=${this.options.iife}('${this.options.entry}', '${chunk.name}');`;
return module;
}
changePublicPath(module, chunk) {
console.log(`Changing static publicPath for chunk: ${chunk.name}`);
const publicPath = this.getInternalPublicPathVariable(module);
return this.setNewPublicPathValueFromRuntime(module, publicPath, chunk);
}
apply(compiler) {
/*
Tap into execution before finishing the compilation.
https://webpack.js.org/api/compiler-hooks/#make
*/
compiler.hooks.make.tap('MutateRuntime', compilation => {
/*
Compilation hook used by Module Federation author for Remote PublicPath Modification
https://gist.github.com/ScriptedAlchemy/60d0c49ce049184f6ce3e86ca351fdca#file-mutateruntimeplugin-js-L23
Note: 'runtimeModule' hook is not yet on webpack docs, but mentioned as a migration footnote:
https://webpack.js.org/blog/2020-10-10-webpack-5-release/#runtime-modules
*/
compilation.hooks.runtimeModule.tap('MutateRuntime', (module, chunk) => {
/*
The hook to get the public path ('__webpack_require__.p')
https://github.com/webpack/webpack/blob/master/lib/runtime/PublicPathRuntimeModule.js
*/
module.constructor.name === 'PublicPathRuntimeModule'
? this.changePublicPath(module, chunk)
: false;
});
});
}
}
module.exports = DynamicContainerPathPlugin;