... /** * Allows static builds to change their `publicName` dynamically at run time rather * than build time. This allows builds to be environment agnostic, where we can * change from Staging, UAT, to Production with the same artefact and have the * `publicName` update accordingly via some run time configuration. * @class */ class DynamicPublicPathPlugin { /** * The Webpack hook to apply our plugin. * @parem {Object} compiler - The Webpack compiler. */ apply(compiler) { compiler.hooks.make.tap("MutateRuntime", (compilation) => { compilation.hooks.runtimeModule.tap("MutateRuntime", (module, chunk) => { const isPublicPathRuntimeModule = module.constructor.name === "PublicPathRuntimeModule"; if (!isPublicPathRuntimeModule) { return; } console.log(`* Update "${chunk.name}" dynamic public path`); // We extract the variable "key" (the namespace to left of the equals sign) // and leave the rest behind as we are going to build our own new value // and assign it back to the variable. const [key] = module.getGeneratedCode().split("="); // Swap out the old static string value for a function that will run in // the browser session and create a public path based on the current // configuration. // // We create the `publicPath` from the "environment.config.json" and // "location.config.json" configuration files that are saved as global // variables in the browser `__ENVIRONEMENT__` and `__LOCATION__`. module._cachedGeneratedCode = `${key}=(function() { const { __LOCATION__, __ENVIRONEMENT__ } = window; const { href } = __LOCATION__.shell[__ENVIRONEMENT__]; const publicPath = href + "/"; return publicPath; })();` return module; }); }); } } ... module.exports = async (_, args) => { ... return { ... plugins: [ new ModuleFederationPlugin({ ... }), new DynamicPublicPathPlugin(), ... ] ... };