feat(react): add richer profiling traces for hooks and hydrate#2235
feat(react): add richer profiling traces for hooks and hydrate#2235Yradex merged 20 commits intolynx-family:mainfrom
Conversation
🦋 Changeset detectedLatest commit: b96b59a The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a streamlined profiling core, installs background/profile hooks, captures vnode source locations, instruments hydration and background-snapshot patch paths with richer trace args, updates imports to the new profile API, and adds comprehensive tests for profiling and vnode-source behaviors. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Web Explorer#7820 Bundle Size — 383.74KiB (0%).b96b59a(current) vs 09929fb main#7815(baseline) Bundle metrics
Bundle size by type
|
| Current #7820 |
Baseline #7815 |
|
|---|---|---|
252.83KiB |
252.83KiB |
|
95.85KiB |
95.85KiB |
|
35.06KiB |
35.06KiB |
Bundle analysis report Branch Yradex:wt/render-trace-20260211 Project dashboard
Generated by RelativeCI Documentation Report issue
5ea9eca to
b108dd8
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
packages/react/runtime/src/backgroundSnapshot.ts (1)
453-631: Consider a helper to reduce profiling-branch duplication.Each
__globalSnapshotPatch!.push(...)call is duplicated in both theif (shouldProfile) { profileStart; try { push } finally { profileEnd } } else { push }branches — this pattern appears ~5 times. The duplication makes future changes to the push arguments error-prone.A small inline helper would eliminate the repetition without measurable overhead:
♻️ Suggested helper (illustrative)
function tracedPush( name: string, args: Record<string, string>, ...pushArgs: Parameters<typeof __globalSnapshotPatch.push> ): void { if (shouldProfile) { profileStart(name, { args }); } __globalSnapshotPatch!.push(...pushArgs); if (shouldProfile) { profileEnd(); } }Note: this drops the try/finally around
push. If you need exception safety forprofileEnd, keep the try/finally inside the helper.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/src/backgroundSnapshot.ts` around lines 453 - 631, Multiple places duplicate the profiling branch around __globalSnapshotPatch!.push; add a small helper (e.g., tracedPush) that accepts the profiling name, profiling args, and the push arguments, moves the profileStart/profileEnd logic (with try/finally around the push to preserve exception-safety) into the helper, and call tracedPush instead of duplicating the if (shouldProfile) { profileStart; try { push } finally { profileEnd } } else { push } pattern. Replace each occurrence in this file (references: the SetAttribute blocks, the RemoveChild/InsertBefore blocks inside diffArrayAction, and any other push sites inside helper/reconstructInstanceTree callbacks) with tracedPush(...) so the push call and its arguments (SnapshotOperation.*, ids, keys, values, target ids) are passed through unchanged while consolidating profiling logic.packages/react/runtime/src/lynx/tt.ts (1)
207-234:snapshotIdcomputed unconditionally; ALOG block still re-derives it inline.
snapshotId(line 207) is extracted before the__PROFILE__guard, so it runs on every event even when profiling is disabled. The__ALOG__block at line 232 then redundantly re-computesNumber(handlerName.split(':')[0])instead of reusing it.♻️ Suggested refactor
- const snapshotId = Number(handlerName.split(':')[0]); const eventHandler = backgroundSnapshotInstanceManager.getValueBySign( handlerName, ) as ((data: unknown) => void) | undefined; if (__PROFILE__) { + const snapshotId = Number(handlerName.split(':')[0]); profileStart(`ReactLynx::publishEvent`, { args: { handlerName, type: data.type, - snapshotInstanceType: backgroundSnapshotInstanceManager.values.get( - snapshotId, - )?.type ?? '', + snapshotInstanceType: backgroundSnapshotInstanceManager.values.get(snapshotId)?.type ?? '', source: getSnapshotVNodeSource(snapshotId) ?? '', jsFunctionName: eventHandler?.name ?? '', }, }); } if (typeof __ALOG__ !== 'undefined' && __ALOG__) { + const snapshotId = Number(handlerName.split(':')[0]); console.alog?.( `[ReactLynxDebug] BTS received event:\n` + JSON.stringify( { handlerName, type: data.type, - snapshotInstanceType: backgroundSnapshotInstanceManager.values.get( - Number(handlerName.split(':')[0]), - )?.type ?? '', + snapshotInstanceType: backgroundSnapshotInstanceManager.values.get(snapshotId)?.type ?? '', jsFunctionName: eventHandler?.name ?? '', },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/src/lynx/tt.ts` around lines 207 - 234, snapshotId is computed unconditionally and then recomputed inside the __ALOG__ block; to fix, defer computing Number(handlerName.split(':')[0]) until needed and reuse the local snapshotId: move the snapshotId extraction behind the __PROFILE__ and __ALOG__ guards (or compute it lazily) and update the __ALOG__ block to reference snapshotId instead of recomputing; ensure eventHandler and backgroundSnapshotInstanceManager lookups still use the same snapshotId variable (references: snapshotId, eventHandler, __PROFILE__, __ALOG__, backgroundSnapshotInstanceManager).packages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx (1)
34-48: Fail fast on unknown snapshot operations.Silently breaking on unknown ops can mask new/invalid patch sequences. Throwing will make test failures more explicit.
🛠️ Suggested change
- if (!params) { - break; - } + if (!params) { + throw new Error(`Unknown snapshot op: ${op}`); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx` around lines 34 - 48, The decodePatch function currently stops processing silently when it encounters an unknown operation because it checks SnapshotOperationParams[op]?.params and breaks when falsy; modify decodePatch (the while loop logic) to throw a descriptive error when params are missing for an op (include the op value and current index) instead of breaking, so unknown/invalid SnapshotOperationParams entries fail tests loudly..changeset/free-dragons-mate.md (1)
8-12: Vary bullet verbs to reduce repetition.The list reads smoother if the bullets don’t all start with “Add.” Consider mixing verbs for readability.
✏️ Optional wording tweak
- - Add trace events for `useEffect` / `useLayoutEffect` hook entry, callback, and cleanup phases. - - Add trace event for `useState` setter calls. - - Add `profileFlowId` support in debug profile utilities and attach flow IDs to related hook traces. - - Add hydrate/background snapshot profiling around patch operations with richer args (e.g. snapshot id/type, dynamic part index, value type, and source when available). - - Capture vnode source mapping in dev and use it in profiling args to improve trace attribution. - - Add/expand debug test coverage for profile utilities, hook profiling behavior, vnode source mapping, and hydrate profiling branches. + - Add trace events for `useEffect` / `useLayoutEffect` hook entry, callback, and cleanup phases. + - Introduce a trace event for `useState` setter calls. + - Wire `profileFlowId` support in debug profile utilities and attach flow IDs to related hook traces. + - Instrument hydrate/background snapshot profiling around patch operations with richer args (e.g. snapshot id/type, dynamic part index, value type, and source when available). + - Capture vnode source mapping in dev and use it in profiling args to improve trace attribution. + - Expand debug test coverage for profile utilities, hook profiling behavior, vnode source mapping, and hydrate profiling branches.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.changeset/free-dragons-mate.md around lines 8 - 12, The bulleted changelog lines all begin with "Add", making the list repetitive; please rewrite the bullets to vary verbs while keeping the same meaning—e.g., use "Record" for hook trace events (useEffect/useLayoutEffect), "Log" or "Attach" for useState setter traces and profileFlowId behavior, "Support" for profileFlowId in debug profile utilities, "Wrap" or "Instrument" for hydrate/background snapshot profiling, and "Capture" for vnode source mapping—ensure each bullet still references the original concepts (useEffect/useLayoutEffect, useState setter, profileFlowId, hydrate/background snapshot profiling, vnode source mapping) so intent remains clear.
🤖 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/react/runtime/src/debug/profileHooks.ts`:
- Around line 108-113: Update the inline comment that follows the profileEnd()
call to reference the correct hook: replace the incorrect "for options[DIFF]"
comment with "for options[DIFF2]" so it matches the trace opened in the DIFF2
hook (see profileEnd() usage in the hook(options, DIFFED, (old, vnode) => { ...
}) block and the corresponding profile start in the DIFF2 hook).
- Around line 159-172: The DIFFED hook callback can leave the Symbol property
sPatchLength on vnode if __globalSnapshotPatch was truthy at DIFF but became
falsy by DIFFED; move the cleanup so delete vnode[sPatchLength] always executes
regardless of the __globalSnapshotPatch check while preserving the existing
profileMark call (which should remain inside the typeof vnode.type ===
'function' && __globalSnapshotPatch guard) — update the hook(DIFFED, (old,
vnode: PatchedVNode) => { ... }) callback so the conditional only wraps the
profileMark/getDisplayName logic and the delete vnode[sPatchLength] runs
unconditionally before invoking old?.(vnode).
In `@packages/react/runtime/src/debug/vnodeSource.ts`:
- Around line 28-34: The formatSource logic currently returns only fileName when
lineNumber is missing even if source.columnNumber exists; update the branching
in formatSource to add an explicit branch that returns fileName:columnNumber (or
fileName::columnNumber or another clear format you choose) when typeof
source.columnNumber === 'number' and typeof source.lineNumber !== 'number',
referencing source.fileName, source.lineNumber and source.columnNumber so the
column-only case is not silently dropped; alternatively, add a comment
documenting intentional omission if you prefer not to emit column-only
information.
---
Nitpick comments:
In @.changeset/free-dragons-mate.md:
- Around line 8-12: The bulleted changelog lines all begin with "Add", making
the list repetitive; please rewrite the bullets to vary verbs while keeping the
same meaning—e.g., use "Record" for hook trace events
(useEffect/useLayoutEffect), "Log" or "Attach" for useState setter traces and
profileFlowId behavior, "Support" for profileFlowId in debug profile utilities,
"Wrap" or "Instrument" for hydrate/background snapshot profiling, and "Capture"
for vnode source mapping—ensure each bullet still references the original
concepts (useEffect/useLayoutEffect, useState setter, profileFlowId,
hydrate/background snapshot profiling, vnode source mapping) so intent remains
clear.
In `@packages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx`:
- Around line 34-48: The decodePatch function currently stops processing
silently when it encounters an unknown operation because it checks
SnapshotOperationParams[op]?.params and breaks when falsy; modify decodePatch
(the while loop logic) to throw a descriptive error when params are missing for
an op (include the op value and current index) instead of breaking, so
unknown/invalid SnapshotOperationParams entries fail tests loudly.
In `@packages/react/runtime/src/backgroundSnapshot.ts`:
- Around line 453-631: Multiple places duplicate the profiling branch around
__globalSnapshotPatch!.push; add a small helper (e.g., tracedPush) that accepts
the profiling name, profiling args, and the push arguments, moves the
profileStart/profileEnd logic (with try/finally around the push to preserve
exception-safety) into the helper, and call tracedPush instead of duplicating
the if (shouldProfile) { profileStart; try { push } finally { profileEnd } }
else { push } pattern. Replace each occurrence in this file (references: the
SetAttribute blocks, the RemoveChild/InsertBefore blocks inside diffArrayAction,
and any other push sites inside helper/reconstructInstanceTree callbacks) with
tracedPush(...) so the push call and its arguments (SnapshotOperation.*, ids,
keys, values, target ids) are passed through unchanged while consolidating
profiling logic.
In `@packages/react/runtime/src/lynx/tt.ts`:
- Around line 207-234: snapshotId is computed unconditionally and then
recomputed inside the __ALOG__ block; to fix, defer computing
Number(handlerName.split(':')[0]) until needed and reuse the local snapshotId:
move the snapshotId extraction behind the __PROFILE__ and __ALOG__ guards (or
compute it lazily) and update the __ALOG__ block to reference snapshotId instead
of recomputing; ensure eventHandler and backgroundSnapshotInstanceManager
lookups still use the same snapshotId variable (references: snapshotId,
eventHandler, __PROFILE__, __ALOG__, backgroundSnapshotInstanceManager).
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
.changeset/free-dragons-mate.mdpackages/react/etc/react.api.mdpackages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsxpackages/react/runtime/__test__/debug/hooks-invalid-args.test.jsxpackages/react/runtime/__test__/debug/profile-module.test.tspackages/react/runtime/__test__/debug/profile.test.jsxpackages/react/runtime/__test__/debug/react-hooks-profile.test.jsxpackages/react/runtime/__test__/debug/vnodeSource.test.tspackages/react/runtime/src/alog/elementPAPICall.tspackages/react/runtime/src/backgroundSnapshot.tspackages/react/runtime/src/debug/profile.tspackages/react/runtime/src/debug/profileHooks.tspackages/react/runtime/src/debug/utils.tspackages/react/runtime/src/debug/vnodeSource.tspackages/react/runtime/src/hooks/react.tspackages/react/runtime/src/hydrate.tspackages/react/runtime/src/lifecycle/destroy.tspackages/react/runtime/src/lifecycle/event/jsReady.tspackages/react/runtime/src/lifecycle/patch/commit.tspackages/react/runtime/src/lifecycle/reload.tspackages/react/runtime/src/lifecycle/render.tspackages/react/runtime/src/listUpdateInfo.tspackages/react/runtime/src/lynx-api.tspackages/react/runtime/src/lynx.tspackages/react/runtime/src/lynx/env.tspackages/react/runtime/src/lynx/tt.tspackages/react/runtime/src/snapshot.ts
💤 Files with no reviewable changes (1)
- packages/react/runtime/src/debug/utils.ts
🚧 Files skipped from review as they are similar to previous changes (14)
- packages/react/runtime/src/lifecycle/destroy.ts
- packages/react/runtime/src/lifecycle/patch/commit.ts
- packages/react/runtime/test/debug/profile-module.test.ts
- packages/react/runtime/test/debug/hooks-invalid-args.test.jsx
- packages/react/runtime/src/lynx-api.ts
- packages/react/etc/react.api.md
- packages/react/runtime/src/hydrate.ts
- packages/react/runtime/src/snapshot.ts
- packages/react/runtime/src/lifecycle/reload.ts
- packages/react/runtime/src/alog/elementPAPICall.ts
- packages/react/runtime/test/debug/profile.test.jsx
- packages/react/runtime/src/lynx.ts
- packages/react/runtime/test/debug/vnodeSource.test.ts
- packages/react/runtime/src/listUpdateInfo.ts
Merging this PR will degrade performance by 10.09%
Performance Changes
Comparing Footnotes
|
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
packages/react/runtime/src/debug/profileHooks.ts (1)
159-172: ThesPatchLengthcleanup concern from the prior review appears addressed.In the current code,
delete vnode[sPatchLength](line 169) executes for all function-type vnodes regardless of__globalSnapshotPatch's truthiness at DIFFED time, while theprofileMarkis correctly guarded. This matches the fix previously suggested.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/src/debug/profileHooks.ts` around lines 159 - 172, The cleanup currently deletes vnode[sPatchLength] for all function-type vnodes even when __globalSnapshotPatch is falsy; to fix, move the delete vnode[sPatchLength] inside the same conditional that calls profileMark (the if (__globalSnapshotPatch && vnode[sPatchLength] === __globalSnapshotPatch.length) block) in the hook callback so sPatchLength is removed only when the snapshot-patch condition is met (references: sPatchLength, __globalSnapshotPatch, profileMark, the hook(options, DIFFED, (old, vnode: PatchedVNode) => { ... }) callback).
🧹 Nitpick comments (2)
packages/react/runtime/src/debug/profileHooks.ts (2)
63-79:setStatehook callsoldfirst, then profiles — the trace reflects post-merge state, which is intentional but worth a brief doc note.Because
old?.call(this, state, callback)runs before theprofileMark,this[NEXT_STATE]already contains the merged state at profiling time. This is fine for capturing "changed keys," but a one-line comment clarifying the ordering would help future readers.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/src/debug/profileHooks.ts` around lines 63 - 79, The setState hook currently calls old?.call(this, state, callback) before invoking profileMark, so this[NEXT_STATE] reflects the post-merge state; add a one-line comment in the setState hook (near the old?.call(...) and profileMark(...) calls) explaining that the ordering is intentional to capture the merged/after-state for buildSetStateProfileMarkArgs and that DIRTY, sFlowID/profileFlowId are used to gate/identify the trace. Ensure the comment references setState, NEXT_STATE, profileMark, and buildSetStateProfileMarkArgs so future readers understand why we profile after calling the original setState.
42-61:EMPTY_OBJis re-allocated on everysetStateprofiling call.
EMPTY_OBJonly serves as a fallback for the nullish-coalescing assignments and is never mutated. Hoisting it outside the function avoids a needless allocation per call.♻️ Suggested diff
+ const EMPTY_OBJ = {}; + function buildSetStateProfileMarkArgs( currentState: Record<string, unknown>, nextState: Record<string, unknown>, ): Record<string, string> { - const EMPTY_OBJ = {}; - currentState ??= EMPTY_OBJ;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/src/debug/profileHooks.ts` around lines 42 - 61, The EMPTY_OBJ constant is being reallocated on every call to buildSetStateProfileMarkArgs; hoist a single immutable shared EMPTY_OBJ (e.g., const EMPTY_OBJ = {} typed as Record<string, unknown>) out of the function and remove the local declaration, then keep using currentState ??= EMPTY_OBJ and nextState ??= EMPTY_OBJ in buildSetStateProfileMarkArgs to avoid per-call allocations.
🤖 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/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx`:
- Around line 189-191: The test currently sets globalThis.__PROFILE__ = true
unconditionally in afterEach, which can leak state; modify the setup to capture
the original value in beforeEach (store it in a local variable, e.g.,
originalProfile) and then restore that value in afterEach by assigning
globalThis.__PROFILE__ = originalProfile; update the existing
beforeEach/afterEach around the tests in backgroundSnapshot-profile.test.jsx
(reference globalThis.__PROFILE__, beforeEach, afterEach) so the original value
is preserved and restored to avoid cross-test pollution.
In `@packages/react/runtime/src/backgroundSnapshot.ts`:
- Around line 395-510: The tracedPush call sites inside the helper (the
hydration loop in backgroundSnapshot.ts) eagerly construct trace arg objects
(calling getSnapshotVNodeSource and allocating {args: {...}}) even when
shouldProfile is false; change tracedPush usage so trace arguments are created
lazily — either update tracedPush to accept a zero-arg thunk for the traceOption
(e.g., () => ({ args: {...} })) and only invoke it when shouldProfile is true,
or wrap construction of getSnapshotVNodeSource(...) and the args object with if
(shouldProfile) before calling tracedPush; apply this pattern to all tracedPush
call sites in the helper (including the dynamicPartIndex branches and the
extraProps loop) so no trace-related work runs on the non-profile path.
---
Duplicate comments:
In `@packages/react/runtime/src/debug/profileHooks.ts`:
- Around line 159-172: The cleanup currently deletes vnode[sPatchLength] for all
function-type vnodes even when __globalSnapshotPatch is falsy; to fix, move the
delete vnode[sPatchLength] inside the same conditional that calls profileMark
(the if (__globalSnapshotPatch && vnode[sPatchLength] ===
__globalSnapshotPatch.length) block) in the hook callback so sPatchLength is
removed only when the snapshot-patch condition is met (references: sPatchLength,
__globalSnapshotPatch, profileMark, the hook(options, DIFFED, (old, vnode:
PatchedVNode) => { ... }) callback).
---
Nitpick comments:
In `@packages/react/runtime/src/debug/profileHooks.ts`:
- Around line 63-79: The setState hook currently calls old?.call(this, state,
callback) before invoking profileMark, so this[NEXT_STATE] reflects the
post-merge state; add a one-line comment in the setState hook (near the
old?.call(...) and profileMark(...) calls) explaining that the ordering is
intentional to capture the merged/after-state for buildSetStateProfileMarkArgs
and that DIRTY, sFlowID/profileFlowId are used to gate/identify the trace.
Ensure the comment references setState, NEXT_STATE, profileMark, and
buildSetStateProfileMarkArgs so future readers understand why we profile after
calling the original setState.
- Around line 42-61: The EMPTY_OBJ constant is being reallocated on every call
to buildSetStateProfileMarkArgs; hoist a single immutable shared EMPTY_OBJ
(e.g., const EMPTY_OBJ = {} typed as Record<string, unknown>) out of the
function and remove the local declaration, then keep using currentState ??=
EMPTY_OBJ and nextState ??= EMPTY_OBJ in buildSetStateProfileMarkArgs to avoid
per-call allocations.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
.changeset/free-dragons-mate.mdpackages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsxpackages/react/runtime/src/backgroundSnapshot.tspackages/react/runtime/src/debug/profileHooks.tspackages/react/runtime/src/lynx/tt.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- .changeset/free-dragons-mate.md
- packages/react/runtime/src/lynx/tt.ts
packages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx
Show resolved
Hide resolved
packages/react/runtime/__test__/debug/hooks-invalid-args.test.jsx
Outdated
Show resolved
Hide resolved
|
@upupming Good catch!
Just pushed the updates, let me know what you think! |
… hooks, capturing stack traces and flow IDs.
…capturing source info during diffing and including it in event and trace data.
…e source, and React hooks, enhancing profiling data with source and value type details for operations.
b625fca to
627f1c2
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8a6b4df991
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
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/devtool-mcp-server@0.5.0 ### Minor Changes - Use `@lynx-js/devtool-connector` instead of `@lynx-js/debug-router-connector`. ([#2284](#2284)) The new connector avoids using keep-alive connections, which makes the connection much more reliable. - **BREAKING CHANGE**: Remove the `./debug-router-connector` exports. ([#2284](#2284)) ## @lynx-js/web-elements@0.12.0 ### Minor Changes - feat: add `willchange` event to `x-viewpager-ng` ([#2305](#2305)) ### Patch Changes - fix: firefox `@supports(width:1rex)` ([#2288](#2288)) - fix: check computed overflow style in `getTheMostScrollableKid` to avoid treating `overflow: visible` elements as scroll containers ([#2309](#2309)) - fix: the inline-truncation should only work as a direct child of x-text ([#2287](#2287)) - fix: getVisibleCells cannot work in firefox due to contentvisibilityautostatechange not propagate list-item ([#2308](#2308)) - fix: foldview stuck issue ([#2304](#2304)) ## @lynx-js/gesture-runtime@2.1.3 ### Patch Changes - Optimize gesture callbacks and relationships to prevent unnecessary gesture registration and rerenders. ([#2277](#2277)) ## @lynx-js/react@0.116.5 ### Patch Changes - Improve React runtime hook profiling. ([#2235](#2235)) Enable Profiling recording first, then enter the target page so the trace includes full render/hydrate phases. - Record trace events for `useEffect` / `useLayoutEffect` hook entry, callback, and cleanup phases. - Log trace events for `useState` setter calls. - Wire `profileFlowId` support in debug profile utilities and attach flow IDs to related hook traces. - Instrument hydrate/background snapshot profiling around patch operations with richer args (e.g. snapshot id/type, dynamic part index, value type, and source when available). - Capture vnode source mapping in dev and use it in profiling args to improve trace attribution. - Expand debug test coverage for profile utilities, hook profiling behavior, vnode source mapping, and hydrate profiling branches. - refactor: call loadWorkletRuntime once in each module ([#2315](#2315)) ## @lynx-js/rspeedy@0.13.5 ### Patch Changes - feat: opt-in the web platform's new binary output format ([#2281](#2281)) Introduce a new flag to enable the new binary output format. Currently it's an internal-use-only flag that will be removed in the future; set the corresponding environment variable to 'true' to enable it. - Avoid generating `Rsbuild vundefined` in greeting message. ([#2275](#2275)) - Updated dependencies \[]: - @lynx-js/web-rsbuild-server-middleware@0.19.8 ## @lynx-js/lynx-bundle-rslib-config@0.2.2 ### Patch Changes - Support bundle and load css in external bundle ([#2143](#2143)) ## @lynx-js/external-bundle-rsbuild-plugin@0.0.3 ### Patch Changes - Updated dependencies \[[`c28b051`](c28b051), [`4cbf809`](4cbf809)]: - @lynx-js/externals-loading-webpack-plugin@0.0.4 ## @lynx-js/react-rsbuild-plugin@0.12.10 ### Patch Changes - Support bundle and load css in external bundle ([#2143](#2143)) - Updated dependencies \[[`59f2933`](59f2933), [`453e006`](453e006)]: - @lynx-js/template-webpack-plugin@0.10.5 - @lynx-js/css-extract-webpack-plugin@0.7.0 - @lynx-js/react-webpack-plugin@0.7.4 - @lynx-js/react-alias-rsbuild-plugin@0.12.10 - @lynx-js/use-sync-external-store@1.5.0 - @lynx-js/react-refresh-webpack-plugin@0.3.4 ## @lynx-js/web-core-wasm@0.0.5 ### Patch Changes - Updated dependencies \[[`4963907`](4963907), [`8fd936a`](8fd936a), [`0d41253`](0d41253), [`d32c4c6`](d32c4c6), [`7518b72`](7518b72), [`fca9d4a`](fca9d4a)]: - @lynx-js/web-elements@0.12.0 ## @lynx-js/externals-loading-webpack-plugin@0.0.4 ### Patch Changes - perf: optimize external bundle loading by merging multiple `fetchBundle` calls for the same URL into a single request. ([#2307](#2307)) - Support bundle and load css in external bundle ([#2143](#2143)) ## @lynx-js/template-webpack-plugin@0.10.5 ### Patch Changes - feat: allow `templateDebugUrl` to be customized via `output.publicPath` or the `beforeEncode` hook. ([#2274](#2274)) - feat: opt-in the web platform's new binary output format ([#2281](#2281)) Introduce a new flag to enable the new binary output format. Currently it's an internal-use-only flag that will be removed in the future; set the corresponding environment variable to 'true' to enable it. - Updated dependencies \[]: - @lynx-js/web-core-wasm@0.0.5 ## create-rspeedy@0.13.5 ## @lynx-js/react-alias-rsbuild-plugin@0.12.10 ## upgrade-rspeedy@0.13.5 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary by CodeRabbit
New Features
Tests
Documentation
Summary
This PR improves React runtime profiling observability and trace attribution while keeping low overhead when profiling is disabled.
What Changed
useEffect/useLayoutEffectentryuseStatesetterprofileFlowIdsupport in debug profile utilities and hooked flow IDs into hook traces..changeset/free-dragons-mate.md.Profiling Usage
Enable Profiling recording first, then enter the target page, so the trace includes full render/hydrate phases.
Testing
pnpm exec vitest run __test__/debug/*.test.*pnpm exec vitest run --coverage.enabled --coverage.include=src/hooks/react.ts --coverage.include=src/backgroundSnapshot.ts --coverage.reporter=textChecklist