Skip to content

feat: allow globalObject config and reuse fetchBundle result#2123

Merged
upupming merged 2 commits intomainfrom
feat/globalObject
Jan 26, 2026
Merged

feat: allow globalObject config and reuse fetchBundle result#2123
upupming merged 2 commits intomainfrom
feat/globalObject

Conversation

@upupming
Copy link
Collaborator

@upupming upupming commented Jan 21, 2026

Summary by CodeRabbit

  • New Features
    • Added a globalObject option to external-bundle plugins and example configs so externals can mount to 'lynx' or 'globalThis' for improved bundle sharing.
  • Tests
    • Added test cases validating default and globalThis mounting behavior.
  • Documentation
    • Public plugin option docs updated to include the new globalObject setting.

✏️ 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 Jan 21, 2026

🦋 Changeset detected

Latest commit: f38c900

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/externals-loading-webpack-plugin Patch
@lynx-js/lynx-bundle-rslib-config Patch
@lynx-js/external-bundle-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 Jan 21, 2026

📝 Walkthrough

Walkthrough

Adds a new optional globalObject option (values 'lynx' | 'globalThis') across externals handling: webpack plugin, rslib external bundle config, rsbuild plugin, examples, and tests; propagates the option into runtime externals generation and example configs.

Changes

Cohort / File(s) Summary
Changeset declaration
/.changeset/wet-fans-sleep.md
Adds a changeset declaring patch releases and noting the new globalObject config for external bundles
Example configurations
examples/react-externals/lynx.config.js, examples/react-externals/rslib-comp-lib.config.ts, examples/react-externals/rslib-reactlynx.config.ts
Add globalObject: 'globalThis' to example external-bundle outputs
Rslib external bundle config
packages/rspeedy/lynx-bundle-rslib-config/src/externalBundleRslibConfig.ts
Adds `OutputConfig.globalObject?: 'lynx'
Rslib config tests
packages/rspeedy/lynx-bundle-rslib-config/test/external-bundle.test.ts
Adds tests for default and globalThis mounting (duplicated suite present) validating externals mounting reference
Rsbuild plugin API & impl
packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md, packages/rspeedy/plugin-external-bundle/src/index.ts
Extends PluginExternalBundleOptions to include globalObject and propagates it to ExternalsLoadingPlugin
Rsbuild plugin tests
packages/rspeedy/plugin-external-bundle/test/index.test.ts
Adds test asserting globalObject is passed into ExternalsLoadingPlugin options
Webpack externals-loading plugin API & impl
packages/webpack/externals-loading-webpack-plugin/etc/externals-loading-webpack-plugin.api.md, packages/webpack/externals-loading-webpack-plugin/src/index.ts
Adds `globalObject?: 'lynx'
Webpack plugin tests & cases
packages/webpack/externals-loading-webpack-plugin/test/cases/externals-loading/filter-duplicate-externals/index.js, packages/webpack/externals-loading-webpack-plugin/test/cases/externals-loading/globalObject-customize/*
Relaxes some assertion patterns and adds a new test case (globalObject-customize) with rspack config and CJS test config to assert mounting to globalThis

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • colinaaa
  • luhc228

Poem

🐰
A tiny rabbit hops and sings,
Threading globals on nimble wings,
From lynx to globalThis we leap,
Externals mount, the changes keep,
Tests applaud — the bundles sleep. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: allow globalObject config and reuse fetchBundle result' accurately reflects the main changes in the changeset—adding globalObject configuration across multiple packages and test cases. It's concise and specific enough to understand the primary feature addition.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@codecov
Copy link

codecov bot commented Jan 21, 2026

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!

@codspeed-hq
Copy link

codspeed-hq bot commented Jan 21, 2026

Merging this PR will degrade performance by 11.15%

❌ 1 regressed benchmark
✅ 62 untouched benchmarks
⏩ 3 skipped benchmarks1

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

Performance Changes

Benchmark BASE HEAD Efficiency
transform 1000 view elements 41.7 ms 46.9 ms -11.15%

Comparing feat/globalObject (f38c900) with main (444f83b)

Open in CodSpeed

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 Jan 21, 2026

Web Explorer

#7323 Bundle Size — 384.14KiB (0%).

f38c900(current) vs 444f83b main#7318(baseline)

Bundle metrics  Change 1 change
                 Current
#7323
     Baseline
#7318
No change  Initial JS 154.12KiB 154.12KiB
No change  Initial CSS 35.05KiB 35.05KiB
No change  Cache Invalidation 0% 0%
No change  Chunks 8 8
No change  Assets 8 8
Change  Modules 238(-0.42%) 239
No change  Duplicate Modules 16 16
No change  Duplicate Code 2.99% 2.99%
No change  Packages 4 4
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#7323
     Baseline
#7318
No change  JS 252.07KiB 252.07KiB
No change  Other 97.02KiB 97.02KiB
No change  CSS 35.05KiB 35.05KiB

Bundle analysis reportBranch feat/globalObjectProject dashboard


Generated by RelativeCIDocumentationReport issue

@upupming upupming marked this pull request as ready for review January 23, 2026 08:57
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: 3

🤖 Fix all issues with AI agents
In @.changeset/wet-fans-sleep.md:
- Line 7: In the changelog sentence about Add `globalObject` config, change the
verb "config" to "configure" so it reads e.g. "user can configure it to
`globalThis` for BTS external bundle sharing"; update the phrase referencing
`globalObject` to use "configure" to correct the grammar while leaving the rest
of the text intact.

In `@packages/rspeedy/lynx-bundle-rslib-config/test/external-bundle.test.ts`:
- Around line 259-296: Update the two failing expectations in the "should mount
externals library to globalThis" test: when rslibConfig sets output.globalObject
= 'globalThis' the bundle will reference
globalThis[Symbol.for("__LYNX_EXTERNAL_GLOBAL__")], so change the asserted
substrings in the expect calls that inspect
decodedResult['custom-sections']['utils'] and
decodedResult['custom-sections']['utils__main-thread'] from
'lynx[Symbol.for("__LYNX_EXTERNAL_GLOBAL__")].ReactLynx.React' to
'globalThis[Symbol.for("__LYNX_EXTERNAL_GLOBAL__")].ReactLynx.React' so the test
matches the configured globalObject behavior.

In `@packages/webpack/externals-loading-webpack-plugin/src/index.ts`:
- Around line 314-316: The current runtimeGlobalsInit string unconditionally
overwrites the shared global returned by
getLynxExternalGlobal(externalsLoadingPluginOptions.globalObject); change it to
only initialize if the global is absent (avoid clobbering existing externals).
Update the runtimeGlobalsInit construction (the code that builds the string
assigned to runtimeGlobalsInit) to perform a conditional init (e.g., a
typeof/undefined check or guard) so it only sets the global to {} when it does
not already exist, using the same getLynxExternalGlobal(...) symbol in the
check.
🧹 Nitpick comments (5)
packages/webpack/externals-loading-webpack-plugin/test/cases/externals-loading/filter-duplicate-externals/index.js (1)

19-29: Make the match whitespace-agnostic to avoid brittle tests.

The updated split still depends on exact spaces, which can change with formatting/minification. A regex with \s* keeps the intent while reducing false negatives.

♻️ Suggested refactor
   const mainThread = fs.readFileSync(
     path.resolve(__dirname, 'main:main-thread.js'),
     'utf-8',
   );
+  const externalAssignRe =
+    /lynx\[Symbol\.for\('__LYNX_EXTERNAL_GLOBAL__'\)\]\["Foo"\]\s*=\s*/g;
+  const countExternalAssign = (s) => (s.match(externalAssignRe) ?? []).length;
-  expect(
-    background.split(
-      `lynx[Symbol.for('__LYNX_EXTERNAL_GLOBAL__')]["Foo"]`
-        + ' = ',
-    ).length - 1,
-  ).toBe(1);
+  expect(countExternalAssign(background)).toBe(1);
   expect(
-    mainThread.split(
-      `lynx[Symbol.for('__LYNX_EXTERNAL_GLOBAL__')]["Foo"] `
-        + '= ',
-    ).length - 1,
-  ).toBe(1);
+    countExternalAssign(mainThread),
+  ).toBe(1);
 });
packages/webpack/externals-loading-webpack-plugin/etc/externals-loading-webpack-plugin.api.md (1)

20-21: Consider adding a @default TSDoc annotation in the source.

The API Extractor warning indicates that the globalObject property is missing a @default tag in the source TypeScript definition. Based on the PR context, the default appears to be 'lynx'. Adding this annotation would improve documentation and eliminate this warning.

packages/webpack/externals-loading-webpack-plugin/test/cases/externals-loading/globalObject-customize/index.js (1)

17-28: Inconsistent string concatenation style in assertions.

The split patterns are written with different whitespace placement:

  • Line 19-20: ]["Foo"] + ' = '
  • Line 25-26: ]["Foo"] + '= '

Both produce the same result ]["Foo"] = , but the inconsistency could confuse future maintainers. Consider using a consistent style.

🔧 Suggested fix for consistency
   expect(
     background.split(
-      `globalThis[Symbol.for('__LYNX_EXTERNAL_GLOBAL__')]["Foo"]`
-        + ' = ',
+      `globalThis[Symbol.for('__LYNX_EXTERNAL_GLOBAL__')]["Foo"] = `,
     ).length - 1,
   ).toBe(1);
   expect(
     mainThread.split(
-      `globalThis[Symbol.for('__LYNX_EXTERNAL_GLOBAL__')]["Foo"] `
-        + '= ',
+      `globalThis[Symbol.for('__LYNX_EXTERNAL_GLOBAL__')]["Foo"] = `,
     ).length - 1,
   ).toBe(1);
packages/rspeedy/lynx-bundle-rslib-config/test/external-bundle.test.ts (1)

230-230: Consider using distinct bundle IDs for better test isolation.

Both tests use id: 'utils-reactlynx' and write to the same output directory. While this works with sequential test execution, using distinct IDs (e.g., 'utils-reactlynx-default' and 'utils-reactlynx-globalThis') would improve test isolation and make debugging easier.

Also applies to: 267-267

packages/rspeedy/lynx-bundle-rslib-config/src/externalBundleRslibConfig.ts (1)

90-103: Tighten globalObject type to preserve API safety.

globalObject?: string allows invalid values to compile and generate broken externals. Consider typing it as OutputConfig['globalObject'] (or the same union) to keep config validation at compile time.

♻️ Suggested refactor
-function transformExternals(
-  externals?: Externals,
-  globalObject?: string,
-): Required<LibOutputConfig>['externals'] {
+function transformExternals(
+  externals?: Externals,
+  globalObject?: OutputConfig['globalObject'],
+): Required<LibOutputConfig>['externals'] {

@upupming upupming enabled auto-merge (squash) January 26, 2026 02:55
@upupming upupming merged commit 959360c into main Jan 26, 2026
46 of 47 checks passed
@upupming upupming deleted the feat/globalObject branch January 26, 2026 03:02
colinaaa pushed a commit that referenced this pull request Jan 26, 2026
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/react@0.116.1

### Patch Changes

- Fix the issue that lazy bundle HMR will lost CSS.
([#2134](#2134))

## @lynx-js/rspeedy@0.13.2

### Patch Changes

- Bump Rsbuild 1.7.2 with Rspack 1.7.1.
([#2136](#2136))

## @lynx-js/lynx-bundle-rslib-config@0.2.1

### Patch Changes

- Add
[`globalObject`](https://webpack.js.org/configuration/output/#outputglobalobject)
config for external bundle loading, user can configure it to
`globalThis` for BTS external bundle sharing.
([#2123](#2123))

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

### Patch Changes

- Add
[`globalObject`](https://webpack.js.org/configuration/output/#outputglobalobject)
config for external bundle loading, user can configure it to
`globalThis` for BTS external bundle sharing.
([#2123](#2123))

- Updated dependencies
\[[`959360c`](959360c)]:
    -   @lynx-js/externals-loading-webpack-plugin@0.0.3

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

### Patch Changes

- Add
[`globalObject`](https://webpack.js.org/configuration/output/#outputglobalobject)
config for external bundle loading, user can configure it to
`globalThis` for BTS external bundle sharing.
([#2123](#2123))

## create-rspeedy@0.13.2



## upgrade-rspeedy@0.13.2

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