From 25745a1e1cc0f2ca987012f6b1954ef5e80481f6 Mon Sep 17 00:00:00 2001 From: hzy <28915578+hzy@users.noreply.github.com> Date: Thu, 31 Jul 2025 17:58:40 +0800 Subject: [PATCH] chore: upgrade preact New hook `_diff2` and `renderComponent` in options To compare: https://github.com/preactjs/preact/compare/10.24.0...hzy:preact:lynx/v10.24.x --- packages/react/package.json | 2 +- .../react/runtime/src/lynx/performance.ts | 27 ++++++-- .../react/runtime/src/lynx/runWithForce.ts | 65 +++++-------------- .../runtime/src/renderToOpcodes/constants.ts | 2 + packages/react/runtime/src/utils.ts | 12 ++++ .../react/runtime/types/internal-preact.d.ts | 2 + pnpm-lock.yaml | 10 +-- 7 files changed, 59 insertions(+), 61 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index 934f48b368..91b2f2833d 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -174,7 +174,7 @@ "api-extractor": "api-extractor run --verbose" }, "dependencies": { - "preact": "npm:@hongzhiyuan/preact@10.24.0-319c684e" + "preact": "npm:@hongzhiyuan/preact@10.24.0-27dc9d8f" }, "devDependencies": { "@lynx-js/types": "3.3.0", diff --git a/packages/react/runtime/src/lynx/performance.ts b/packages/react/runtime/src/lynx/performance.ts index fc0405acf9..3d3afa6cfb 100644 --- a/packages/react/runtime/src/lynx/performance.ts +++ b/packages/react/runtime/src/lynx/performance.ts @@ -5,8 +5,8 @@ import { options } from 'preact'; import type { VNode } from 'preact'; import { __globalSnapshotPatch } from '../lifecycle/patch/snapshotPatch.js'; -import { DIFF } from '../renderToOpcodes/constants.js'; -import { isSdkVersionGt } from '../utils.js'; +import { RENDER_COMPONENT, ROOT } from '../renderToOpcodes/constants.js'; +import { hook, isSdkVersionGt } from '../utils.js'; const PerformanceTimingKeys = [ 'updateSetStateTrigger', @@ -116,8 +116,8 @@ function markTiming(timestampKey: typeof PerformanceTimingKeys[number], force?: } function initTimingAPI(): void { - const oldDiff = options[DIFF]; - options[DIFF] = (vnode: VNode) => { + // eslint-disable-next-line unicorn/consistent-function-scoping + const helper = () => { // check `__globalSnapshotPatch` to make sure this only runs after hydrate if (__JS__ && __globalSnapshotPatch) { if (!globalPipelineOptions) { @@ -128,8 +128,25 @@ function initTimingAPI(): void { markTimingLegacy('updateDiffVdomStart'); } } - oldDiff?.(vnode); }; + + hook(options, RENDER_COMPONENT, (old, vnode: VNode, c) => { + helper(); + /* v8 ignore start */ + if (old) { + old(vnode, c); + } + /* v8 ignore stop */ + }); + + hook(options, ROOT, (old, vnode: VNode, parentDom) => { + helper(); + /* v8 ignore start */ + if (old) { + old(vnode, parentDom); + } + /* v8 ignore stop */ + }); } /** diff --git a/packages/react/runtime/src/lynx/runWithForce.ts b/packages/react/runtime/src/lynx/runWithForce.ts index ec83287969..f26016ec53 100644 --- a/packages/react/runtime/src/lynx/runWithForce.ts +++ b/packages/react/runtime/src/lynx/runWithForce.ts @@ -2,66 +2,31 @@ // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. import { options } from 'preact'; -import type { Component, VNode } from 'preact'; +import type { VNode } from 'preact'; -import { COMPONENT, DIFF, DIFFED, FORCE } from '../renderToOpcodes/constants.js'; - -const sForcedVNode = Symbol('FORCE'); - -type PatchedVNode = VNode & { [sForcedVNode]?: true }; +import { COMPONENT, DIFF2, FORCE } from '../renderToOpcodes/constants.js'; export function runWithForce(cb: () => void): void { - // save vnode and its `_component` in WeakMap - const m = new WeakMap(); - - const oldDiff = options[DIFF]; - - options[DIFF] = (vnode: PatchedVNode) => { + const oldDiff = options[DIFF2]; + options[DIFF2] = (vnode: VNode, oldVNode: VNode) => { + /* v8 ignore start */ if (oldDiff) { - oldDiff(vnode); - } - - // when `options[DIFF]` is called, a newVnode is passed in - // so its `vnode[COMPONENT]` should be null, - // but it will be set later - Object.defineProperty(vnode, COMPONENT, { - configurable: true, - set(c: Component) { - m.set(vnode, c); - if (c) { - c[FORCE] = true; - } - }, - get(): Component | undefined { - return m.get(vnode); - }, - }); - vnode[sForcedVNode] = true; - }; - - const oldDiffed = options[DIFFED]; - - options[DIFFED] = (vnode: PatchedVNode) => { - if (oldDiffed) { - oldDiffed(vnode); + oldDiff(vnode, oldVNode); } - - // There would be cases when `options[DIFF]` has been reset while options[DIFFED] is not, - // so we need to check if `vnode` is patched by `options[DIFF]`. - // We only want to change the patched vnode - if (vnode[sForcedVNode]) { - // delete is a reverse operation of previous `Object.defineProperty` - delete vnode[COMPONENT]; - delete vnode[sForcedVNode]; - // restore - vnode[COMPONENT] = m.get(vnode)!; + /* v8 ignore stop */ + + const c = oldVNode[COMPONENT]; + if (c) { + c[FORCE] = true; + } else { + // mount phase of a new Component + // `isNew` is true, no need to set FORCE } }; try { cb(); } finally { - options[DIFF] = oldDiff as (vnode: VNode) => void; - options[DIFFED] = oldDiffed as (vnode: VNode) => void; + options[DIFF2] = oldDiff as (vnode: VNode, oldVNode: VNode) => void; } } diff --git a/packages/react/runtime/src/renderToOpcodes/constants.ts b/packages/react/runtime/src/renderToOpcodes/constants.ts index 0748d1330a..a06e824914 100644 --- a/packages/react/runtime/src/renderToOpcodes/constants.ts +++ b/packages/react/runtime/src/renderToOpcodes/constants.ts @@ -2,12 +2,14 @@ // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. export const DIFF = '__b'; +export const DIFF2 = '_diff2'; export const RENDER = '__r'; export const DIFFED = 'diffed'; export const COMMIT = '__c'; export const SKIP_EFFECTS = '__s'; export const CATCH_ERROR = '__e'; export const ROOT = '__'; +export const RENDER_COMPONENT = 'renderComponent'; // VNode properties export const COMPONENT = '__c'; diff --git a/packages/react/runtime/src/utils.ts b/packages/react/runtime/src/utils.ts index bf0fbd6c27..24fd8e6975 100644 --- a/packages/react/runtime/src/utils.ts +++ b/packages/react/runtime/src/utils.ts @@ -67,3 +67,15 @@ export function maybePromise(value: unknown): value is Promise { export function getDisplayName(type: ComponentClass): string { return type.displayName ?? type.name; } + +export function hook( + object: T, + key: K, + fn: Required[K] extends (...args: infer P) => infer Q ? ((old?: T[K], ...args: P) => Q) + : never, +): void { + const oldFn = object[key]; + object[key] = function(this: T, ...args: unknown[]) { + return fn.call(this, oldFn, ...args); + } as T[K]; +} diff --git a/packages/react/runtime/types/internal-preact.d.ts b/packages/react/runtime/types/internal-preact.d.ts index 36549e66f0..44296125b6 100644 --- a/packages/react/runtime/types/internal-preact.d.ts +++ b/packages/react/runtime/types/internal-preact.d.ts @@ -18,6 +18,8 @@ declare module 'preact' { oldVNode?: VNode, errorInfo?: ErrorInfo, ): void; + /** root */ + __?(vnode: VNode, parentDom: any): void; } interface VNode { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33c336379f..7f2792babd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -199,8 +199,8 @@ importers: packages/react: dependencies: preact: - specifier: npm:@hongzhiyuan/preact@10.24.0-319c684e - version: '@hongzhiyuan/preact@10.24.0-319c684e' + specifier: npm:@hongzhiyuan/preact@10.24.0-27dc9d8f + version: '@hongzhiyuan/preact@10.24.0-27dc9d8f' devDependencies: '@lynx-js/types': specifier: 3.3.0 @@ -2037,8 +2037,8 @@ packages: resolution: {integrity: sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@hongzhiyuan/preact@10.24.0-319c684e': - resolution: {integrity: sha512-weWzMUnmXk7gynEpOo/iIyfq95pRoFO2+18eiwD0hk/TeIQUeHbyG4W/S3lCEjB54jvft/itXwhkF+vz623BEg==} + '@hongzhiyuan/preact@10.24.0-27dc9d8f': + resolution: {integrity: sha512-NpUD1p4NIh+vpN5+YMvtF8CqtO7tS7VwTKxpdoI58Fp3SOmtv0Xr9Bzg+vWitn1K/jBscsonqDX4qZ4qvVd2PA==} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -9078,7 +9078,7 @@ snapshots: '@eslint/core': 0.14.0 levn: 0.4.1 - '@hongzhiyuan/preact@10.24.0-319c684e': {} + '@hongzhiyuan/preact@10.24.0-27dc9d8f': {} '@humanfs/core@0.19.1': {}