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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions