Skip to content

feat: introduce external-bundle-rsbuild-plugin#2006

Merged
luhc228 merged 1 commit intolynx-family:mainfrom
luhc228:feat/plugin-external-bundle
Dec 22, 2025
Merged

feat: introduce external-bundle-rsbuild-plugin#2006
luhc228 merged 1 commit intolynx-family:mainfrom
luhc228:feat/plugin-external-bundle

Conversation

@luhc228
Copy link
Collaborator

@luhc228 luhc228 commented Dec 18, 2025

Summary by CodeRabbit

  • New Features

    • Added an rsbuild plugin to register and manage external bundles.
    • React plugin now exposes LAYERS for other plugins to consume.
  • Documentation

    • Added README, CHANGELOG and API report for the new plugin with usage examples.
    • Website docs and example project updated to show new plugin configuration.
  • Tests

    • Added integration tests and test stubs covering plugin registration, layer exposure, and error cases.
  • Chores

    • Added package metadata, TypeScript build/test configs, vitest config, and changeset entries.

✏️ Tip: You can customize this high-level summary in your review settings.

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

@changeset-bot
Copy link

changeset-bot bot commented Dec 18, 2025

🦋 Changeset detected

Latest commit: a161a87

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@lynx-js/external-bundle-rsbuild-plugin Patch
@lynx-js/react-rsbuild-plugin Patch
@lynx-js/react-alias-rsbuild-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 18, 2025

📝 Walkthrough

Walkthrough

Adds a new rsbuild plugin package @lynx-js/external-bundle-rsbuild-plugin that wraps ExternalsLoadingPlugin, exposes and consumes LAYERS via the rsbuild API, includes tests, docs, example migration, config/build files, and registers docs sidebar entries.

Changes

Cohort / File(s) Summary
New external-bundle package
packages/rspeedy/plugin-external-bundle/src/index.ts, packages/rspeedy/plugin-external-bundle/package.json, packages/rspeedy/plugin-external-bundle/api-extractor.json, packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
Adds pluginExternalBundle(options: PluginExternalBundleOptions): RsbuildPlugin and PluginExternalBundleOptions (Pick of ExternalsLoadingPluginOptions.externals); wraps ExternalsLoadingPlugin, reads LAYERS via rsbuild API, maps layer names into plugin options, and provides package metadata and API extractor.
Tests & test helpers
packages/rspeedy/plugin-external-bundle/test/index.test.ts, packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts
Adds tests verifying plugin registration, layer propagation, empty externals behavior, and missing LAYERS error; adds pluginStubLayers test helper that exposes LAYERS.
Package build & dev config
packages/rspeedy/plugin-external-bundle/tsconfig.build.json, packages/rspeedy/plugin-external-bundle/tsconfig.json, packages/rspeedy/plugin-external-bundle/vitest.config.ts
Adds TypeScript build config, package tsconfig, and Vitest project config for the new package.
Docs, changelog & changesets
packages/rspeedy/plugin-external-bundle/README.md, packages/rspeedy/plugin-external-bundle/CHANGELOG.md, .changeset/plugin-externals-rsbuild.md, .changeset/sixty-emus-call.md
Adds README and CHANGELOG for the plugin and changeset entries documenting plugin addition and LAYERS exposure.
Example migration & website
examples/react-externals/lynx.config.js, examples/react-externals/package.json, website/package.json, website/rspress.config.ts
Migrates example to use pluginExternalBundle(...), swaps example devDependency, adds website devDependency, and registers API sidebar entries for the plugin.
Expose LAYERS from React plugin
packages/rspeedy/plugin-react/src/pluginReactLynx.ts
Adds api.expose(Symbol.for('LAYERS'), LAYERS) in plugin setup so other rsbuild plugins can consume layer names.
Misc repo updates
packages/rspeedy/lynx-bundle-rslib-config/src/index.ts, packages/rspeedy/tsconfig.json
Removes large header comments from package index and adds a project reference for the new package in the repo TS config.
Changesets entry
.changeset/plugin-externals-rsbuild.md
New changeset added describing the plugin and example usage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30–40 minutes

  • Pay extra attention to:
    • LAYERS exposure/consumption and the error path when LAYERS are missing.
    • Type alignment with ExternalsLoadingPluginOptions and the Pick usage.
    • Tests that mock/intercept rspack plugin registration and their assertions.

Possibly related PRs

Suggested reviewers

  • colinaaa
  • upupming

Poem

🐇 I hopped a plugin into sight,
wrapped externals snug and tight,
layers shared so others might,
tests danced under lantern light.
carrots for the release tonight.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: introduce external-bundle-rsbuild-plugin' clearly and specifically describes the main change: introducing a new external-bundle-rsbuild-plugin. It directly matches the primary objective of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@luhc228 luhc228 enabled auto-merge (squash) December 18, 2025 12:28
@luhc228 luhc228 disabled auto-merge December 18, 2025 12:28
@luhc228 luhc228 enabled auto-merge (squash) December 18, 2025 12:29
@luhc228 luhc228 disabled auto-merge December 18, 2025 12:29
@luhc228 luhc228 enabled auto-merge (squash) December 18, 2025 12:29
Copy link
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: 4

🧹 Nitpick comments (2)
packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1)

6-9: Consider extracting ExposedLayers to a shared location.

The ExposedLayers interface is duplicated here and likely in other locations. While acceptable for test stubs, consider exporting this interface from a shared package to maintain consistency and prevent type drift.

packages/rspeedy/plugin-external-bundle/test/index.test.ts (1)

105-139: Consider testing invalid configurations.

While the current tests cover the happy path, empty config, and custom layers, consider adding tests for invalid configurations such as:

  • Missing required fields (url, background, mainThread)
  • Malformed URLs
  • Invalid layer names

This would improve test robustness and help catch configuration errors early.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7add9c4 and 7b12ccd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/plugin-externals-rsbuild.md (1 hunks)
  • .changeset/sixty-emus-call.md (1 hunks)
  • examples/react-externals/lynx.config.js (2 hunks)
  • examples/react-externals/package.json (1 hunks)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts (0 hunks)
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/README.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/api-extractor.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/package.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/src/index.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts (1 hunks)
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts (1 hunks)
  • packages/rspeedy/tsconfig.json (1 hunks)
  • website/package.json (1 hunks)
  • website/rspress.config.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts
🧰 Additional context used
📓 Path-based instructions (2)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, generate and commit a Changeset describing your changes

Files:

  • .changeset/plugin-externals-rsbuild.md
  • .changeset/sixty-emus-call.md
packages/**/etc/*.api.md

📄 CodeRabbit inference engine (AGENTS.md)

Always commit API extractor output after running pnpm turbo api-extractor -- --local (commit updated API report files)

Files:

  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
🧠 Learnings (25)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/package.json
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts
  • packages/rspeedy/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • packages/rspeedy/plugin-external-bundle/README.md
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • packages/rspeedy/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • website/package.json
  • .changeset/plugin-externals-rsbuild.md
  • examples/react-externals/package.json
  • .changeset/sixty-emus-call.md
  • packages/rspeedy/plugin-external-bundle/README.md
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • website/package.json
  • .changeset/plugin-externals-rsbuild.md
  • packages/rspeedy/plugin-external-bundle/package.json
  • examples/react-externals/package.json
  • .changeset/sixty-emus-call.md
  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • website/package.json
  • .changeset/plugin-externals-rsbuild.md
  • packages/rspeedy/plugin-external-bundle/package.json
  • examples/react-externals/package.json
  • packages/rspeedy/plugin-external-bundle/README.md
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • website/package.json
  • examples/react-externals/package.json
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • website/package.json
  • .changeset/plugin-externals-rsbuild.md
  • packages/rspeedy/plugin-external-bundle/package.json
  • examples/react-externals/package.json
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1771
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_component_with_static_sibling.js:2-2
Timestamp: 2025-09-18T04:43:54.426Z
Learning: In the lynx-family/lynx-stack repository, the `add_pure_comment` function in packages/react/transform/src/swc_plugin_compat/mod.rs (around lines 478-482) is specifically for `wrapWithLynxComponent` calls, not `createSnapshot` calls. The PURE comment injection for `createSnapshot` is handled separately in swc_plugin_snapshot/mod.rs.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
📚 Learning: 2025-08-07T04:00:59.645Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1454
File: pnpm-workspace.yaml:46-46
Timestamp: 2025-08-07T04:00:59.645Z
Learning: In the lynx-family/lynx-stack repository, the webpack patch (patches/webpack5.101.0.patch) was created to fix issues with webpack5.99.9 but only takes effect on webpack5.100.0 and later versions. The patchedDependencies entry should use "webpack@^5.100.0" to ensure the patch applies to the correct version range.

Applied to files:

  • website/package.json
  • .changeset/plugin-externals-rsbuild.md
  • examples/react-externals/package.json
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • website/package.json
  • .changeset/plugin-externals-rsbuild.md
  • packages/rspeedy/plugin-external-bundle/package.json
  • examples/react-externals/package.json
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-13T11:36:12.075Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:52-72
Timestamp: 2025-08-13T11:36:12.075Z
Learning: The lynx-stack project requires Node.js >=22 as specified in package.json engines, so Node.js compatibility fallbacks for features introduced before v22 are unnecessary.

Applied to files:

  • website/package.json
  • packages/rspeedy/plugin-external-bundle/package.json
  • examples/react-externals/package.json
📚 Learning: 2025-08-06T08:25:15.392Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1447
File: pnpm-workspace.yaml:20-22
Timestamp: 2025-08-06T08:25:15.392Z
Learning: In pnpm, configDependencies in pnpm-workspace.yaml (used for plugins like pnpm/plugin-better-defaults and pnpm/plugin-trusted-deps) do not appear in or modify pnpm-lock.yaml. These plugins are managed separately by pnpm itself, not as part of the workspace's dependency tree. This is different from the internal configDependencies field that can appear within pnpm-lock.yaml for tracking configuration file dependencies.

Applied to files:

  • website/package.json
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • website/package.json
  • .changeset/plugin-externals-rsbuild.md
  • .changeset/sixty-emus-call.md
📚 Learning: 2025-08-06T08:25:15.392Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1447
File: pnpm-workspace.yaml:20-22
Timestamp: 2025-08-06T08:25:15.392Z
Learning: In pnpm, configDependencies in pnpm-workspace.yaml (used for plugins like pnpm/plugin-better-defaults and pnpm/plugin-trusted-deps) do not appear in or modify pnpm-lock.yaml. These plugins are managed separately by pnpm itself as configuration-level dependencies, not as part of the workspace's dependency tree. Running pnpm install after adding configDependencies will not change the lockfile.

Applied to files:

  • website/package.json
📚 Learning: 2025-08-20T04:56:36.011Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1566
File: package.json:53-53
Timestamp: 2025-08-20T04:56:36.011Z
Learning: In lynx-stack, Node.js v24 is the preferred/default version for development (established in PR #1557), but Node.js v22 compatibility is maintained specifically for external CI systems like rspack-ecosystem-ci. The engines.node specification uses "^22 || ^24" to support both versions while keeping v24 as the primary target.

Applied to files:

  • website/package.json
  • packages/rspeedy/plugin-external-bundle/package.json
  • examples/react-externals/package.json
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • website/package.json
  • examples/react-externals/package.json
📚 Learning: 2025-07-22T09:23:07.797Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Applied to files:

  • .changeset/plugin-externals-rsbuild.md
  • .changeset/sixty-emus-call.md
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • .changeset/plugin-externals-rsbuild.md
  • packages/rspeedy/plugin-external-bundle/package.json
  • examples/react-externals/package.json
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-29T06:43:40.182Z
Learnt from: CR
Repo: lynx-family/lynx-stack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:43:40.182Z
Learning: Applies to packages/**/etc/*.api.md : Always commit API extractor output after running `pnpm turbo api-extractor -- --local` (commit updated API report files)

Applied to files:

  • packages/rspeedy/plugin-external-bundle/api-extractor.json
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
📚 Learning: 2025-08-14T12:54:51.143Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: .changeset/brave-melons-add.md:1-7
Timestamp: 2025-08-14T12:54:51.143Z
Learning: In the lynx-family/lynx-stack repository, packages use 0.x.x versioning where minor version bumps indicate breaking changes (not major bumps), following pre-1.0 semantic versioning conventions.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/package.json
📚 Learning: 2025-10-29T10:28:27.519Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/lib.rs/should_static_extract_dynamic_inline_style.js:20-24
Timestamp: 2025-10-29T10:28:27.519Z
Learning: Files inside packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/ are auto-generated test snapshot files and should not be manually updated. Any issues with the generated code should be addressed in the code generator/transform logic, not in the snapshots themselves.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-08-18T08:46:20.001Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1547
File: packages/rspeedy/core/src/config/loadConfig.ts:11-11
Timestamp: 2025-08-18T08:46:20.001Z
Learning: `#register` and similar imports starting with "#" are Node.js subpath imports defined in the "imports" field of package.json, not TypeScript path mapping aliases. These are natively supported by both Node.js and TypeScript without requiring additional tsconfig.json configuration like "moduleResolution" or "resolvePackageJsonImports" settings.

Applied to files:

  • packages/rspeedy/tsconfig.json
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • .changeset/sixty-emus-call.md
  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
📚 Learning: 2025-08-11T06:00:04.376Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:59-61
Timestamp: 2025-08-11T06:00:04.376Z
Learning: In the lynx-family/lynx-stack repository, the `testingLibraryPlugin` in `packages/react/testing-library/src/plugins/vitest.ts` intentionally uses `process.exit` when jsdom installation fails, maintaining consistency with the previous implementation from `packages/react/testing-library/src/vitest.config.js`. This behavior should not be changed to use `this.error` despite being a Vite plugin best practice.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
🧬 Code graph analysis (2)
website/rspress.config.ts (1)
website/sidebars/api.ts (1)
  • createAPI (155-192)
packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1)
packages/rspeedy/core/src/index.ts (1)
  • RsbuildPlugin (67-67)
🔇 Additional comments (21)
.changeset/sixty-emus-call.md (1)

1-5: LGTM!

The changeset correctly documents the new LAYERS exposure feature with appropriate patch-level versioning.

packages/rspeedy/plugin-external-bundle/CHANGELOG.md (1)

1-1: LGTM!

Standard initial CHANGELOG header for the new package. Changesets will populate this automatically on version bumps.

packages/rspeedy/plugin-external-bundle/api-extractor.json (1)

1-6: LGTM!

API Extractor configuration correctly extends the base config. Ensure API report files are committed after running pnpm turbo api-extractor -- --local.

packages/rspeedy/plugin-react/src/pluginReactLynx.ts (1)

371-372: LGTM!

The LAYERS exposure correctly uses Symbol.for('LAYERS') to ensure consistent symbol identity across modules, enabling the external-bundle plugin and other plugins to access LAYERS configuration.

packages/rspeedy/plugin-external-bundle/README.md (1)

1-25: Well-structured documentation.

The README provides clear installation instructions, usage examples, and appropriate references to documentation and contributing guidelines.

Also applies to: 27-53

packages/rspeedy/plugin-external-bundle/vitest.config.ts (1)

1-10: LGTM!

Vitest configuration is properly structured with a test name that matches the package.json test script reference.

packages/rspeedy/plugin-external-bundle/package.json (2)

47-49: Verify Node.js version requirement.

The package specifies node: ">=18" while the root project requires ^22 || ^24. Confirm this broader compatibility range is intentional for this plugin package.

Based on learnings, the root lynx-stack project requires Node.js ^22 || ^24. If this plugin needs to support older Node.js versions for specific compatibility reasons (similar to the devtool-mcp-server package that targets >=18.19), please document the rationale. Otherwise, consider aligning with the root project's Node.js version requirement.


1-46: Package manifest looks well-structured.

The package.json follows repository conventions with proper ESM setup, exports, workspace dependencies, and catalog references.

Also applies to: 50-50

packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1)

14-24: Well-designed test helper.

The stub plugin provides a clean way to mock LAYERS exposure for testing without requiring the full React plugin, with sensible defaults and type safety.

packages/rspeedy/plugin-external-bundle/src/index.ts (2)

26-29: LGTM! Clean type abstraction.

Good use of Pick to expose only the externals field from the underlying plugin options, keeping the public API surface minimal and focused.


61-90: LAYERS exposure from react-rsbuild-plugin is correctly implemented.

Verification confirms that react-rsbuild-plugin properly exposes LAYERS via api.expose(Symbol.for('LAYERS'), LAYERS) at line 371 in pluginReactLynx.ts. The external-bundle plugin correctly consumes it with matching Symbol.for('LAYERS') key. The defensive error handling is appropriate.

packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md (1)

1-16: API report looks correct.

The API surface matches the implementation. As per coding guidelines, ensure this file was generated by running pnpm turbo api-extractor -- --local before committing.

packages/rspeedy/tsconfig.json (1)

13-13: LGTM! Project reference added correctly.

The new plugin is properly integrated into the TypeScript project graph, following the established pattern.

website/package.json (1)

24-24: LGTM! Dependency added correctly.

The new plugin package is properly added as a workspace devDependency for website documentation generation.

packages/rspeedy/plugin-external-bundle/tsconfig.json (1)

1-11: LGTM! TypeScript configuration is correct.

Standard configuration that extends the build config and includes test files for type checking. The reference to core package is appropriate for dependency resolution.

packages/rspeedy/plugin-external-bundle/tsconfig.build.json (1)

1-12: LGTM! Build configuration is correct.

Standard build setup with composite mode enabled and proper project references. Output configuration follows the established pattern.

examples/react-externals/package.json (1)

16-16: LGTM! Clean dependency migration.

The dependency update from @lynx-js/externals-loading-webpack-plugin to @lynx-js/external-bundle-rsbuild-plugin correctly reflects the plugin migration introduced in this PR.

examples/react-externals/lynx.config.js (2)

1-3: Clean import migration to the new plugin.

The imports correctly reflect the transition from ExternalsLoadingPlugin to pluginExternalBundle.


18-84: The externals configuration looks good and maintains all previous external dependencies. The plugin configuration properly exposes the required LAYERS API since pluginReactLynx() is registered before pluginExternalBundle(). The implementation in pluginReactLynx calls api.expose(Symbol.for('LAYERS'), LAYERS), making it available for pluginExternalBundle to consume via api.useExposed().

packages/rspeedy/plugin-external-bundle/test/index.test.ts (2)

13-72: Well-structured integration test.

The test correctly verifies that ExternalsLoadingPlugin is registered with the expected options by capturing rspack plugins through the tools hook. The approach is appropriate for testing plugin integration.


74-103: Good error handling coverage.

The test correctly validates that the plugin throws a clear error when LAYERS is not exposed, which helps catch integration issues early.

@codecov
Copy link

codecov bot commented Dec 18, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@luhc228 luhc228 force-pushed the feat/plugin-external-bundle branch from 7b12ccd to f9355d9 Compare December 18, 2025 12:38
Copy link
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

♻️ Duplicate comments (1)
packages/rspeedy/plugin-external-bundle/test/index.test.ts (1)

35-35: Test fixture file missing.

The entry point './fixtures/basic.tsx' referenced across all tests does not exist. This will cause all tests to fail. Create the fixture file or update the entry configuration.

#!/bin/bash
# Verify if fixtures directory and basic.tsx exist
echo "=== Checking for fixtures directory and basic.tsx ==="
fd -t d "fixtures" packages/rspeedy/plugin-external-bundle/test/
fd -t f "basic.tsx" packages/rspeedy/plugin-external-bundle/

# List all files in the test directory
echo ""
echo "=== Files in test directory ==="
ls -la packages/rspeedy/plugin-external-bundle/test/ 2>/dev/null || echo "Test directory not found"
🧹 Nitpick comments (2)
website/rspress.config.ts (1)

214-217: Minor ordering inconsistency between locales.

The Chinese sidebar entry is positioned after lynx-bundle-rslib-config, while the English entry (lines 67-69) is positioned after qrcode-rsbuild-plugin. Consider aligning the order for consistency across locales.

🔎 Apply this diff to align ordering:
     createAPI({
       base: 'zh/api',
       name: 'qrcode-rsbuild-plugin',
       skips: [
         'PluginQRCodeOptions',
       ],
     }),
+    createAPI({
+      base: 'zh/api',
+      name: 'external-bundle-rsbuild-plugin',
+    }),
     createAPI({
       base: 'zh/api',
       name: 'lynx-bundle-rslib-config',
     }),
-    createAPI({
-      base: 'zh/api',
-      name: 'external-bundle-rsbuild-plugin',
-    }),
packages/rspeedy/plugin-external-bundle/src/index.ts (1)

16-19: Consider documenting the type contract with react-rsbuild-plugin.

This local interface mirrors the LAYERS structure exposed by react-rsbuild-plugin. If the source type changes, this definition could drift. A brief comment noting the dependency would help maintainability, e.g., // Mirrors LAYERS exposed by @lynx-js/react-rsbuild-plugin.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b12ccd and f9355d9.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/plugin-externals-rsbuild.md (1 hunks)
  • .changeset/sixty-emus-call.md (1 hunks)
  • examples/react-externals/lynx.config.js (2 hunks)
  • examples/react-externals/package.json (1 hunks)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts (0 hunks)
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/README.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/api-extractor.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/package.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/src/index.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts (1 hunks)
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts (1 hunks)
  • packages/rspeedy/tsconfig.json (1 hunks)
  • website/package.json (1 hunks)
  • website/rspress.config.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (11)
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • .changeset/plugin-externals-rsbuild.md
  • website/package.json
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts
  • packages/rspeedy/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
  • packages/rspeedy/plugin-external-bundle/package.json
  • packages/rspeedy/plugin-external-bundle/api-extractor.json
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json
  • packages/rspeedy/plugin-external-bundle/README.md
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, generate and commit a Changeset describing your changes

Files:

  • .changeset/sixty-emus-call.md
🧠 Learnings (21)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • .changeset/sixty-emus-call.md
  • examples/react-externals/package.json
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • examples/react-externals/lynx.config.js
  • examples/react-externals/package.json
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1771
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_component_with_static_sibling.js:2-2
Timestamp: 2025-09-18T04:43:54.426Z
Learning: In the lynx-family/lynx-stack repository, the `add_pure_comment` function in packages/react/transform/src/swc_plugin_compat/mod.rs (around lines 478-482) is specifically for `wrapWithLynxComponent` calls, not `createSnapshot` calls. The PURE comment injection for `createSnapshot` is handled separately in swc_plugin_snapshot/mod.rs.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • examples/react-externals/lynx.config.js
  • examples/react-externals/package.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • examples/react-externals/lynx.config.js
  • .changeset/sixty-emus-call.md
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • .changeset/sixty-emus-call.md
  • examples/react-externals/package.json
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • examples/react-externals/package.json
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • website/rspress.config.ts
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • examples/react-externals/package.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • examples/react-externals/package.json
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
📚 Learning: 2025-07-22T09:23:07.797Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • .changeset/sixty-emus-call.md
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • .changeset/sixty-emus-call.md
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • examples/react-externals/package.json
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-08-07T04:00:59.645Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1454
File: pnpm-workspace.yaml:46-46
Timestamp: 2025-08-07T04:00:59.645Z
Learning: In the lynx-family/lynx-stack repository, the webpack patch (patches/webpack5.101.0.patch) was created to fix issues with webpack5.99.9 but only takes effect on webpack5.100.0 and later versions. The patchedDependencies entry should use "webpack@^5.100.0" to ensure the patch applies to the correct version range.

Applied to files:

  • examples/react-externals/package.json
📚 Learning: 2025-10-29T10:28:27.519Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/lib.rs/should_static_extract_dynamic_inline_style.js:20-24
Timestamp: 2025-10-29T10:28:27.519Z
Learning: Files inside packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/ are auto-generated test snapshot files and should not be manually updated. Any issues with the generated code should be addressed in the code generator/transform logic, not in the snapshots themselves.

Applied to files:

  • examples/react-externals/package.json
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-08-13T11:36:12.075Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:52-72
Timestamp: 2025-08-13T11:36:12.075Z
Learning: The lynx-stack project requires Node.js >=22 as specified in package.json engines, so Node.js compatibility fallbacks for features introduced before v22 are unnecessary.

Applied to files:

  • examples/react-externals/package.json
📚 Learning: 2025-08-20T04:56:36.011Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1566
File: package.json:53-53
Timestamp: 2025-08-20T04:56:36.011Z
Learning: In lynx-stack, Node.js v24 is the preferred/default version for development (established in PR #1557), but Node.js v22 compatibility is maintained specifically for external CI systems like rspack-ecosystem-ci. The engines.node specification uses "^22 || ^24" to support both versions while keeping v24 as the primary target.

Applied to files:

  • examples/react-externals/package.json
📚 Learning: 2025-08-11T06:00:04.376Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:59-61
Timestamp: 2025-08-11T06:00:04.376Z
Learning: In the lynx-family/lynx-stack repository, the `testingLibraryPlugin` in `packages/react/testing-library/src/plugins/vitest.ts` intentionally uses `process.exit` when jsdom installation fails, maintaining consistency with the previous implementation from `packages/react/testing-library/src/vitest.config.js`. This behavior should not be changed to use `this.error` despite being a Vite plugin best practice.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-09-23T08:54:39.966Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1670
File: packages/webpack/css-extract-webpack-plugin/test/hotCases/hot/hot-update-json/dual-thread/__snapshot__/index.css:6-8
Timestamp: 2025-09-23T08:54:39.966Z
Learning: In the lynx-stack CSS extract webpack plugin tests, many test fixture CSS files intentionally use invalid CSS syntax like `color: 'red';` with quoted values. The snapshots correctly reflect this invalid CSS from the source fixtures. To fix CSS validation issues, the source fixture files should be updated first, then snapshots regenerated, rather than manually editing snapshots.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
🧬 Code graph analysis (3)
examples/react-externals/lynx.config.js (1)
packages/rspeedy/plugin-external-bundle/src/index.ts (1)
  • pluginExternalBundle (61-90)
packages/rspeedy/plugin-react/src/pluginReactLynx.ts (3)
packages/rspeedy/lynx-bundle-rslib-config/src/index.ts (1)
  • LAYERS (13-13)
packages/webpack/react-webpack-plugin/src/index.ts (1)
  • LAYERS (15-15)
packages/rspeedy/plugin-react/src/index.ts (1)
  • LAYERS (22-22)
website/rspress.config.ts (1)
website/sidebars/api.ts (1)
  • createAPI (155-192)
🔇 Additional comments (13)
.changeset/sixty-emus-call.md (1)

1-5: Changeset looks good.

The entry properly documents a meaningful public API addition (exposing LAYERS via api.expose) with an appropriate patch version bump. This change enables the new external-bundle-rsbuild-plugin to consume layer information at config time, aligning well with the PR objectives.

packages/rspeedy/plugin-external-bundle/CHANGELOG.md (1)

1-1: LGTM!

Standard initial CHANGELOG header for the new @lynx-js/external-bundle-rsbuild-plugin package.

examples/react-externals/package.json (1)

16-16: LGTM!

The devDependency correctly migrated from the webpack plugin to the new rsbuild plugin, aligning with the configuration changes in lynx.config.js.

website/rspress.config.ts (1)

67-69: LGTM!

The English sidebar entry for external-bundle-rsbuild-plugin is correctly added.

packages/rspeedy/plugin-react/src/pluginReactLynx.ts (1)

371-372: LGTM!

The LAYERS exposure via api.expose(Symbol.for('LAYERS'), LAYERS) enables the new external-bundle-rsbuild-plugin to retrieve layer configuration. Using Symbol.for ensures consistent symbol identity across module boundaries.

packages/rspeedy/plugin-external-bundle/test/index.test.ts (3)

13-72: Test structure is well-designed.

The test properly validates:

  • ExternalsLoadingPlugin registration
  • Correct options propagation (backgroundLayer, mainThreadLayer, externals)
  • Plugin instance detection via instanceof

Once the missing fixture is resolved, this test provides good coverage.


74-103: Error handling test is appropriate.

Good coverage for the error case when LAYERS is not exposed. The error message 'external-bundle-rsbuild-plugin requires exposed LAYERS' is descriptive.


141-192: Custom layer propagation test is valuable.

This test ensures that custom layer names from pluginStubLayers are correctly passed through to ExternalsLoadingPlugin, validating the integration between the two plugins.

examples/react-externals/lynx.config.js (2)

1-3: LGTM!

Import updated correctly to use the new pluginExternalBundle from @lynx-js/external-bundle-rsbuild-plugin.


18-84: Well-structured externals configuration migration.

The migration from ExternalsLoadingPlugin to pluginExternalBundle is complete and well-organized:

  • All @lynx-js/react subpath exports are properly configured
  • Consistent structure across all entries (libraryName, url, background, mainThread, async)
  • Environment variable EXTERNAL_BUNDLE_PREFIX correctly prefixes URLs
  • Local module ./App.js correctly included for component library externalization
packages/rspeedy/plugin-external-bundle/src/index.ts (3)

21-29: LGTM!

Good use of Pick to expose a minimal, focused API surface while leveraging the existing type definitions.


31-60: LGTM!

Clear documentation with a practical example that correctly demonstrates the required plugin order.


78-89: LGTM!

Defensive initialization of config.plugins and correct configuration of ExternalsLoadingPlugin with the exposed layer names.

@codspeed-hq
Copy link

codspeed-hq bot commented Dec 18, 2025

CodSpeed Performance Report

Merging #2006 will degrade performance by 5.18%

Comparing luhc228:feat/plugin-external-bundle (a161a87) with main (8b2f07e)

Summary

❌ 1 regression
✅ 62 untouched
⏩ 3 skipped1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Efficiency
transform 1000 view elements 44.2 ms 46.6 ms -5.18%

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@relativeci
Copy link

relativeci bot commented Dec 18, 2025

React Example

#6604 Bundle Size — 236.9KiB (0%).

a161a87(current) vs 8b2f07e main#6600(baseline)

Bundle metrics  no changes
                 Current
#6604
     Baseline
#6600
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 162 162
No change  Duplicate Modules 65 65
No change  Duplicate Code 46.74% 46.74%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#6604
     Baseline
#6600
No change  IMG 145.76KiB 145.76KiB
No change  Other 91.14KiB 91.14KiB

Bundle analysis reportBranch luhc228:feat/plugin-external-bun...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link

relativeci bot commented Dec 18, 2025

Web Explorer

#6764 Bundle Size — 372.84KiB (0%).

a161a87(current) vs 8b2f07e main#6760(baseline)

Bundle metrics  Change 2 changes
                 Current
#6764
     Baseline
#6760
No change  Initial JS 146.57KiB 146.57KiB
No change  Initial CSS 32.4KiB 32.4KiB
No change  Cache Invalidation 0% 0%
No change  Chunks 8 8
No change  Assets 8 8
Change  Modules 230(+0.88%) 228
No change  Duplicate Modules 16 16
Change  Duplicate Code 2.96%(-0.34%) 2.97%
No change  Packages 4 4
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#6764
     Baseline
#6760
No change  JS 243.46KiB 243.46KiB
No change  Other 96.98KiB 96.98KiB
No change  CSS 32.4KiB 32.4KiB

Bundle analysis reportBranch luhc228:feat/plugin-external-bun...Project dashboard


Generated by RelativeCIDocumentationReport issue

@luhc228 luhc228 force-pushed the feat/plugin-external-bundle branch from df33ba6 to 54ba6e1 Compare December 19, 2025 04:52
Copy link
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

♻️ Duplicate comments (1)
packages/rspeedy/plugin-external-bundle/test/index.test.ts (1)

35-35: Test fixture file still missing.

The entry point './fixtures/basic.tsx' referenced in all tests (lines 35, 81, 114, 155) does not exist. This was previously flagged and remains unresolved. Create the missing packages/rspeedy/plugin-external-bundle/test/fixtures/basic.tsx file or update the entry paths to reference an existing fixture.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df33ba6 and 54ba6e1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/plugin-externals-rsbuild.md (1 hunks)
  • .changeset/sixty-emus-call.md (1 hunks)
  • examples/react-externals/lynx.config.js (2 hunks)
  • examples/react-externals/package.json (1 hunks)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts (0 hunks)
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/README.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/api-extractor.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/package.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/src/index.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts (1 hunks)
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts (1 hunks)
  • packages/rspeedy/tsconfig.json (1 hunks)
  • website/package.json (1 hunks)
  • website/rspress.config.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (13)
  • packages/rspeedy/tsconfig.json
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
  • .changeset/sixty-emus-call.md
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • examples/react-externals/package.json
  • packages/rspeedy/plugin-external-bundle/src/index.ts
  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json
  • .changeset/plugin-externals-rsbuild.md
  • website/package.json
  • packages/rspeedy/plugin-external-bundle/package.json
🧰 Additional context used
📓 Path-based instructions (1)
packages/**/etc/*.api.md

📄 CodeRabbit inference engine (AGENTS.md)

Always commit API extractor output after running pnpm turbo api-extractor -- --local (commit updated API report files)

Files:

  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
🧠 Learnings (18)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
📚 Learning: 2025-09-29T06:43:40.182Z
Learnt from: CR
Repo: lynx-family/lynx-stack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:43:40.182Z
Learning: Applies to packages/**/etc/*.api.md : Always commit API extractor output after running `pnpm turbo api-extractor -- --local` (commit updated API report files)

Applied to files:

  • packages/rspeedy/plugin-external-bundle/api-extractor.json
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-10-29T10:28:27.519Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/lib.rs/should_static_extract_dynamic_inline_style.js:20-24
Timestamp: 2025-10-29T10:28:27.519Z
Learning: Files inside packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/ are auto-generated test snapshot files and should not be manually updated. Any issues with the generated code should be addressed in the code generator/transform logic, not in the snapshots themselves.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-11T06:00:04.376Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:59-61
Timestamp: 2025-08-11T06:00:04.376Z
Learning: In the lynx-family/lynx-stack repository, the `testingLibraryPlugin` in `packages/react/testing-library/src/plugins/vitest.ts` intentionally uses `process.exit` when jsdom installation fails, maintaining consistency with the previous implementation from `packages/react/testing-library/src/vitest.config.js`. This behavior should not be changed to use `this.error` despite being a Vite plugin best practice.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-09-23T08:54:39.966Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1670
File: packages/webpack/css-extract-webpack-plugin/test/hotCases/hot/hot-update-json/dual-thread/__snapshot__/index.css:6-8
Timestamp: 2025-09-23T08:54:39.966Z
Learning: In the lynx-stack CSS extract webpack plugin tests, many test fixture CSS files intentionally use invalid CSS syntax like `color: 'red';` with quoted values. The snapshots correctly reflect this invalid CSS from the source fixtures. To fix CSS validation issues, the source fixture files should be updated first, then snapshots regenerated, rather than manually editing snapshots.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-08-11T05:59:28.530Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:4-6
Timestamp: 2025-08-11T05:59:28.530Z
Learning: In the lynx-family/lynx-stack repository, the `packages/react/testing-library` package does not have `vite` as a direct dependency. It relies on `vitest` being available from the monorepo root and accesses Vite types through re-exports from `vitest/node`. Direct imports from `vite` should not be suggested for this package.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • website/rspress.config.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • examples/react-externals/lynx.config.js
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1771
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_component_with_static_sibling.js:2-2
Timestamp: 2025-09-18T04:43:54.426Z
Learning: In the lynx-family/lynx-stack repository, the `add_pure_comment` function in packages/react/transform/src/swc_plugin_compat/mod.rs (around lines 478-482) is specifically for `wrapWithLynxComponent` calls, not `createSnapshot` calls. The PURE comment injection for `createSnapshot` is handled separately in swc_plugin_snapshot/mod.rs.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-14T12:54:51.143Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: .changeset/brave-melons-add.md:1-7
Timestamp: 2025-08-14T12:54:51.143Z
Learning: In the lynx-family/lynx-stack repository, packages use 0.x.x versioning where minor version bumps indicate breaking changes (not major bumps), following pre-1.0 semantic versioning conventions.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • examples/react-externals/lynx.config.js
🧬 Code graph analysis (2)
website/rspress.config.ts (1)
website/sidebars/api.ts (1)
  • createAPI (155-192)
examples/react-externals/lynx.config.js (1)
packages/rspeedy/plugin-external-bundle/src/index.ts (1)
  • pluginExternalBundle (61-90)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / clippy
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (6)
website/rspress.config.ts (2)

67-69: LGTM! English sidebar entry is correctly structured.

The API entry follows the established pattern and uses the createAPI helper appropriately.


326-332: Verify if the new plugin should be added to CHANGELOG tracking.

The CHANGELOG configurations for Rspeedy packages (both English and Chinese) don't include @lynx-js/external-bundle-rsbuild-plugin. Since this is a new package introduction, this might be intentional. However, please verify if the plugin should be added to these arrays for future changelog tracking:

  • Lines 326-332: English CHANGELOG
  • Lines 354-361: Chinese CHANGELOG

If it should be tracked, add '@lynx-js/external-bundle-rsbuild-plugin' to both arrays.

Also applies to: 354-361

packages/rspeedy/plugin-external-bundle/api-extractor.json (1)

1-6: LGTM!

The API Extractor configuration correctly extends the base configuration and follows the monorepo pattern.

examples/react-externals/lynx.config.js (1)

1-84: LGTM!

The migration to pluginExternalBundle is clean and correctly structured. The externals configuration properly maps all React-related modules and the component library with appropriate bundle URLs and layer sections.

packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1)

1-24: LGTM!

The test stub plugin is well-implemented and clearly documented. It properly exposes the LAYERS symbol that the external bundle plugin depends on, making tests clean and focused.

packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md (1)

1-16: LGTM!

The API report correctly documents the public surface of the plugin. Ensure this was generated by running pnpm turbo api-extractor -- --local as per coding guidelines for packages/**/etc/*.api.md files.

Based on coding guidelines, API Extractor output must be committed after running the extraction command.

@luhc228 luhc228 force-pushed the feat/plugin-external-bundle branch from 54ba6e1 to e827d10 Compare December 20, 2025 01:21
Copy link
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: 0

♻️ Duplicate comments (1)
packages/rspeedy/plugin-external-bundle/src/index.ts (1)

73-77: Error message needs to cover multiple failure scenarios.

The error currently assumes a version issue, but LAYERS could be missing because: the plugin isn't installed, isn't registered, or is registered after this plugin.

🔎 Suggested improvement (as noted in previous review)
         if (!LAYERS) {
           throw new Error(
-            'external-bundle-rsbuild-plugin requires exposed LAYERS. Please upgrade @lynx-js/react-rsbuild-plugin to latest.',
+            'external-bundle-rsbuild-plugin requires exposed LAYERS. ' +
+            'Ensure @lynx-js/react-rsbuild-plugin is installed, registered before this plugin, and up to date.',
           )
         }
🧹 Nitpick comments (1)
packages/rspeedy/plugin-external-bundle/src/index.ts (1)

64-66: Consider adding plugin ordering constraint.

The plugin depends on LAYERS exposed by pluginReactLynx, but doesn't enforce execution order. While the current implementation relies on user-specified plugin order, consider adding an explicit constraint for better error prevention:

🔎 Suggested ordering constraint
 return {
   name: 'lynx:external-bundle',
+  pre: ['lynx:react'],
   setup(api) {

This would ensure the plugin runs after pluginReactLynx has exposed LAYERS, making the dependency explicit and preventing ordering mistakes.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54ba6e1 and e827d10.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/plugin-externals-rsbuild.md (1 hunks)
  • .changeset/sixty-emus-call.md (1 hunks)
  • examples/react-externals/lynx.config.js (2 hunks)
  • examples/react-externals/package.json (1 hunks)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts (0 hunks)
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/README.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/api-extractor.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/package.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/src/index.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts (1 hunks)
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts (1 hunks)
  • packages/rspeedy/tsconfig.json (1 hunks)
  • website/package.json (1 hunks)
  • website/rspress.config.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • .changeset/sixty-emus-call.md
🚧 Files skipped from review as they are similar to previous changes (9)
  • examples/react-externals/package.json
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json
  • .changeset/plugin-externals-rsbuild.md
  • packages/rspeedy/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts
  • website/package.json
  • packages/rspeedy/plugin-external-bundle/package.json
  • packages/rspeedy/plugin-external-bundle/api-extractor.json
🧰 Additional context used
📓 Path-based instructions (1)
packages/**/etc/*.api.md

📄 CodeRabbit inference engine (AGENTS.md)

Always commit API extractor output after running pnpm turbo api-extractor -- --local (commit updated API report files)

Files:

  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
🧠 Learnings (15)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1771
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_component_with_static_sibling.js:2-2
Timestamp: 2025-09-18T04:43:54.426Z
Learning: In packages/react/transform/src/swc_plugin_compat/mod.rs, the `add_pure_comment` function at lines 478-482 is specifically for `wrapWithLynxComponent` calls, not `createSnapshot` calls. The PURE comment injection for `createSnapshot` is handled separately in swc_plugin_snapshot/mod.rs. These are two distinct code paths that should be treated differently.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/README.md
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1771
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_component_with_static_sibling.js:2-2
Timestamp: 2025-09-18T04:43:54.426Z
Learning: In the lynx-family/lynx-stack repository, the `add_pure_comment` function in packages/react/transform/src/swc_plugin_compat/mod.rs (around lines 478-482) is specifically for `wrapWithLynxComponent` calls, not `createSnapshot` calls. The PURE comment injection for `createSnapshot` is handled separately in swc_plugin_snapshot/mod.rs.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-11T06:00:04.376Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1305
File: packages/react/testing-library/src/plugins/vitest.ts:59-61
Timestamp: 2025-08-11T06:00:04.376Z
Learning: In the lynx-family/lynx-stack repository, the `testingLibraryPlugin` in `packages/react/testing-library/src/plugins/vitest.ts` intentionally uses `process.exit` when jsdom installation fails, maintaining consistency with the previous implementation from `packages/react/testing-library/src/vitest.config.js`. This behavior should not be changed to use `this.error` despite being a Vite plugin best practice.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/README.md
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • website/rspress.config.ts
  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-18T08:46:20.001Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1547
File: packages/rspeedy/core/src/config/loadConfig.ts:11-11
Timestamp: 2025-08-18T08:46:20.001Z
Learning: `#register` and similar imports starting with "#" are Node.js subpath imports defined in the "imports" field of package.json, not TypeScript path mapping aliases. These are natively supported by both Node.js and TypeScript without requiring additional tsconfig.json configuration like "moduleResolution" or "resolvePackageJsonImports" settings.

Applied to files:

  • packages/rspeedy/plugin-external-bundle/tsconfig.json
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • examples/react-externals/lynx.config.js
🧬 Code graph analysis (3)
packages/rspeedy/plugin-react/src/pluginReactLynx.ts (3)
packages/rspeedy/lynx-bundle-rslib-config/src/index.ts (1)
  • LAYERS (13-13)
packages/webpack/react-webpack-plugin/src/index.ts (1)
  • LAYERS (15-15)
packages/rspeedy/plugin-react/src/index.ts (1)
  • LAYERS (22-22)
website/rspress.config.ts (1)
website/sidebars/api.ts (1)
  • createAPI (155-192)
examples/react-externals/lynx.config.js (1)
packages/rspeedy/plugin-external-bundle/src/index.ts (1)
  • pluginExternalBundle (61-90)
🔇 Additional comments (7)
website/rspress.config.ts (1)

326-333: Verify whether the new plugin should be added to CHANGELOG aggregation.

The new @lynx-js/external-bundle-rsbuild-plugin is registered in the API sidebars but is not included in the Rspeedy CHANGELOG package lists (lines 330-331 and 358-359). Other Rspeedy plugins like @lynx-js/react-rsbuild-plugin and @lynx-js/qrcode-rsbuild-plugin are present in these lists.

For consistency and to ensure changelog entries appear automatically once the package is published, consider adding @lynx-js/external-bundle-rsbuild-plugin to both changelog arrays.

🔎 Proposed fix to include the new plugin in changelog aggregation
  rspeedy: createChangelogs(
    'Rspeedy CHANGELOG',
    [
      '@lynx-js/rspeedy',
      '@lynx-js/react-rsbuild-plugin',
      '@lynx-js/qrcode-rsbuild-plugin',
+     '@lynx-js/external-bundle-rsbuild-plugin',
    ],
  ),

And for the Chinese version:

  rspeedy: createChangelogs(
    'Rspeedy CHANGELOG',
    [
      '@lynx-js/rspeedy',
      '@lynx-js/react-rsbuild-plugin',
      '@lynx-js/qrcode-rsbuild-plugin',
+     '@lynx-js/external-bundle-rsbuild-plugin',
    ],
    'zh',
  ),

Also applies to: 354-362

packages/rspeedy/plugin-external-bundle/README.md (1)

1-53: LGTM! Documentation is clear and complete.

The README follows standard patterns, includes all necessary sections (installation, usage, documentation links, contributing, license), and provides a clear code example showing how to configure the plugin.

packages/rspeedy/plugin-external-bundle/vitest.config.ts (1)

1-10: LGTM! Vitest configuration is appropriate.

The minimal configuration correctly sets up a vitest workspace project for the external-bundle plugin tests.

packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md (1)

1-16: API report is correctly structured.

This generated API Extractor report documents the public API surface. As per coding guidelines, ensure this was generated by running pnpm turbo api-extractor -- --local before committing.

packages/rspeedy/plugin-react/src/pluginReactLynx.ts (1)

371-372: LGTM! LAYERS exposure enables cross-plugin integration.

The public exposure of LAYERS via api.expose(Symbol.for('LAYERS'), LAYERS) correctly enables the new pluginExternalBundle to access layer configuration. The placement outside the lazy bundle conditional ensures LAYERS are always available.

packages/rspeedy/plugin-external-bundle/tsconfig.json (1)

1-11: LGTM! TypeScript configuration follows established patterns.

The configuration appropriately extends the build config, includes source and test files, and references the core package dependency.

examples/react-externals/lynx.config.js (1)

1-84: LGTM! Example correctly demonstrates the plugin usage.

The migration from direct ExternalsLoadingPlugin configuration to pluginExternalBundle is correctly implemented. The plugin ordering (pluginReactLynx before pluginExternalBundle) is crucial and correctly maintained, as pluginExternalBundle depends on LAYERS exposed by pluginReactLynx.

@luhc228 luhc228 force-pushed the feat/plugin-external-bundle branch from e827d10 to 9c22529 Compare December 20, 2025 01:33
Copy link
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: 0

♻️ Duplicate comments (1)
packages/rspeedy/plugin-external-bundle/src/index.ts (1)

73-77: Improve error message to guide users on resolution.

The error message should cover multiple failure scenarios: the plugin might not be installed, not registered, or registered after this plugin. The current message only mentions upgrading.

🔎 Enhanced error message covering common failure scenarios
         if (!LAYERS) {
           throw new Error(
-            'external-bundle-rsbuild-plugin requires exposed LAYERS. Please upgrade @lynx-js/react-rsbuild-plugin to latest.',
+            'external-bundle-rsbuild-plugin requires exposed LAYERS. ' +
+            'Ensure @lynx-js/react-rsbuild-plugin is installed, registered BEFORE this plugin in the plugins array, and up to date.',
           )
         }
🧹 Nitpick comments (2)
examples/react-externals/lynx.config.js (1)

18-84: Externals configuration migrated successfully.

The externals configuration is properly structured and all entries include the required fields (libraryName, url, background, mainThread, async). The migration to pluginExternalBundle is complete and correct.

💡 Optional: Extract externals configuration for improved maintainability

Consider extracting the large externals object to a separate constant to improve readability:

+const REACT_EXTERNALS = {
+  '@lynx-js/react': {
+    libraryName: ['ReactLynx', 'React'],
+    url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`,
+    background: { sectionPath: 'ReactLynx' },
+    mainThread: { sectionPath: 'ReactLynx__main-thread' },
+    async: false,
+  },
+  // ... rest of externals
+};
+
 export default defineConfig({
   plugins: [
     pluginReactLynx(),
     pluginQRCode({
       schema(url) {
         return `${url}?fullscreen=true`;
       },
     }),
     pluginExternalBundle({
-      externals: {
-        '@lynx-js/react': {
-          // ...
-        },
-        // ...
-      },
+      externals: REACT_EXTERNALS,
     }),
   ],
packages/rspeedy/plugin-external-bundle/src/index.ts (1)

61-63: Consider validating the externals option.

The function doesn't validate that options.externals is provided or is a valid object. While ExternalsLoadingPlugin may handle this, early validation would provide clearer error messages.

💡 Optional: Add input validation
 export function pluginExternalBundle(
   options: PluginExternalBundleOptions,
 ): RsbuildPlugin {
+  if (!options?.externals || typeof options.externals !== 'object') {
+    throw new Error(
+      'external-bundle-rsbuild-plugin requires a valid externals object in options.',
+    )
+  }
+
   return {
     name: 'lynx:external-bundle',
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e827d10 and 9c22529.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/plugin-externals-rsbuild.md (1 hunks)
  • .changeset/sixty-emus-call.md (1 hunks)
  • examples/react-externals/lynx.config.js (2 hunks)
  • examples/react-externals/package.json (1 hunks)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts (0 hunks)
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/README.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/api-extractor.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md (1 hunks)
  • packages/rspeedy/plugin-external-bundle/package.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/src/index.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/tsconfig.json (1 hunks)
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts (1 hunks)
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts (1 hunks)
  • packages/rspeedy/tsconfig.json (1 hunks)
  • website/package.json (1 hunks)
  • website/rspress.config.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (15)
  • packages/rspeedy/tsconfig.json
  • examples/react-externals/package.json
  • .changeset/sixty-emus-call.md
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • website/package.json
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json
  • .changeset/plugin-externals-rsbuild.md
  • packages/rspeedy/plugin-external-bundle/api-extractor.json
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts
  • packages/rspeedy/plugin-external-bundle/package.json
  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1771
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_component_with_static_sibling.js:2-2
Timestamp: 2025-09-18T04:43:54.426Z
Learning: In the lynx-family/lynx-stack repository, the `add_pure_comment` function in packages/react/transform/src/swc_plugin_compat/mod.rs (around lines 478-482) is specifically for `wrapWithLynxComponent` calls, not `createSnapshot` calls. The PURE comment injection for `createSnapshot` is handled separately in swc_plugin_snapshot/mod.rs.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • examples/react-externals/lynx.config.js
🧬 Code graph analysis (2)
website/rspress.config.ts (1)
website/sidebars/api.ts (1)
  • createAPI (155-192)
examples/react-externals/lynx.config.js (1)
packages/rspeedy/plugin-external-bundle/src/index.ts (1)
  • pluginExternalBundle (61-90)
🔇 Additional comments (3)
website/rspress.config.ts (1)

67-69: Sidebar ordering is now consistent across locales.

The previous review flagged an ordering inconsistency, but both English and Chinese sidebars now correctly place external-bundle-rsbuild-plugin before lynx-bundle-rslib-config. The issue has been resolved.

Also applies to: 210-213

examples/react-externals/lynx.config.js (1)

1-3: LGTM! Import changes align with the new plugin architecture.

The imports correctly reflect the migration from direct ExternalsLoadingPlugin usage to the new pluginExternalBundle wrapper, which encapsulates layer management.

packages/rspeedy/plugin-external-bundle/src/index.ts (1)

1-90: Well-structured plugin implementation.

The plugin correctly wraps ExternalsLoadingPlugin and retrieves layer names via the rsbuild exposed API. The JSDoc example is helpful and the overall structure follows rsbuild plugin patterns.

Copy link
Collaborator

@upupming upupming left a comment

Choose a reason for hiding this comment

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

Generally LGTM, but we should think other DSLs

@luhc228 luhc228 force-pushed the feat/plugin-external-bundle branch from 9c22529 to 02b8363 Compare December 22, 2025 07:34
upupming
upupming previously approved these changes Dec 22, 2025
Copy link
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: 0

🧹 Nitpick comments (2)
packages/rspeedy/plugin-external-bundle/src/index.ts (2)

73-77: Consider making the error message more actionable.

The error message is appropriately generic (not tied to a specific DSL plugin), but could be more helpful by guiding users on common causes and remediation steps, such as:

  • A DSL plugin (e.g., pluginReactLynx) must be registered before this plugin
  • Plugin registration order matters
  • The DSL plugin must expose LAYERS via api.expose(Symbol.for('LAYERS'), ...)
🔎 Suggested improvement
        if (!LAYERS) {
          throw new Error(
-            'external-bundle-rsbuild-plugin requires exposed `LAYERS` variable.',
+            'external-bundle-rsbuild-plugin requires exposed `LAYERS` variable. ' +
+            'Ensure a DSL plugin that exposes LAYERS (e.g., pluginReactLynx) is registered before this plugin.',
          )
        }

69-82: Optional: Add runtime validation for LAYERS properties.

While TypeScript provides compile-time type checking, adding runtime validation for LAYERS.BACKGROUND and LAYERS.MAIN_THREAD could provide clearer error messages if a plugin exposes a malformed LAYERS object.

🔎 Suggested improvement
        const LAYERS = api.useExposed<ExposedLayers>(
          Symbol.for('LAYERS'),
        )

        if (!LAYERS) {
          throw new Error(
            'external-bundle-rsbuild-plugin requires exposed `LAYERS` variable. ' +
            'Ensure a DSL plugin that exposes LAYERS (e.g., pluginReactLynx) is registered before this plugin.',
          )
        }
+
+        if (!LAYERS.BACKGROUND || !LAYERS.MAIN_THREAD) {
+          throw new Error(
+            'Exposed LAYERS object must contain BACKGROUND and MAIN_THREAD properties.',
+          )
+        }
+
        config.plugins = config.plugins || []
        config.plugins.push(
          new ExternalsLoadingPlugin({
            backgroundLayer: LAYERS.BACKGROUND,
            mainThreadLayer: LAYERS.MAIN_THREAD,
            externals: options.externals,
          }),
        )
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02b8363 and 3372075.

📒 Files selected for processing (1)
  • packages/rspeedy/plugin-external-bundle/src/index.ts
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (4)
packages/rspeedy/plugin-external-bundle/src/index.ts (4)

1-10: LGTM!

The copyright header and package documentation are clear and appropriate.


11-14: LGTM!

Imports are clean and all are properly utilized in the implementation.


16-29: LGTM!

The type definitions are well-structured. Using Pick for PluginExternalBundleOptions is a good practice that maintains consistency with the underlying plugin options.


61-90: LGTM!

The plugin implementation follows rsbuild patterns correctly:

  • Uses the appropriate modifyRspackConfig hook
  • Safely initializes config.plugins before modification
  • Returns the modified config
  • Comprehensive JSDoc example demonstrates proper plugin ordering

Copy link
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: 0

🧹 Nitpick comments (1)
packages/rspeedy/plugin-external-bundle/src/index.ts (1)

67-77: Consider improving the inline comment and error message for better clarity.

Based on past review feedback:

  1. Line 68 comment: The comment "Get layer names from react-rsbuild-plugin" could be more generic since this plugin can work with any DSL plugin that exposes LAYERS, not just React.

  2. Lines 73-77 error message: While the current message is generic (good!), it could be more actionable by mentioning common failure scenarios:

    • The DSL plugin (e.g., pluginReactLynx) is not registered
    • This plugin is registered before the DSL plugin
    • The DSL plugin version doesn't expose LAYERS
🔎 Proposed improvements
-        // Get layer names from react-rsbuild-plugin
+        // Get layer names from DSL plugin
         const LAYERS = api.useExposed<ExposedLayers>(
           Symbol.for('LAYERS'),
         )
 
         if (!LAYERS) {
           throw new Error(
-            'external-bundle-rsbuild-plugin requires exposed `LAYERS`.',
+            'external-bundle-rsbuild-plugin requires exposed `LAYERS`. ' +
+            'Ensure a DSL plugin (e.g., pluginReactLynx) is registered before this plugin and exposes LAYERS.',
           )
         }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3372075 and a161a87.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/plugin-externals-rsbuild.md
  • .changeset/sixty-emus-call.md
  • examples/react-externals/lynx.config.js
  • examples/react-externals/package.json
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-external-bundle/api-extractor.json
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
  • packages/rspeedy/plugin-external-bundle/package.json
  • packages/rspeedy/plugin-external-bundle/src/index.ts
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
  • packages/rspeedy/tsconfig.json
  • website/package.json
  • website/rspress.config.ts
💤 Files with no reviewable changes (1)
  • packages/rspeedy/lynx-bundle-rslib-config/src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/sixty-emus-call.md
🚧 Files skipped from review as they are similar to previous changes (15)
  • packages/rspeedy/plugin-external-bundle/tsconfig.json
  • packages/rspeedy/plugin-external-bundle/api-extractor.json
  • packages/rspeedy/plugin-external-bundle/tsconfig.build.json
  • packages/rspeedy/plugin-react/src/pluginReactLynx.ts
  • website/package.json
  • packages/rspeedy/tsconfig.json
  • .changeset/plugin-externals-rsbuild.md
  • packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md
  • packages/rspeedy/plugin-external-bundle/CHANGELOG.md
  • packages/rspeedy/plugin-external-bundle/package.json
  • packages/rspeedy/plugin-external-bundle/test/index.test.ts
  • packages/rspeedy/plugin-external-bundle/README.md
  • packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts
  • packages/rspeedy/plugin-external-bundle/vitest.config.ts
  • examples/react-externals/package.json
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1771
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_component_with_static_sibling.js:2-2
Timestamp: 2025-09-18T04:43:54.426Z
Learning: In the lynx-family/lynx-stack repository, the `add_pure_comment` function in packages/react/transform/src/swc_plugin_compat/mod.rs (around lines 478-482) is specifically for `wrapWithLynxComponent` calls, not `createSnapshot` calls. The PURE comment injection for `createSnapshot` is handled separately in swc_plugin_snapshot/mod.rs.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-13T11:36:12.075Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:52-72
Timestamp: 2025-08-13T11:36:12.075Z
Learning: The lynx-stack project requires Node.js >=22 as specified in package.json engines, so Node.js compatibility fallbacks for features introduced before v22 are unnecessary.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-13T11:46:43.737Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1523
File: vitest.config.ts:5-6
Timestamp: 2025-08-13T11:46:43.737Z
Learning: In the lynx-stack codebase, default imports are consistently used for Node.js built-in modules (e.g., `import os from 'node:os'`, `import fs from 'node:fs'`). The TypeScript configuration supports esModuleInterop and allowSyntheticDefaultImports, making default imports the preferred pattern over namespace imports for Node.js built-ins.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-11-06T01:19:23.670Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1917
File: packages/mcp-servers/devtool-mcp-server/tsconfig.json:8-8
Timestamp: 2025-11-06T01:19:23.670Z
Learning: The lynx-js/devtool-mcp-server package in lynx-family/lynx-stack targets Node.js >=18.19 (specified in its package.json engines), which is different from the root project's requirement of Node.js ^22 || ^24. The package uses "lib": ["ES2024.Promise"] in its tsconfig.json because it manually includes polyfills for Promise.withResolvers while maintaining compatibility with Node.js v18.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • examples/react-externals/lynx.config.js
📚 Learning: 2025-08-12T16:09:32.413Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1497
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_full_static.js:9-10
Timestamp: 2025-08-12T16:09:32.413Z
Learning: In the Lynx stack, functions prefixed with `__` that are called in transformed code may be injected globally by the Lynx Engine at runtime rather than exported from the React runtime package. For example, `__CreateFrame` is injected globally by the Lynx Engine, not exported from lynx-js/react.

Applied to files:

  • examples/react-externals/lynx.config.js
🧬 Code graph analysis (1)
website/rspress.config.ts (1)
website/sidebars/api.ts (1)
  • createAPI (155-192)
🔇 Additional comments (8)
website/rspress.config.ts (2)

67-69: LGTM! API registration follows established patterns.

The English sidebar entry for external-bundle-rsbuild-plugin is correctly registered using the createAPI helper and maintains consistent ordering with the Chinese sidebar.


210-213: LGTM! Chinese sidebar entry is properly configured.

The Chinese API entry correctly mirrors the English sidebar structure with the appropriate base: 'zh/api' path and maintains consistent ordering.

examples/react-externals/lynx.config.js (2)

1-3: LGTM! Import migration is clean and correct.

The imports properly reflect the new pattern: pluginExternalBundle replaces the direct usage of ExternalsLoadingPlugin and LAYERS, which are now encapsulated within the plugin.


18-84: LGTM! Externals configuration correctly migrated to the new plugin.

The configuration demonstrates proper usage of pluginExternalBundle:

  • All external dependencies are correctly defined with required fields (libraryName, url, background, mainThread, async)
  • Plugin ordering is correct (after pluginReactLynx, which exposes the required LAYERS)
  • The structure matches the expected ExternalsLoadingPluginOptions.externals format

This serves as a good migration example for users adopting the new plugin.

packages/rspeedy/plugin-external-bundle/src/index.ts (4)

16-19: LGTM! Interface clearly defines the expected LAYERS structure.

The ExposedLayers interface properly models the layer names that must be exposed by the DSL plugin (e.g., pluginReactLynx).


26-29: LGTM! Clean public API surface.

The PluginExternalBundleOptions type appropriately narrows the external plugin options to only expose the externals configuration, hiding internal details like layer names which are automatically retrieved.


31-60: LGTM! Comprehensive documentation with clear usage example.

The JSDoc provides excellent guidance:

  • Explains the plugin's purpose and automatic layer retrieval
  • Shows proper plugin ordering (critical for the useExposed to work)
  • Demonstrates the externals configuration structure

78-86: LGTM! Plugin integration is correctly implemented.

The code properly:

  • Initializes the plugins array if needed
  • Instantiates ExternalsLoadingPlugin with the correct configuration
  • Maps the exposed layer names to the plugin's expected options
  • Returns the modified config

@luhc228 luhc228 merged commit ac31e72 into lynx-family:main Dec 22, 2025
74 of 78 checks passed
colinaaa pushed a commit that referenced this pull request Dec 29, 2025
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @lynx-js/lynx-bundle-rslib-config@0.1.0

### Minor Changes

- Update external bundle minimum SDK version to 3.5.
([#2037](#2037))

### Patch Changes

- Fix `globDynamicComponentEntry is not defined` error when minify is
enabled in external bundle consumer.
([#2058](#2058))

## @lynx-js/web-elements@0.10.0

### Minor Changes

- chore: migrate all @lynx-js/web-elements-\* packages into one
([#2057](#2057))

    ### Before

    ```js
    import "@lynx-js/web-elements-template";
    import "@lynx-js/web-elements-compat/LinearContainer";
    ```

    ### After

    ```js
    import "@lynx-js/web-elements/html-templates";
    import "@lynx-js/web-elements/compat/LinearContainer";
    ```

### Patch Changes

- refactor: change code structure for improved readability and
maintainability
([#2004](#2004))

    -   enable noUnusedLocals for web-elements
    -   add source field for supporting @rsbuild/plugin-source-build

    This is a part of #1937

## @lynx-js/react@0.115.2

### Patch Changes

- Fix `undefined factory
(react:background)/./node_modules/.pnpm/@lynx-js+react...` error when
loading a standalone lazy bundle after hydration.
([#2048](#2048))

- Partially fix "main-thread.js exception: TypeError: cannot read
property '\_\_elements' of undefined" by recursively calling
`snapshotDestroyList`.
([#2041](#2041))

- Fix a bug where React throws `CtxNotFound` error when lazy bundle
resolves after unmount.
([#2003](#2003))

## @lynx-js/rspeedy@0.12.4

### Patch Changes

-   Updated dependencies \[]:
    -   @lynx-js/web-rsbuild-server-middleware@0.19.3

## @lynx-js/external-bundle-rsbuild-plugin@0.0.1

### Patch Changes

- Introduce `@lynx-js/external-bundle-rsbuild-plugin`.
([#2006](#2006))

    ```ts
    // lynx.config.ts
import { pluginExternalBundle } from
"@lynx-js/external-bundle-rsbuild-plugin";
    import { pluginReactLynx } from "@lynx-js/react-rsbuild-plugin";

    export default {
      plugins: [
        pluginReactLynx(),
        pluginExternalBundle({
          externals: {
            lodash: {
              url: "http://lodash.lynx.bundle",
              background: { sectionPath: "background" },
              mainThread: { sectionPath: "mainThread" },
            },
          },
        }),
      ],
    };
    ```

- Updated dependencies
\[[`491c5ef`](491c5ef)]:
    -   @lynx-js/externals-loading-webpack-plugin@0.0.2

## @lynx-js/react-rsbuild-plugin@0.12.3

### Patch Changes

- expose LAYERS via `api.expose` for other rsbuild plugins.
([#2006](#2006))

- Updated dependencies
\[[`cd89bf9`](cd89bf9)]:
    -   @lynx-js/template-webpack-plugin@0.10.1
    -   @lynx-js/react-alias-rsbuild-plugin@0.12.3
    -   @lynx-js/use-sync-external-store@1.5.0
    -   @lynx-js/react-refresh-webpack-plugin@0.3.4
    -   @lynx-js/react-webpack-plugin@0.7.3
    -   @lynx-js/css-extract-webpack-plugin@0.7.0

## @lynx-js/web-constants@0.19.3

### Patch Changes

- Updated dependencies
\[[`986761d`](986761d)]:
    -   @lynx-js/web-worker-rpc@0.19.3

## @lynx-js/web-core@0.19.3

### Patch Changes

- Updated dependencies
\[[`986761d`](986761d)]:
    -   @lynx-js/web-worker-rpc@0.19.3
    -   @lynx-js/web-constants@0.19.3
    -   @lynx-js/web-worker-runtime@0.19.3
    -   @lynx-js/web-mainthread-apis@0.19.3

## @lynx-js/web-mainthread-apis@0.19.3

### Patch Changes

-   Updated dependencies \[]:
    -   @lynx-js/web-constants@0.19.3

## @lynx-js/web-worker-rpc@0.19.3

### Patch Changes

- feat: support lazy message port assigning in web-worker-rpc
([#2040](#2040))

## @lynx-js/web-worker-runtime@0.19.3

### Patch Changes

- Updated dependencies
\[[`986761d`](986761d)]:
    -   @lynx-js/web-worker-rpc@0.19.3
    -   @lynx-js/web-constants@0.19.3
    -   @lynx-js/web-mainthread-apis@0.19.3

## @lynx-js/externals-loading-webpack-plugin@0.0.2

### Patch Changes

- Export `ExternalValue` ts type.
([#2037](#2037))

## @lynx-js/template-webpack-plugin@0.10.1

### Patch Changes

- fix: pass updated css from encodeData to resolvedEncodeOptions
([#2053](#2053))

Previously, the initial CSS was used in resolvedEncodeOptions instead of
the potentially updated CSS from encodeData after the beforeEncode hook.
This fix ensures resolvedEncodeOptions receives the latest CSS data.

## create-rspeedy@0.12.4



## @lynx-js/react-alias-rsbuild-plugin@0.12.3



## upgrade-rspeedy@0.12.4



## @lynx-js/web-core-server@0.19.3



## @lynx-js/web-rsbuild-server-middleware@0.19.3

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants