Description
We'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.