Skip to content

fix: web-core-wasm triggerEvent & lazy component for special DSL usage#2399

Merged
PupilTong merged 2 commits intolynx-family:mainfrom
PupilTong:p/hw/fix-lazy-component-without-eval-result-function
Mar 30, 2026
Merged

fix: web-core-wasm triggerEvent & lazy component for special DSL usage#2399
PupilTong merged 2 commits intolynx-family:mainfrom
PupilTong:p/hw/fix-lazy-component-without-eval-result-function

Conversation

@PupilTong
Copy link
Copy Markdown
Collaborator

@PupilTong PupilTong commented Mar 30, 2026

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed queryComponent fallback behavior when processing evaluation results is unavailable
    • Improved event handling to correctly process non-bubbling events
  • Tests

    • Added end-to-end tests for component query execution with and without result processing
    • Added test coverage for non-bubbling event propagation scenarios

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

@PupilTong PupilTong requested a review from Sherry-hue as a code owner March 30, 2026 08:38
@PupilTong PupilTong self-assigned this Mar 30, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 30, 2026

🦋 Changeset detected

Latest commit: bf1c891

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 30, 2026

📝 Walkthrough

Walkthrough

This PR introduces event bubble support by adding an is_bubble parameter to the WASM event handler, enabling proper handling of non-bubbling events. It also fixes queryComponent to preserve the original export chunk when processEvalResult is unavailable or returns null/undefined. Changes span WASM type definitions, Rust implementation, TypeScript bindings, and comprehensive test coverage.

Changes

Cohort / File(s) Summary
Release Notes
.changeset/add-event-bubble-support.md, .changeset/fix-query-component-processevalresult.md
Added two changeset entries documenting patch releases: one for event bubble support in common_event_handler, another for queryComponent fallback fix.
WASM Type Definitions
packages/web-platform/web-core/binary/client/client.d.ts, packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts, packages/web-platform/web-core/binary/client_legacy/client.d.ts, packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts
Updated TypeScript declarations for common_event_handler and mainthreadwasmcontext_common_event_handler to accept an additional is_bubble: boolean (or number in WASM bindings) parameter, expanding function signatures from 6 to 7 arguments.
Rust Event Handler Implementation
packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs
Updated common_event_handler to accept is_bubble: bool parameter; now conditionally dispatches bubbling events only when is_bubble is true, otherwise dispatches single-target non-capture event.
TypeScript Event Handler Bridge
packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts, packages/web-platform/web-core/ts/client/mainthread/LynxViewInstance.ts
Event handler now forwards event.bubbles property to WASM handler; queryComponent uses nullish coalescing to preserve original export chunk when processEvalResult is absent or returns null/undefined.
Test Coverage
packages/web-platform/web-core-e2e/resources/mock-component.json, packages/web-platform/web-core-e2e/tests/web-core.test.ts, packages/web-platform/web-core/tests/element-apis.spec.ts
Added mock component resource, two E2E tests validating __QueryComponent behavior with/without processEvalResult, and spec test validating non-bubbling event propagation behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • feat: improve web-core-wasm #2148: Refactors web-core-wasm bindings and event API surface, directly related to this PR's is_bubble parameter addition to MainThreadWasmContext.common_event_handler.

Suggested labels

platform:Web

Suggested reviewers

  • Sherry-hue
  • colinaaa

Poem

🐰 Bubbles pop and events cascade,
With is_bubble we've got it made,
Non-bubbling events dance with grace,
While queryComponent finds its place! ✨

🚥 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
Title check ✅ Passed The PR title addresses two main issues: handling missing processEvalResult in lazy component loading and adding bubble event support. Both aspects are reflected in the changeset.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

Codecov Report

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

Files with missing lines Patch % Lines
.../src/main_thread/client/element_apis/event_apis.rs 0.00% 6 Missing ⚠️
.../web-core/ts/client/mainthread/LynxViewInstance.ts 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/web-platform/web-core-e2e/tests/web-core.test.ts (2)

186-188: Minor: Redundant unhandledrejection listener pattern.

The unhandledrejection listener is added inside every page.evaluate call but only captures rejections that occur before the callback resolves. If __QueryComponent always invokes the callback (even on error), this listener may never trigger. Consider whether this pattern is necessary or if it could be simplified.

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

In `@packages/web-platform/web-core-e2e/tests/web-core.test.ts` around lines 186 -
188, The unhandledrejection listener added via
globalThis.addEventListener('unhandledrejection', ...) inside each page.evaluate
is redundant because __QueryComponent appears to always invoke the callback
(even on error), so the listener will rarely fire and is added repeatedly;
remove the per-evaluation listener and instead rely on the callback path from
__QueryComponent to report errors (or add a single global unhandledrejection
handler once outside page.evaluate if you need to capture asynchronous
rejections not reported by the callback), ensuring you reference and use the
existing callback resolution logic for error propagation.

175-241: Good test coverage, but consider adding a test for intentional null/undefined returns.

The two tests cover:

  1. Absent processEvalResult → fallback to original export
  2. Present processEvalResult returning a value → use that value

However, given the concern raised about the ?? operator in LynxViewInstance.ts, consider adding a third test case where processEvalResult intentionally returns null or undefined to verify the expected behavior:

📝 Suggested additional test case
test('__QueryComponent with processEvalResult returning null', async ({ page, browserName }) => {
  test.skip(browserName === 'firefox');
  await goto(page);

  await page.evaluate(() => {
    (globalThis as any).runtime.processEvalResult = () => null;
  });

  const evalResult = await page.evaluate(async () => {
    return new Promise((resolve) => {
      globalThis.addEventListener('unhandledrejection', (e) => {
        resolve({ error: e.reason?.message ?? String(e.reason) });
      });
      globalThis.runtime.__QueryComponent(
        '/resources/mock-component.json',
        (res: any) => {
          resolve(res);
        },
      );
    });
  });

  expect(evalResult).toMatchObject({ code: 0 });
  // This assertion depends on intended behavior:
  // If null is a valid intentional return, expect null
  // If null should fallback, expect { mockResult: 'MOCKED_EVAL_RESULT' }
  expect((evalResult as any).data.evalResult).toBeNull();
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web-platform/web-core-e2e/tests/web-core.test.ts` around lines 175 -
241, Add a third E2E test in
packages/web-platform/web-core-e2e/tests/web-core.test.ts named
"__QueryComponent with processEvalResult returning null" that mirrors the
existing two tests: skip for firefox, call goto(page), set (globalThis as
any).runtime.processEvalResult = () => null before invoking
globalThis.runtime.__QueryComponent('/resources/mock-component.json', ...),
await the resolved evalResult, and assert code === 0; then assert (evalResult as
any).data.evalResult is either null or the original export depending on the
intended behavior in LynxViewInstance.ts (choose and document which behavior you
expect). Ensure the test also covers undefined by adding a similar case or
changing the stub to return undefined to validate both scenarios.
.changeset/fix-query-component-processevalresult.md (1)

1-5: Changeset description may be misleading.

The description says "when processEvalResult is absent" but the implementation uses ?? which also triggers when processEvalResult returns null or undefined. If the regression concern in LynxViewInstance.ts is addressed, this description would be accurate.

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

In @.changeset/fix-query-component-processevalresult.md around lines 1 - 5, The
changeset description is misleading because the code uses the nullish coalescing
operator (processEvalResult ?? fallback) which also triggers when
processEvalResult returns null or undefined, not only when the symbol is absent;
update the changeset text to say "when processEvalResult is absent or returns
null/undefined during queryComponent execution" and/or change the implementation
in the queryComponent code to use an explicit undefined check (e.g., check
processEvalResult === undefined) so only a truly missing value (not null) falls
back—refer to processEvalResult, queryComponent, and LynxViewInstance.ts when
making the change.
🤖 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/LynxViewInstance.ts`:
- Around line 249-252: The current assignment uses the nullish coalescing
operator and can overwrite intentional null/undefined returns from
mainThreadGlobalThis.processEvalResult; change the logic in LynxViewInstance
where lepusRootChunkExport is set so it only invokes processEvalResult if
mainThreadGlobalThis.processEvalResult exists and then assigns its return value
directly to lepusRootChunkExport (do not use ?? fallback), i.e., check for
presence of mainThreadGlobalThis.processEvalResult before calling it and let its
result (including null or undefined) be the assigned value.

---

Nitpick comments:
In @.changeset/fix-query-component-processevalresult.md:
- Around line 1-5: The changeset description is misleading because the code uses
the nullish coalescing operator (processEvalResult ?? fallback) which also
triggers when processEvalResult returns null or undefined, not only when the
symbol is absent; update the changeset text to say "when processEvalResult is
absent or returns null/undefined during queryComponent execution" and/or change
the implementation in the queryComponent code to use an explicit undefined check
(e.g., check processEvalResult === undefined) so only a truly missing value (not
null) falls back—refer to processEvalResult, queryComponent, and
LynxViewInstance.ts when making the change.

In `@packages/web-platform/web-core-e2e/tests/web-core.test.ts`:
- Around line 186-188: The unhandledrejection listener added via
globalThis.addEventListener('unhandledrejection', ...) inside each page.evaluate
is redundant because __QueryComponent appears to always invoke the callback
(even on error), so the listener will rarely fire and is added repeatedly;
remove the per-evaluation listener and instead rely on the callback path from
__QueryComponent to report errors (or add a single global unhandledrejection
handler once outside page.evaluate if you need to capture asynchronous
rejections not reported by the callback), ensuring you reference and use the
existing callback resolution logic for error propagation.
- Around line 175-241: Add a third E2E test in
packages/web-platform/web-core-e2e/tests/web-core.test.ts named
"__QueryComponent with processEvalResult returning null" that mirrors the
existing two tests: skip for firefox, call goto(page), set (globalThis as
any).runtime.processEvalResult = () => null before invoking
globalThis.runtime.__QueryComponent('/resources/mock-component.json', ...),
await the resolved evalResult, and assert code === 0; then assert (evalResult as
any).data.evalResult is either null or the original export depending on the
intended behavior in LynxViewInstance.ts (choose and document which behavior you
expect). Ensure the test also covers undefined by adding a similar case or
changing the stub to return undefined to validate both scenarios.
🪄 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: 7f49eea9-7bd7-4660-a041-230380a0c687

📥 Commits

Reviewing files that changed from the base of the PR and between 78493b4 and bf1c891.

📒 Files selected for processing (12)
  • .changeset/add-event-bubble-support.md
  • .changeset/fix-query-component-processevalresult.md
  • packages/web-platform/web-core-e2e/resources/mock-component.json
  • packages/web-platform/web-core-e2e/tests/web-core.test.ts
  • packages/web-platform/web-core/binary/client/client.d.ts
  • packages/web-platform/web-core/binary/client/client_bg.wasm.d.ts
  • packages/web-platform/web-core/binary/client_legacy/client.d.ts
  • packages/web-platform/web-core/binary/client_legacy/client_bg.wasm.d.ts
  • packages/web-platform/web-core/src/main_thread/client/element_apis/event_apis.rs
  • packages/web-platform/web-core/tests/element-apis.spec.ts
  • packages/web-platform/web-core/ts/client/mainthread/LynxViewInstance.ts
  • packages/web-platform/web-core/ts/client/mainthread/elementAPIs/WASMJSBinding.ts

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 30, 2026

Merging this PR will improve performance by 26.99%

⚡ 1 improved benchmark
✅ 71 untouched benchmarks
⏩ 21 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
002-hello-reactLynx-destroyBackground 861.5 µs 678.4 µs +26.99%

Comparing PupilTong:p/hw/fix-lazy-component-without-eval-result-function (bf1c891) with main (78493b4)

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.

@relativeci
Copy link
Copy Markdown

relativeci bot commented Mar 30, 2026

React Example

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

bf1c891(current) vs 78493b4 main#6942(baseline)

Bundle metrics  no changes
                 Current
#6951
     Baseline
#6942
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 180 180
No change  Duplicate Modules 71 71
No change  Duplicate Code 46.4% 46.4%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#6951
     Baseline
#6942
No change  IMG 145.76KiB 145.76KiB
No change  Other 92.13KiB 92.13KiB

Bundle analysis reportBranch PupilTong:p/hw/fix-lazy-componen...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci bot commented Mar 30, 2026

React MTF Example

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

bf1c891(current) vs 78493b4 main#76(baseline)

Bundle metrics  no changes
                 Current
#85
     Baseline
#76
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 174 174
No change  Duplicate Modules 68 68
No change  Duplicate Code 46.09% 46.09%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#85
     Baseline
#76
No change  IMG 111.23KiB 111.23KiB
No change  Other 96.24KiB 96.24KiB

Bundle analysis reportBranch PupilTong:p/hw/fix-lazy-componen...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci bot commented Mar 30, 2026

Web Explorer

#8529 Bundle Size — 728.84KiB (+0.03%).

bf1c891(current) vs 78493b4 main#8520(baseline)

Bundle metrics  Change 4 changes Regression 1 regression
                 Current
#8529
     Baseline
#8520
Regression  Initial JS 43.31KiB(~+0.01%) 43.3KiB
No change  Initial CSS 2.16KiB 2.16KiB
Change  Cache Invalidation 48.73% 0%
No change  Chunks 8 8
No change  Assets 10 10
Change  Modules 150(+1.35%) 148
No change  Duplicate Modules 11 11
Change  Duplicate Code 34.68%(-0.06%) 34.7%
No change  Packages 3 3
No change  Duplicate Packages 0 0
Bundle size by type  Change 2 changes Regression 2 regressions
                 Current
#8529
     Baseline
#8520
Regression  Other 384.62KiB (+0.06%) 384.4KiB
Regression  JS 342.07KiB (~+0.01%) 342.04KiB
No change  CSS 2.16KiB 2.16KiB

Bundle analysis reportBranch PupilTong:p/hw/fix-lazy-componen...Project dashboard


Generated by RelativeCIDocumentationReport issue

@PupilTong PupilTong merged commit 75960cd into lynx-family:main Mar 30, 2026
48 of 50 checks passed
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