Skip to content

fix: Prevent partial bundle loading and double fetching in `TemplateM…#2386

Merged
PupilTong merged 2 commits intolynx-family:mainfrom
PupilTong:p/hw/fetchBundle-race
Mar 27, 2026
Merged

fix: Prevent partial bundle loading and double fetching in `TemplateM…#2386
PupilTong merged 2 commits intolynx-family:mainfrom
PupilTong:p/hw/fetchBundle-race

Conversation

@PupilTong
Copy link
Copy Markdown
Collaborator

@PupilTong PupilTong commented Mar 26, 2026

…anager.fetchBundle` by handling concurrent requests and renaming template-related methods to bundle.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed a race condition where concurrently requesting the same bundle could produce partial loads, duplicate network fetches, or missed callbacks. Concurrent requests now share a single load operation, ensure complete bundle content is stored, cleanup is handled correctly on errors, and all awaiting callbacks are invoked.

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).

…anager.fetchBundle` by handling concurrent requests and renaming template-related methods to bundle.
@PupilTong PupilTong self-assigned this Mar 26, 2026
@PupilTong PupilTong requested a review from Sherry-hue as a code owner March 26, 2026 12:16
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 26, 2026

🦋 Changeset detected

Latest commit: 9dca8a0

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

This PR includes changesets to release 9 packages
Name Type
@lynx-js/web-core Patch
upgrade-rspeedy Patch
@lynx-js/web-rsbuild-server-middleware Patch
@lynx-js/template-webpack-plugin Patch
@lynx-js/react-rsbuild-plugin Patch
create-rspeedy Patch
@lynx-js/web-worker-rpc Patch
@lynx-js/react-alias-rsbuild-plugin Patch
@lynx-js/rspeedy 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
Copy Markdown
Contributor

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

Walkthrough

Refactors TemplateManager to split storage into completed (#bundles) and in-flight (#loadingBundles) entries, adds #loadingPromises to deduplicate concurrent fetchBundle calls, renames template-centric APIs to bundle-centric names, and updates call sites and tests to use the new bundle model. (50 words)

Changes

Cohort / File(s) Summary
Changeset Entry
.changeset/fix-bundle-race-condition.md
Added patch changeset describing fix for partial bundle loading and duplicate network fetches when fetchBundle is called concurrently.
TemplateManager core
packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts
Replaced single #templates map with #bundles and #loadingBundles; introduced #loadingPromises to reuse in-flight loads; renamed lifecycle helpers (createTemplatecreateBundle, getTemplategetBundle, removeTemplateremoveBundle); promote/cleanup logic adjusted and blob URL/style revocation expanded.
Call-site updates
packages/web-platform/web-core/ts/client/mainthread/LynxViewInstance.ts, packages/web-platform/web-core/ts/client/mainthread/createMainThreadGlobalAPIs.ts
Replaced getTemplate(...) usages with getBundle(...) and adjusted locations where lepusCode, backgroundCode, config, and customSections are read.
Tests
packages/web-platform/web-core/tests/template-manager.spec.ts
Updated assertions to use getBundle(...), switched commented helpers toward createBundle/removeBundle, and added a concurrency test that calls fetchBundle twice for the same URL and verifies no partial bundle state and both callbacks fire.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • Sherry-hue
  • colinaaa

Poem

🐰 I hopped through code where bundles collide,
I stitched their paths so races subside.
Promises pooled, no duplicate streams,
Complete bundles now fulfill our dreams. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: preventing partial bundle loading and double fetching in TemplateManager, which is the core purpose across all modified files.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown

codecov bot commented Mar 26, 2026

Codecov Report

❌ Patch coverage is 67.41573% with 29 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...m/web-core/ts/client/mainthread/TemplateManager.ts 71.42% 24 Missing ⚠️
.../web-core/ts/client/mainthread/LynxViewInstance.ts 0.00% 4 Missing ⚠️
...ts/client/mainthread/createMainThreadGlobalAPIs.ts 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 26, 2026

Merging this PR will degrade performance by 21.15%

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

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

Performance Changes

Benchmark BASE HEAD Efficiency
002-hello-reactLynx-destroyBackground 678.9 µs 861 µs -21.15%

Comparing PupilTong:p/hw/fetchBundle-race (9dca8a0) with main (a32bc28)

Open in CodSpeed

Footnotes

  1. 21 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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/web-platform/web-core/tests/template-manager.spec.ts (1)

398-455: Cover the mixed overrideConfig race in this regression test.

The bug report path is fetchBundle(url) racing with fetchBundle(url, ..., { enableCSSSelector: ... }) from queryComponent(). This test only covers two identical requests, so it won't catch URL-only dedupe dropping the second caller's override. I'd extend it with one overridden caller and assert both the override and single-fetch behavior.

✅ Suggested test extension
     await Promise.all([
       templateManager.fetchBundle(
         'http://example.com/template_concurrent',
         Promise.resolve(instance1 as unknown as LynxViewInstance),
         false,
         false,
       ),
       templateManager.fetchBundle(
         'http://example.com/template_concurrent',
         Promise.resolve(instance2 as unknown as LynxViewInstance),
         false,
         false,
+        { enableCSSSelector: 'true' } as any,
       ),
     ]);
@@
     expect(decodedCustomSections).toEqual(sampleTasm.customSections);
     expect(instance1.onPageConfigReady).toHaveBeenCalled();
-    expect(instance2.onPageConfigReady).toHaveBeenCalled();
+    expect(instance2.onPageConfigReady).toHaveBeenCalledWith(
+      expect.objectContaining({ enableCSSSelector: 'true' }),
+    );
+    expect(globalThis.fetch).toHaveBeenCalledTimes(1);
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web-platform/web-core/tests/template-manager.spec.ts` around lines
398 - 455, Extend the concurrent-fetch test to also exercise the mixed-override
race: call templateManager.fetchBundle twice concurrently where one call passes
an overrideConfig (e.g., { enableCSSSelector: true } or the real override shape
used by queryComponent) and the other call uses the default override (no
overrideConfig), then assert both callers complete and that (1) the stored
bundle from templateManager.getBundle(url) remains correct for the fetched
bundle, and (2) the caller that supplied overrideConfig received the overridden
behavior (verify via the instance's onPageConfigReady / pageConfig or other
public observable produced by fetchBundle) while the other caller still receives
normal behavior; reference templateManager.fetchBundle, getBundle,
queryComponent, overrideConfig and the instances' onPageConfigReady to locate
and implement the assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts`:
- Around line 65-75: The dedupe branch is collapsing concurrent requests by URL
only, which loses per-call overrideConfig from queryComponent; update the logic
around `#loadingPromises` (the dedupe path that returns
this.#loadingPromises.get(url)) so it preserves per-caller overrideConfig:
either include overrideConfig in the dedupe key (e.g., use a composite key of
url + serialized overrideConfig when storing/checking `#loadingPromises` for
fetchBundle) or, if overrideConfig exists on the waiting caller, skip the
URL-only dedupe and start a new fetch; then ensure the waiting caller uses its
overrideConfig when calling lynxViewInstance.onPageConfigReady and related
methods (references: `#loadingPromises`, fetchBundle, queryComponent,
lynxViewInstancePromise, onPageConfigReady).
- Around line 198-213: When handling the 'done' case, ensure the in-flight entry
is settled and removed even if lynxViewInstancePromise rejects: move the calls
to this.#resolvePromise(url) and this.#loadingPromises.delete(url) out of the
.then handler and into a .finally (or mirror them in both .then and .catch), and
in the .catch propagate or log the error so callers don't hang; keep the
existing backgroundThread markTiming calls inside the successful path
(lynxViewInstancePromise.then) and ensure bundle promotion (this.#bundles/set
and this.#loadingBundles.delete) remains unchanged.

---

Nitpick comments:
In `@packages/web-platform/web-core/tests/template-manager.spec.ts`:
- Around line 398-455: Extend the concurrent-fetch test to also exercise the
mixed-override race: call templateManager.fetchBundle twice concurrently where
one call passes an overrideConfig (e.g., { enableCSSSelector: true } or the real
override shape used by queryComponent) and the other call uses the default
override (no overrideConfig), then assert both callers complete and that (1) the
stored bundle from templateManager.getBundle(url) remains correct for the
fetched bundle, and (2) the caller that supplied overrideConfig received the
overridden behavior (verify via the instance's onPageConfigReady / pageConfig or
other public observable produced by fetchBundle) while the other caller still
receives normal behavior; reference templateManager.fetchBundle, getBundle,
queryComponent, overrideConfig and the instances' onPageConfigReady to locate
and implement the assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e032d625-beda-403b-ad39-d5fccb8df10a

📥 Commits

Reviewing files that changed from the base of the PR and between dae9fed and dfae1be.

📒 Files selected for processing (5)
  • .changeset/fix-bundle-race-condition.md
  • packages/web-platform/web-core/tests/template-manager.spec.ts
  • packages/web-platform/web-core/ts/client/mainthread/LynxViewInstance.ts
  • packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts
  • packages/web-platform/web-core/ts/client/mainthread/createMainThreadGlobalAPIs.ts

@relativeci
Copy link
Copy Markdown

relativeci bot commented Mar 26, 2026

Web Explorer

#8469 Bundle Size — 728.55KiB (+0.09%).

9dca8a0(current) vs a32bc28 main#8457(baseline)

Bundle metrics  Change 4 changes Regression 1 regression
                 Current
#8469
     Baseline
#8457
Regression  Initial JS 43.29KiB(+1.57%) 42.62KiB
No change  Initial CSS 2.16KiB 2.16KiB
Change  Cache Invalidation 15.49% 0%
No change  Chunks 8 8
No change  Assets 10 10
Change  Modules 150(+0.67%) 149
No change  Duplicate Modules 11 11
Change  Duplicate Code 34.68%(-0.14%) 34.73%
No change  Packages 3 3
No change  Duplicate Packages 0 0
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#8469
     Baseline
#8457
No change  Other 384.4KiB 384.4KiB
Regression  JS 342KiB (+0.19%) 341.33KiB
No change  CSS 2.16KiB 2.16KiB

Bundle analysis reportBranch PupilTong:p/hw/fetchBundle-raceProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci bot commented Mar 26, 2026

React MTF Example

#25 Bundle Size — 207.47KiB (0%).

9dca8a0(current) vs a32bc28 main#13(baseline)

Bundle metrics  no changes
                 Current
#25
     Baseline
#13
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 3 3
No change  Modules 168 168
No change  Duplicate Modules 66 66
No change  Duplicate Code 46.13% 46.13%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#25
     Baseline
#13
No change  IMG 111.23KiB 111.23KiB
No change  Other 96.24KiB 96.24KiB

Bundle analysis reportBranch PupilTong:p/hw/fetchBundle-raceProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci bot commented Mar 26, 2026

React Example

#6891 Bundle Size — 237.89KiB (0%).

9dca8a0(current) vs a32bc28 main#6879(baseline)

Bundle metrics  no changes
                 Current
#6891
     Baseline
#6879
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 174 174
No change  Duplicate Modules 69 69
No change  Duplicate Code 46.44% 46.44%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#6891
     Baseline
#6879
No change  IMG 145.76KiB 145.76KiB
No change  Other 92.13KiB 92.13KiB

Bundle analysis reportBranch PupilTong:p/hw/fetchBundle-raceProject dashboard


Generated by RelativeCIDocumentationReport issue

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts (1)

54-85: ⚠️ Potential issue | 🟠 Major

overrideConfig is still missing from the cache/dedupe key.

This state is still keyed by bare url, so a load started with one override can be replayed for concurrent callers with a different override, and the completed #bundles entry can later serve that overridden config back to a no-override caller on the fast path. Please key shared entries by (url, overrideConfig) or avoid sharing/caching overridden loads.

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

In `@packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts`
around lines 54 - 85, The cache/dedupe keys for bundle loading are currently
only using url, so entries in this.#bundles and this.#loadingPromises can be
reused across different overrideConfig values causing incorrect config replay;
change the keying to include overrideConfig (for example, combine url and a
stable serialization of overrideConfig) wherever entries are set and looked up
(references: this.#bundles, this.#loadingPromises, createBundle, and the call
site of this.#load) or alternatively avoid caching when overrideConfig is
present by branching to always call this.#load for overrideConfig !== undefined;
ensure lookups, set calls, and the fast path that reads bundle?.config all use
the same (url, overrideConfig) composite key so no cross-contamination occurs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts`:
- Around line 275-319: createBundle currently destroys the existing entry in
`#bundles` immediately, exposing a missing/partial bundle during reloads; change
the flow so createBundle only creates an empty in-flight record in
`#loadingBundles` (do not revoke or delete from `#bundles` there), perform
fetch/build into that loading entry, and on the successful completion event
('done') swap the completed bundle into `#bundles` while then revoking/cleaning
the previous `#bundles` entry; update getBundle usage so it falls back to `#bundles`
as before; also modify `#removeBundle` to only clear the in-flight state in
`#loadingBundles` (do not call createBundle to perform the clear), and ensure
cleanup/revocation logic references bundle.lepusCode, bundle.backgroundCode, and
bundle.styleSheet when swapping/removing the old bundle.
- Around line 198-206: The 'done' branch in TemplateManager (within
`#handleSection` and similar branches) promotes the bundle from `#loadingBundles` to
`#bundles` and deletes the `#loadingBundles` entry immediately, which lets async
section writers resume later and silently lose updates; change the logic so you
either (a) wait until the per-URL section queue/section writers have drained
before deleting the `#loadingBundles` entry (i.e., keep the loading entry until
all pending section promises for that URL have completed), or (b) update the
section-writer paths to detect a promoted bundle and apply their
config/style/code writes to the already-promoted bundle (fall back to `#bundles`
when `#loadingBundles.get`(url) is missing). Apply the same fix to other similar
blocks that call `#cleanup`, move entries between `#loadingBundles` and `#bundles`,
call `#resolvePromise`, and delete `#loadingPromises` (the other occurrences noted
in the review).

---

Duplicate comments:
In `@packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts`:
- Around line 54-85: The cache/dedupe keys for bundle loading are currently only
using url, so entries in this.#bundles and this.#loadingPromises can be reused
across different overrideConfig values causing incorrect config replay; change
the keying to include overrideConfig (for example, combine url and a stable
serialization of overrideConfig) wherever entries are set and looked up
(references: this.#bundles, this.#loadingPromises, createBundle, and the call
site of this.#load) or alternatively avoid caching when overrideConfig is
present by branching to always call this.#load for overrideConfig !== undefined;
ensure lookups, set calls, and the fast path that reads bundle?.config all use
the same (url, overrideConfig) composite key so no cross-contamination occurs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d5d139b4-3a6b-4924-9e8f-08eee14b0ac5

📥 Commits

Reviewing files that changed from the base of the PR and between dfae1be and 9dca8a0.

📒 Files selected for processing (1)
  • packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts

@PupilTong PupilTong merged commit 62bebcf into lynx-family:main Mar 27, 2026
72 of 78 checks passed
colinaaa pushed a commit that referenced this pull request Apr 6, 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/rspeedy@0.14.0

### Minor Changes

- feat: add `Minify.mainThreadOptions` and `Minify.backgroundOptions`
for thread-specific minifier.
([#2336](#2336))

### Patch Changes

- Bump Rsbuild v1.7.4 with Rspack v1.7.10.
([#2384](#2384))

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

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

### Minor Changes

- **BREAKING CHANGE**:
([#2370](#2370))

Simplify the API for external bundle builds by `externalsPresets` and
`externalsPresetDefinitions`.

### Patch Changes

- Preserve the default external-bundle `output.minify.jsOptions` when
users set `output.minify: true` in `defineExternalBundleRslibConfig`, so
required minifier options are not lost.
([#2390](#2390))

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

### Minor Changes

- **BREAKING CHANGE**:
([#2370](#2370))

Simplify the API for external bundle builds by `externalsPresets` and
`externalsPresetDefinitions`.

### Patch Changes

- Updated dependencies
\[[`7b7a0c6`](7b7a0c6)]:
    -   @lynx-js/externals-loading-webpack-plugin@0.1.0

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

### Minor Changes

- feat: support `optimizeBundleSize` option to remove unused code for
main-thread and background.
([#2336](#2336))

- If `optimizeBundleSize` is `true` or `optimizeBundleSize.background`
is `true`, `lynx.registerDataProcessors` calls will be marked as pure
for the background thread output.
- If `optimizeBundleSize` is `true` or `optimizeBundleSize.mainThread`
is `true`, `NativeModules.call` and `lynx.getJSModule` calls will be
marked as pure for the main-thread output.

### Patch Changes

- refactor: remove `modifyWebpackChain` since Rsbuild 2.0 dropped
webpack support
([#2397](#2397))

- Updated dependencies
\[[`9193711`](9193711)]:
    -   @lynx-js/template-webpack-plugin@0.10.7
    -   @lynx-js/css-extract-webpack-plugin@0.7.0
    -   @lynx-js/react-webpack-plugin@0.8.0
    -   @lynx-js/react-alias-rsbuild-plugin@0.14.0
    -   @lynx-js/use-sync-external-store@1.5.0
    -   @lynx-js/react-refresh-webpack-plugin@0.3.5

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

### Minor Changes

- **This is a breaking change**
([#2322](#2322))

    ## Architectural Upgrade: `web-core-wasm` replaces `web-core`

This release marks a major architectural upgrade for the web platform.
The experimental, WASM-powered engine formerly known as `web-core-wasm`
has been fully stabilized and merged into the main branch, completely
replacing the previous pure JS/TS based `web-core` implementation. This
consolidation massively improves execution performance and aligns the
API boundaries of the Web platform directly with other native Lynx
implementations.

    ### 🎉 Added Features

- **Core API Enhancements**: Successfully exposed and supported
`__QuerySelector` and `__InvokeUIMethod` methods.
- **Security & CSP Compliance**: Added a `nonce` attribute to the
iframe's `srcdoc` script execution, strengthening Content Security
Policy (CSP) compliance.
    -   **`<lynx-view>` Parameter Enhancements**:
- Added the `browser-config` attribute and property to `<lynx-view>`.
Development environments can now supply a `BrowserConfig` object (e.g.,
configuring `pixelRatio`, `pixelWidth`, `pixelHeight`) allowing the
`systemInfo` payload to be dynamically configured at the instance level.

    ### 🔄 Changed Features

- **Legacy JSON Backwards Compatibility**: Delivered comprehensive fixes
and optimizations to deeply support legacy JSON output templates:
- Added support for lazy loading execution mode (`lazy usage`).
- Implemented the correct decoding and handling of `@keyframe` animation
rules.
- Rectified rule scoping matching including scoped CSS, root selectors,
and type selectors.

- **Ecosystem Migration**: Updated testing and ecosystem applications
(such as `web-explorer` and `shell-project`) to migrate away from
obsolete fragmented dependencies. The new WASM architecture seamlessly
integrates Element APIs and CSS directly inside the core client module,
requiring a much simpler initialization footprint.

        **Before (Legacy `web-core` + `web-elements`):**

        ```typescript
        // Required multiple imports to assemble the environment
        import "@lynx-js/web-core/client";
import type { LynxViewElement as LynxView } from "@lynx-js/web-core";

        // Had to manually import separate elements and their CSS
        import "@lynx-js/web-elements/index.css";
        import "@lynx-js/web-elements/all";

const lynxView = document.createElement("lynx-view") as LynxView;
        // ...
        ```

        **After (New `web-core` unified architecture):**

        ```typescript
// The new engine natively registers Web Components and injects
fundamental CSS
        import "@lynx-js/web-core/client";
import type { LynxViewElement as LynxView } from
"@lynx-js/web-core/client";

const lynxView = document.createElement("lynx-view") as LynxView;
        // ...
        ```

_(Applications can now drop `@lynx-js/web-elements` entirely from their
`package.json` dependencies)._

- **Dependency & Boot Sequence Improvements**: Re-architected module
loading pathways. Promoted `wasm-feature-detect` directly to a core
dependency, and hardened the web worker count initialization assertions.

- **Initialization Optimizations**: Converted `SERVER_IN_SHADOW_CSS`
initialization bounds to use compilation-time constant expressions for
better optimization.

    ### 🗑️ Deleted Features & Structural Deprecations

    -   **`<lynx-view>` Parameter Removals**:
- Removed the `thread-strategy` property and attribute. Historically,
this permitted consumers to toggle between `'multi-thread'` and
`'all-on-ui'` modes depending on how they wanted the background logic to
be executed. The WASM-driven architecture enforces a consolidated
concurrency model, deprecating this `<lynx-view>` attribute entirely.
- Removed the `overrideLynxTagToHTMLTagMap` property/attribute. HTML tag
overriding mechanism has been deprecated in the new engine.
- Removed the `customTemplateLoader` property handler from
`<lynx-view>`.
- Removed the `inject-head-links` property and attribute
(`injectHeadLinks`), which previously was used to automatically inject
`<link rel="stylesheet">` tags from the document head into the
`lynx-view` shadow root.
- **Fragmented Packages Removal**: The new cohesive WASM architecture
native to `@lynx-js/web-core` handles cross-thread communication, worker
boundaries, and rendering loops uniformly. Consequently, multiple
obsolete packages have been completely removed from the workspace:
        -   `@lynx-js/web-mainthread-apis`
        -   `@lynx-js/web-worker-runtime`
        -   `@lynx-js/web-core-server`
- `@lynx-js/web-core-wasm-e2e` (transitioned into standard test suites)

- Added support for `rpx` unit
([#2377](#2377))

    **This is a breaking change**

    The following Styles has been added to `web-core`

    ```css
    lynx-view {
      width: 100%;
      container-name: lynx-view;
      container-type: inline-size;
      --rpx-unit: 1cqw;
    }
    ```

    Check MDN for the details about these styles:

-
<https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/container-name>
-
<https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/container-type>
-
<https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Containment/Container_queries>

    ### how it works?

    For the following code

    ```html
    <view style="height:1rpx"></view>
    ```

    it will be transformed to

    ```html
    <view style="height:calc(1 * var(--rpx-unit))"></view>
    ```

Therefore you could use any `<length>` value to replace the unit, for
example:

    ```html
    <lynx-view style="--rpx-unit:1px"></lynx-view>
    ```

    By default, the --rpx-unit value is `1cqw`

- Added support for transform `vw` and `vh` unit
([#2377](#2377))

Add `transform-vw` and `transform-vh` attributes and properties on
`<lynx-view>`.

    For the following code

    ```html
    <view style="height:1vw"></view>
    ```

If the `transform-vw` is enabled `<lynx-view transform-vw="true">`, it
will be transformed to

    ```html
    <view style="height:calc(1 * var(--vw-unit))"></view>
    ```

Therefore you could use any `<length>` value to replace the unit, for
example:

    ```html
    <lynx-view style="--vw-unit:1px"></lynx-view>
    ```

### Patch Changes

- feat(web-core): add `is_bubble` parameter to `common_event_handler` to
properly handle non-bubbling events like `window.Event('click', {
bubbles: false })`.
([#2399](#2399))

- chore: update readme
([#2380](#2380))

- fix: the output format should be module
([#2388](#2388))

- opt: use opt-level 3 to compile wasm
([#2371](#2371))

- fix(web-core): avoid partial bundle loading and double fetching when
fetchBundle is called concurrently for the same url.
([#2386](#2386))

- fix(web-core): fallback to the original export chunk when
`processEvalResult` is absent during `queryComponent` execution
([#2399](#2399))

- fix: tokenizing inline style values correctly to support rpx and ppx
unit conversion
([#2381](#2381))

This fixes an issue where the `transform_inline_style_key_value_vec` API
bypassed the CSS tokenizer, preventing dimension units like `rpx` or
`ppx` from being successfully transformed into `calc` strings when
specified via inline styles.

- feat: add mts lynx.querySelectorAll API
([#2382](#2382))

- fix: mts in lazy component
([#2375](#2375))

- fix: enableJSDataProcessor not work
([#2372](#2372))

- feat: add `ppx` unit support for CSS, transforming to `calc(... *
var(--ppx-unit))` directly.
([#2381](#2381))

-   Updated dependencies \[]:
    -   @lynx-js/web-worker-rpc@0.20.0

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

### Minor Changes

- **BREAKING CHANGE**:
([#2370](#2370))

Simplify the API for external bundle builds by `externalsPresets` and
`externalsPresetDefinitions`.

## @lynx-js/devtool-connector@0.1.1

### Patch Changes

- fix: align GlobalKeys with Android DevToolSettings keys and filter
global switch responses
([#2392](#2392))

## @lynx-js/devtool-mcp-server@0.5.1

### Patch Changes

- Updated dependencies
\[[`95fff27`](95fff27)]:
    -   @lynx-js/devtool-connector@0.1.1

## @lynx-js/react@0.117.1

### Patch Changes

- Update preact version to simplify `setProperty` implementation
([#2367](#2367))

## @lynx-js/react-umd@0.117.1

### Patch Changes

- Add a new `entry` export to `@lynx-js/react-umd` for reuse by wrapper
libraries of `@lynx-js/react`.
([#2370](#2370))

## create-rspeedy@0.14.0

### Patch Changes

- Add optional Lynx DevTool skill.
([#2421](#2421))

- move Vitest integration to create-rstack extraTools and merge the
Vitest templates into a single incremental overlay
([#2408](#2408))

## @lynx-js/kitten-lynx-test-infra@0.1.2

### Patch Changes

- Updated dependencies
\[[`95fff27`](95fff27)]:
    -   @lynx-js/devtool-connector@0.1.1

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

### Patch Changes

- use path.posix.format instead of path.format to ensure consistent path
separators across platforms
([#2359](#2359))

- Updated dependencies
\[[`75960cd`](75960cd),
[`518c310`](518c310),
[`863469e`](863469e),
[`dc18c5c`](dc18c5c),
[`7d242f3`](7d242f3),
[`62bebcf`](62bebcf),
[`75960cd`](75960cd),
[`182f568`](182f568),
[`1aa051d`](1aa051d),
[`6b46f7e`](6b46f7e),
[`fcda36a`](fcda36a),
[`182f568`](182f568),
[`138f727`](138f727),
[`138f727`](138f727)]:
    -   @lynx-js/web-core@0.20.0

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



## upgrade-rspeedy@0.14.0



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



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

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

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants