Skip to content

feat(esbuild): rebuild module federation plugin architecture#4389

Closed
ScriptedAlchemy wants to merge 57 commits intomainfrom
cursor/esbuild-module-federation-plugin-2869
Closed

feat(esbuild): rebuild module federation plugin architecture#4389
ScriptedAlchemy wants to merge 57 commits intomainfrom
cursor/esbuild-module-federation-plugin-2869

Conversation

@ScriptedAlchemy
Copy link
Member

@ScriptedAlchemy ScriptedAlchemy commented Feb 8, 2026

Summary

  • rebuild @module-federation/esbuild for full Module Federation runtime/container support with expanded test coverage
  • add migration-oriented docs and update related app fixtures/workflows used for esbuild/router verification
  • align bridge-react helper behavior and enhanced shared tree-shaking integration with the new esbuild flow

Changed Packages

  • @module-federation/esbuild
  • @module-federation/bridge-react
  • @module-federation/enhanced

Changesets

  • .changeset/esbuild-module-federation-rebuild.md (@module-federation/esbuild: minor)
  • .changeset/real-schools-breathe.md (@module-federation/bridge-react: patch, @module-federation/enhanced: patch)

Base

  • main

Single-PR Review Guide (No Additional PRs)

This PR will remain a single PR. Improvements are being done in-place (no stacked or follow-up PR splitting).

Suggested Review Order

  1. Core behavior/runtime changes first.
  2. Build/tooling and workflow updates second.
  3. Docs/examples/app fixtures last.

In-Place Scope Trim Checklist

  • Remove unrelated churn not required for this PR goal.
  • Keep lockfile and generated changes only when strictly needed.
  • Confirm acceptance criteria and regression tests are explicit in this PR.
  • Resolve merge conflict status and required CI checks before final re-review.

Rewrote the esbuild plugin from the ground up for proper Module Federation support:

ARCHITECTURE:
- Uses @module-federation/runtime directly (no webpack runtime emulation)
- Clean ESM virtual module system with esbuild namespaces
- Top-level await for async boundaries (shared negotiation, remote loading)
- Code splitting for shared dependency chunks

SHARED MODULES:
- Intercepts shared dependency imports via onResolve/onLoad hooks
- Generates virtual proxy modules that call loadShare() from MF runtime
- Bundled fallback versions as separate chunks via dynamic imports
- Version negotiation between containers through the share scope
- Supports singleton, strictVersion, requiredVersion, eager configuration

REMOTE MODULES:
- Intercepts remote imports (e.g., 'mfe1/component') via prefix matching
- Generates virtual proxy modules that call loadRemote() from MF runtime
- Runtime handles container loading, init(), and get() protocol
- Default export forwarding for seamless component imports

CONTAINER ENTRY (remoteEntry.js):
- Generates standard MF container with get()/init() exports
- get(module) dynamically imports exposed modules
- init(shareScope) negotiates shared deps with host via runtime
- Separate chunk generation for exposed modules

RUNTIME INITIALIZATION:
- Injects runtime init import at top of entry points
- ESM evaluation order ensures init completes before app code
- Configures remotes, shared deps, and share strategy
- Initializes sharing for cross-container negotiation

MANIFEST:
- Generates mf-manifest.json for runtime discovery
- Includes shared deps, remotes, exposes, and build metadata

Also added @module-federation/runtime as dependency/peerDependency
and updated exports from index.ts and build.ts.
- Shared module proxy now correctly handles subpath imports
  (e.g., 'react/jsx-runtime' when 'react' is shared)
- Added comprehensive README with architecture docs, examples,
  and API reference
- Improved code generation with proper subpath fallback chains
- Simplified remote module proxy to use clean default + __mfModule exports
- Removed broken dynamic export generation attempts
- Updated shell example to use default import pattern for remote modules
- Remote exports are loaded at runtime via loadRemote() and the module
  object is available through the default export
@cursor
Copy link

cursor bot commented Feb 8, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@changeset-bot
Copy link

changeset-bot bot commented Feb 8, 2026

🦋 Changeset detected

Latest commit: 28a4035

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

This PR includes changesets to release 1 package
Name Type
@module-federation/esbuild Minor

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

@netlify
Copy link

netlify bot commented Feb 8, 2026

Deploy Preview for module-federation-docs ready!

Name Link
🔨 Latest commit 28a4035
🔍 Latest deploy log https://app.netlify.com/projects/module-federation-docs/deploys/69a937d2a5bdeb000815ad4e
😎 Deploy Preview https://deploy-preview-4389--module-federation-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 8, 2026

Bundle Size Report

3 package(s) changed, 38 unchanged.

Package Total dist Delta ESM gzip Delta
esbuild 199.1 kB -67531 B (-24.9%) 457 B +341 B (+294.0%)
runtime-core 245.5 kB -226 B (-0.1%) 474 B no change
webpack-bundler-runtime 89.5 kB -64 B (-0.1%) 405 B no change

Total dist: 6.65 MB (-67821 B (-1.0%))
Total ESM gzip: 79.4 kB (+341 B (+0.4%))

- Remove dead postProcessContainerEntry code (new container uses proper
  dynamic imports, no __MODULE_MAP__ placeholder needed)
- Fix hook registration order: remote hooks now registered before shared
  hooks so remote names take priority over shared package names
- Clean up subpath shared module proxy: remove unreachable try/catch
- Forward initScope parameter in container init() to runtime
- Remove unused createExactFilter utility function
- Reduce plugin.mjs from 28.5kB to 26.5kB by removing dead code
Features added:
- shareStrategy passthrough: config.shareStrategy now correctly flows
  to both runtime init and container init code (was hardcoded)
- Eager shared modules: shared deps with eager:true now use static
  imports instead of dynamic imports, loaded synchronously at init time
- HTTPS remote support: name@https://... format now correctly parsed
  (was only matching @http, missing @https)
- Filename normalization: withFederation() now ensures .js extension
  on filename to prevent container entry matching failures

Test suite (62 tests):
- generateRuntimeInitCode: 11 tests covering init generation, remotes,
  shared config, eager modules, shareStrategy, name@url parsing
- generateContainerEntryCode: 9 tests covering get/init exports,
  module map, shared config, multiple exposes, eager, strategy
- generateSharedProxyCode: 5 tests covering loadShare, fallback,
  subpath imports, scoped packages
- generateRemoteProxyCode: 7 tests covering loadRemote, default
  export, error handling, top-level await
- moduleFederationPlugin: 5 tests covering plugin creation with
  various config shapes
- esbuild integration: 6 tests running actual esbuild builds
  verifying host builds, container builds, format/splitting auto-set,
  metafile generation, runtime init injection, remote virtual modules
- withFederation: 8 tests covering config normalization, filename
  extension handling, defaults
- Edge cases: 11 tests covering scoped packages, multiple remotes,
  multiple shared deps, empty configs, special characters, deep paths
Removed files (no longer imported after the plugin rewrite):

adapters/lib/:
- containerPlugin.ts - old webpack-emulating container (replaced by plugin.ts)
- containerReference.ts - old host init with import maps (replaced by plugin.ts)
- linkRemotesPlugin.ts - old remote handling via externals (replaced by plugin.ts)
- commonjs.ts - CJS-to-ESM transform (no longer needed)
- lexer.ts - string parser used only by commonjs.ts
- utils.ts - utility functions used only by commonjs.ts
- transform.ts - esbuild transform wrapper (unused)
- react-replacements.ts - React CJS path mappings (unused)

lib/core/:
- build-adapter.ts - abstract build adapter (unused)
- createContainerTemplate.ts - old 181-line webpack runtime emulation (replaced)
- federation-options.ts - options interface (unused)
- write-federation-info.ts - old manifest writer (replaced by manifest.ts)

Also cleaned:
- Removed dead normalizeSharedMappings function from with-native-federation.ts
- Removed unused MappedPath import from federation-config.ts
- Removed dead comment block from plugin.ts
- Removed 3 unused npm dependencies:
  @chialab/esbuild-plugin-commonjs, @hyrious/esbuild-plugin-commonjs,
  @module-federation/sdk

Net: -1,352 lines of dead code removed.
New features implemented for maximum parity with enhanced webpack plugin:

SHARE SCOPE:
- Global shareScope config (defaults to 'default', configurable)
- Per-shared-module shareScope override for isolated scoping
- Per-remote shareScope override
- shareScope flows through to initializeSharing and initShareScopeMap

RUNTIME PLUGINS:
- runtimePlugins config accepts array of file paths / package names
- Plugins are imported and injected into the MF runtime init
- Works in both host runtime init and container entry

SHARED MODULE FEATURES:
- import:false - disable local fallback, module must come from scope
- shareKey - custom key in share scope (defaults to package name)
- packageName - explicit package name for version auto-detection
- Auto version detection from node_modules package.json

PUBLIC PATH:
- publicPath config flows to manifest generation
- Defaults to 'auto'

REMOTE FEATURES:
- Per-remote shareScope config via NormalizedRemoteConfig object
- Remote config accepts both string URLs and config objects
- withFederation normalizes both formats

CONFIG NORMALIZATION:
- withFederation passes through all new fields
- Remote config objects normalized to NormalizedRemoteConfig
- All shared config fields (import, shareKey, shareScope, packageName)
  preserved through normalization

TYPES:
- NormalizedRemoteConfig interface for advanced remote config
- All new fields added to NormalizedSharedConfig
- NormalizedFederationConfig extended with shareScope, runtimePlugins,
  publicPath

CODE GENERATION:
- Shared config builder extracted to buildSharedCodeEntries() for reuse
- Empty module namespace (mf-empty) for import:false fallback handling
- Runtime plugins import/injection code generation

Tests: 83 passing (was 62), covering all new features
@ScriptedAlchemy
Copy link
Member Author

@codex review pr deeply for feature parity

Copy link

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

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: 6e3d7fe01c

ℹ️ 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".

…rage

Modeled after webpack enhanced plugin test patterns (configCases, unit, integration).

Test categories and counts:
- generateRuntimeInitCode: 27 tests
  - Basic init generation, container name, all remote entries
  - name@http and name@https parsing, plain URL fallback
  - Remote type:esm, per-remote shareScope
  - Shared config: version/scope/get, singleton/strictVersion/eager booleans
  - Eager static imports vs non-eager dynamic imports
  - import:false (no fallback), custom shareKey, per-shared shareScope
  - Global shareScope, shareStrategy, initializeSharing with await/try-catch
  - runtimePlugins injection (single, multiple, function-or-object pattern)
  - Empty remotes, empty shared, multiple shared deps

- generateContainerEntryCode: 16 tests
  - get/init function exports, module map with exposes
  - Factory return from get(), error for unknown module
  - Multiple exposes (including root '.'), initShareScopeMap/initOptions
  - initScope forwarding, initializeSharing call
  - shareStrategy, custom shareScope, shared deps
  - Eager shared, runtimePlugins, empty exposes, import:false

- generateSharedProxyCode: 13 tests
  - loadShare call, MF runtime import, fallback dynamic import
  - Default export with 'default' check, subpath imports
  - Catch for subpath loadShare failure
  - import:false (throw error, no fallback)
  - Custom shareKey in loadShare, scoped packages, scoped subpaths
  - Packages with dots, console.warn on failure

- generateRemoteProxyCode: 9 tests
  - loadRemote call, runtime import, top-level await
  - Throw on null result, export default, prefer module.default
  - __mfModule export, deep paths, dashes/underscores in names

- moduleFederationPlugin: 6 tests
  - Plugin name/setup, minimal config, host/remote/combined configs
  - Full config with all options (shareScope, runtimePlugins, publicPath, shareStrategy)

- esbuild integration: 12 tests
  - Host build with shared deps (externalized)
  - Container build with exposes (absolute paths)
  - Auto-set format/splitting, metafile generation
  - Runtime init injection into entry, no injection when not needed
  - Remote imports as virtual modules (loadRemote in output)
  - Valid ESM output (no module.exports)
  - Container entry output contains get/init functions
  - Multiple shared deps build, eager shared dep build

- withFederation normalization: 21 tests
  - Basic normalization, filename .js/.mjs handling, defaults
  - Shared config defaults (singleton, strictVersion, requiredVersion)
  - Pass-through: shareScope, shareStrategy, runtimePlugins, publicPath
  - Remote string vs config object normalization, array external
  - Shared advanced: import:false, shareKey, shareScope, packageName, eager

- Edge cases: 13 tests
  - Container with no shared, host with no remotes, minimal config
  - import:false + custom shareKey combined
  - Multiple share scopes in same config
  - Version auto-detection from requiredVersion
  - Mixed eager/non-eager shared modules
  - Special characters: dot paths, scoped packages, numbers, underscores
  - runtimePlugins: single, multiple, function-or-object dispatch
collect-exports.ts:
- Implement re-export following (was TODO): recursively resolve
  'export * from' and CJS reexports up to depth 5, with cycle detection
- Remove dead resolvePackageJson export (never imported)
- Replace console.log with console.warn for error logging
- Deduplicate export names in result

plugin.ts:
- Remove unused _fallback parameter from parseRemoteEntry()
- Replace 'any' type on getEntryPaths with proper EntryPoints union type
  (string[] | {in,out}[] | Record<string,string> | undefined)

with-native-federation.ts:
- Replace Record<string, any> with proper typed remotes map

logger.ts:
- Replace @ts-ignore with @ts-expect-error with descriptive message
- Remove eslint-disable comment (no longer needed)

share-utils.ts:
- Replace console.log with logger.warn for missing entry point warning
Dead files removed:
- src/lib/utils/mapped-paths.ts: zero importers since
  normalizeSharedMappings was removed (50 lines)
- src/resolve/esm-resolver.mjs: not imported by any source, not in
  package.json exports (19 lines)
- src/resolve/package.json: companion to esm-resolver

Dead dependency removed:
- json5: only used by mapped-paths.ts which is now deleted

Build config cleanup:
- rslib.config.ts: removed copy directive for src/resolve (no longer exists)

Code cleanup:
- collect-exports.ts: removed unnecessary 'export' on 'resolve' constant
  (only used internally by getExports, not imported elsewhere)

All 15 remaining source files verified reachable from entry points.
117 tests pass, build and types clean.
…est remotes, add changeset

P1 (shared fallback path): When shareKey differs from the package name,
the fallback import path now correctly uses the actual package name
(e.g., __mf_fallback__/react) instead of the shareKey
(e.g., __mf_fallback__/my-react). loadShare() still uses the shareKey
for scope negotiation. This ensures the local fallback can always find
the installed package on disk.

P2 (manifest object remotes): When remotes are configured as objects
({ entry: '...', shareScope: '...' }) via withFederation, the manifest
now correctly extracts the entry URL from the object. Previously it
would write an empty string, breaking tooling that reads mf-manifest.json.

Also added changeset for the minor version bump.

Added 2 regression tests for P1 (119 total).
Address maintainer feedback: remote component imports now work cleanly
without destructuring, matching the standard MF pattern.

Before (required workaround):
  import RemoteModule from 'mfe1/component';
  const RemoteApp = RemoteModule.App || RemoteModule;

After (clean default import):
  import RemoteApp from 'mfe1/component';

Changes:
- mfe1/app.tsx: changed to 'export default function App()' instead of
  named 'export function App()'. This is the standard pattern for MF
  exposed modules across the ecosystem.
- shell/app.tsx: simplified to 'import RemoteApp from mfe1/component'
  with no destructuring needed.
- README: updated docs explaining why default exports are recommended
  for exposed modules, and why named imports from remotes differ from
  webpack (real ESM requires static export declarations vs webpack's
  own module system that resolves exports dynamically at runtime).
Users can now write standard named imports from remote modules:

  import { App } from 'mfe1/component';
  import Default, { helper } from 'mfe1/utils';
  import * as Lib from 'mfe1/lib';

The plugin automatically transforms these at build time into a pattern
esbuild can handle. For example:

  import { App } from 'mfe1/component';
  // is transformed to:
  import { __mfModule as __mfR0 } from 'mfe1/component';
  const { App } = __mfR0;

This is transparent to the user - they write standard MF imports just
like webpack, and the plugin handles the ESM static export limitation.

Implementation:
- Added transformRemoteImports() using es-module-lexer to parse source
  files and rewrite import statements from remote modules
- The onLoad hook for source files now intercepts ALL files that import
  from remotes (not just entry points), applies the transform, and
  also injects runtime init for entry points
- Handles all import forms: named, aliased (as), default+named,
  namespace (*), and correctly skips type-only imports
- The remote proxy's __mfModule export provides the full loaded module
  for destructuring

Example app reverted to natural named import syntax:
  import { App as RemoteApp } from 'mfe1/component';

Tests: 135 passing (+16 new: 13 transform unit tests + 3 integration)
…sues

Security (resolves 4 'Improper code sanitization' CodeQL alerts):
- Added safeStr() wrapper around JSON.stringify for all user-provided
  config values embedded in generated code (package names, URLs, paths,
  share keys, module specifiers). JSON.stringify is safe for JS string
  embedding (escapes quotes, backslashes, control chars, unicode), but
  the explicit wrapper makes the sanitization intent visible to both
  the security scanner and reviewers.

Bug fixes:
- transformRemoteImports now handles re-exports: export { App } from
  'remote/mod' is correctly transformed to import + local binding +
  re-export. Previously this would cause an esbuild error.
- Fixed false-positive matching in the transform quick-check: now looks
  for the remote name inside quote delimiters ('name/' or 'name') instead
  of bare string.includes(name) which would match variable names.
- Added outdir validation warning when splitting is enabled without outdir.
- Removed unused _remoteName parameter from generateRemoteProxyCode.

135 tests passing.
@ScriptedAlchemy ScriptedAlchemy changed the title feat(esbuild): rebuild module federation plugin feat(esbuild): rebuild module federation plugin architecture Feb 12, 2026
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 14, 2026

Open in StackBlitz

@module-federation/devtools

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

@module-federation/cli

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

create-module-federation

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

@module-federation/data-prefetch

pnpm add https://pkg.pr.new/@module-federation/data-prefetch@0f2bc21

@module-federation/dts-plugin

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

@module-federation/enhanced

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

@module-federation/error-codes

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

@module-federation/esbuild

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

@module-federation/managers

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

@module-federation/manifest

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

@module-federation/metro

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

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

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

@module-federation/metro-plugin-rnef

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

@module-federation/modern-js

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

@module-federation/modern-js-v3

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

@module-federation/native-federation-tests

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

@module-federation/native-federation-typescript

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

@module-federation/nextjs-mf

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

@module-federation/node

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

@module-federation/retry-plugin

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

@module-federation/rsbuild-plugin

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

@module-federation/rspack

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

@module-federation/rspress-plugin

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

@module-federation/runtime

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

@module-federation/runtime-core

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

@module-federation/runtime-tools

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

@module-federation/sdk

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

@module-federation/storybook-addon

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

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

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

@module-federation/treeshake-frontend

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

@module-federation/treeshake-server

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

@module-federation/typescript

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

@module-federation/utilities

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

@module-federation/webpack-bundler-runtime

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

@module-federation/bridge-react

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

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

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

@module-federation/bridge-shared

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

@module-federation/bridge-vue3

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

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

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

commit: 0f2bc21

@github-actions
Copy link
Contributor

github-actions bot commented Feb 14, 2026

Android Release APK for all devices

🔗 Download link.

Note: if the download link expires, please re-run the workflow to generate a new build.

Generated at 2026-02-14T23:25:37.297Z UTC

@github-actions
Copy link
Contributor

github-actions bot commented Feb 14, 2026

iOS Release APP for simulators

🔗 Download link.

Note: if the download link expires, please re-run the workflow to generate a new build.

Generated at 2026-02-14T23:18:40.072Z UTC

ScriptedAlchemy and others added 22 commits February 14, 2026 14:46
…-federation-plugin-2869

# Conflicts:
#	pnpm-lock.yaml
…-federation-plugin-2869

# Conflicts:
#	pnpm-lock.yaml
Resolve the dts-plugin TYPE-001 failure by correcting package entry paths for
workspace dependencies and updating RawSource usage for webpack typings.

Co-authored-by: Cursor <cursoragent@cursor.com>
Update pnpm-lock.yaml to match branch package specifiers so checkout-install
and publish-preview no longer fail with ERR_PNPM_OUTDATED_LOCKFILE.

Co-authored-by: Cursor <cursoragent@cursor.com>
Restore sdk and error-codes export paths to the filenames emitted by the
current build so CI package resolution no longer fails on these branches.

Co-authored-by: Cursor <cursoragent@cursor.com>
…-federation-plugin-2869

# Conflicts:
#	pnpm-lock.yaml
@zhoushaw zhoushaw closed this Mar 9, 2026
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