Skip to content

Tracking: split #5863 into 19 small PRs #5871

@killagu

Description

@killagu

Goal

Split #5863 (a 4812-line monolithic PR adding @eggjs/egg-bundler for turbopack-based application bundling) into 19 small, independently-reviewable stacked PRs.

#5863 stays open as the reference / smoke-test PR. The 19 small PRs land incrementally via a stacked-PR workflow.

Architecture (5 layers — see #5863 for detailed explanation)

  1. Manifest pre-computationManifestLoader spawns generate-manifest.mjs (with tsx loader injected) to dump file discovery / resolveCache / tegg metadata; realpath → node_modules/<pkg> normalization.
  2. Externals resolutionExternalsResolver excludes native addons / ESM-only-without-require / peerDeps. Final commit removes @eggjs/* from always-external so the framework itself can be bundled.
  3. Entry generationEntryGenerator writes a synthetic worker.entry.ts with sorted static imports, inlined MANIFEST_DATA, dual-keyed BUNDLE_MAP, runtime baseDir via process.argv[1], and startEgg({mode:'single'}) + app.listen().
  4. Build orchestrationBundler wires the 4 layers; PackRunner wraps @utoo/pack/cjs/commands/build.js with pre-written tsconfig (decorators) + package.json {type:'commonjs'}.
  5. Runtime support APIs@eggjs/utils.setBundleModuleLoader, @eggjs/core.ManifestStore.fromBundle, ManifestStore.setBundleStore. State on globalThis to cross bundled/external module-instance boundaries.

Plus plugin compatibility patches (onerror/development/watcher) that inline templates and replace path-based references with class imports.

cnpmcore E2E result on #5863: externals 76 → 12, HTTP 200.

PR map (19 PRs, stacked)

Stack A — Runtime APIs (base: next)

# PR Title Status
01 #5867 feat(utils): add setBundleModuleLoader runtime hook Open
02 #5876 feat(core): add ManifestStore.fromBundle for bundled artifacts Open (stacked on #5867)
03 #5877 feat(core): add ManifestStore.setBundleStore hook Open (stacked on #5876)

Stack B — Plugin patches (independent, base: next)

# PR Title Status
04 #5868 refactor(onerror): inline error page template as string constant Open
05 #5869 refactor(development): inline loader trace template as string constant Open
06 #5870 refactor(watcher): use direct class imports for event sources Open

Stack C — Bundler package (stacked on Stack A)

# PR Title Status
07 #5878 feat(bundler): scaffold @eggjs/egg-bundler package Open (stacked on #5877)
08 #5879 feat(bundler): add ExternalsResolver Open (stacked on #5878)
09 #5880 feat(bundler): add ManifestLoader with realpath normalization Open (stacked on #5879)
10 #5881 feat(bundler): add generate-manifest subprocess with tsx injection Open (stacked on #5880)
11 #5882 feat(bundler): define BundlerConfig public API Open (stacked on #5881)
12 #5883 feat(bundler): add EntryGenerator with sorted static imports Open (stacked on #5882)
13 #5884 feat(bundler): add PackRunner wrapper over @utoo/pack Open (stacked on #5883)
14 #5885 feat(bundler): add Bundler orchestrator Open (stacked on #5884)
15 #5886 test(bundler): verify no-fs-scan contract and bundle determinism Open (stacked on #5885)
16 #5887 test(bundler): add tegg-app fixture with HTTPController + service Open (stacked on #5886)

Stack D+E — CLI + final integration (stacked on Stack C)

# PR Title Status
17 #5888 feat(egg-bin): add bundle subcommand Open (stacked on #5887)
18 #5889 feat(bundler): remove @eggjs/* from auto-externals Open (stacked on #5888)
19 #5890 feat(bundler): post-process turbopack output to fix import.meta.url Open (stacked on #5889)

Merge order

Stack A (#5867#5876#5877) must merge first — other stacks depend on the runtime APIs.

Stack B (#5868, #5869, #5870) can merge in any order, at any time — fully independent.

Stack C (#5878 → ... → #5887) merges after Stack A. Each PR in sequence.

Stack D+E (#5888#5889#5890) merges after Stack C.

When merging a stacked PR: after the bottom PR lands into next, GitHub will auto-update the next PR's base to next. Review and merge in order.

Improvements over #5863

These split PRs fix issues present in #5863:

Handoff context for agents

Branch structure

All 19 split/* branches are pushed to origin (eggjs/egg). They form a linear stack:

origin/next
  └─ split/01-utils-bundle-module-loader          (A1)
       └─ split/05-core-from-bundle                (A2)
            └─ split/06-core-set-bundle-store       (A3)
                 └─ split/07-bundler-scaffold       (C1)
                      └─ ... (linear chain) ...
                           └─ split/19-bundler-patch-import-meta (E2)

Stack B branches (split/02-*, split/03-*, split/04-*) are independently based on origin/next.

After a PR merges

When the bottom PR of a stack merges into next:

  1. GitHub auto-retargets the next PR to next
  2. If there are merge conflicts (unlikely since each PR touches different files), rebase the branch onto origin/next and force-push
  3. No action needed for higher PRs in the stack — they still point at their intermediate base branches

If next advances with unrelated commits

The split branches may need rebasing. Procedure:

  1. git fetch origin next
  2. In the split/c-orchestration branch: git rebase origin/next
  3. Recreate per-PR branches: git branch -f split/XX-name <commit-oid>
  4. Force-push all branches: git push origin --force split/01-* split/05-* ... split/19-*

Key files per PR

PR Primary files
#5867 (A1) packages/utils/src/import.ts, packages/utils/test/bundle-import.test.ts
#5876 (A2) packages/core/src/loader/manifest.ts
#5877 (A3) packages/core/src/loader/manifest.ts
#5868 (B1) plugins/onerror/src/lib/onerror_page.ts, plugins/onerror/src/app.ts, plugins/onerror/src/config/config.default.ts
#5869 (B2) plugins/development/src/app/middleware/loader_trace_template.ts, plugins/development/src/app/middleware/egg_loader_trace.ts
#5870 (B3) plugins/watcher/src/config/config.default.ts
#5878 (C1) tools/egg-bundler/{package.json,tsconfig.json,tsdown.config.ts,vitest.config.ts}, pnpm-workspace.yaml, root tsconfig.json, root tsdown.config.ts
#5879 (C2) tools/egg-bundler/src/lib/ExternalsResolver.ts, tools/egg-bundler/test/ExternalsResolver.test.ts
#5880 (C3) tools/egg-bundler/src/lib/ManifestLoader.ts
#5881 (C4) tools/egg-bundler/src/scripts/generate-manifest.mjs, tools/egg-bundler/src/lib/ManifestLoader.ts
#5882 (C5) tools/egg-bundler/src/index.ts, tools/egg-bundler/test/index.test.ts
#5883 (C6) tools/egg-bundler/src/lib/EntryGenerator.ts, tools/egg-bundler/test/EntryGenerator.test.ts
#5884 (C7) tools/egg-bundler/src/lib/PackRunner.ts, tools/egg-bundler/test/PackRunner*.test.ts
#5885 (C8) tools/egg-bundler/src/lib/Bundler.ts, tools/egg-bundler/test/integration.test.ts, tools/egg-bundler/docs/output-structure.md
#5886 (C9) tools/egg-bundler/test/deterministic.test.ts, tools/egg-bundler/test/no-filesystem-scan.test.ts
#5887 (C10) tools/egg-bundler/test/fixtures/apps/tegg-app/**
#5888 (D1) tools/egg-bin/src/commands/bundle.ts, tools/egg-bin/src/index.ts, tools/egg-bin/package.json
#5889 (E1) tools/egg-bundler/src/lib/ExternalsResolver.ts, tools/egg-bundler/test/ExternalsResolver.test.ts
#5890 (E2) tools/egg-bundler/src/lib/Bundler.ts

Test commands

# Stack A
pnpm --filter=@eggjs/utils test    # A1: 60 pass + 13 skip
pnpm --filter=@eggjs/core test     # A2, A3: 420 pass + 25 skip

# Stack B
pnpm --filter=@eggjs/onerror test      # B1: 36/36
pnpm --filter=@eggjs/development test  # B2: 12 pass + 5 skip
pnpm --filter=@eggjs/watcher test      # B3: 4/4 + 4 skip

# Stack C, D, E
pnpm --filter=@eggjs/egg-bundler test  # 60 pass + 1 skip
pnpm --filter=@eggjs/bin typecheck     # D1: typecheck clean

🤖 Generated with Claude Code


Agent operational notes

Local master branch for rebasing

All 19 per-PR branches are derived from a single linear branch split/c-orchestration (current tip: 9911d5363). When rebasing is needed:

# 1. Rebase the master branch
cd /path/to/egg
git checkout split/c-orchestration
git fetch origin next
git rebase origin/next

# 2. Recreate per-PR branches from new OIDs
git log --oneline split/c-orchestration -16  # read new OIDs
git branch -f split/01-utils-bundle-module-loader <A1-oid>
git branch -f split/05-core-from-bundle <A2-oid>
# ... etc for all 16 stack branches

# 3. Cherry-pick B branches independently (not in c-orchestration stack)
# B1, B2, B3 touch different files; cherry-pick onto origin/next

# 4. Force-push BOTH remotes
git push origin --force split/01-* split/02-* split/03-* split/04-* split/05-* split/06-* split/07-* split/08-* split/09-* split/10-* split/11-* split/12-* split/13-* split/14-* split/15-* split/16-* split/17-* split/18-* split/19-*
git push fork --force split/01-* split/02-* split/03-* split/04-* split/05-* split/06-* split/07-* split/08-* split/09-* split/10-* split/11-* split/12-* split/13-* split/14-* split/15-* split/16-* split/17-* split/18-* split/19-*

Branches exist on both remotes

All split/* branches are pushed to:

  • origin (eggjs/egg) — needed as stacked PR base branches
  • fork (killagu/egg) — the original source

Both must be force-pushed when rebasing.

pnpm install constraint

ut install (the utoo skill) does NOT support pnpm workspace catalog: specifiers. For dependency install, use pnpm install directly:

pnpm install --no-frozen-lockfile  # catalog deps require this

For running tests, use pnpm --filter=<pkg> run test or npx vitest run --project=<pkg> directly.

lint-staged quirk with fixture-only commits

The pre-commit hook runs oxlint via lint-staged. Commits touching only test/fixtures/** files will be rejected with "No files found to lint" because oxlint ignores fixture dirs. Workaround: include at least one non-fixture source change in the commit (e.g., a structural assertion test in integration.test.ts).

Agent worktrees (may have been pruned)

Previous session created worktrees under .claude/worktrees/agent-*. Check git worktree list — they may still exist. The key one is agent-aa51f131 which had split/c-orchestration checked out.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions