Module Federation with Webpacker/Rails host resulting in ScriptLoadError
See original GitHub issueWe’ve been successfully testing Module Federation with apps that use React and Webpack directly but recently ran into the need to integrate an app that uses Webpack through Webpacker and for some reason we’re running into ScriptLoadError
issues anytime we try to load the remote-entry that comes from the Rails/Webpacker side.
On the Rails/Webpacker remote the remote-entry.js
returns 200 but the issue appears to occur at evaluation time:
We’ve also noticed that the remote-entry.js output from Webpacker/Rails-side is significantly smaller (in code) than the one we get from our
The Rails Webpacker remote side is using Webpack 5.51.1. Our host is using Webpack 5.50.0.
Remote Webpack/Rails app
Compile Webpack config output
{
mode: 'development',
output: {
filename: 'js/[name].js',
chunkFilename: 'js/[name].chunk.js',
hotUpdateChunkFilename: 'js/[id].[fullhash].hot-update.js',
path: '<removed>/webpacker-module-federation/public/packs',
publicPath: '/packs/'
},
entry: {
application: '<removed>/webpacker-module-federation/app/javascript/packs/application.js',
hello_react: '<removed>/webpacker-module-federation/app/javascript/packs/hello_react.jsx'
},
resolve: {
extensions: [ '.js', '.jsx', '.mjs', '.ts', '.tsx', '.coffee' ],
modules: [
'<removed>/webpacker-module-federation/app/javascript',
'node_modules'
],
plugins: [ [Object] ]
},
plugins: [
EnvironmentPlugin { keys: [Array], defaultValues: [Object] },
WebpackAssetsManifest {
hooks: [Object],
options: [Object],
assets: [Object: null prototype] {},
assetNames: Map(0) {},
currentAsset: null,
compiler: null,
[Symbol(isMerging)]: false
},
ModuleFederationPlugin { _options: [Object] }
],
resolveLoader: { modules: [ 'node_modules' ], plugins: [ [Object] ] },
optimization: { splitChunks: { chunks: 'all' }, runtimeChunk: 'single' },
module: {
strictExportPresence: true,
rules: [ [Object], [Object], [Object] ]
},
devtool: 'cheap-module-source-map',
stats: {
colors: true,
entrypoints: false,
errorDetails: true,
modules: false,
moduleTrace: false
},
devServer: {
devMiddleware: { publicPath: '/packs/' },
compress: true,
allowedHosts: 'all',
host: 'localhost',
port: 3035,
https: false,
hot: false,
liveReload: true,
historyApiFallback: { disableDotRule: true },
headers: { 'Access-Control-Allow-Origin': '*' },
static: {
publicPath: '<removed>/webpacker-module-federation/public/packs',
watch: [Object]
},
client: { overlay: true }
}
}
Here’s the generated remote-entry.js
from that same remote:
"use strict";
var demo;
(self["webpackChunkwebpacker_module_federation"] = self["webpackChunkwebpacker_module_federation"] || []).push([["demo"],{
/***/ "webpack/container/entry/demo":
/*!***********************!*\
!*** container entry ***!
\***********************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
var moduleMap = {
"./app": function() {
return Promise.all([__webpack_require__.e("vendors-node_modules_prop-types_index_js"), __webpack_require__.e("webpack_sharing_consume_default_react-dom_react-dom-webpack_sharing_consume_default_react_react"), __webpack_require__.e("app_javascript_packs_hello_react_jsx")]).then(function() { return function() { return (__webpack_require__(/*! ./app/javascript/packs/hello_react */ "./app/javascript/packs/hello_react.jsx")); }; });
}
};
var get = function(module, getScope) {
__webpack_require__.R = getScope;
getScope = (
__webpack_require__.o(moduleMap, module)
? moduleMap[module]()
: Promise.resolve().then(function() {
throw new Error('Module "' + module + '" does not exist in container.');
})
);
__webpack_require__.R = undefined;
return getScope;
};
var init = function(shareScope, initScope) {
if (!__webpack_require__.S) return;
var oldScope = __webpack_require__.S["default"];
var name = "default"
if(oldScope && oldScope !== shareScope) throw new Error("Container initialization failed as it has already been initialized with a different share scope");
__webpack_require__.S[name] = shareScope;
return __webpack_require__.I(name, initScope);
};
// This exports getters to disallow modifications
__webpack_require__.d(exports, {
get: function() { return get; },
init: function() { return init; }
});
/***/ })
},
/******/ function(__webpack_require__) { // webpackRuntimeModules
/******/ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId); }
/******/ __webpack_require__.O(0, ["vendors-node_modules_react-dom_index_js-node_modules_react_index_js-node_modules_webpack-dev--3a93d3","webpack_sharing_consume_default_react_react-webpack_sharing_provide_default_react-dom-webpack-f6baa5"], function() { return __webpack_exec__("./node_modules/webpack-dev-server/client/index.js?protocol=ws%3A&hostname=localhost&port=3035&pathname=%2Fws&logging=info"), __webpack_exec__("webpack/container/entry/demo"); });
/******/ var __webpack_exports__ = __webpack_require__.O();
/******/ demo = __webpack_exports__;
/******/ }
]);
//# sourceMappingURL=remote-entry.js.map
Host
Module config
new ModuleFederationPlugin({
name: "ilx",
remotes: {
demo: `demo@http://localhost:3035/packs/remote-entry.js`,
},
shared: {
react: {
eager: true,
singleton: true,
},
"react-dom": {
eager: true,
singleton: true,
},
},
}),
We’re aware that it’s strange that everything from the webpack-dev-server compiled via Webpacker is hosted at /packs/
but that’s the convention. We’re obviously fairly confused by these issues and could use any guidance you might have. Thanks.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:3
- Comments:22 (11 by maintainers)
Top GitHub Comments
Nah I think what you’ve got should be fine
@ScriptedAlchemy I celebrated too quickly. Unsurprisingly setting
publicPath: 'auto'
led to the Rails Webpacker setup no longer working appropriately. Likely because the particular location of packs inapp/javascripts/packs/
within Rails isn’t compatible with that setting.So the remote entry works from the host but the remote app starts having 404s when attempting to load assets. We need an explicit solution to this that doesn’t rely on whatever
auto
does internally.I’m prepared to schedule a group call (with my co-worker @meglkts) with you soon but I think there’s a large missed opportunity in appropriate error handling within the logic that fetches chunks. Is there anything we can do to raise exceptions at the appropriate level when individual chunks result in 404s?