fix(bundler): normalize tegg manifest paths#5932
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR implements and integrates a bundler-based module loader mechanism. It adds support for loading pre-bundled modules via ChangesBundler Module Loader Integration
Sequence DiagramsequenceDiagram
actor User as Application Code
participant Load as LoaderUtil.loadFile()
participant Global as globalThis
participant Bundle as __EGG_BUNDLE_MODULE_LOADER__
participant Dynamic as import()
User->>Load: loadFile(filePath)
Load->>Load: normalize path (\ to /)
Load->>Global: read __EGG_BUNDLE_MODULE_LOADER__
Global-->>Load: loader function
Load->>Bundle: call loader(normalizedPath)
alt Bundle Returns Module
Bundle-->>Load: module object
Load-->>User: parsed prototypes
else Bundle Returns null/undefined
Bundle-->>Load: null/undefined
Load->>Load: apply Windows file:// conversion
Load->>Dynamic: import(filePath)
Dynamic-->>Load: module exports
Load-->>User: parsed prototypes
else Bundle Throws Error
Bundle-->>Load: Error thrown
Load->>Load: createLoadError(filePath, error)
Load-->>User: wrapped Error with cause
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Deploying egg with
|
| Latest commit: |
49408cc
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://3324b18c.egg-cci.pages.dev |
| Branch Preview URL: | https://agent-egg-dev-85bc11ed.egg-cci.pages.dev |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## next #5932 +/- ##
=======================================
Coverage 85.18% 85.19%
=======================================
Files 668 668
Lines 19284 19288 +4
Branches 3782 3784 +2
=======================================
+ Hits 16428 16432 +4
Misses 2464 2464
Partials 392 392 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request introduces a bundle module loader mechanism to tegg/core/loader and updates tools/egg-bundler to support path normalization for moduleReferences and moduleDescriptors. The changes include adding a global hook for module loading, updating the loadFile utility, and adding comprehensive tests for the new functionality. A review comment suggests improving error handling in the catch block to safely handle non-Error exceptions.
Deploying egg-v3 with
|
| Latest commit: |
49408cc
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://aa037ac2.egg-v3.pages.dev |
| Branch Preview URL: | https://agent-egg-dev-85bc11ed.egg-v3.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tegg/core/loader/src/LoaderUtil.ts`:
- Around line 73-91: The bundle loader can return null to indicate "not bundled"
but the current fallback only checks exports === undefined causing a later
TypeError; update the check around the bundle result (the local variable exports
produced by (globalThis as BundleModuleGlobalThis).__EGG_BUNDLE_MODULE_LOADER__
invocation in LoaderUtil.ts) to treat both null and undefined as "not bundled"
(e.g., use exports == null or explicit exports === undefined || exports ===
null) so the dynamic import fallback (await import(filePath)) runs when the
bundle loader returns null.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d8b70aa8-a84f-446c-b4dc-5f3f7812fbb7
📒 Files selected for processing (5)
tegg/core/loader/src/LoaderUtil.tstegg/core/loader/test/Loader.test.tstools/egg-bundler/src/lib/ManifestLoader.tstools/egg-bundler/test/EntryGenerator.test.tstools/egg-bundler/test/ManifestLoader.test.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tegg/core/loader/src/LoaderUtil.ts`:
- Around line 73-75: The call to the global bundle loader in LoaderUtil.loadFile
is not wrapped in a try/catch so thrown values bypass the standard
"[tegg/loader] load ... failed" wrapper; update the code around the
__EGG_BUNDLE_MODULE_LOADER__ invocation in loadFile to catch any thrown value
(including non-Error), and rethrow a new Error that prefixes the original
message/stack with "[tegg/loader] load <originalFilePath> failed: " (or include
the original error message when no stack exists) so behavior matches the
import-failure handling currently used in the later catch block.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: df572c9c-91e5-441a-bf15-9b21cb511433
📒 Files selected for processing (2)
tegg/core/loader/src/LoaderUtil.tstegg/core/loader/test/Loader.test.ts
There was a problem hiding this comment.
Pull request overview
This PR updates the bundling pipeline and tegg loader integration so that tegg manifest paths and decorated files remain resolvable in a bundled runtime, and so tegg can load pre-bundled modules via the bundle module loader before falling back to dynamic import.
Changes:
- Normalize tegg
moduleReferences[].pathandmoduleDescriptors[].unitPathto consistent, app-relative (or moduleMap-normalized) paths during manifest normalization. - Expand
EntryGeneratorcoverage to include decorated files underapp/portfrom tegg manifest descriptors. - Enhance
LoaderUtil.loadFile()to consult a registeredglobalThis.__EGG_BUNDLE_MODULE_LOADER__first, with tests covering the fast-path and fallback behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/egg-bundler/src/lib/ManifestLoader.ts | Normalize tegg module reference/descriptor paths via a shared helper to ensure consistent keys at runtime. |
| tools/egg-bundler/test/ManifestLoader.test.ts | Add regression test asserting tegg path normalization and decorated-file resolution. |
| tools/egg-bundler/test/EntryGenerator.test.ts | Add test ensuring app/port tegg-decorated files are included in generated worker imports. |
| tegg/core/loader/src/LoaderUtil.ts | Add bundle-module-loader fast path before dynamic import for pre-bundled file loading. |
| tegg/core/loader/test/Loader.test.ts | Add tests for bundle-module-loader loading and fallback, plus global cleanup between tests. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tegg/core/loader/src/LoaderUtil.ts`:
- Around line 88-90: The import failure wrapper is using filePath (which can be
a file:// URL on Windows) when calling createLoadError; change the catch to call
createLoadError with originalFilePath instead so the error uses the
caller-facing path. Locate the catch block around the dynamic import (the line
with "exports = await import(filePath);" and the subsequent throw
createLoadError(...)) and replace the second argument from filePath to
originalFilePath; keep the original caught error (e) passed through unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e465c7db-34d3-4a51-9328-1ccd149139dd
⛔ Files ignored due to path filters (1)
tools/egg-bundler/test/__snapshots__/EntryGenerator.worker.canonical.snapis excluded by!**/*.snap
📒 Files selected for processing (4)
packages/utils/src/import.tstegg/core/loader/src/LoaderUtil.tstegg/core/loader/test/Loader.test.tstools/egg-bundler/src/lib/EntryGenerator.ts
## 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>
## 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>
## 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`: ```js 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](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## 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. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Tests
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Chores