Skip to content

Conversation

@hzy
Copy link
Collaborator

@hzy hzy commented Jul 23, 2025

Summary by CodeRabbit

  • New Features

    • Added support for advanced profiling in production builds, including new metrics for component diffing, rendering, and state updates.
    • Enhanced profiling labels for improved traceability, with suggestions for better readability in minified builds.
    • Introduced profiling instrumentation around patch application and commit phases with flow ID tracking.
    • Enabled runtime-controlled profiling initialization for background execution.
    • Added a new lifecycle hook to the rendering process for improved profiling granularity.
  • Bug Fixes

    • Improved synchronization and accuracy of profiling start and end events to ensure reliable performance data.
  • Refactor

    • Streamlined profiling logic and lifecycle hook management for better maintainability and encapsulation.
    • Unified commit hook replacement and improved global options state management.
    • Modernized flow ID management and replaced legacy console profiling with Lynx 3.0+ API.
  • Tests

    • Updated and expanded test coverage to validate new profiling features and ensure accurate flow ID tracking in patch operations.
    • Added lifecycle hooks in tests to verify balanced profiling calls and updated snapshots with flow ID data.

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

Copilot AI review requested due to automatic review settings July 23, 2025 08:52
@changeset-bot
Copy link

changeset-bot bot commented Jul 23, 2025

🦋 Changeset detected

Latest commit: 45f2597

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

This PR includes changesets to release 1 package
Name Type
@lynx-js/react 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 Jul 23, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

This change introduces advanced profiling support to the @lynx-js/react runtime using the Lynx 3.0+ performance API. It adds new profiling hooks, flow ID tracking, and instrumentation for diff, render, setState, and commit phases. Test utilities and snapshots are updated to reflect the new profiling metadata and lifecycle hook changes.

Changes

Cohort / File(s) Change Summary
Profiling Infrastructure & Hooks
packages/react/runtime/src/debug/profile.ts, packages/react/runtime/src/lynx.ts, packages/react/runtime/src/renderToOpcodes/index.ts
Replaces legacy console profiling with Lynx 3.0+ API, adds DIFF2 hook, flow ID management, and detailed profiling for diff, render, setState, and commit phases. Profiling initialization is now thread/context-aware.
Lifecycle Commit Refactor
packages/react/runtime/src/lifecycle/patch/commit.ts, packages/react/runtime/src/lifecycle/patch/updateMainThread.ts
Refactors commit hook replacement using a hook utility, introduces global patch/flush options helpers, and adds profiling instrumentation for patch application using flow IDs.
Test Utilities and Mocks
packages/react/runtime/__test__/utils/globals.js, packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createPerformanceApis.ts
Adds new mocked performance methods, lifecycle hooks for test isolation, and ensures balanced profiling start/end calls in tests. Adds stub implementations for profiling APIs in background thread runtime.
Profiling Tests
packages/react/runtime/__test__/debug/profile.test.jsx, packages/react/runtime/__test__/debug/hook.js
Updates tests to assert against Lynx performance API, adjusts call counts, and incorporates DIFF2 hook in test setup.
Test Snapshots for Patch Options
packages/react/runtime/__test__/lifecycle/reload.test.jsx, packages/react/runtime/__test__/lifecycle/updateData.test.jsx, packages/react/runtime/__test__/lynx/timing.test.jsx
Updates test snapshots to include new flowIds property in patch options, reflecting the new profiling metadata.
Type Declarations Update
packages/web-platform/web-constants/src/types/NativeApp.ts
Extends NativeApp interface with new profiling methods: profileMark, profileFlowId, and isProfileRecording.
Changeset Documentation
.changeset/forty-aliens-play.md
Documents the minor update, profiling support, and new metrics for the @lynx-js/react package.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Suggested reviewers

  • Yradex
  • colinaaa

Poem

🐇 Hopping through code with nimble feet,
Profiling metrics now complete.
Diff and render, setState too,
Flow IDs track what components do.
Tests refreshed and snapshots bright,
Lynx performance shines in light!
✨📊🐰

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR enables profiling capabilities in production builds by adding dynamic profiling support that can be enabled at runtime, moving away from build-time-only profiling. The key changes refactor the profiling system to use runtime API calls instead of compile-time flags and console methods.

  • Adds dynamic profiling support through lynx.performance API methods
  • Refactors profiling hooks to use a new utility function for cleaner code
  • Updates tests to use the new profiling API instead of console methods

Reviewed Changes

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

Show a summary per file
File Description
packages/react/runtime/src/utils.ts Adds new hook utility function for monkey-patching objects
packages/react/runtime/src/lynx.ts Updates profiling condition to check runtime state in addition to build flag
packages/react/runtime/src/debug/profile.ts Refactors profiling implementation to use lynx.performance API and hook utility
packages/react/runtime/test/utils/globals.js Adds mock profiling methods and test validation for balanced profile calls
packages/react/runtime/test/debug/profile.test.jsx Updates test expectations to use new profiling API
.changeset/forty-aliens-play.md Documents the feature addition

@codecov
Copy link

codecov bot commented Jul 23, 2025

Codecov Report

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

Files with missing lines Patch % Lines
packages/react/runtime/src/lynx.ts 25.00% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq
Copy link

codspeed-hq bot commented Jul 23, 2025

CodSpeed Performance Report

Merging #1336 will not alter performance

Comparing hzy:p/hzy/profile_in_production_build (45f2597) with main (ea325d6)

Summary

✅ 10 untouched benchmarks

@relativeci
Copy link

relativeci bot commented Jul 23, 2025

React Example

#3946 Bundle Size — 236.85KiB (+0.67%).

45f2597(current) vs ea325d6 main#3934(baseline)

Bundle metrics  Change 3 changes
                 Current
#3946
     Baseline
#3934
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 38.04% 0%
No change  Chunks 0 0
No change  Assets 4 4
Change  Modules 158(-0.63%) 159
No change  Duplicate Modules 64 64
Change  Duplicate Code 45.85%(+0.09%) 45.81%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#3946
     Baseline
#3934
No change  IMG 145.76KiB 145.76KiB
Regression  Other 91.09KiB (+1.77%) 89.5KiB

Bundle analysis reportBranch hzy:p/hzy/profile_in_production_...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link

relativeci bot commented Jul 23, 2025

Web Explorer

#3942 Bundle Size — 344.07KiB (+0.08%).

45f2597(current) vs ea325d6 main#3930(baseline)

Bundle metrics  Change 2 changes
                 Current
#3942
     Baseline
#3930
No change  Initial JS 143.27KiB 143.27KiB
No change  Initial CSS 31.84KiB 31.84KiB
Change  Cache Invalidation 17.58% 41.63%
No change  Chunks 7 7
No change  Assets 7 7
Change  Modules 211(-0.47%) 212
No change  Duplicate Modules 17 17
No change  Duplicate Code 3.96% 3.96%
No change  Packages 4 4
No change  Duplicate Packages 0 0
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#3942
     Baseline
#3930
Regression  JS 229.27KiB (+0.12%) 229.01KiB
No change  Other 82.95KiB 82.95KiB
No change  CSS 31.84KiB 31.84KiB

Bundle analysis reportBranch hzy:p/hzy/profile_in_production_...Project dashboard


Generated by RelativeCIDocumentationReport issue

@hzy hzy force-pushed the p/hzy/profile_in_production_build branch from 868c44f to b219b4b Compare July 23, 2025 13: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: 1

♻️ Duplicate comments (2)
packages/react/runtime/src/debug/profile.ts (1)

10-21: Check for profileEnd availability before using it

The code checks for profileStart but uses profileEnd without verification. This could cause runtime errors if profileEnd is undefined.

Apply this fix to ensure both methods are available:

 export function initProfileHook(): void {
   // `profileStart`, `profileEnd`, `profileMark` and `profileFlowId` are only available in Lynx 3.0+
   // if (!isSdkVersionGt(3, 0)) {
-  if (!lynx.performance || typeof lynx.performance.profileStart !== 'function') {
+  if (!lynx.performance || typeof lynx.performance.profileStart !== 'function' || typeof lynx.performance.profileEnd !== 'function') {
     return;
   }
packages/react/runtime/src/utils.ts (1)

71-81: Use proper type parameter for arguments to maintain type safety

The function signature uses unknown[] for args but the type definition expects specific parameter types.

Consider using P type parameter:

-  object[key] = function(this: T, ...args: unknown[]) {
+  object[key] = function(this: T, ...args: P) {
     return fn.call(this, oldFn, ...args);
   } as T[K];
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 868c44f and b219b4b.

📒 Files selected for processing (6)
  • .changeset/forty-aliens-play.md (1 hunks)
  • packages/react/runtime/__test__/debug/profile.test.jsx (1 hunks)
  • packages/react/runtime/__test__/utils/globals.js (3 hunks)
  • packages/react/runtime/src/debug/profile.ts (1 hunks)
  • packages/react/runtime/src/lynx.ts (1 hunks)
  • packages/react/runtime/src/utils.ts (1 hunks)
🧠 Learnings (3)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
packages/react/runtime/src/debug/profile.ts (3)

Learnt from: colinaaa
PR: #1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

Learnt from: PupilTong
PR: #1292
File: packages/web-platform/web-core-server/src/createLynxView.ts:144-151
Timestamp: 2025-07-15T10:00:56.154Z
Learning: In the lynx-stack codebase, PupilTong prefers the "let it crash" approach over defensive null safety checks when the condition should never occur in normal operation. This applies to cases like the element.getAttribute(lynxUniqueIdAttribute)! call in SSR event capture where the attribute is expected to always be present.

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-core-server/src/createLynxView.ts:0-0
Timestamp: 2025-07-16T06:26:22.230Z
Learning: In the lynx-stack SSR implementation, each createLynxView instance is used to render once and then discarded. There's no reuse of the same instance for multiple renders, so event arrays and other state don't need to be cleared between renders.

packages/react/runtime/src/utils.ts (1)

Learnt from: colinaaa
PR: #1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/react/runtime/src/lynx.ts
  • .changeset/forty-aliens-play.md
  • packages/react/runtime/test/debug/profile.test.jsx
  • packages/react/runtime/test/utils/globals.js
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
packages/react/runtime/src/debug/profile.ts (3)

Learnt from: colinaaa
PR: #1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

Learnt from: PupilTong
PR: #1292
File: packages/web-platform/web-core-server/src/createLynxView.ts:144-151
Timestamp: 2025-07-15T10:00:56.154Z
Learning: In the lynx-stack codebase, PupilTong prefers the "let it crash" approach over defensive null safety checks when the condition should never occur in normal operation. This applies to cases like the element.getAttribute(lynxUniqueIdAttribute)! call in SSR event capture where the attribute is expected to always be present.

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-core-server/src/createLynxView.ts:0-0
Timestamp: 2025-07-16T06:26:22.230Z
Learning: In the lynx-stack SSR implementation, each createLynxView instance is used to render once and then discarded. There's no reuse of the same instance for multiple renders, so event arrays and other state don't need to be cleared between renders.

packages/react/runtime/src/utils.ts (1)

Learnt from: colinaaa
PR: #1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

@hzy hzy force-pushed the p/hzy/profile_in_production_build branch from b219b4b to f3d5d0a Compare July 24, 2025 03:58
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/react/runtime/src/debug/profile.ts (1)

13-15: Add missing method availability checks

The availability check only verifies profileStart and profileEnd, but the code later uses profileMark (line 49) and profileFlowId (line 50) without verification, which could cause runtime errors.

Add these methods to the availability check:

-  if (!lynx.performance || typeof lynx.performance.profileStart !== 'function') {
+  if (!lynx.performance || 
+      typeof lynx.performance.profileStart !== 'function' || 
+      typeof lynx.performance.profileEnd !== 'function' ||
+      typeof lynx.performance.profileMark !== 'function' ||
+      typeof lynx.performance.profileFlowId !== 'function') {
     return;
   }
🧹 Nitpick comments (1)
packages/react/runtime/src/debug/profile.ts (1)

79-79: Fix typo in constant name

There's a typo in the constant name.

-  const EMPYT_OBJ = {};
+  const EMPTY_OBJ = {};

And update the usage:

-  currentState ??= EMPYT_OBJ;
-  nextState ??= EMPYT_OBJ;
+  currentState ??= EMPTY_OBJ;
+  nextState ??= EMPTY_OBJ;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b219b4b and f3d5d0a.

📒 Files selected for processing (6)
  • .changeset/forty-aliens-play.md (1 hunks)
  • packages/react/runtime/__test__/debug/profile.test.jsx (1 hunks)
  • packages/react/runtime/__test__/utils/globals.js (3 hunks)
  • packages/react/runtime/src/debug/profile.ts (1 hunks)
  • packages/react/runtime/src/lynx.ts (1 hunks)
  • packages/react/runtime/src/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/react/runtime/src/lynx.ts
  • packages/react/runtime/test/debug/profile.test.jsx
  • .changeset/forty-aliens-play.md
  • packages/react/runtime/test/utils/globals.js
  • packages/react/runtime/src/utils.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
packages/react/runtime/src/debug/profile.ts (3)

Learnt from: colinaaa
PR: #1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

Learnt from: PupilTong
PR: #1292
File: packages/web-platform/web-core-server/src/createLynxView.ts:144-151
Timestamp: 2025-07-15T10:00:56.154Z
Learning: In the lynx-stack codebase, PupilTong prefers the "let it crash" approach over defensive null safety checks when the condition should never occur in normal operation. This applies to cases like the element.getAttribute(lynxUniqueIdAttribute)! call in SSR event capture where the attribute is expected to always be present.

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-core-server/src/createLynxView.ts:0-0
Timestamp: 2025-07-16T06:26:22.230Z
Learning: In the lynx-stack SSR implementation, each createLynxView instance is used to render once and then discarded. There's no reuse of the same instance for multiple renders, so event arrays and other state don't need to be cleared between renders.

🔇 Additional comments (5)
packages/react/runtime/src/debug/profile.ts (5)

4-8: LGTM: Clean imports

The imports are well-organized and all utilities are properly used throughout the file.


22-40: LGTM: Well-structured diff profiling hooks

The implementation correctly:

  • Filters for function components only
  • Handles flow ID lifecycle with proper cleanup
  • Maintains balanced profileStart/profileEnd calls
  • Preserves existing hook chains

42-55: LGTM: Sophisticated setState profiling

The implementation intelligently:

  • Only profiles when the component is dirty (actual state change)
  • Manages flow IDs efficiently with the WeakMap
  • Generates detailed profiling metadata about state changes
  • Properly chains the original setState call

The conditional profiling based on DIRTY flag is a good optimization.


58-73: LGTM: Clever render method profiling

The temporary method replacement pattern is well-implemented:

  • Ensures balanced profiling calls with try/finally
  • Properly restores the original render method
  • Maintains the correct component context

75-94: LGTM: Comprehensive state change metadata

The helper function provides valuable profiling information:

  • Current and next state keys for debugging
  • Shallow diff to identify what actually changed
  • Proper null/undefined handling
  • JSON serialization for readability

The logic correctly assumes nextState is a superset of currentState for the diff calculation.

@hzy hzy force-pushed the p/hzy/profile_in_production_build branch from f3d5d0a to 140a049 Compare July 24, 2025 04:04
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/react/runtime/src/debug/profile.ts (1)

84-84: Fix typo in constant name.

The constant name has a typo: EMPYT_OBJ should be EMPTY_OBJ.

-  const EMPYT_OBJ = {};
+  const EMPTY_OBJ = {};

Also update the usage on lines 86-87:

-  currentState ??= EMPYT_OBJ;
-  nextState ??= EMPYT_OBJ;
+  currentState ??= EMPTY_OBJ;
+  nextState ??= EMPTY_OBJ;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3d5d0a and 140a049.

📒 Files selected for processing (6)
  • .changeset/forty-aliens-play.md (1 hunks)
  • packages/react/runtime/__test__/debug/profile.test.jsx (1 hunks)
  • packages/react/runtime/__test__/utils/globals.js (3 hunks)
  • packages/react/runtime/src/debug/profile.ts (1 hunks)
  • packages/react/runtime/src/lynx.ts (1 hunks)
  • packages/react/runtime/src/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/react/runtime/src/lynx.ts
  • packages/react/runtime/test/debug/profile.test.jsx
  • packages/react/runtime/test/utils/globals.js
  • .changeset/forty-aliens-play.md
  • packages/react/runtime/src/utils.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
packages/react/runtime/src/debug/profile.ts (3)

Learnt from: colinaaa
PR: #1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

Learnt from: PupilTong
PR: #1292
File: packages/web-platform/web-core-server/src/createLynxView.ts:144-151
Timestamp: 2025-07-15T10:00:56.154Z
Learning: In the lynx-stack codebase, PupilTong prefers the "let it crash" approach over defensive null safety checks when the condition should never occur in normal operation. This applies to cases like the element.getAttribute(lynxUniqueIdAttribute)! call in SSR event capture where the attribute is expected to always be present.

Learnt from: PupilTong
PR: #1029
File: packages/web-platform/web-core-server/src/createLynxView.ts:0-0
Timestamp: 2025-07-16T06:26:22.230Z
Learning: In the lynx-stack SSR implementation, each createLynxView instance is used to render once and then discarded. There's no reuse of the same instance for multiple renders, so event arrays and other state don't need to be cleared between renders.

🔇 Additional comments (7)
packages/react/runtime/src/debug/profile.ts (7)

4-8: LGTM! Import statements properly support the refactored profiling functionality.

The imports correctly include all necessary utilities and constants for the new Lynx profiling API integration.


11-20: Good defensive programming with comprehensive API availability checks.

The early exit logic now properly verifies all required profiling methods (profileStart, profileEnd, profileMark, profileFlowId) are available before proceeding. This addresses the previous review feedback about missing checks.


22-25: Well-designed flow ID management setup.

Using WeakMap for component-to-flow-ID association is appropriate as it enables automatic cleanup when components are garbage collected. Method binding ensures correct execution context.


27-45: Well-implemented DIFF/DIFFED profiling hooks.

The logic correctly:

  • Profiles only function components
  • Uses mapGetAndDelete for efficient flow ID management
  • Properly starts/ends profiling traces with meaningful labels
  • Maintains backward compatibility by calling old hooks

47-60: Sophisticated setState profiling implementation with efficient dirty checking.

The hook correctly:

  • Only profiles when this[DIRTY] is true for performance efficiency
  • Uses nullishCoalescingMapSet for optimal flow ID management
  • Provides detailed state change information via the helper function
  • Maintains proper method call order

63-78: Robust RENDER hook with proper error handling and cleanup.

The implementation uses a sound pattern:

  • Temporarily wraps the render method with profiling
  • Uses try/finally to guarantee cleanup and profiling end
  • Restores original render method even if exceptions occur
  • Provides meaningful profiling labels with component display names

86-98: Well-designed state change profiling helper with comprehensive information.

The function provides valuable profiling data:

  • Safe handling of undefined states with nullish coalescing
  • Comprehensive state change information (current, next, changed keys)
  • Efficient shallow comparison for change detection
  • Clear comments explaining the setState behavior assumptions

@hzy hzy force-pushed the p/hzy/profile_in_production_build branch from 140a049 to b37d007 Compare July 24, 2025 04:08
@hzy hzy force-pushed the p/hzy/profile_in_production_build branch 2 times, most recently from 9332ae0 to 8b9dc6d Compare July 24, 2025 15:31
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

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b37d007 and 8b9dc6d.

📒 Files selected for processing (6)
  • .changeset/forty-aliens-play.md (1 hunks)
  • packages/react/runtime/__test__/debug/profile.test.jsx (1 hunks)
  • packages/react/runtime/__test__/utils/globals.js (3 hunks)
  • packages/react/runtime/src/debug/profile.ts (1 hunks)
  • packages/react/runtime/src/lynx.ts (1 hunks)
  • packages/react/runtime/src/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/react/runtime/test/debug/profile.test.jsx
  • .changeset/forty-aliens-play.md
  • packages/react/runtime/test/utils/globals.js
  • packages/react/runtime/src/lynx.ts
  • packages/react/runtime/src/utils.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
packages/react/runtime/src/debug/profile.ts (2)

Learnt from: colinaaa
PR: #1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

Learnt from: PupilTong
PR: #1292
File: packages/web-platform/web-core-server/src/createLynxView.ts:144-151
Timestamp: 2025-07-15T10:00:56.154Z
Learning: In the lynx-stack codebase, PupilTong prefers the "let it crash" approach over defensive null safety checks when the condition should never occur in normal operation. This applies to cases like the element.getAttribute(lynxUniqueIdAttribute)! call in SSR event capture where the attribute is expected to always be present.

🪛 GitHub Check: test-typos
packages/react/runtime/src/debug/profile.ts

[warning] 111-111:
"EMPYT" should be "EMPTY".


[warning] 110-110:
"EMPYT" should be "EMPTY".


[warning] 108-108:
"EMPYT" should be "EMPTY".

⏰ 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). (4)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: code-style-check
  • GitHub Check: CodeQL Analyze (javascript-typescript)
  • GitHub Check: CodeQL Analyze (actions)
🔇 Additional comments (7)
packages/react/runtime/src/debug/profile.ts (7)

4-9: LGTM! Import statements are well-organized.

The imports correctly support the refactored profiling implementation using the new utility functions and constants.


12-21: Excellent! Comprehensive availability checks address previous concerns.

The early exit pattern with checks for all required profiling methods (profileStart, profileEnd, profileMark, profileFlowId) properly addresses the runtime safety concerns raised in previous reviews.


23-28: Good use of WeakMaps and method binding.

Using WeakMaps for component-specific tracking prevents memory leaks, and binding the profiling methods ensures proper context. This is a solid architectural approach.


29-48: Well-structured DIFF hook implementation.

The refactored hook correctly uses the new hook utility, manages flow IDs for tracing, and includes proper conditional logic for background snapshot patching. The component type checking and profiling trace naming are appropriate.


50-66: Excellent DIFFED hook with no-op detection.

The implementation properly ends profiling traces, includes smart no-op detection for background processing, and maintains proper cleanup of the snapshot patch length map. The profiling marks will be helpful for debugging performance issues.


68-84: Solid setState hook with proper flow ID management.

The implementation correctly wraps setState with profiling, includes proper TypeScript typing, and uses the DIRTY flag optimization to avoid unnecessary profiling. The flow ID management and detailed state change tracking will be valuable for debugging.


87-102: Robust RENDER hook with proper cleanup.

The temporary method replacement approach with try/finally ensures accurate profiling of render logic while maintaining proper cleanup. The error handling and context preservation are well-implemented.

@hzy hzy force-pushed the p/hzy/profile_in_production_build branch 2 times, most recently from 5182334 to e4c6f13 Compare July 29, 2025 12:05
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

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5182334 and e4c6f13.

📒 Files selected for processing (4)
  • packages/react/runtime/src/debug/profile.ts (1 hunks)
  • packages/react/runtime/src/lifecycle/patch/commit.ts (2 hunks)
  • packages/react/runtime/src/lifecycle/patch/updateMainThread.ts (2 hunks)
  • packages/react/runtime/src/lynx.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/react/runtime/src/lynx.ts
  • packages/react/runtime/src/debug/profile.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
packages/react/runtime/src/lifecycle/patch/commit.ts (1)

Learnt from: colinaaa
PR: #1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

🔇 Additional comments (5)
packages/react/runtime/src/lifecycle/patch/updateMainThread.ts (1)

27-34: LGTM! Conditional profiling implementation looks good.

The profiling logic correctly extracts flowIds from patch options and conditionally starts profiling with appropriate metadata. The @ts-expect-error comment acknowledges the type limitation for flowIds property.

packages/react/runtime/src/lifecycle/patch/commit.ts (4)

29-29: Good encapsulation with atomic state management.

The takeGlobalFlushOptions function provides atomic access to global flush options with proper cleanup, improving state management compared to direct access patterns.

Also applies to: 36-40


72-84: Well-designed type refinement and state management.

The GlobalPatchOptions type appropriately omits the reloadVersion field that's managed internally, and takeGlobalPatchOptions follows the same atomic pattern as the flush options helper.


90-166: Excellent refactoring using the hook utility pattern.

The commit hook replacement is well-structured using the hook utility, maintaining all existing functionality while improving encapsulation. The logic flow is preserved: skipping main thread commits, collecting patches, managing background instance cleanup, and coordinating with the native layer.


172-172: Type signature improvement aligns with new type system.

Using GlobalPatchOptions instead of the inline Omit type improves readability and maintainability.

@hzy hzy force-pushed the p/hzy/profile_in_production_build branch 6 times, most recently from 058b4f0 to 22c2457 Compare August 1, 2025 10:05
@hzy hzy enabled auto-merge (squash) August 7, 2025 14:00
@hzy hzy force-pushed the p/hzy/profile_in_production_build branch from 6409e7c to 0895f4d Compare August 7, 2025 14:00
colinaaa
colinaaa previously approved these changes Aug 8, 2025
@hzy hzy force-pushed the p/hzy/profile_in_production_build branch from 7c5b84f to 99d7ad0 Compare August 8, 2025 06:51
@hzy hzy force-pushed the p/hzy/profile_in_production_build branch from 99d7ad0 to 2591d46 Compare August 8, 2025 07:50
@hzy hzy requested a review from PupilTong as a code owner August 8, 2025 07:50
PupilTong
PupilTong previously approved these changes Aug 8, 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: 1

🔭 Outside diff range comments (1)
packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createPerformanceApis.ts (1)

8-16: Return type missing newly added properties; will trigger excess property errors

You added profileMark, profileFlowId, and isProfileRecording to the returned object, but the Pick<NativeApp, ...> return type doesn’t include them. With object-literal excess property checks, this will fail type-checking. Include the new keys in the Pick.

Apply this diff:

 export function createPerformanceApis(timingSystem: TimingSystem): Pick<
   NativeApp,
   | 'generatePipelineOptions'
   | 'onPipelineStart'
   | 'markPipelineTiming'
   | 'bindPipelineIdWithTimingFlag'
   | 'profileStart'
   | 'profileEnd'
+  | 'profileMark'
+  | 'profileFlowId'
+  | 'isProfileRecording'
 > {
🧹 Nitpick comments (1)
packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createPerformanceApis.ts (1)

51-57: Use warn-level logging or add a tracking link (optional)

Console errors in production can be noisy for NYI stubs. Consider console.warn and add a TODO with a concrete issue link in lynx-core for traceability.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99d7ad0 and 2591d46.

📒 Files selected for processing (14)
  • .changeset/forty-aliens-play.md (1 hunks)
  • packages/react/runtime/__test__/debug/hook.js (1 hunks)
  • packages/react/runtime/__test__/debug/profile.test.jsx (2 hunks)
  • packages/react/runtime/__test__/lifecycle/reload.test.jsx (7 hunks)
  • packages/react/runtime/__test__/lifecycle/updateData.test.jsx (8 hunks)
  • packages/react/runtime/__test__/lynx/timing.test.jsx (6 hunks)
  • packages/react/runtime/__test__/utils/globals.js (3 hunks)
  • packages/react/runtime/src/debug/profile.ts (1 hunks)
  • packages/react/runtime/src/lifecycle/patch/commit.ts (2 hunks)
  • packages/react/runtime/src/lifecycle/patch/updateMainThread.ts (2 hunks)
  • packages/react/runtime/src/lynx.ts (2 hunks)
  • packages/react/runtime/src/renderToOpcodes/index.ts (4 hunks)
  • packages/web-platform/web-constants/src/types/NativeApp.ts (1 hunks)
  • packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createPerformanceApis.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/react/runtime/test/debug/hook.js
  • packages/web-platform/web-constants/src/types/NativeApp.ts
🚧 Files skipped from review as they are similar to previous changes (11)
  • packages/react/runtime/test/debug/profile.test.jsx
  • packages/react/runtime/test/lifecycle/updateData.test.jsx
  • packages/react/runtime/test/lifecycle/reload.test.jsx
  • packages/react/runtime/src/lynx.ts
  • packages/react/runtime/src/lifecycle/patch/updateMainThread.ts
  • packages/react/runtime/test/lynx/timing.test.jsx
  • .changeset/forty-aliens-play.md
  • packages/react/runtime/test/utils/globals.js
  • packages/react/runtime/src/debug/profile.ts
  • packages/react/runtime/src/renderToOpcodes/index.ts
  • packages/react/runtime/src/lifecycle/patch/commit.ts
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.139Z
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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1454
File: pnpm-workspace.yaml:46-46
Timestamp: 2025-08-07T04:00:59.627Z
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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.139Z
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.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-core-server/src/createLynxView.ts:0-0
Timestamp: 2025-07-16T06:26:22.230Z
Learning: In the lynx-stack SSR implementation, each createLynxView instance is used to render once and then discarded. There's no reuse of the same instance for multiple renders, so event arrays and other state don't need to be cleared between renders.

hzy and others added 4 commits August 8, 2025 16:21
Co-authored-by: Qingyu Wang <[email protected]>
Signed-off-by: Zhiyuan Hong <[email protected]>
Co-authored-by: Qingyu Wang <[email protected]>
Signed-off-by: Zhiyuan Hong <[email protected]>
Co-authored-by: Qingyu Wang <[email protected]>
Signed-off-by: Zhiyuan Hong <[email protected]>
@hzy hzy force-pushed the p/hzy/profile_in_production_build branch from 2591d46 to 45f2597 Compare August 8, 2025 08: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: 1

🧹 Nitpick comments (1)
packages/react/runtime/src/debug/profile.ts (1)

42-61: Avoid double–stringifying state-key arrays

buildSetStateProfileMarkArgs converts arrays to JSON strings.
If the downstream consumer of profileMark later serialises its arguments again
(the common case for bridge or log forwarding) you end up with escaped JSON
inside JSON.

Prefer passing the raw arrays (or a comma-joined string) and let the
transport layer stringify once.

-  return {
-    'current state keys': JSON.stringify(Object.keys(currentState)),
-    'next state keys': JSON.stringify(Object.keys(nextState)),
-    'changed (shallow diff) state keys': JSON.stringify(
-      Object.keys(nextState).filter(key => currentState[key] !== nextState[key]),
-    ),
-  };
+  const currentKeys = Object.keys(currentState);
+  const nextKeys    = Object.keys(nextState);
+  return {
+    currentKeys,
+    nextKeys,
+    changedKeys: nextKeys.filter(k => currentState[k] !== nextState[k]),
+  };
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2591d46 and 45f2597.

📒 Files selected for processing (14)
  • .changeset/forty-aliens-play.md (1 hunks)
  • packages/react/runtime/__test__/debug/hook.js (1 hunks)
  • packages/react/runtime/__test__/debug/profile.test.jsx (2 hunks)
  • packages/react/runtime/__test__/lifecycle/reload.test.jsx (7 hunks)
  • packages/react/runtime/__test__/lifecycle/updateData.test.jsx (8 hunks)
  • packages/react/runtime/__test__/lynx/timing.test.jsx (6 hunks)
  • packages/react/runtime/__test__/utils/globals.js (3 hunks)
  • packages/react/runtime/src/debug/profile.ts (1 hunks)
  • packages/react/runtime/src/lifecycle/patch/commit.ts (2 hunks)
  • packages/react/runtime/src/lifecycle/patch/updateMainThread.ts (2 hunks)
  • packages/react/runtime/src/lynx.ts (2 hunks)
  • packages/react/runtime/src/renderToOpcodes/index.ts (4 hunks)
  • packages/web-platform/web-constants/src/types/NativeApp.ts (1 hunks)
  • packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createPerformanceApis.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (13)
  • packages/react/runtime/test/debug/hook.js
  • packages/react/runtime/src/lynx.ts
  • packages/react/runtime/test/lifecycle/reload.test.jsx
  • .changeset/forty-aliens-play.md
  • packages/web-platform/web-constants/src/types/NativeApp.ts
  • packages/react/runtime/src/lifecycle/patch/updateMainThread.ts
  • packages/react/runtime/test/debug/profile.test.jsx
  • packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createPerformanceApis.ts
  • packages/react/runtime/test/lifecycle/updateData.test.jsx
  • packages/react/runtime/src/renderToOpcodes/index.ts
  • packages/react/runtime/src/lifecycle/patch/commit.ts
  • packages/react/runtime/test/utils/globals.js
  • packages/react/runtime/test/lynx/timing.test.jsx
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.139Z
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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1454
File: pnpm-workspace.yaml:46-46
Timestamp: 2025-08-07T04:00:59.627Z
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.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.139Z
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.
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1029
File: packages/web-platform/web-core-server/src/createLynxView.ts:0-0
Timestamp: 2025-07-16T06:26:22.230Z
Learning: In the lynx-stack SSR implementation, each createLynxView instance is used to render once and then discarded. There's no reuse of the same instance for multiple renders, so event arrays and other state don't need to be cleared between renders.
📚 Learning: 2025-07-18T04:27:18.291Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.

Applied to files:

  • packages/react/runtime/src/debug/profile.ts
📚 Learning: 2025-07-15T10:00:56.154Z
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1292
File: packages/web-platform/web-core-server/src/createLynxView.ts:144-151
Timestamp: 2025-07-15T10:00:56.154Z
Learning: In the lynx-stack codebase, PupilTong prefers the "let it crash" approach over defensive null safety checks when the condition should never occur in normal operation. This applies to cases like the `element.getAttribute(lynxUniqueIdAttribute)!` call in SSR event capture where the attribute is expected to always be present.

Applied to files:

  • packages/react/runtime/src/debug/profile.ts
⏰ 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). (4)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: CodeQL Analyze (javascript-typescript)
  • GitHub Check: CodeQL Analyze (actions)
🔇 Additional comments (2)
packages/react/runtime/src/debug/profile.ts (2)

14-27: Guard against multiple initialisations

initProfileHook() can be imported from multiple bundles; without
idempotence it will stack multiple hook layers around the same methods.

Add a static guard:

 export function initProfileHook(): void {
+  if ((initProfileHook as any)._didInit) return;
+  (initProfileHook as any)._didInit = true;

85-96: TraceOption type-safety check

profileOptions is declared TraceOption = {} and later assigned
flowId / flowIds. Ensure these fields exist on TraceOption; otherwise
this file will only compile due to --suppressImplicitAnyIndexErrors.

If they are not part of the public type, extend locally:

type ExtendedTraceOption = TraceOption & { flowId?: number; flowIds?: number[] };
const profileOptions: ExtendedTraceOption = {};

@hzy hzy merged commit 23ccb2e into lynx-family:main Aug 8, 2025
94 of 100 checks passed
upupming pushed a commit to upupming/lynx-stack that referenced this pull request Aug 8, 2025
<!--
  Thank you for submitting a pull request!

We appreciate the time and effort you have invested in making these
changes. Please ensure that you provide enough information to allow
others to review your pull request.

Upon submission, your pull request will be automatically assigned with
reviewers.

If you want to learn more about contributing to this project, please
visit:
https://github.com/lynx-family/lynx-stack/blob/main/CONTRIBUTING.md.
-->

<!-- The AI summary below will be auto-generated - feel free to replace
it with your own. -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added support for advanced profiling in production builds, including
new metrics for component diffing, rendering, and state updates.
* Enhanced profiling labels for improved traceability, with suggestions
for better readability in minified builds.
* Introduced profiling instrumentation around patch application and
commit phases with flow ID tracking.

* **Bug Fixes**
* Improved synchronization and accuracy of profiling start and end
events to ensure reliable performance data.

* **Refactor**
* Streamlined profiling logic and lifecycle hook management for better
maintainability and encapsulation.
* Unified commit hook replacement and improved global options state
management.

* **Tests**
* Updated and expanded test coverage to validate new profiling features
and ensure accurate flow ID tracking in patch operations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

## Checklist

<!--- Check and mark with an "x" -->

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

---------

Signed-off-by: Zhiyuan Hong <[email protected]>
Co-authored-by: Qingyu Wang <[email protected]>
colinaaa pushed a commit that referenced this pull request Aug 9, 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/[email protected]

### Patch Changes

- Supports `recyclable` attribute in `<list-item>` to control whether
the list item is recyclable. The `recyclable` attribute depends on Lynx
Engine 3.4 or later.
([#1388](#1388))

    ```jsx
    <list-item recyclable={false} />
    ```

- feat: Support using a host element as direct child of Suspense
([#1455](#1455))

- Add profile in production build:
([#1336](#1336))

    1.  `diff:__COMPONENT_NAME__`: how long ReactLynx diff took.
    2.  `render:__COMPONENT_NAME__`: how long your render function took.
3. `setState`: an instant trace event, indicate when your setState was
called.

NOTE: `__COMPONENT_NAME__` may be unreadable when minified, setting
`displayName` may help.

- Add `onBackgroundSnapshotInstanceUpdateId` event on dev for Preact
Devtools to keep the correct snapshotInstanceId info.
([#1173](#1173))

- fix: Prevent error when spreading component props onto an element
([#1459](#1459))

- fix: Correctly check for the existence of background functions in MTS
([#1416](#1416))

    ```ts
    function handleTap() {
      "main thread";
      // The following check always returned false before this fix
      if (myHandleTap) {
        runOnBackground(myHandleTap)();
      }
    }
    ```

## @lynx-js/[email protected]

### Patch Changes

- Remove the experimental `provider` option.
([#1432](#1432))

- Add `output.filename.wasm` and `output.filename.assets` options.
([#1449](#1449))

- fix deno compatibility
([#1412](#1412))

- Should call the `api.onCloseBuild` hook after the build finished.
([#1446](#1446))

- Bump Rsbuild v1.4.15.
([#1423](#1423))

- Support using function in `output.filename.*`.
([#1449](#1449))

## [email protected]

### Patch Changes

- Support ESLint for ReactLynx templates
([#1274](#1274))

## @lynx-js/[email protected]

### Patch Changes

- Updated dependencies
\[[`c8ce6aa`](c8ce6aa)]:
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- Fix the `Package subpath './compat' is not defined by "exports"`
error. ([#1460](#1460))

## @lynx-js/[email protected]

### Patch Changes

- Fix `GlobalEventEmitter` type definition, the `emit(eventName: string,
data: unknown)` function should recevie an array typed `data` and pass
as param list of listeners.
([#1479](#1479))

## @lynx-js/[email protected]

### Patch Changes

- fix: load main-thread chunk in ESM format
([#1437](#1437))

See [nodejs/node#59362](nodejs/node#59362) for
more details.

- feat: support path() for `createQuerySelector`
([#1456](#1456))

- Added `getPathInfo` API to `NativeApp` and its cross-thread handler
for retrieving the path from a DOM node to the root.
- Implemented endpoint and handler registration in both background and
UI threads.
    -   Implemented `nativeApp.getPathInfo()`

-   Updated dependencies \[]:
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- fix: load main-thread chunk in ESM format
([#1437](#1437))

See [nodejs/node#59362](nodejs/node#59362) for
more details.

- feat: support path() for `createQuerySelector`
([#1456](#1456))

- Added `getPathInfo` API to `NativeApp` and its cross-thread handler
for retrieving the path from a DOM node to the root.
- Implemented endpoint and handler registration in both background and
UI threads.
    -   Implemented `nativeApp.getPathInfo()`

- fix: when `onNativeModulesCall` is delayed in mounting, the
NativeModules execution result may be undefined.
([#1457](#1457))

- fix: `onNativeModulesCall` && `onNapiModulesCall` use getter to get.
([#1466](#1466))

- Updated dependencies
\[[`29434ae`](29434ae),
[`fb7096b`](fb7096b)]:
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- fix: load main-thread chunk in ESM format
([#1437](#1437))

See [nodejs/node#59362](nodejs/node#59362) for
more details.

## @lynx-js/[email protected]

### Patch Changes

- feat: add autocomplete attribute support for x-input component
([#1444](#1444))

Implements autocomplete attribute forwarding from the x-input custom
element to the internal HTML input element in the shadow DOM. This
enables standard browser autocomplete functionality for x-input
elements.

- Add referrerpolicy attribute support to x-image web component
([#1420](#1420))

-   Updated dependencies \[]:
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- fix: load main-thread chunk in ESM format
([#1437](#1437))

See [nodejs/node#59362](nodejs/node#59362) for
more details.

- Updated dependencies
\[[`29434ae`](29434ae),
[`fb7096b`](fb7096b)]:
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- feat: support path() for `createQuerySelector`
([#1456](#1456))

- Added `getPathInfo` API to `NativeApp` and its cross-thread handler
for retrieving the path from a DOM node to the root.
- Implemented endpoint and handler registration in both background and
UI threads.
    -   Implemented `nativeApp.getPathInfo()`

- Updated dependencies
\[[`29434ae`](29434ae),
[`fb7096b`](fb7096b)]:
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]

## [email protected]



## @lynx-js/[email protected]



## @lynx-js/[email protected]



## @lynx-js/[email protected]

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.

4 participants