Skip to content

feat(core): add manifest-backed loader fs#5943

Open
killagu wants to merge 1 commit into
nextfrom
agent/egg-dev/1539d7a6
Open

feat(core): add manifest-backed loader fs#5943
killagu wants to merge 1 commit into
nextfrom
agent/egg-dev/1539d7a6

Conversation

@killagu
Copy link
Copy Markdown
Contributor

@killagu killagu commented May 10, 2026

Summary

  • Add ManifestLoaderFS, a manifest-first LoaderFS implementation backed by StartupManifest discovery/resolve data and the bundled module loader.
  • Wire EggLoader to use ManifestLoaderFS for bundled stores and manifest-backed startup while keeping real filesystem fallback.
  • Include package metadata files in generated manifest discovery and add tests for manifest-backed glob/stat/readJSON/loadFile, plugin metadata, and fallback behavior.

Tests

  • pnpm exec vitest run packages/core/test/loader/loader_fs.test.ts packages/core/test/loader/manifest_loader_fs.test.ts packages/core/test/loader/file_loader.test.ts packages/core/test/loader/manifest_coverage.test.ts packages/core/test/loader/manifest_roundtrip.test.ts --testTimeout 20000
  • pnpm --filter @eggjs/core typecheck
  • pnpm exec oxlint packages/core/src/loader/loader_fs.ts packages/core/test/loader/manifest_loader_fs.test.ts --type-aware

Issue: EGG-98

Summary by CodeRabbit

  • New Features

    • Manifest-backed filesystem access for loading files and bundled modules; loader now prefers manifest entries when available.
  • Refactor

    • Plugin config and package checks now use the abstracted loader and respect manifest-backed files.
    • Startup manifest generation records discovered package.json basenames and avoids duplicate entries.
  • Tests

    • Added/expanded tests for manifest-backed loading, globbing, JSON parsing, bundled module loading, and related regressions.

Review Change Stack

Copilot AI review requested due to automatic review settings May 10, 2026 02:31
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 10, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 47cf31c1-abf7-4fa3-95e9-38716790d3ac

📥 Commits

Reviewing files that changed from the base of the PR and between 5aff2fd and 44f3c9a.

⛔ Files ignored due to path filters (1)
  • packages/core/test/__snapshots__/index.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (5)
  • packages/core/package.json
  • packages/core/src/loader/egg_loader.ts
  • packages/core/src/loader/loader_fs.ts
  • packages/core/test/loader/manifest_coverage.test.ts
  • packages/core/test/loader/manifest_loader_fs.test.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/core/test/loader/manifest_loader_fs.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/core/test/loader/manifest_coverage.test.ts
  • packages/core/package.json
  • packages/core/src/loader/egg_loader.ts
  • packages/core/src/loader/loader_fs.ts

📝 Walkthrough

Walkthrough

Adds ManifestLoaderFS as a manifest-backed LoaderFS, integrates it into EggLoader initialization and plugin package.json reads, records discovered package.json entries into startup manifest.fileDiscovery, adds multimatch for manifest-aware globbing, and introduces tests covering manifest-backed behavior and fallback.

Changes

Manifest-Based Filesystem Loading

Layer / File(s) Summary
ManifestLoaderFS API
packages/core/src/loader/loader_fs.ts
New ManifestLoaderFS implements LoaderFS with manifest-aware exists(), stat(), realpath(), readJSON(), glob(), and loadFile(), delegating to a RealLoaderFS fallback for unmapped paths.
Internal Utilities & Imports
packages/core/src/loader/loader_fs.ts
Imports and helpers added: manifest entry types, path normalization, glob-pattern normalization (multimatch), bundled-module default-export unwrapping, and virtual fs.Stats creation.
EggLoader Integration
packages/core/src/loader/egg_loader.ts
EggLoader now prefers or wraps ManifestLoaderFS when a bundled ManifestStore matches baseDir; plugin package.json reads use loaderFS.exists/loaderFS.readJSON; adds #collectConventionFile to record discovered package.json into manifest.fileDiscovery.
Dependency: multimatch
packages/core/package.json
Adds multimatch dependency used to filter manifest-known file candidates for glob() behavior.
Tests / Coverage
packages/core/test/loader/manifest_loader_fs.test.ts, packages/core/test/loader/manifest_coverage.test.ts
Tests validate manifest-backed exists/stat/realpath/glob/readJSON/loadFile, fallback to real FS, precedence of manifest/bundle results, and that discovered plugin package.json is recorded in manifest.fileDiscovery.

Sequence Diagram(s)

sequenceDiagram
  participant Client as EggLoader
  participant ManifestStore
  participant ManifestLoaderFS
  participant RealLoaderFS
  Client->>ManifestStore: check for manifest for baseDir
  alt manifest exists
    Client->>ManifestLoaderFS: construct with manifest + fallback RealLoaderFS
  else no manifest
    Client->>RealLoaderFS: use RealLoaderFS or provided loaderFS
  end
  Client->>ManifestLoaderFS: loaderFS.exists(package.json)
  Client->>ManifestLoaderFS: loaderFS.readJSON(package.json)
  Client->>Client: collectConventionFile -> manifest.fileDiscovery
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • eggjs/egg#5867: Introduced/used the global bundle-module loader hook consumed by ManifestLoaderFS.
  • eggjs/egg#5936: Related changes threading the LoaderFS abstraction through EggLoader and loaders.
  • eggjs/egg#5844: Prior ManifestStore and EggLoader integration that this change builds upon.

Suggested reviewers

  • fengmk2
  • gxkl
  • jerryliang64
  • akitaSummer

Poem

🐰 I hopped through manifests neat and small,
I peeked at package.json down the hall,
I matched the globs and wrapped defaults light,
When files hide, I fall back just right,
A bundle, a loader — springtime delight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(core): add manifest-backed loader fs' clearly and concisely describes the main feature addition—introducing a manifest-backed loader filesystem implementation.
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 agent/egg-dev/1539d7a6

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

Copy link
Copy Markdown
Contributor

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

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 introduces ManifestLoaderFS, a filesystem abstraction that enables loading files from a manifest or bundle map with a fallback to the physical filesystem. It integrates this into EggLoader to facilitate bundled application support. The review feedback identifies critical limitations in the custom globToRegExp implementation, specifically regarding character classes and wildcards within groups. Additionally, it is recommended to enhance createVirtualStats by including standard fs.Stats date properties to prevent potential runtime errors in external libraries.

Comment thread packages/core/src/loader/loader_fs.ts Outdated
Comment thread packages/core/src/loader/loader_fs.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/loader/egg_loader.ts (1)

653-660: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep plugin export-path probing on loaderFS too.

This now reads package.json through the manifest abstraction, but #formatPluginPathFromPackageJSON() still probes exports.import/require with utility.exists(). In manifest-only startup, that check sees no real file and can wrongly fall back to eggPlugin.exports.typescript, so bundled plugins resolve to a path that is not actually present in the manifest.

Suggested fix
-      if (exports.typescript && isSupportTypeScript() && !(await exists(realPluginPath))) {
+      if (exports.typescript && isSupportTypeScript() && !this.loaderFS.exists(realPluginPath)) {
         // if require/import path not exists, use typescript path for development stage
         realPluginPath = path.join(pluginPath, exports.typescript);
         debug('[formatPluginPathFromPackageJSON] use typescript path %o', realPluginPath);
       }
🤖 Prompt for 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.

In `@packages/core/src/loader/egg_loader.ts` around lines 653 - 660, The plugin
export-path probing currently uses a plain filesystem check inside
`#formatPluginPathFromPackageJSON` which calls utility.exists() and thus misses
manifest-only files; update `#formatPluginPathFromPackageJSON` to use the loaderFS
abstraction (this.loaderFS.exists) when probing exports.import/exports.require
and any path checks so that package.json -> plugin.path resolution honors the
manifest-only startup. Ensure the method still handles both import/require keys
and returns the same plugin.path behavior, referencing plugin.path, pkg, and
`#formatPluginPathFromPackageJSON` in your change.
🤖 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 `@packages/core/src/loader/loader_fs.ts`:
- Around line 88-99: Summary: ManifestLoaderFS.glob returns relative paths when
options.absolute is true if cwd is relative. Fix: keep using cwdRel =
this.#toRelative(...) for manifest lookup but resolve the caller-supplied cwd to
an absolute path before joining when options?.absolute is set; e.g., compute an
absolute cwd (path.resolve(cwd)) and use that in the matched.map((file) =>
path.join(absCwd, file)) so behaviour matches RealLoaderFS.glob; update the glob
method (symbols: glob, cwd, cwdRel, `#toRelative`, filterManifestGlob,
`#fallback.glob`, options.absolute) accordingly.

---

Outside diff comments:
In `@packages/core/src/loader/egg_loader.ts`:
- Around line 653-660: The plugin export-path probing currently uses a plain
filesystem check inside `#formatPluginPathFromPackageJSON` which calls
utility.exists() and thus misses manifest-only files; update
`#formatPluginPathFromPackageJSON` to use the loaderFS abstraction
(this.loaderFS.exists) when probing exports.import/exports.require and any path
checks so that package.json -> plugin.path resolution honors the manifest-only
startup. Ensure the method still handles both import/require keys and returns
the same plugin.path behavior, referencing plugin.path, pkg, and
`#formatPluginPathFromPackageJSON` in your change.
🪄 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: 5895165b-2f77-4cc2-a6b4-459e7e37142e

📥 Commits

Reviewing files that changed from the base of the PR and between 0dec2c9 and 6fc9b6c.

📒 Files selected for processing (4)
  • packages/core/src/loader/egg_loader.ts
  • packages/core/src/loader/loader_fs.ts
  • packages/core/test/loader/manifest_coverage.test.ts
  • packages/core/test/loader/manifest_loader_fs.test.ts

Comment thread packages/core/src/loader/loader_fs.ts
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 10, 2026

Deploying egg with  Cloudflare Pages  Cloudflare Pages

Latest commit: 44f3c9a
Status: ✅  Deploy successful!
Preview URL: https://f0af3aee.egg-cci.pages.dev
Branch Preview URL: https://agent-egg-dev-1539d7a6.egg-cci.pages.dev

View logs

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 10, 2026

Deploying egg-v3 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 44f3c9a
Status: ✅  Deploy successful!
Preview URL: https://1cf5af81.egg-v3.pages.dev
Branch Preview URL: https://agent-egg-dev-1539d7a6.egg-v3.pages.dev

View logs

@killagu killagu force-pushed the agent/egg-dev/1539d7a6 branch from 6fc9b6c to f7dc977 Compare May 10, 2026 02:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a manifest-first filesystem abstraction for Egg’s loader pipeline so bundled or manifest-backed startups can resolve/scan/load files using StartupManifest data (and the bundle module loader) with a real filesystem fallback.

Changes:

  • Introduces ManifestLoaderFS (manifest-first LoaderFS) supporting manifest-backed exists/stat/realpath/glob/readJSON/loadFile.
  • Wires EggLoader to select ManifestLoaderFS automatically for bundle stores and for manifest-backed startup flows, while keeping a real FS fallback.
  • Extends manifest generation to include package.json in conventional discovery, plus adds/updates tests for manifest-backed behavior and plugin metadata inclusion.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

File Description
packages/core/src/loader/loader_fs.ts Adds ManifestLoaderFS implementation and manifest-backed glob/matching helpers.
packages/core/src/loader/egg_loader.ts Integrates ManifestLoaderFS selection/wrapping and collects package.json into manifest discovery; switches plugin package.json reads to loaderFS.
packages/core/test/loader/manifest_loader_fs.test.ts Adds new unit tests covering manifest-backed FS behavior and fallback/priority rules.
packages/core/test/loader/manifest_coverage.test.ts Asserts plugin package metadata (package.json) is included in manifest fileDiscovery.

Comment thread packages/core/src/loader/loader_fs.ts Outdated
Comment thread packages/core/src/loader/loader_fs.ts
Comment thread packages/core/test/loader/manifest_loader_fs.test.ts
@killagu killagu force-pushed the agent/egg-dev/1539d7a6 branch from f7dc977 to aba2f64 Compare May 10, 2026 02:39
Copilot AI review requested due to automatic review settings May 10, 2026 02:41
@killagu killagu force-pushed the agent/egg-dev/1539d7a6 branch from aba2f64 to 5aff2fd Compare May 10, 2026 02:41
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/core/src/loader/loader_fs.ts (1)

89-102: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

absolute: true still returns relative paths when caller passes a relative cwd.

At Line 90, cwd keeps the caller-supplied value verbatim. When options.absolute is set on Line 98, path.join(cwd, file) on Line 99 yields a relative result, diverging from RealLoaderFS.glob() which goes through globby.sync(...) and returns absolute paths under the same options. This is a behavioral mismatch in what's intended to be a drop-in replacement.

Resolve cwd to an absolute path at the source so both manifest lookup and the join produce consistent results.

🔧 Suggested fix
   glob(patterns: string | string[], options?: LoaderFSGlobOptions): string[] {
-    const cwd = options?.cwd === undefined ? process.cwd() : String(options.cwd);
+    const cwd = path.resolve(options?.cwd === undefined ? process.cwd() : String(options.cwd));
     const cwdRel = this.#toRelative(cwd);
🤖 Prompt for 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.

In `@packages/core/src/loader/loader_fs.ts` around lines 89 - 102, The glob method
currently uses the caller-supplied cwd verbatim which causes path.join(cwd,
file) in the absolute branch to produce relative paths; change glob to resolve
cwd to an absolute path up-front (e.g., using path.resolve or similar) before
calling this.#toRelative and this.#listManifestFilesUnder so that both manifest
lookup and the matched.map((file) => path.join(cwd, file)) produce absolute
paths; update references in glob that use cwd (including the cwdRel assignment
and the manifest lookup) so the rest of the method and filterManifestGlob
behavior remain correct and consistent with RealLoaderFS.glob.
🤖 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.

Duplicate comments:
In `@packages/core/src/loader/loader_fs.ts`:
- Around line 89-102: The glob method currently uses the caller-supplied cwd
verbatim which causes path.join(cwd, file) in the absolute branch to produce
relative paths; change glob to resolve cwd to an absolute path up-front (e.g.,
using path.resolve or similar) before calling this.#toRelative and
this.#listManifestFilesUnder so that both manifest lookup and the
matched.map((file) => path.join(cwd, file)) produce absolute paths; update
references in glob that use cwd (including the cwdRel assignment and the
manifest lookup) so the rest of the method and filterManifestGlob behavior
remain correct and consistent with RealLoaderFS.glob.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec452c67-5f10-4098-a746-998b4a94c070

📥 Commits

Reviewing files that changed from the base of the PR and between 6fc9b6c and f7dc977.

📒 Files selected for processing (5)
  • packages/core/package.json
  • packages/core/src/loader/egg_loader.ts
  • packages/core/src/loader/loader_fs.ts
  • packages/core/test/loader/manifest_coverage.test.ts
  • packages/core/test/loader/manifest_loader_fs.test.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/core/test/loader/manifest_coverage.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/test/loader/manifest_loader_fs.test.ts
  • packages/core/src/loader/egg_loader.ts

@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

❌ Patch coverage is 92.42424% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.26%. Comparing base (0dec2c9) to head (44f3c9a).

Files with missing lines Patch % Lines
packages/core/src/loader/loader_fs.ts 91.62% 15 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             next    #5943      +/-   ##
==========================================
+ Coverage   85.21%   85.26%   +0.04%     
==========================================
  Files         669      669              
  Lines       19304    19498     +194     
  Branches     3787     3849      +62     
==========================================
+ Hits        16449    16624     +175     
- Misses       2463     2482      +19     
  Partials      392      392              

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

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