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: convert node pkg to rollup build #3007

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d722647
fix(nextjs-mf): add UniverseEntryChunkTrackerPlugin to applyServerPlu…
ScriptedAlchemy Sep 26, 2024
ba6d2d9
feat(nextjs-mf): add moduleGraphDirty flag for offline handling
ScriptedAlchemy Sep 26, 2024
f0b3b69
fix(node): ensure moduleGraphDirty flag is checked before revalidation
ScriptedAlchemy Sep 26, 2024
0427c2b
Merge branch 'main' into next-hmr
ScriptedAlchemy Sep 27, 2024
589f42b
Merge branch 'main' into next-hmr
ScriptedAlchemy Sep 27, 2024
127ebf4
fix(node): use module cache for hot reload
ScriptedAlchemy Sep 28, 2024
4eec8b8
Merge remote-tracking branch 'origin/next-hmr' into next-hmr
ScriptedAlchemy Sep 28, 2024
bcbc210
fix(node): use module cache for hot reload
ScriptedAlchemy Sep 28, 2024
91961bc
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
3c98b81
Merge remote-tracking branch 'origin/fix-dts--match-error' into next-hmr
ScriptedAlchemy Sep 28, 2024
a128e75
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
cc617e2
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
3999784
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
8f23bc1
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
381e3f5
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
ecc3dba
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
6f0e565
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
e4c06e5
fix(dts-plugin): update paths in vue-tsc2 test file
ScriptedAlchemy Sep 28, 2024
4650478
refactor(node): use rollup for build
ScriptedAlchemy Sep 28, 2024
fc73a15
refactor(node): use rollup for build
ScriptedAlchemy Sep 28, 2024
79affdd
refactor(node): use rollup for build
ScriptedAlchemy Sep 28, 2024
31d1354
Revert "refactor(node): use rollup for build"
ScriptedAlchemy Sep 28, 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/ai-calm-cat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@module-federation/nextjs-mf": patch
---
- Added `globalThis.moduleGraphDirty = true` to mark the module graph as dirty when an error is detected.
- Replaced `new Function('return globalThis')()` with a direct reference to `globalThis`.
10 changes: 10 additions & 0 deletions .changeset/ai-eager-wolf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@module-federation/node": patch
---

Add global flag `moduleGraphDirty` to control forced revalidation in hot-reload.

- Introduced new global variable `moduleGraphDirty`.
- Initialized `moduleGraphDirty` to `false` in the global scope.
- Modified `revalidate` function to check `moduleGraphDirty` flag.
- Forces revalidation if `moduleGraphDirty` is `true`.
14 changes: 14 additions & 0 deletions .changeset/ai-noisy-lion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@module-federation/node": minor
---

Enhanced hot-reload functionality with module decaching and improved type safety.

- Added `callsite` package for resolving module paths.
- Implemented `decache` and `searchCache` functions to remove modules from cache safely.
- Ensure proper handling of relative module paths.
- Avoid issues with native modules during decaching.
- Refactored hot-reload logic to use the new decache functionality.
- Improved type definitions and type safety throughout `hot-reload.ts`.
- Properly typed function return values.
- Added TypeScript annotations for better clarity.
8 changes: 8 additions & 0 deletions .changeset/ai-noisy-owl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@module-federation/nextjs-mf": minor
---

Added the UniverseEntryChunkTrackerPlugin to track entry chunks in the server plugin.

- Applied UniverseEntryChunkTrackerPlugin in the applyServerPlugins function.
- This change aims to enhance tracking of entry chunks in the server environment for hot reloading prod instances
12 changes: 10 additions & 2 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,18 @@ jobs:
run: npx nx run-many --targets=build --projects=tag:type:pkg --skip-nx-cache

- name: Run Affected Test
run: npx nx affected -t test --parallel=2 --exclude='*,!tag:type:pkg' --skip-nx-cache
uses: nick-fields/retry@v3
with:
max_attempts: 2
timeout_minutes: 10
command: npx nx affected -t test --parallel=3 --exclude='*,!tag:type:pkg' --skip-nx-cache

- name: Run Affected Experimental Tests
run: npx nx affected -t test:experiments --parallel=2 --exclude='*,!tag:type:pkg' --skip-nx-cache
uses: nick-fields/retry@v3
with:
max_attempts: 2
timeout_minutes: 10
command: npx nx affected -t test:experiments --parallel=1 --exclude='*,!tag:type:pkg' --skip-nx-cache

e2e-modern:
needs: checkout-install
Expand Down
6 changes: 3 additions & 3 deletions packages/dts-plugin/tests/vue-tsc2/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ describe('DTSManager', () => {
children: [
{
name: 'Button.vue.d.ts',
path: join(distFolder, 'compiled-types/Button.vue.d.ts'),
},
],
name: 'compiled-types',
},
{
name: 'index.d.ts',
path: join(distFolder, 'compiled-types'),
},
],
name: '@mf-types-dts-vue-test',
path: distFolder,
});
});
});
11 changes: 11 additions & 0 deletions packages/enhanced/test/ConfigTestCases.basictest.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
if (globalThis.__FEDERATION__) {
globalThis.__GLOBAL_LOADING_REMOTE_ENTRY__ = {};
//@ts-ignore
globalThis.__FEDERATION__.__INSTANCES__.map((i) => {
i.moduleCache.clear();
if (globalThis[i.name]) {
delete globalThis[i.name];
}
});
globalThis.__FEDERATION__.__INSTANCES__ = [];
}
const { describeCases } = require('./ConfigTestCases.template');

describeCases({
Expand Down
11 changes: 11 additions & 0 deletions packages/enhanced/test/ConfigTestCases.embedruntime.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
if (globalThis.__FEDERATION__) {
globalThis.__GLOBAL_LOADING_REMOTE_ENTRY__ = {};
//@ts-ignore
globalThis.__FEDERATION__.__INSTANCES__.map((i) => {
i.moduleCache.clear();
if (globalThis[i.name]) {
delete globalThis[i.name];
}
});
globalThis.__FEDERATION__.__INSTANCES__ = [];
}
const { describeCases } = require('./ConfigTestCases.template');
jest.resetModules();
describeCases({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
if (global.__FEDERATION__) {
global.__GLOBAL_LOADING_REMOTE_ENTRY__ = {};
//@ts-ignore
global.__FEDERATION__.__INSTANCES__.map((i) => {
i.moduleCache.clear();
if (global[i.name]) {
delete global[i.name];
}
});
global.__FEDERATION__.__INSTANCES__ = [];
}

it('should load the component from container', () => {
return import('./App').then(({ default: App }) => {
const rendered = App();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
import type { moduleFederationPlugin } from '@module-federation/sdk';
import path from 'path';
import InvertedContainerPlugin from '../container/InvertedContainerPlugin';
import UniverseEntryChunkTrackerPlugin from '@module-federation/node/universe-entry-chunk-tracker-plugin';

type EntryStaticNormalized = Awaited<
ReturnType<Extract<WebpackOptionsNormalized['entry'], () => any>>
Expand Down Expand Up @@ -74,7 +75,7 @@ export function applyServerPlugins(
suffix,
);
}

new UniverseEntryChunkTrackerPlugin().apply(compiler);
new InvertedContainerPlugin().apply(compiler);
}

Expand Down
80 changes: 38 additions & 42 deletions packages/nextjs-mf/src/plugins/container/runtimePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ export default function (): FederationRuntimePlugin {
url: string;
attrs?: Record<string, any>;
}) {
// Updated type
var url = args.url;
var attrs = args.attrs;
const url = args.url;
const attrs = args.attrs;
if (typeof window !== 'undefined') {
var script = document.createElement('script');
const script = document.createElement('script');
script.src = url;
script.async = true;
delete attrs?.['crossorigin'];
Expand All @@ -26,20 +25,21 @@ export default function (): FederationRuntimePlugin {
from: string;
origin: any;
}) {
var id = args.id;
var error = args.error;
var from = args.from;
const id = args.id;
const error = args.error;
const from = args.from;
//@ts-ignore
globalThis.moduleGraphDirty = true;
console.error(id, 'offline');
var pg = function () {
const pg = function () {
console.error(id, 'offline', error);
return null;
};

(pg as any).getInitialProps = function (ctx: any) {
// Type assertion to add getInitialProps
return {};
};
var mod;
let mod;
if (from === 'build') {
mod = function () {
return {
Expand Down Expand Up @@ -70,10 +70,11 @@ export default function (): FederationRuntimePlugin {
return args;
}

var moduleCache = args.origin.moduleCache;
var name = args.origin.name;
var gs = new Function('return globalThis')();
var attachedRemote = gs[name];
const moduleCache = args.origin.moduleCache;
const name = args.origin.name;
const gs = globalThis;
//@ts-ignore
const attachedRemote = gs[name];
if (attachedRemote) {
moduleCache.set(name, attachedRemote);
}
Expand All @@ -84,10 +85,10 @@ export default function (): FederationRuntimePlugin {
return args;
},
beforeRequest: function (args: any) {
var options = args.options;
var id = args.id;
var remoteName = id.split('/').shift();
var remote = options.remotes.find(function (remote: any) {
const options = args.options;
const id = args.id;
const remoteName = id.split('/').shift();
const remote = options.remotes.find(function (remote: any) {
return remote.name === remoteName;
});
if (!remote) return args;
Expand All @@ -101,41 +102,41 @@ export default function (): FederationRuntimePlugin {
return args;
},
onLoad: function (args: any) {
var exposeModuleFactory = args.exposeModuleFactory;
var exposeModule = args.exposeModule;
var id = args.id;
var moduleOrFactory = exposeModuleFactory || exposeModule;
if (!moduleOrFactory) return args; // Ensure moduleOrFactory is defined
const exposeModuleFactory = args.exposeModuleFactory;
const exposeModule = args.exposeModule;
const id = args.id;
const moduleOrFactory = exposeModuleFactory || exposeModule;
if (!moduleOrFactory) return args;

if (typeof window === 'undefined') {
var exposedModuleExports: any;
let exposedModuleExports: any;
try {
exposedModuleExports = moduleOrFactory();
} catch (e) {
exposedModuleExports = moduleOrFactory;
}

var handler: ProxyHandler<any> = {
const handler: ProxyHandler<any> = {
get: function (target, prop, receiver) {
// Check if accessing a static property of the function itself
if (
target === exposedModuleExports &&
typeof exposedModuleExports[prop] === 'function'
) {
return function (this: unknown) {
globalThis.usedChunks.add(id);
//eslint-disable-next-line
return exposedModuleExports[prop].apply(this, arguments);
};
}

var originalMethod = target[prop];
const originalMethod = target[prop];
if (typeof originalMethod === 'function') {
var proxiedFunction = function (this: unknown) {
const proxiedFunction = function (this: unknown) {
globalThis.usedChunks.add(id);
//eslint-disable-next-line
return originalMethod.apply(this, arguments);
};

// Copy all enumerable properties from the original method to the proxied function
Object.keys(originalMethod).forEach(function (prop) {
Object.defineProperty(proxiedFunction, prop, {
value: originalMethod[prop],
Expand All @@ -153,12 +154,9 @@ export default function (): FederationRuntimePlugin {
};

if (typeof exposedModuleExports === 'function') {
// If the module export is a function, we create a proxy that can handle both its
// call (as a function) and access to its properties (including static methods).
exposedModuleExports = new Proxy(exposedModuleExports, handler);

// Proxy static properties specifically
var staticProps = Object.getOwnPropertyNames(exposedModuleExports);
const staticProps = Object.getOwnPropertyNames(exposedModuleExports);
staticProps.forEach(function (prop) {
if (typeof exposedModuleExports[prop] === 'function') {
exposedModuleExports[prop] = new Proxy(
Expand All @@ -171,7 +169,6 @@ export default function (): FederationRuntimePlugin {
return exposedModuleExports;
};
} else {
// For objects, just wrap the exported object itself
exposedModuleExports = new Proxy(exposedModuleExports, handler);
}

Expand All @@ -189,23 +186,22 @@ export default function (): FederationRuntimePlugin {
) {
return args;
}
var shareScopeMap = args.shareScopeMap;
var scope = args.scope;
var pkgName = args.pkgName;
var version = args.version;
var GlobalFederation = args.GlobalFederation;
var host = GlobalFederation['__INSTANCES__'][0];
const shareScopeMap = args.shareScopeMap;
const scope = args.scope;
const pkgName = args.pkgName;
const version = args.version;
const GlobalFederation = args.GlobalFederation;
const host = GlobalFederation['__INSTANCES__'][0];
if (!host) {
return args;
}

if (!host.options.shared[pkgName]) {
return args;
}
//handle react host next remote, disable resolving when not next host
args.resolver = function () {
shareScopeMap[scope][pkgName][version] =
host.options.shared[pkgName][0]; // replace local share scope manually with desired module
host.options.shared[pkgName][0];
return shareScopeMap[scope][pkgName][version];
};
return args;
Expand Down
28 changes: 28 additions & 0 deletions packages/node/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": [
"jest.config.ts",
".*\\.spec.tsx?$",
".*\\.test.tsx?$",
"./src/jest-setup.ts$",
"./**/jest-setup.ts$",
]
}
Loading
Loading