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

chore: split runtime as core and entry #3154

Merged
merged 35 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d56d6fa
chore: split runtime as core and entry
2heal1 Nov 1, 2024
b1e88e4
chore: stage from main
ScriptedAlchemy Nov 9, 2024
94a02bf
chore: stage from main
ScriptedAlchemy Nov 9, 2024
7c129dc
chore: stage from main
ScriptedAlchemy Nov 9, 2024
958baa4
fix: type errors
ScriptedAlchemy Nov 9, 2024
4bf9369
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Nov 12, 2024
4f87e22
fix: locks
ScriptedAlchemy Nov 12, 2024
56fcc57
fix: broken test imports
ScriptedAlchemy Nov 12, 2024
d3ac120
test: update import paths for tests
ScriptedAlchemy Nov 12, 2024
6ba0973
test: remove cyclic references in core to runtime, and tests
ScriptedAlchemy Nov 12, 2024
2058b0e
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Nov 12, 2024
833f766
chore: locks
ScriptedAlchemy Nov 12, 2024
a278079
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Nov 13, 2024
e9202be
chore: locks
ScriptedAlchemy Nov 13, 2024
76710d5
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Nov 13, 2024
55297e6
chore: timeouts on selectors
ScriptedAlchemy Nov 13, 2024
cf0bcbc
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Nov 13, 2024
55ed004
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Nov 13, 2024
6054604
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Nov 14, 2024
d36604c
chore: getGlobalFederationInstance should be moved to runtime-core
2heal1 Nov 15, 2024
213f349
chore: merge main
2heal1 Nov 15, 2024
757ed46
chore: export getGlobalFederationInstance from helpers
2heal1 Nov 18, 2024
18d2809
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Nov 22, 2024
5fe3f65
chore: locks
ScriptedAlchemy Nov 22, 2024
101a337
Merge branch 'main' into chore/external-runtime-core
ScriptedAlchemy Dec 3, 2024
091299e
chore: locks
ScriptedAlchemy Dec 3, 2024
8e13a48
fix(runtime-core): update build output configurations
ScriptedAlchemy Dec 3, 2024
f763dd9
chore: merge main
2heal1 Dec 20, 2024
6261dae
feat: add externalRuntime option
2heal1 Dec 20, 2024
f0b1d4c
chore: add changeset
2heal1 Dec 20, 2024
4c3951d
chore: remove runtime plugin test command
2heal1 Dec 20, 2024
2f5bc75
chore: add provideExternalRuntime field
2heal1 Dec 20, 2024
496f677
Merge branch 'main' into chore/external-runtime-core
2heal1 Dec 30, 2024
b43c49a
chore: merge main
2heal1 Dec 30, 2024
d44098e
Merge branch 'main' into chore/external-runtime-core
2heal1 Dec 31, 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
3 changes: 2 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"@module-federation/retry-plugin",
"@module-federation/data-prefetch",
"@module-federation/rsbuild-plugin",
"@module-federation/error-codes"
"@module-federation/error-codes",
"@module-federation/inject-external-runtime-core-plugin"
]
],
"ignorePatterns": ["^alpha|^beta"],
Expand Down
8 changes: 8 additions & 0 deletions .changeset/nervous-starfishes-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@module-federation/inject-external-runtime-core-plugin': patch
'@module-federation/runtime-core': patch
'@module-federation/enhanced': patch
'@module-federation/runtime': patch
---

feat: add externalRuntime and provideExternalRuntime fields to help optimize assets size
3 changes: 3 additions & 0 deletions apps/manifest-demo/3009-webpack-provider/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ module.exports = composePlugins(
requiredVersion: '^18.3.1',
},
},
experiments: {
externalRuntime: true,
},
}),
);

Expand Down
3 changes: 3 additions & 0 deletions apps/manifest-demo/3010-rspack-provider/rspack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ module.exports = composePlugins(
},
},
dataPrefetch: true,
experiments: {
externalRuntime: true,
},
}),
);
(config.devServer = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ module.exports = composePlugins(
requiredVersion: '^18.3.1',
},
},
experiments: {
externalRuntime: true,
},
}),
);
(config.devServer = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ module.exports = composePlugins(
},
},
manifest: false,
experiments: {
externalRuntime: true,
},
}),
);
(config.devServer = {
Expand Down
50 changes: 0 additions & 50 deletions apps/manifest-demo/webpack-host/src/bootstrap.tsx

This file was deleted.

9 changes: 5 additions & 4 deletions apps/manifest-demo/webpack-host/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ module.exports = composePlugins(withNx(), withReact(), (config, context) => {
'modern-js-provider': 'app1@http://127.0.0.1:4001/mf-manifest.json',
},
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/Button.tsx',
},
shared: {
lodash: {},
antd: {},
Expand All @@ -47,8 +44,12 @@ module.exports = composePlugins(withNx(), withReact(), (config, context) => {
},
},
dataPrefetch: true,
experiments: { federationRuntime: 'hoisted' },
// experiments: { federationRuntime: 'hoisted' },
runtimePlugins: [path.join(__dirname, './runtimePlugin.ts')],
experiments: {
provideExternalRuntime: true,
federationRuntime: 'hoisted',
},
}),
);

Expand Down
19 changes: 19 additions & 0 deletions apps/website-new/docs/en/configure/experiments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,22 @@ There should be no "eager consumption" errors possible, as the initialization of
Instead of federation runtime initilizing in the entrypoint code, it is initialized in a RuntimeModule, within the webpack runtime.
This allows module federation to be avaliable ahead of time, thus enabling "Async Startup" capabilities etc.

## externalRuntime

- Type: `boolean`
- Required: No
- Default: `false`

After setting `true`, the external MF runtime will be used and the runtime provided by the consumer will be used. (Please make sure your consumer has `provideExternalRuntime: true` set, otherwise it will not run properly!)

## provideExternalRuntime

- Type: `boolean`
- Required: No
- Default: `false`

::: warning note
Make sure to only configure it on the topmost consumer! If multiple consumers inject runtime at the same time, the ones executed later will not overwrite the existing runtime.
:::

Setting `true` will inject the MF runtime at the consumer.
5 changes: 5 additions & 0 deletions apps/website-new/docs/zh/configure/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,10 @@
"type": "file",
"name": "shareStrategy",
"label": "shareStrategy"
},
{
"type": "file",
"name": "experiments",
"label": "experiments"
}
]
88 changes: 88 additions & 0 deletions apps/website-new/docs/zh/configure/experiments.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Experiments

`experiments` 配置用于启用插件中的实验功能。

- Example

```ts
new ModuleFederationPlugin({
name: '@demo/host',
experiments: {
federationRuntime: 'hoisted'
},
shared: {
react: {
singleton: true,
},
'react-dom': {
singleton: true,
},
},
//...
});
```

## federationRuntime

- Type: `enum`
- Required: No
- Default: `false`
- Options: `false | "hoisted"`

### `Hoisted` Runtime

当设置 `federationRuntime: 'hoisted'` 时,会发生以下情况:

这些配置可用于下列场景:

- 设置`runtimeChunk: 'single'`。
- 避免在应用程序顶部或用户代码入口点使用“import()”,以防止急切消费错误。过去,这通常是强制性的,并且在示例应用程序中通常被视为“import('./bootstrap.js')”。
- 将模块联合运行时包移动到运行时块中,使它们远离入口点 - 减少代码重复

下面会详细解释对应的场景。

1)优化

原先 `module-federation/runtime` 会被加入到编译入口,这意味着在多 entry 的情况下会打包多次 mf runtime,会增大产物体积。
当设置了某些特定的分包策略,还会导致共享依赖 `eager consumption` 的问题。

并且 `federationRuntime: 'hoisted'` 还允许设置 `runtimeChunk: "single"`。

2)异步启动

:::警告
此模式仍然允许设置异步入口。导出 UMD 库时,它会返回 Promise resolve 导出。
如果您手动 require() Node 中的入口点,它将 module.exports 设置为 Promise.resolve(exports)。
:::

入口启动将切换到“主动”初始化并使用异步依赖项启动。

你将不再需要强制的设置异步入口:`“import('./bootsrtap')”`。

不再出现共享依赖 `eager consumption` 错误,因为文件本身的初始化表现为异步块。

3) 提升 MF 运行时访问优先级

与原先在入口挂载 MF runtime 不同,现在将会提升到 bundler runtime 初始化阶段挂载 MF runtime 。

这允许 MF runtime 提前可用,从而支持 “异步启动”(不再需要异步入口) 功能等。

## externalRuntime

- Type: `boolean`
- Required: No
- Default: `false`

设置 `true` 后 会 external MF runtime,并使用消费者提供的 runtime 。(请确保你的消费者有设置 `provideExternalRuntime: true`,否则无法正常运行!)

## provideExternalRuntime

- Type: `boolean`
- Required: No
- Default: `false`

::: warning 注意
请确保仅在最顶层消费者配置!若同时有多个消费者注入 runtime,后执行的不会覆盖已有的 runtime。
:::

设置 `true` 后会在消费者处注入 MF runtime。
2 changes: 1 addition & 1 deletion packages/chrome-devtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"release": "npm publish --tag canary",
"test": "vitest run",
"test:e2e": "E2ETEST=true pnpm build && playwright test",
"test:e2e:ui": "E2ETEST=true pnpm build && playwright test --ui",
"test:e2e:ui": "E2ETEST=true pnpm build && playwright test --ui",
"start": "modern start",
"serve": "modern serve",
"new": "modern new",
Expand Down
5 changes: 4 additions & 1 deletion packages/chrome-devtools/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
timeout: 2 * 60 * 1000,
timeout: 90000,
testDir: './e2e',
fullyParallel: true,
forbidOnly: Boolean(process.env.CI),
Expand All @@ -10,6 +10,9 @@ export default defineConfig({
use: {
trace: 'on-first-retry',
},
expect: {
timeout: 10000,
},
projects: [
{
name: 'chromium',
Expand Down
10 changes: 9 additions & 1 deletion packages/chrome-devtools/src/component/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
GlobalModuleInfo,
MODULE_DEVTOOL_IDENTIFIER,
} from '@module-federation/sdk';
import type { Federation } from '@module-federation/runtime';

import FormComponent from '../Form';
import Dependency from '../Graph';
Expand Down Expand Up @@ -33,12 +34,19 @@ import {
BROWSER_ENV_KEY,
__FEDERATION_DEVTOOLS__,
} from '../../template/constant';

interface FormItemType {
key: string;
value: string;
checked: boolean;
}
declare global {
interface Window {
__FEDERATION__: Federation & {
originModuleInfo: GlobalModuleInfo;
moduleInfo: GlobalModuleInfo;
};
}
}

const Layout = (
props: { moduleInfo: GlobalModuleInfo } & RootComponentProps,
Expand Down
37 changes: 21 additions & 16 deletions packages/data-prefetch/src/prefetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ import {
ProviderModuleInfo,
} from '@module-federation/sdk';
import { Remote } from '@module-federation/runtime/types';

import type { Federation } from '@module-federation/runtime';
import { getPrefetchId, compatGetPrefetchId } from './common/runtime-utils';

declare module '@module-federation/runtime' {
export interface Federation {
__PREFETCH__: {
entryLoading: Record<string, undefined | Promise<void>>;
instance: Map<string, MFDataPrefetch>;
__PREFETCH_EXPORTS__: Record<string, () => Promise<Record<string, any>>>;
};
}
// Define an interface that extends Federation to include __PREFETCH__
interface FederationWithPrefetch extends Federation {
__PREFETCH__: {
entryLoading: Record<string, undefined | Promise<void>>;
instance: Map<string, MFDataPrefetch>;
__PREFETCH_EXPORTS__: Record<string, () => Promise<Record<string, any>>>;
};
}

type PrefetchExports = Record<string, any>;
Expand All @@ -40,11 +39,13 @@ export interface prefetchOptions {

// @ts-ignore init global variable for test
globalThis.__FEDERATION__ ??= {};
globalThis.__FEDERATION__.__PREFETCH__ ??= {
(
globalThis.__FEDERATION__ as unknown as FederationWithPrefetch
).__PREFETCH__ ??= {
entryLoading: {},
instance: new Map(),
__PREFETCH_EXPORTS__: {},
};
} as FederationWithPrefetch['__PREFETCH__'];
export class MFDataPrefetch {
public prefetchMemory: Map<string, Promise<any>>;
public recordOutdate: Record<string, Record<string, boolean>>;
Expand All @@ -59,12 +60,15 @@ export class MFDataPrefetch {
this.global.instance.set(options.name, this);
}

get global(): Record<string, any> {
return globalThis.__FEDERATION__.__PREFETCH__;
get global(): FederationWithPrefetch['__PREFETCH__'] {
return (globalThis.__FEDERATION__ as unknown as FederationWithPrefetch)
.__PREFETCH__;
}

static getInstance(id: string): MFDataPrefetch | undefined {
return globalThis.__FEDERATION__.__PREFETCH__.instance.get(id);
return (
globalThis.__FEDERATION__ as unknown as FederationWithPrefetch
).__PREFETCH__.instance.get(id);
}

async loadEntry(entry: string | undefined): Promise<any> {
Expand Down Expand Up @@ -94,8 +98,9 @@ export class MFDataPrefetch {
return this._exports;
}
const { name } = this._options;
const exportsPromiseFn =
globalThis.__FEDERATION__.__PREFETCH__.__PREFETCH_EXPORTS__?.[name];
const exportsPromiseFn = (
globalThis.__FEDERATION__ as unknown as FederationWithPrefetch
).__PREFETCH__.__PREFETCH_EXPORTS__?.[name];
const exportsPromise =
typeof exportsPromiseFn === 'function'
? exportsPromiseFn()
Expand Down
1 change: 1 addition & 0 deletions packages/enhanced/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"@module-federation/rspack": "workspace:*",
"@module-federation/bridge-react-webpack-plugin": "workspace:*",
"@module-federation/data-prefetch": "workspace:*",
"@module-federation/inject-external-runtime-core-plugin": "workspace:*",
"upath": "2.0.1",
"btoa": "^1.2.1"
}
Expand Down
Loading
Loading