Skip to content

feat(runtime): add pause/resume hooks and preserve ESM entries - #4891

Closed
zackarychapple wants to merge 3 commits into
mainfrom
codex/miniapp-platform
Closed

zackarychapple wants to merge 3 commits into
mainfrom
codex/miniapp-platform

Conversation

@zackarychapple

@zackarychapple zackarychapple commented Jul 13, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds runtime primitives for host-supervised application pause/resume transitions and preserves native ESM remote-entry metadata in emitted manifests.

Changes

  • Adds typed prePause, pause, preResume, resume, and lifecycleError runtime-plugin hooks.
  • Carries transition ID, lifecycle epoch, scope, reason, force flag, optional deadline/abort signal, context, checkpoint reference, and commit timestamp through the public lifecycle contracts.
  • Exposes the lifecycle types from both @module-federation/runtime-core and @module-federation/runtime.
  • Preserves library.type: "module" when reconciling pre-emitted Rspack stats so generated manifests select the ESM remote-entry loader.
  • Covers serial lifecycle-hook dispatch and verifies that bridge renders remain separate instrumentation, not lifecycle transitions.

Scope

This PR provides Federation runtime primitives only. The host remains responsible for transition serialization, deadline enforcement, cancellation/force policy, checkpoints, authorization, activation/mount/update/rollback, and installation state. Bridge render/destroy hooks remain rendering instrumentation rather than authoritative lifecycle boundaries.

Validation

  • pnpm --filter @module-federation/runtime-core run test -- hooks.spec.ts
  • pnpm --filter @module-federation/runtime run test
  • pnpm --filter @module-federation/manifest run test
  • Builds and lint for @module-federation/runtime-core, @module-federation/runtime, and @module-federation/manifest
  • pnpm exec prettier --check for the touched files

@changeset-bot

changeset-bot Bot commented Jul 13, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c641af6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 47 packages
Name Type
@module-federation/manifest Major
@module-federation/runtime-core Major
@module-federation/runtime Major
@module-federation/enhanced Major
@module-federation/modern-js-v3 Major
@module-federation/modern-js Major
@module-federation/rspack Major
@module-federation/nextjs-mf Patch
@module-federation/bridge-react Major
@module-federation/devtools Major
@module-federation/dts-plugin Major
@module-federation/esbuild Patch
@module-federation/metro Major
@module-federation/node Patch
@module-federation/observability-plugin Patch
@module-federation/playground Patch
@module-federation/retry-plugin Major
@module-federation/runtime-tools Major
@module-federation/webpack-bundler-runtime Major
@module-federation/bridge-vue3 Major
website-new Patch
@module-federation/rsbuild-plugin Major
@module-federation/rspress-plugin Major
@module-federation/storybook-addon Major
shared-tree-shaking-no-server-host Patch
shared-tree-shaking-no-server-provider Patch
@module-federation/metro-plugin-rnc-cli Major
@module-federation/metro-plugin-rnef Major
@module-federation/metro-plugin-rock Major
shared-tree-shaking-with-server-host Patch
shared-tree-shaking-with-server-provider Patch
node-dynamic-remote-new-version Patch
node-dynamic-remote Patch
@module-federation/inject-external-runtime-core-plugin Major
remote5 Patch
remote6 Patch
@module-federation/sdk Major
@module-federation/managers Major
@module-federation/third-party-dts-extractor Major
@module-federation/bridge-shared Major
@module-federation/bridge-react-webpack-plugin Major
@module-federation/error-codes Major
create-module-federation Major
@module-federation/cli Major
@module-federation/treeshake-server Major
@module-federation/treeshake-frontend Major
@module-federation/utilities Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 13, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@module-federation/devtools

pnpm add https://pkg.pr.new/@module-federation/devtools@c641af6

@module-federation/cli

pnpm add https://pkg.pr.new/@module-federation/cli@c641af6

create-module-federation

pnpm add https://pkg.pr.new/create-module-federation@c641af6

@module-federation/dts-plugin

pnpm add https://pkg.pr.new/@module-federation/dts-plugin@c641af6

@module-federation/enhanced

pnpm add https://pkg.pr.new/@module-federation/enhanced@c641af6

@module-federation/error-codes

pnpm add https://pkg.pr.new/@module-federation/error-codes@c641af6

@module-federation/esbuild

pnpm add https://pkg.pr.new/@module-federation/esbuild@c641af6

@module-federation/managers

pnpm add https://pkg.pr.new/@module-federation/managers@c641af6

@module-federation/manifest

pnpm add https://pkg.pr.new/@module-federation/manifest@c641af6

@module-federation/metro

pnpm add https://pkg.pr.new/@module-federation/metro@c641af6

@module-federation/metro-plugin-rnc-cli

pnpm add https://pkg.pr.new/@module-federation/metro-plugin-rnc-cli@c641af6

@module-federation/metro-plugin-rnef

pnpm add https://pkg.pr.new/@module-federation/metro-plugin-rnef@c641af6

@module-federation/metro-plugin-rock

pnpm add https://pkg.pr.new/@module-federation/metro-plugin-rock@c641af6

@module-federation/modern-js

pnpm add https://pkg.pr.new/@module-federation/modern-js@c641af6

@module-federation/modern-js-v3

pnpm add https://pkg.pr.new/@module-federation/modern-js-v3@c641af6

@module-federation/native-federation-tests

pnpm add https://pkg.pr.new/@module-federation/native-federation-tests@c641af6

@module-federation/native-federation-typescript

pnpm add https://pkg.pr.new/@module-federation/native-federation-typescript@c641af6

@module-federation/nextjs-mf

pnpm add https://pkg.pr.new/@module-federation/nextjs-mf@c641af6

@module-federation/node

pnpm add https://pkg.pr.new/@module-federation/node@c641af6

@module-federation/observability-plugin

pnpm add https://pkg.pr.new/@module-federation/observability-plugin@c641af6

@module-federation/playground

pnpm add https://pkg.pr.new/@module-federation/playground@c641af6

@module-federation/retry-plugin

pnpm add https://pkg.pr.new/@module-federation/retry-plugin@c641af6

@module-federation/rsbuild-plugin

pnpm add https://pkg.pr.new/@module-federation/rsbuild-plugin@c641af6

@module-federation/rspack

pnpm add https://pkg.pr.new/@module-federation/rspack@c641af6

@module-federation/rspress-plugin

pnpm add https://pkg.pr.new/@module-federation/rspress-plugin@c641af6

@module-federation/runtime

pnpm add https://pkg.pr.new/@module-federation/runtime@c641af6

@module-federation/runtime-core

pnpm add https://pkg.pr.new/@module-federation/runtime-core@c641af6

@module-federation/runtime-tools

pnpm add https://pkg.pr.new/@module-federation/runtime-tools@c641af6

@module-federation/sdk

pnpm add https://pkg.pr.new/@module-federation/sdk@c641af6

@module-federation/storybook-addon

pnpm add https://pkg.pr.new/@module-federation/storybook-addon@c641af6

@module-federation/third-party-dts-extractor

pnpm add https://pkg.pr.new/@module-federation/third-party-dts-extractor@c641af6

@module-federation/treeshake-frontend

pnpm add https://pkg.pr.new/@module-federation/treeshake-frontend@c641af6

@module-federation/treeshake-server

pnpm add https://pkg.pr.new/@module-federation/treeshake-server@c641af6

@module-federation/typescript

pnpm add https://pkg.pr.new/@module-federation/typescript@c641af6

@module-federation/utilities

pnpm add https://pkg.pr.new/@module-federation/utilities@c641af6

@module-federation/webpack-bundler-runtime

pnpm add https://pkg.pr.new/@module-federation/webpack-bundler-runtime@c641af6

@module-federation/bridge-react

pnpm add https://pkg.pr.new/@module-federation/bridge-react@c641af6

@module-federation/bridge-react-webpack-plugin

pnpm add https://pkg.pr.new/@module-federation/bridge-react-webpack-plugin@c641af6

@module-federation/bridge-shared

pnpm add https://pkg.pr.new/@module-federation/bridge-shared@c641af6

@module-federation/bridge-vue3

pnpm add https://pkg.pr.new/@module-federation/bridge-vue3@c641af6

@module-federation/inject-external-runtime-core-plugin

pnpm add https://pkg.pr.new/@module-federation/inject-external-runtime-core-plugin@c641af6

commit: c641af6

@github-actions

github-actions Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor

Bundle Size Report

13 package(s) changed, 29 unchanged.

Package dist + ESM entry

Package Total dist (raw) Delta ESM gzip Delta
@module-federation/bridge-vue3 174.1 kB +427 B (+0.2%) 25.8 kB +58 B (+0.2%)
@module-federation/dts-plugin 316.4 kB +2.3 kB (+0.7%) 4.7 kB no change
@module-federation/manifest 131.9 kB +924 B (+0.7%) 106 B no change
@module-federation/playground 28.93 MB +710 B (+0.0%) 51.8 kB no change
@module-federation/runtime 20.9 kB +937 B (+4.6%) 715 B no change
@module-federation/runtime-core 292.4 kB +4.6 kB (+1.6%) 477 B no change
@module-federation/webpack-bundler-runtime 101.3 kB +3.1 kB (+3.1%) 405 B no change

Bundle targets

Package Web bundle (gzip) Delta Node bundle (gzip) Delta
@module-federation/bridge-vue3 19.0 kB +56 B (+0.3%) 19.2 kB +59 B (+0.3%)
@module-federation/cli 2.3 kB -7 B (-0.3%) 2.4 kB -32 B (-1.3%)
@module-federation/core 1.0 kB -4 B (-0.4%) 1.0 kB -33 B (-3.0%)
@module-federation/devtools 30.3 kB -6 B (-0.0%) 30.3 kB -30 B (-0.1%)
@module-federation/enhanced 2.7 kB +7 B (+0.3%) 2.8 kB -44 B (-1.5%)
@module-federation/manifest 5.5 kB +22 B (+0.4%) 5.5 kB +22 B (+0.4%)
@module-federation/metro-plugin-rnc-cli 416 B -1 B (-0.2%) 435 B -26 B (-5.6%)
@module-federation/node 9.2 kB +1 B (+0.0%) 9.2 kB -29 B (-0.3%)
@module-federation/runtime-core 15.1 kB +54 B (+0.4%) 14.9 kB +58 B (+0.4%)

Consumer scenarios

Scenario Web output (gzip) Delta Node output (gzip) Delta Gap (node-web) Delta
Enhanced remoteEntry 21.5 kB +40 B (+0.2%) 23.1 kB +55 B (+0.2%) +1.7 kB +15 B

Total dist (raw): 35.71 MB (+12.9 kB (+0.0%))
Total ESM gzip: 122.9 kB (+58 B (+0.0%))
Total web bundle (gzip): 251.7 kB (+122 B (+0.0%))
Total node bundle (gzip): 254.3 kB (-55 B (-0.0%))
Tracked ./bundler entry gzip: 556 B (no change)
Tracked ./bundler web bundle (gzip): 4.7 kB (no change)
Tracked ./bundler node bundle (gzip): 4.7 kB (no change)

Bundle sizes are generated with rslib (Rspack). Package-root metrics preserve the historical report. Tracked subpath exports such as ./bundler are measured separately so ENV_TARGET-driven tree-shaking is visible. Bare imports are externalized to keep package-level sizes consistent, and assets are emitted as resources.

@zackarychapple zackarychapple changed the title feat(runtime): support isolated ESM application lifecycles feat(runtime): add pause/resume hooks and preserve ESM entries Jul 13, 2026
@zackarychapple
zackarychapple marked this pull request as ready for review July 13, 2026 03:40

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c641af636f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +85 to +87
export interface ResumeCommittedEvent extends ApplicationLifecycleTransition {
committedAt: number;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve checkpoint on committed resumes

When a host resumes from a checkpoint, preResume exposes checkpointReference, but the committed resume event drops it here. Plugins that only react after a successful resume cannot tell which checkpoint was activated without keeping separate state or casting around the public type, so the new lifecycle API loses the checkpoint metadata on the completion event.

Useful? React with 👍 / 👎.

@Nsttt Nsttt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few lifecycle contract questions from a local pass. The ESM metadata change looks good to me; these are the pieces in the new hook group that still feel risky.

>(),
});
applicationHook = new PluginSystem({
prePause: new AsyncHook<

@Nsttt Nsttt Jul 13, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we define aggregation here instead of inheriting the AsyncHook last-result-wins behavior? With two plugins returning { delayMs: 5000 } and { delayMs: 10 }, the host only receives 10, so it cannot consider the first request. Returning all decisions, or explicitly taking the maximum, plus a multi-plugin test would make this contract predictable.

| false
| Promise<LifecycleDecision | void | false>
>('prePause'),
pause: new AsyncHook<

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think the generic AsyncHook semantics fit these committed/error notifications. A listener can return false, or reject, which prevents every later plugin from seeing a pause or resume that already happened. Could these hooks use serial fan-out that always attempts every listener, with an explicit error policy?

instance.snapshotHandler.hooks,
instance.loaderHook,
instance.bridgeHook,
instance.applicationHook,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One subtle side effect of adding another PluginSystem: every runtime plugin now goes through applyPlugin once more, and each system has its own registration map. That changes plugin.apply(instance) from six calls to seven even for plugins with no application hooks. Could apply be owned by host-level registration and run once, separately from wiring callbacks into each hook group?

2heal1 commented Jul 13, 2026

Copy link
Copy Markdown
Member

Could you please split the ESM remote-entry metadata fix into a separate PR?

That fix addresses a general manifest/runtime loading issue and is independent of the application pause/resume proposal. Keeping it separate will make the change easier to review, validate, and merge on its own.

2heal1 commented Jul 13, 2026

Copy link
Copy Markdown
Member

The pause/resume lifecycle model appears specific to your application platform rather than a general Module Federation runtime concern. Please implement this behavior through a custom MF RuntimePlugin instead of adding these hooks and types to runtime-core.

You can follow the approach used in packages/bridge/bridge-react/src/plugins/lazy-load-component-plugin.ts: use the plugin's apply method to extend the MF instance with the platform-specific pause, resume, checkpoint, and error-handling APIs. The related state, coordination rules, and types can remain within that plugin package.

If multiple unrelated consumers later need the same lifecycle model, we can revisit whether a smaller, proven abstraction belongs in core.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants