Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: shareable runtime #3018

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
2d5f114
feat(enhanced): custom plugin hooks
ScriptedAlchemy Sep 7, 2024
d489991
fix: support multi runtime chunk
ScriptedAlchemy Sep 8, 2024
2670170
fix: remove entry patching
ScriptedAlchemy Sep 9, 2024
70beb33
fix: remove entry patching
ScriptedAlchemy Sep 9, 2024
71f5193
fix: remove entry patching
ScriptedAlchemy Sep 9, 2024
6be1290
fix: pass experiments to container plugin
ScriptedAlchemy Sep 9, 2024
6bfe53f
fix: move container entry embedding to next
ScriptedAlchemy Sep 9, 2024
9ebbe76
fix(enhanced): put entry patching behind flag
ScriptedAlchemy Sep 9, 2024
2760ed3
fix(enhanced): put entry patching behind flag
ScriptedAlchemy Sep 9, 2024
f9da09e
fix(enhanced): remove old hoisting code
ScriptedAlchemy Sep 9, 2024
6ebff16
fix(enhanced): remove old hoisting code
ScriptedAlchemy Sep 9, 2024
772e821
fix(enhanced): remove old hoisting code
ScriptedAlchemy Sep 10, 2024
d3c8aea
Update packages/enhanced/src/lib/container/runtime/FederationModulesP…
ScriptedAlchemy Sep 10, 2024
287ddab
fix(enhanced): remove old hoisting code
ScriptedAlchemy Sep 10, 2024
47bd54e
Merge remote-tracking branch 'origin/feat/federation-hooks' into feat…
ScriptedAlchemy Sep 10, 2024
0c35086
fix(enhanced): include container module in all if multiple runtime
ScriptedAlchemy Sep 10, 2024
c084b92
Merge branch 'main' into feat/federation-hooks
ScriptedAlchemy Sep 10, 2024
bed1290
chore: update types
ScriptedAlchemy Sep 10, 2024
a66501a
fix(enhanced): update flag logic to support use host
ScriptedAlchemy Sep 11, 2024
81620e3
chore: update compiler types
ScriptedAlchemy Sep 12, 2024
0cb9794
chore: remove old declarations
ScriptedAlchemy Sep 12, 2024
031322f
chore: remove old declarations
ScriptedAlchemy Sep 12, 2024
d8d1f6e
fix(nextjs-mf): fix types
ScriptedAlchemy Sep 12, 2024
5f0e1c7
fix(enhanced): update wrapper plugin apis
ScriptedAlchemy Sep 12, 2024
490c5e0
fix(enhanced): remove declarations from enhanced
ScriptedAlchemy Sep 12, 2024
d300711
fix(enhanced): shared runtime (#2960)
ScriptedAlchemy Sep 30, 2024
653cb9e
sync with main
ScriptedAlchemy Sep 30, 2024
798a4e7
sync with main
ScriptedAlchemy Sep 30, 2024
6b574e2
sync with main
ScriptedAlchemy Sep 30, 2024
aa6b88d
Merge branch 'main' into shared-runtime
ScriptedAlchemy Sep 30, 2024
9d2c57a
fix: sync with main branch
ScriptedAlchemy Sep 30, 2024
9400a1d
chore: format
ScriptedAlchemy Sep 30, 2024
336c63e
chore: filter federaiton manager off instance
ScriptedAlchemy Sep 30, 2024
043ac9d
Merge branch 'main' into shared-runtime
ScriptedAlchemy Sep 30, 2024
098a6e5
Shared Runtime Staging branch (#3029)
ScriptedAlchemy Oct 1, 2024
5da852c
chore: test fixes
ScriptedAlchemy Oct 1, 2024
5abd1ba
refactor(enhanced): use outgoing connections for graph over mgm
ScriptedAlchemy Oct 1, 2024
3b4708f
Merge branch 'main' into shared-runtime
ScriptedAlchemy Oct 1, 2024
d85557e
Merge branch 'main' into shared-runtime
ScriptedAlchemy Oct 2, 2024
f5a7816
chore: lint
ScriptedAlchemy Oct 2, 2024
8c0fb2d
Merge branch 'main' into shared-runtime
ScriptedAlchemy Oct 3, 2024
0955be8
feat(runtime): add shareable runtime and utility functions
ScriptedAlchemy Oct 8, 2024
42acab2
Merge branch 'main' into shared-runtime
ScriptedAlchemy Oct 8, 2024
db45027
Merge branch 'main' into shared-runtime
ScriptedAlchemy Oct 10, 2024
bc24baf
fix(enhanced): remove full federation runtime dep set when minimal ru…
ScriptedAlchemy Oct 11, 2024
c130648
Merge branch 'main' into shared-runtime
ScriptedAlchemy Oct 11, 2024
5106c5a
Merge remote-tracking branch 'origin/shared-runtime' into shared-runtime
ScriptedAlchemy Oct 11, 2024
b7e8350
Merge branch 'main' into shared-runtime
ScriptedAlchemy Oct 15, 2024
77c7186
fix: add option to getAllReferncedModules so it does not include init…
ScriptedAlchemy Oct 15, 2024
e4bbbd0
Merge branch 'main' into shared-runtime
ScriptedAlchemy Oct 15, 2024
37ed459
feat(nextjs-mf): support shareable runtime
ScriptedAlchemy Oct 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wild-guests-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@module-federation/enhanced': patch
---

support minimal runtime and use-host experimental option on federationRuntime
12 changes: 12 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@
"request": "launch",
"type": "node-terminal"
},
{
"name": "Run home_app",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/path/to/your/home_app.js",
"args": [],
"console": "integratedTerminal",
"runtimeExecutable": "nx",
"runtimeArgs": ["run", "3000-home:serve:development"],
"preLaunchTask": "pnpm build",
"skipFiles": ["<node_internals>/**"]
},
{
"command": "npm run app:next:prod",
"name": "Run app:next:prod",
Expand Down
11 changes: 11 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "pnpm build",
"type": "shell",
"command": "pnpm run build",
"problemMatcher": []
},
]
}

This file was deleted.

4 changes: 4 additions & 0 deletions packages/enhanced/src/lib/container/AsyncBoundaryPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Zackary Jackson @ScriptedAlchemy
*/
import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-path';
import { moduleFederationPlugin } from '@module-federation/sdk';
import type {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class ContainerEntryDependency extends Dependency {
public exposes: [string, ExposeOptions][];
public shareScope: string;
public injectRuntimeEntry: string;
/** Additional experimental options for container plugin customization */
public experiments: containerPlugin.ContainerPluginOptions['experiments'];

/**
Expand Down
96 changes: 64 additions & 32 deletions packages/enhanced/src/lib/container/ContainerPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,25 @@ import ContainerEntryModuleFactory from './ContainerEntryModuleFactory';
import ContainerExposedDependency from './ContainerExposedDependency';
import { parseOptions } from './options';
import type {
optimize,
Compiler,
Compilation,
WebpackError,
WebpackPluginInstance,
WebpackPluginFunction,
} from 'webpack';
import type { containerPlugin } from '@module-federation/sdk';
import FederationRuntimePlugin from './runtime/FederationRuntimePlugin';
import FederationModulesPlugin from './runtime/FederationModulesPlugin';
import checkOptions from '../../schemas/container/ContainerPlugin.check';
import schema from '../../schemas/container/ContainerPlugin';
import FederationRuntimeDependency from './runtime/FederationRuntimeDependency';
import type { OptimizationSplitChunksCacheGroup } from 'webpack/lib/optimize/SplitChunksPlugin';
import type { Falsy } from 'webpack/declarations/WebpackOptions';

const ModuleDependency = require(
normalizeWebpackPath('webpack/lib/dependencies/ModuleDependency'),
) as typeof import('webpack/lib/dependencies/ModuleDependency');

type ExcludeUndefined<T> = T extends undefined ? never : T;
type NonUndefined<T> = ExcludeUndefined<T>;

type OptimizationSplitChunksOptions = NonUndefined<
ConstructorParameters<typeof optimize.SplitChunksPlugin>[0]
>;

type CacheGroups = OptimizationSplitChunksOptions['cacheGroups'];
type CacheGroup = NonUndefined<CacheGroups>[string];

const createSchemaValidation = require(
normalizeWebpackPath('webpack/lib/util/create-schema-validation'),
) as typeof import('webpack/lib/util/create-schema-validation');
Expand Down Expand Up @@ -80,16 +72,21 @@ class ContainerPlugin {
};
}

// container should not be affected by splitChunks
static patchChunkSplit(compiler: Compiler, name: string): void {
const { splitChunks } = compiler.options.optimization;
const patchChunkSplit = (cacheGroup: CacheGroup) => {
const patchChunkSplit = (
cacheGroup:
| string
| false
| ((...args: any[]) => any)
| RegExp
| OptimizationSplitChunksCacheGroup,
) => {
switch (typeof cacheGroup) {
case 'boolean':
case 'string':
case 'function':
break;
// cacheGroup.chunks will inherit splitChunks.chunks, so you only need to modify the chunks that are set separately
case 'object':
{
if (cacheGroup instanceof RegExp) {
Expand Down Expand Up @@ -144,23 +141,21 @@ class ContainerPlugin {
if (!splitChunks) {
return;
}
// patch splitChunk.chunks
patchChunkSplit(splitChunks);

const cacheGroups = splitChunks.cacheGroups;
if (!cacheGroups) {
return;
}

// patch splitChunk.cacheGroups[key].chunks
Object.keys(cacheGroups).forEach((cacheGroupKey) => {
patchChunkSplit(cacheGroups[cacheGroupKey]);
});
}

apply(compiler: Compiler): void {
const useModuleFederationPlugin = compiler.options.plugins.find(
(p: WebpackPluginInstance) => {
(p: Falsy | WebpackPluginInstance | WebpackPluginFunction) => {
if (typeof p !== 'object' || !p) {
return false;
}
Expand Down Expand Up @@ -225,7 +220,7 @@ class ContainerPlugin {
resolve(undefined);
},
);
}).catch(callback);
}).catch((error) => callback(error));

await new Promise((resolve, reject) => {
compilation.addInclude(
Expand All @@ -242,17 +237,15 @@ class ContainerPlugin {
resolve(undefined);
},
);
}).catch(callback);
}).catch((error) => callback(error));

callback();
},
);

// this will still be copied into child compiler, so it needs a check to avoid running hook on child
// we have to use finishMake in order to check the entries created and see if there are multiple runtime chunks
compiler.hooks.finishMake.tapAsync(
PLUGIN_NAME,
(compilation: Compilation, callback) => {
async (compilation: Compilation, callback) => {
if (
compilation.compiler.parentCompilation &&
compilation.compiler.parentCompilation !== compilation
Expand Down Expand Up @@ -288,16 +281,46 @@ class ContainerPlugin {

dep.loc = { name };

compilation.addInclude(
compilation.options.context || '',
dep,
{ name: undefined },
(error: WebpackError | null | undefined) => {
if (error) return callback(error);
hooks.addContainerEntryModule.call(dep);
callback();
},
);
await new Promise<void>((resolve, reject) => {
compilation.addInclude(
compilation.options.context || '',
dep,
{ name: undefined },
(error: WebpackError | null | undefined) => {
if (error) return reject(error);
hooks.addContainerEntryModule.call(dep);
resolve();
},
);
}).catch((error) => callback(error));

const addDependency = async (
dependency: FederationRuntimeDependency,
) => {
await new Promise<void>((resolve, reject) => {
compilation.addInclude(
compiler.context,
dependency,
{ name: name, runtime: runtime },
(err, module) => {
if (err) return reject(err);
hooks.addFederationRuntimeModule.call(dependency);
resolve();
},
);
}).catch((error) => callback(error));
};

if (this._options?.experiments?.federationRuntime === 'use-host') {
const externalRuntimeDependency =
federationRuntimePluginInstance.getMinimalDependency(compiler);
await addDependency(externalRuntimeDependency);
} else {
const federationRuntimeDependency =
federationRuntimePluginInstance.getDependency(compiler);
await addDependency(federationRuntimeDependency);
}
callback();
},
);

Expand All @@ -314,6 +337,15 @@ class ContainerPlugin {
ContainerExposedDependency,
normalModuleFactory,
);

compilation.dependencyFactories.set(
FederationRuntimeDependency,
normalModuleFactory,
);
compilation.dependencyTemplates.set(
FederationRuntimeDependency,
new ModuleDependency.Template(),
);
},
);

Expand Down
Loading
Loading