Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
27 changes: 22 additions & 5 deletions packages/react/runtime/src/lynx/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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) {
Expand All @@ -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 */
});
}

/**
Expand Down
65 changes: 15 additions & 50 deletions packages/react/runtime/src/lynx/runWithForce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<VNode, Component>();

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;
}
}
2 changes: 2 additions & 0 deletions packages/react/runtime/src/renderToOpcodes/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
12 changes: 12 additions & 0 deletions packages/react/runtime/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,15 @@ export function maybePromise<T>(value: unknown): value is Promise<T> {
export function getDisplayName(type: ComponentClass): string {
return type.displayName ?? type.name;
}

export function hook<T, K extends keyof T>(
object: T,
key: K,
fn: Required<T>[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];
}
2 changes: 2 additions & 0 deletions packages/react/runtime/types/internal-preact.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ declare module 'preact' {
oldVNode?: VNode<any>,
errorInfo?: ErrorInfo,
): void;
/** root */
__?(vnode: VNode, parentDom: any): void;
}

interface VNode {
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading