Skip to content

fix(bundler): externalize native optional wrappers#5919

Merged
killagu merged 1 commit intonextfrom
agent/egg-dev/70acad08
May 3, 2026
Merged

fix(bundler): externalize native optional wrappers#5919
killagu merged 1 commit intonextfrom
agent/egg-dev/70acad08

Conversation

@killagu
Copy link
Copy Markdown
Contributor

@killagu killagu commented May 3, 2026

Summary

  • externalize packages whose installed optional dependencies contain native binary signals
  • add resolver fixture coverage for native optional-wrapper packages and plain JS optional dependencies
  • verify cnpmcore @cnpmjs/packument is now classified as external

Validation

  • pnpm exec oxfmt --check src/lib/ExternalsResolver.ts test/ExternalsResolver.test.ts test/fixtures/externals/basic-app/package.json
  • pnpm exec oxlint --type-aware src/lib/ExternalsResolver.ts test/ExternalsResolver.test.ts
  • pnpm exec tsgo --noEmit
  • pnpm exec vitest run test/ExternalsResolver.test.ts
  • pnpm test in tools/egg-bundler

cnpmcore smoke

  • cnpmcore commit: 9717849939271f1144d211b862ae86c04ba7605d
  • installed @cnpmjs/packument@1.7.0 includes optional platform package @cnpmjs/packument-linux-x64-gnu with packument.linux-x64-gnu.node
  • patched resolver output includes @cnpmjs/packument
  • patched bundle manifest includes @cnpmjs/packument; forced-inline bundle manifest does not
  • local worker run still stops earlier on supports-color interop before reaching packument in this environment, so this PR fixes the packument external classification boundary rather than the next runtime blocker

Summary by CodeRabbit

  • New Features

    • Improved bundler detection to externalize packages that include native code via their optional dependencies.
  • Tests

    • Added tests confirming packages with native optional dependencies are externalized.
    • Added tests ensuring packages with only JS optional dependencies remain internal.

Copilot AI review requested due to automatic review settings May 3, 2026 07:00
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 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: 28bd0421-aaef-4ee8-805d-40b222662dfa

📥 Commits

Reviewing files that changed from the base of the PR and between 1699b14 and 3daeece.

⛔ Files ignored due to path filters (5)
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-platform/addon.node is excluded by !**/node_modules/**
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-platform/package.json is excluded by !**/node_modules/**
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-wrapper/package.json is excluded by !**/node_modules/**
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/optional-js-dep/package.json is excluded by !**/node_modules/**
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/optional-js-wrapper/package.json is excluded by !**/node_modules/**
📒 Files selected for processing (3)
  • tools/egg-bundler/src/lib/ExternalsResolver.ts
  • tools/egg-bundler/test/ExternalsResolver.test.ts
  • tools/egg-bundler/test/fixtures/externals/basic-app/package.json
✅ Files skipped from review due to trivial changes (2)
  • tools/egg-bundler/test/ExternalsResolver.test.ts
  • tools/egg-bundler/test/fixtures/externals/basic-app/package.json

📝 Walkthrough

Walkthrough

Adds detection of native binaries inside a package's optionalDependencies: ExternalsResolver now resolves each optional dependency, reads its package.json, and externalizes the parent package if any optional dependency contains native indicators.

Changes

Native optional-dependency native detection

Layer / File(s) Summary
Control / Decision
tools/egg-bundler/src/lib/ExternalsResolver.ts
#shouldExternalize now returns true when #hasNativeOptionalDependency(pkgDir, pkg) detects a native optional dependency (added after existing native/peer checks).
Core Implementation
tools/egg-bundler/src/lib/ExternalsResolver.ts
Added private #hasNativeOptionalDependency(pkgDir, pkg) which iterates pkg.optionalDependencies, resolves each dependency directory relative to pkgDir, loads the dependency's package.json, and calls #hasNativeBinary on each; returns true if any are native.
Test Fixtures
tools/egg-bundler/test/fixtures/externals/basic-app/package.json
Added native-optional-wrapper and optional-js-wrapper to dependencies for test coverage.
Tests
tools/egg-bundler/test/ExternalsResolver.test.ts
Added assertions: expect native-optional-wrapper to be externalized when its installed optional dependency is native; expect optional-js-wrapper not to appear in externals when its optional dependencies are plain JS.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hop through manifests, sniffing each nest,
Optional deps checked, I do my best.
If native greens hide in a sibling's den,
I mark the parent outbound, again and again.
A tiny rabbit, with bundler approved, I rest then.

🚥 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): externalize native optional wrappers' directly and specifically describes the main change: extending native binary detection to include optional dependencies.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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/70acad08

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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

@codecov
Copy link
Copy Markdown

codecov Bot commented May 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.04%. Comparing base (9ae1df0) to head (3daeece).
⚠️ Report is 2 commits behind head on next.

Additional details and impacted files
@@           Coverage Diff           @@
##             next    #5919   +/-   ##
=======================================
  Coverage   85.04%   85.04%           
=======================================
  Files         667      667           
  Lines       19123    19123           
  Branches     3723     3723           
=======================================
  Hits        16263    16263           
  Misses       2467     2467           
  Partials      393      393           

☔ 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

@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 logic to detect native binaries within optional dependencies, ensuring that wrapper packages are correctly externalized if any of their optional dependencies are native. This is implemented via a new #hasNativeOptionalDependency method in ExternalsResolver, accompanied by relevant test cases and fixtures. A review comment suggests reordering the checks in the resolution logic to prioritize the faster #hasNativeBinary check over the more expensive #hasNativeOptionalDependency check to improve performance through earlier short-circuiting.

Comment thread tools/egg-bundler/src/lib/ExternalsResolver.ts Outdated
@cloudflare-workers-and-pages
Copy link
Copy Markdown

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

Deploying egg with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3daeece
Status: ✅  Deploy successful!
Preview URL: https://85ab7720.egg-cci.pages.dev
Branch Preview URL: https://agent-egg-dev-70acad08.egg-cci.pages.dev

View logs

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.

🧹 Nitpick comments (1)
tools/egg-bundler/src/lib/ExternalsResolver.ts (1)

112-120: ⚡ Quick win

Confirm whether one hop of optional-dep scanning is enough.

This only checks each immediate optional dependency with #hasNativeBinary(). A chain like wrapper-a -> optional wrapper-b -> optional native-c still returns false for wrapper-a, so another native optional wrapper would be inlined. If wrapper-of-wrapper packages are in scope here, recurse into #hasNativeOptionalDependency(depDir, depPkg) with a visited set and add a fixture for that shape.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/egg-bundler/src/lib/ExternalsResolver.ts` around lines 112 - 120, The
current `#hasNativeOptionalDependency` only checks immediate optionalDependencies
and misses chains (e.g., wrapper-a -> optional wrapper-b -> optional native-c);
update `#hasNativeOptionalDependency` to recursively scan optional dependencies by
calling itself for each optional dep (after resolving with `#findPackageDir` and
reading with `#readPackageJson`), track visited package dirs/names to avoid
cycles, and return true if either `#hasNativeBinary`(...) or the recursive
`#hasNativeOptionalDependency`(...) on a dependency returns true; also add a unit
fixture that models a wrapper-of-wrapper scenario to verify the recursion and
visited-set handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tools/egg-bundler/src/lib/ExternalsResolver.ts`:
- Around line 112-120: The current `#hasNativeOptionalDependency` only checks
immediate optionalDependencies and misses chains (e.g., wrapper-a -> optional
wrapper-b -> optional native-c); update `#hasNativeOptionalDependency` to
recursively scan optional dependencies by calling itself for each optional dep
(after resolving with `#findPackageDir` and reading with `#readPackageJson`), track
visited package dirs/names to avoid cycles, and return true if either
`#hasNativeBinary`(...) or the recursive `#hasNativeOptionalDependency`(...) on a
dependency returns true; also add a unit fixture that models a
wrapper-of-wrapper scenario to verify the recursion and visited-set handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 043ba6a3-1fdc-4964-b5fb-ffb7d33f2416

📥 Commits

Reviewing files that changed from the base of the PR and between 9ae1df0 and 1699b14.

⛔ Files ignored due to path filters (5)
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-platform/addon.node is excluded by !**/node_modules/**
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-platform/package.json is excluded by !**/node_modules/**
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-wrapper/package.json is excluded by !**/node_modules/**
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/optional-js-dep/package.json is excluded by !**/node_modules/**
  • tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/optional-js-wrapper/package.json is excluded by !**/node_modules/**
📒 Files selected for processing (3)
  • tools/egg-bundler/src/lib/ExternalsResolver.ts
  • tools/egg-bundler/test/ExternalsResolver.test.ts
  • tools/egg-bundler/test/fixtures/externals/basic-app/package.json

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

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

Deploying egg-v3 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3daeece
Status: ✅  Deploy successful!
Preview URL: https://7a2d85f4.egg-v3.pages.dev
Branch Preview URL: https://agent-egg-dev-70acad08.egg-v3.pages.dev

View logs

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

Updates ExternalsResolver in tools/egg-bundler to classify “wrapper” packages as externals when their installed optionalDependencies exhibit native-addon signals (e.g., *.node, binding.gyp, prebuilds/, native install scripts). This tightens bundling correctness for cases like @cnpmjs/packument where the wrapper is JS but optionally installs a native platform package.

Changes:

  • Add optional-dependency scanning (#hasNativeOptionalDependency) to externalize wrapper packages when an installed optional dep is native.
  • Extend resolver fixture set with a “native optional wrapper” and a “plain JS optional wrapper” to cover both positive and negative cases.
  • Add Vitest assertions validating the new externalization behavior.

Reviewed changes

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

Show a summary per file
File Description
tools/egg-bundler/src/lib/ExternalsResolver.ts Adds #hasNativeOptionalDependency check into native externalization decision path.
tools/egg-bundler/test/ExternalsResolver.test.ts Adds test coverage for native optional-wrapper externalization and JS-only optional dependency non-externalization.
tools/egg-bundler/test/fixtures/externals/basic-app/package.json Declares new fixture dependencies used by the added tests.
tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-wrapper/package.json Fixture wrapper package with an optional dependency.
tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-platform/package.json Fixture optional dependency package.
tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/native-optional-platform/addon.node Native signal fixture (*.node) for detection.
tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/optional-js-wrapper/package.json Fixture JS-only wrapper package with optional dependency.
tools/egg-bundler/test/fixtures/externals/basic-app/node_modules/optional-js-dep/package.json Fixture JS-only optional dependency package.

@killagu killagu force-pushed the agent/egg-dev/70acad08 branch from 1699b14 to 3daeece Compare May 3, 2026 07:25
@killagu killagu merged commit 77fbaef into next May 3, 2026
38 of 40 checks passed
@killagu killagu deleted the agent/egg-dev/70acad08 branch May 3, 2026 08:42
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