Skip to content

fix(bundler): absolutize tegg manifest paths in bundled runtime#5973

Merged
killagu merged 1 commit into
nextfrom
fix/tegg-manifest-abs-path
Jun 20, 2026
Merged

fix(bundler): absolutize tegg manifest paths in bundled runtime#5973
killagu merged 1 commit into
nextfrom
fix/tegg-manifest-abs-path

Conversation

@killagu

@killagu killagu commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Motivation

In bundle mode the tegg manifest stores moduleReferences[].path and moduleDescriptors[].unitPath relative to baseDir (normalized by #5932). LoaderFactory.loadApp matches a module reference to its descriptor by exact path equality, and the descriptor carries the precomputed decoratedFiles. For that match to feed the precomputed files into the loader, both sides must agree on the same absolute-path contract that a non-bundle run sees — so the decorated controller/repository files flow through the manifest descriptor into LoaderFactory.loadApp without any global-store direct read.

Scope

Two small, self-contained changes:

  1. tools/egg-bundler EntryGenerator — the generated worker entry now resolves both extensions.tegg.moduleReferences[].path and moduleDescriptors[].unitPath to absolute paths under the runtime __outputDir:

    const __toAbs = (p) => (path.isAbsolute(p) ? p : path.resolve(__outputDir, p));

    The bundler copies each module's package.json under __outputDir, so these resolve correctly. Canonical worker snapshot updated to match.

  2. tegg/plugin/config App#loadModuleConfigs — resolve reference.path against baseDir directly instead of ModuleConfigUtil.resolveModuleDir, which joins relative paths under baseDir/config (the config/module.json convention) — wrong for manifest-sourced references. Manifest reference paths are kept as-is in #scanModuleReferences so they keep matching the descriptor unitPath keys.

Non-bundle behavior is unchanged

Non-bundle module references are always absolute (ModuleScanner / config/module.json are resolved at read time via path.join(configDir, ...)), so both the old resolveModuleDir and the new code pass them through untouched.

Out of scope

This deliberately does not touch ModuleLoader.ts or introduce any global bundle-store direct read; that loader-fs path is handled separately. It also does not overlap with #5932 — that PR normalized the manifest paths to relative form; this PR re-absolutizes them at runtime so every consumer sees the same contract.

Tests

  • tools/egg-bundler/test/EntryGenerator.test.ts — relative tegg manifest paths emit the absolutization block and collect controller/repository decorated files.
  • tegg/plugin/config/test/ManifestModuleReference.test.ts — a manifest-relative reference resolves under baseDir (regression: previously ENOENT under baseDir/config); an absolute reference is passed through unchanged.

Verified locally:

  • egg-bundler EntryGenerator suite (new + existing tests pass; the 8 pre-existing /private/var realpath failures are macOS-local and present on next)
  • tegg/plugin/config (5 tests) and tegg/core/loader (16 tests)
  • oxlint --type-aware, oxfmt --check, and tsgo --noEmit clean on all touched files

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved module reference path handling during app configuration loading, keeping manifest-relative paths aligned with the configured base directory and preserving absolute paths.
    • Updated bundled worker generation to runtime-absolutize tegg manifest moduleReferences.path and moduleDescriptors.unitPath under the output directory, without altering already-absolute values.
  • Tests

    • Added/expanded coverage to verify correct resolution for both relative and absolute manifest module reference paths in configuration loading and bundled worker output.

Copilot AI review requested due to automatic review settings June 19, 2026 13:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e29967b4-27cb-4e6e-9932-fbaffe964951

📥 Commits

Reviewing files that changed from the base of the PR and between d66b90d and 096bf27.

⛔ Files ignored due to path filters (1)
  • tools/egg-bundler/test/__snapshots__/EntryGenerator.worker.canonical.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • tegg/plugin/config/src/app.ts
  • tegg/plugin/config/test/ManifestModuleReference.test.ts
  • tools/egg-bundler/src/lib/EntryGenerator.ts
  • tools/egg-bundler/test/EntryGenerator.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • tools/egg-bundler/src/lib/EntryGenerator.ts
  • tegg/plugin/config/src/app.ts
  • tegg/plugin/config/test/ManifestModuleReference.test.ts
  • tools/egg-bundler/test/EntryGenerator.test.ts

📝 Walkthrough

Walkthrough

The PR fixes manifest-derived module reference path resolution in two places: #loadModuleConfigs in the tegg config plugin now resolves relative paths directly against baseDir using path.resolve instead of ModuleConfigUtil.resolveModuleDir, and EntryGenerator.#renderWorkerEntry in the egg-bundler injects a runtime block that absolutizes moduleReferences[].path and moduleDescriptors[].unitPath against __outputDir.

Changes

Manifest Module Reference Path Absolutization

Layer / File(s) Summary
Config plugin: manifest-relative path resolution fix
tegg/plugin/config/src/app.ts, tegg/plugin/config/test/ManifestModuleReference.test.ts
#loadModuleConfigs replaces ModuleConfigUtil.resolveModuleDir with path.resolve(this.app.baseDir, reference.path) for relative paths and leaves absolute paths unchanged; comments clarify the resolution semantics including bundle mode. Tests verify relative paths resolve against baseDir (not baseDir/config) and absolute paths are preserved unchanged.
Bundler: runtime tegg path absolutization in worker entry
tools/egg-bundler/src/lib/EntryGenerator.ts, tools/egg-bundler/test/EntryGenerator.test.ts
A new runtime block is injected into the generated worker entry that, when MANIFEST_DATA.extensions?.tegg is present, loops over moduleReferences and moduleDescriptors to convert each relative path/unitPath to an absolute path under __outputDir, leaving already-absolute values unchanged. The new test verifies the emitted absolutization code and that the inlined manifest retains the original relative strings.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • eggjs/egg#5846: Generates and writes moduleReferences[].path and moduleDescriptors[].unitPath into the tegg manifest extension, which are the exact fields this PR changes how to resolve.
  • eggjs/egg#5911: Modifies EntryGenerator.ts's renderWorkerEntry logic, overlapping at the same code site where this PR injects the runtime absolutization block.
  • eggjs/egg#5921: Also changes #renderWorkerEntry to handle runtime path conversion against __outputDir, directly adjacent to the tegg path absolutization added in this PR.

Suggested reviewers

  • fengmk2
  • jerryliang64
  • gxkl

Poem

🐇 Paths were wandering, lost and bare,
Relative roots hanging in the air.
path.resolve to the rescue, hip hooray!
__outputDir shows the absolute way.
No more guessing where the modules hide —
Now every reference stands dignified! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(bundler): absolutize tegg manifest paths in bundled runtime' clearly identifies the main change: a fix in the bundler that absolutizes manifest paths in the bundled runtime.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tegg-manifest-abs-path

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the tegg module path resolution logic to correctly handle relative paths in bundled environments by resolving them directly against baseDir instead of baseDir/config. It also updates the egg-bundler to emit a runtime block in the generated worker entry that resolves relative manifest paths to absolute paths under the output directory. The review feedback suggests adding defensive checks to this runtime block to prevent potential runtime crashes when mutating the manifest data.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +323 to +332
const __teggExt: any = (MANIFEST_DATA as any).extensions?.tegg;
if (__teggExt) {
const __toAbs = (p: string) => (path.isAbsolute(p) ? p : path.resolve(__outputDir, p));
if (Array.isArray(__teggExt.moduleReferences)) {
for (const __ref of __teggExt.moduleReferences) __ref.path = __toAbs(__ref.path);
}
if (Array.isArray(__teggExt.moduleDescriptors)) {
for (const __desc of __teggExt.moduleDescriptors) __desc.unitPath = __toAbs(__desc.unitPath);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

In the generated worker entry, the manifest data is cast to any and mutated at runtime. To prevent potential runtime crashes (e.g., TypeError if __ref or __desc is null/undefined, or if path/unitPath is not a string), we should add defensive checks before accessing and resolving these properties.

Suggested change
const __teggExt: any = (MANIFEST_DATA as any).extensions?.tegg;
if (__teggExt) {
const __toAbs = (p: string) => (path.isAbsolute(p) ? p : path.resolve(__outputDir, p));
if (Array.isArray(__teggExt.moduleReferences)) {
for (const __ref of __teggExt.moduleReferences) __ref.path = __toAbs(__ref.path);
}
if (Array.isArray(__teggExt.moduleDescriptors)) {
for (const __desc of __teggExt.moduleDescriptors) __desc.unitPath = __toAbs(__desc.unitPath);
}
}
const __teggExt: any = (MANIFEST_DATA as any).extensions?.tegg;
if (__teggExt) {
const __toAbs = (p: string) => (typeof p === 'string' ? (path.isAbsolute(p) ? p : path.resolve(__outputDir, p)) : p);
if (Array.isArray(__teggExt.moduleReferences)) {
for (const __ref of __teggExt.moduleReferences) {
if (__ref) __ref.path = __toAbs(__ref.path);
}
}
if (Array.isArray(__teggExt.moduleDescriptors)) {
for (const __desc of __teggExt.moduleDescriptors) {
if (__desc) __desc.unitPath = __toAbs(__desc.unitPath);
}
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — applied defensive guards in the generated worker block: __toAbs now no-ops on non-string values (typeof p === 'string'), and both loops skip null/undefined entries (if (__ref) / if (__desc)). Snapshot and the EntryGenerator assertions updated accordingly. Done in 096bf27.

@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.57%. Comparing base (7b062db) to head (096bf27).

Additional details and impacted files
@@           Coverage Diff           @@
##             next    #5973   +/-   ##
=======================================
  Coverage   85.57%   85.57%           
=======================================
  Files         669      669           
  Lines       19849    19850    +1     
  Branches     3923     3924    +1     
=======================================
+ Hits        16985    16986    +1     
  Misses       2475     2475           
  Partials      389      389           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 19, 2026

Copy link
Copy Markdown

Deploying egg with  Cloudflare Pages  Cloudflare Pages

Latest commit: 096bf27
Status: ✅  Deploy successful!
Preview URL: https://96fed1de.egg-cci.pages.dev
Branch Preview URL: https://fix-tegg-manifest-abs-path.egg-cci.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 19, 2026

Copy link
Copy Markdown

Deploying egg-v3 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 096bf27
Status: ✅  Deploy successful!
Preview URL: https://eaa629fb.egg-v3.pages.dev
Branch Preview URL: https://fix-tegg-manifest-abs-path.egg-v3.pages.dev

View logs

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@killagu killagu force-pushed the fix/tegg-manifest-abs-path branch from ba024fe to d66b90d Compare June 20, 2026 13:41
## Motivation

In bundle mode the tegg manifest stores `moduleReferences[].path` and
`moduleDescriptors[].unitPath` relative to baseDir (normalized by #5932).
`LoaderFactory.loadApp` matches a module reference to its descriptor by exact
path equality, and the descriptor carries the precomputed `decoratedFiles`.
For that match to feed the precomputed files into the loader, both sides must
agree on the same absolute-path contract that a non-bundle run sees.

## Scope

- EntryGenerator: the generated worker entry now resolves both
  `extensions.tegg.moduleReferences[].path` and `moduleDescriptors[].unitPath`
  to absolute paths under the runtime `__outputDir`
  (`path.isAbsolute(p) ? p : path.resolve(__outputDir, p)`). The bundler copies
  each module's package.json under `__outputDir`, so these resolve correctly.
  Canonical worker snapshot updated to match.
- tegg-config App#loadModuleConfigs: resolve `reference.path` against baseDir
  directly instead of `ModuleConfigUtil.resolveModuleDir`, which joins relative
  paths under `baseDir/config` (the `config/module.json` convention) — wrong for
  manifest-sourced references. Manifest reference paths are kept as-is in
  `#scanModuleReferences` so they keep matching the descriptor unitPath keys.

Non-bundle module references are always absolute (ModuleScanner /
`config/module.json` are resolved at read time), so their behavior is
unchanged: both the old and new code pass absolute paths through untouched.

This deliberately does NOT touch `ModuleLoader.ts` or introduce any global
bundle-store direct read; that loader-fs path is handled separately.

## Tests

- tools/egg-bundler EntryGenerator.test.ts: relative tegg manifest paths emit
  the absolutization block and collect controller/repository decorated files.
- tegg/plugin/config ManifestModuleReference.test.ts: a manifest-relative
  reference resolves under baseDir (regression: previously ENOENT under
  baseDir/config); an absolute reference is passed through unchanged.

Verified: egg-bundler EntryGenerator suite, tegg/plugin/config (5 tests),
tegg/core/loader (16 tests); lint, fmtcheck, typecheck clean on touched files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@killagu killagu force-pushed the fix/tegg-manifest-abs-path branch from d66b90d to 096bf27 Compare June 20, 2026 13:44
Copilot AI review requested due to automatic review settings June 20, 2026 13:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@killagu killagu merged commit f28e3ed into next Jun 20, 2026
26 checks passed
@killagu killagu deleted the fix/tegg-manifest-abs-path branch June 20, 2026 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants