Skip to content

Commit

Permalink
feat(enhanced): make hoisted runtime the default implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ScriptedAlchemy committed Jan 21, 2025
1 parent 3d83f9d commit 3fbece2
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 790 deletions.
3 changes: 0 additions & 3 deletions apps/modernjs/modern.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ export default defineConfig({
requiredVersion: '^18.3.1',
},
},
experiments: {
federationRuntime: 'hoisted',
},
dataPrefetch: true,
}) as any,
]);
Expand Down
2 changes: 2 additions & 0 deletions apps/next-app-router-4000/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
NEXT_PRIVATE_LOCAL_WEBPACK=true
NODE_OPTIONS="--experimental-vm-modules"
2 changes: 2 additions & 0 deletions apps/next-app-router-4001/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
NEXT_PRIVATE_LOCAL_WEBPACK=true
NODE_OPTIONS="--experimental-vm-modules"
18 changes: 2 additions & 16 deletions packages/enhanced/src/lib/container/ContainerEntryModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,8 @@ class ContainerEntryModule extends Module {
) as unknown as Dependency,
);

if (!this._experiments?.federationRuntime) {
this.addDependency(new EntryDependency(this._injectRuntimeEntry));
}
this.addDependency(new EntryDependency(this._injectRuntimeEntry));

callback();
}

Expand Down Expand Up @@ -272,18 +271,6 @@ class ContainerEntryModule extends Module {
)}`,
);
}
const initRuntimeDep = this.dependencies[1];
// no runtime module getter needed if runtime is hoisted
const initRuntimeModuleGetter = this._experiments?.federationRuntime
? ''
: runtimeTemplate.moduleRaw({
module: moduleGraph.getModule(initRuntimeDep),
chunkGraph,
// @ts-expect-error flaky type definition for Dependency
request: initRuntimeDep.userRequest,
weak: false,
runtimeRequirements,
});
const federationGlobal = getFederationGlobalScope(
RuntimeGlobals || ({} as typeof RuntimeGlobals),
);
Expand Down Expand Up @@ -326,7 +313,6 @@ class ContainerEntryModule extends Module {
],
)};`,
this._dataPrefetch ? PrefetchPlugin.setRemoteIdentifier() : '',
`${initRuntimeModuleGetter}`,
this._dataPrefetch ? PrefetchPlugin.removeRemoteIdentifier() : '',
'// This exports getters to disallow modifications',
`${RuntimeGlobals.definePropertyGetters}(exports, {`,
Expand Down
6 changes: 4 additions & 2 deletions packages/enhanced/src/lib/container/ModuleFederationPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,10 @@ class ModuleFederationPlugin implements WebpackPluginInstance {
}).apply(compiler);
}

if (options.experiments?.federationRuntime) {
new FederationModulesPlugin().apply(compiler);
// federation hooks
new FederationModulesPlugin().apply(compiler);

if (options.experiments?.asyncStartup) {
new StartupChunkDependenciesPlugin({
asyncChunkLoading: true,
}).apply(compiler);
Expand Down
132 changes: 52 additions & 80 deletions packages/enhanced/src/lib/container/runtime/FederationRuntimePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,9 @@ const BundlerRuntimePath = require.resolve(
const RuntimePath = require.resolve('@module-federation/runtime', {
paths: [RuntimeToolsPath],
});
const EmbeddedRuntimePath = require.resolve(
'@module-federation/runtime/embedded',
{
paths: [RuntimeToolsPath],
},
);
const EmbeddedRuntimePath = require.resolve('@module-federation/runtime-core', {
paths: [RuntimeToolsPath],
});

const federationGlobal = getFederationGlobalScope(RuntimeGlobals);

Expand Down Expand Up @@ -167,6 +164,7 @@ class FederationRuntimePlugin {
);
return path.join(TEMP_DIR, `entry.${hash}.js`);
}

getFilePath(compiler: Compiler) {
if (this.entryFilePath) {
return this.entryFilePath;
Expand Down Expand Up @@ -195,6 +193,7 @@ class FederationRuntimePlugin {
}
return this.entryFilePath;
}

ensureFile(compiler: Compiler) {
if (!this.options) {
return;
Expand Down Expand Up @@ -237,61 +236,38 @@ class FederationRuntimePlugin {
this.ensureFile(compiler);
}

//if using runtime experiment, use the new include method else patch entry
if (this.options?.experiments?.federationRuntime) {
compiler.hooks.thisCompilation.tap(
this.constructor.name,
(compilation: Compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
FederationRuntimeDependency,
normalModuleFactory,
);
compilation.dependencyTemplates.set(
FederationRuntimeDependency,
new ModuleDependency.Template(),
);
},
);
compiler.hooks.make.tapAsync(
this.constructor.name,
(compilation: Compilation, callback) => {
const federationRuntimeDependency = this.getDependency(compiler);
const hooks =
FederationModulesPlugin.getCompilationHooks(compilation);
compilation.addInclude(
compiler.context,
federationRuntimeDependency,
{ name: undefined },
(err, module) => {
if (err) {
return callback(err);
}
hooks.addFederationRuntimeModule.call(
federationRuntimeDependency,
);
callback();
},
);
},
);
} else {
const entryFilePath = this.getFilePath(compiler);
modifyEntry({
compiler,
prependEntry: (entry: Record<string, EntryDescription>) => {
Object.keys(entry).forEach((entryName) => {
const entryItem = entry[entryName];
if (!entryItem.import) {
// TODO: maybe set this variable as constant is better https://github.com/webpack/webpack/blob/main/lib/config/defaults.js#L176
entryItem.import = ['./src'];
}
if (!entryItem.import.includes(entryFilePath)) {
entryItem.import.unshift(entryFilePath);
compiler.hooks.thisCompilation.tap(
this.constructor.name,
(compilation: Compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
FederationRuntimeDependency,
normalModuleFactory,
);
compilation.dependencyTemplates.set(
FederationRuntimeDependency,
new ModuleDependency.Template(),
);
},
);
compiler.hooks.make.tapAsync(
this.constructor.name,
(compilation: Compilation, callback) => {
const federationRuntimeDependency = this.getDependency(compiler);
const hooks = FederationModulesPlugin.getCompilationHooks(compilation);
compilation.addInclude(
compiler.context,
federationRuntimeDependency,
{ name: undefined },
(err, module) => {
if (err) {
return callback(err);
}
});
},
});
}
hooks.addFederationRuntimeModule.call(federationRuntimeDependency);
callback();
},
);
},
);
}

injectRuntime(compiler: Compiler) {
Expand Down Expand Up @@ -360,14 +336,12 @@ class FederationRuntimePlugin {

setRuntimeAlias(compiler: Compiler) {
const { experiments, implementation } = this.options || {};
const isHoisted = experiments?.federationRuntime === 'hoisted';
let runtimePath = isHoisted ? EmbeddedRuntimePath : RuntimePath;
let runtimePath = EmbeddedRuntimePath;

if (implementation) {
runtimePath = require.resolve(
`@module-federation/runtime${isHoisted ? '/embedded' : ''}`,
{ paths: [implementation] },
);
runtimePath = require.resolve(`@module-federation/runtime/embedded`, {
paths: [implementation],
});
}

const alias: any = compiler.options.resolve.alias || {};
Expand Down Expand Up @@ -432,24 +406,22 @@ class FederationRuntimePlugin {
);
}

if (this.options?.experiments?.federationRuntime === 'hoisted') {
new EmbedFederationRuntimePlugin().apply(compiler);
new EmbedFederationRuntimePlugin().apply(compiler);

new HoistContainerReferences().apply(compiler);
new HoistContainerReferences().apply(compiler);

new compiler.webpack.NormalModuleReplacementPlugin(
/@module-federation\/runtime/,
(resolveData) => {
if (/webpack-bundler-runtime/.test(resolveData.contextInfo.issuer)) {
resolveData.request = RuntimePath;
new compiler.webpack.NormalModuleReplacementPlugin(
/@module-federation\/runtime/,
(resolveData) => {
if (/webpack-bundler-runtime/.test(resolveData.contextInfo.issuer)) {
resolveData.request = RuntimePath;

if (resolveData.createData) {
resolveData.createData.request = resolveData.request;
}
if (resolveData.createData) {
resolveData.createData.request = resolveData.request;
}
},
).apply(compiler);
}
}
},
).apply(compiler);
// dont run multiple times on every apply()
if (!onceForCompler.has(compiler)) {
this.prependEntry(compiler);
Expand Down
Loading

0 comments on commit 3fbece2

Please sign in to comment.