From e31ed399dee17abc64fa97abe2635fc67bfad4cd Mon Sep 17 00:00:00 2001 From: * <8> Date: Wed, 3 Aug 2022 14:46:06 +0800 Subject: [PATCH] Match-id-0dfbd7fa96536fa2974eadfdad81039cf02f279a --- babel.config.js | 3 +- libs/horizon/src/external/JSXElement.ts | 15 +++++-- libs/horizon/src/external/devtools.ts | 42 +++++++++---------- libs/horizon/src/renderer/Types.ts | 20 +++++---- libs/horizon/src/renderer/vnode/VNode.ts | 11 ++++- .../src/renderer/vnode/VNodeCreator.ts | 21 +++++----- package.json | 1 + 7 files changed, 68 insertions(+), 45 deletions(-) diff --git a/babel.config.js b/babel.config.js index 9f82d978..7381b622 100644 --- a/babel.config.js +++ b/babel.config.js @@ -2,7 +2,7 @@ module.exports = { presets: [ '@babel/react', '@babel/preset-typescript', - ['@babel/preset-env', { targets: { node: 'current' } }] + ['@babel/preset-env', { targets: { node: 'current' } }], ], plugins: [ ['@babel/plugin-proposal-class-properties', { loose: true }], @@ -34,5 +34,6 @@ module.exports = { pragma: 'Horizon.createElement', pragmaFrag: 'Horizon.Fragment' }], + ['@babel/plugin-transform-react-jsx-source'], ], }; diff --git a/libs/horizon/src/external/JSXElement.ts b/libs/horizon/src/external/JSXElement.ts index d805b843..1f1f1385 100644 --- a/libs/horizon/src/external/JSXElement.ts +++ b/libs/horizon/src/external/JSXElement.ts @@ -9,10 +9,11 @@ import { getProcessingClassVNode } from '../renderer/GlobalVar'; * ref ref属性 * props 其他常规属性 */ -export function JSXElement(type, key, ref, vNode, props) { +export function JSXElement(type, key, ref, vNode, props, source) { return { // 元素标识符 vtype: TYPE_COMMON_ELEMENT, + source: source, // 属于元素的内置属性 type: type, @@ -26,7 +27,13 @@ export function JSXElement(type, key, ref, vNode, props) { } function isValidKey(key) { - return key !== 'key' && key !== 'ref' && key !== '__source'; + const keyArray = [ + 'key', + 'ref', + '__source', + '__self' + ]; + return !keyArray.includes(key); } function mergeDefault(sourceObj, defaultObj) { @@ -67,7 +74,9 @@ function buildElement(isClone, type, setting, children) { mergeDefault(props, element.defaultProps); } - return JSXElement(element, key, ref, vNode, props); + const source = setting?.__source === undefined ? null : setting.__source; + + return JSXElement(element, key, ref, vNode, props, source); } // 创建Element结构体,供JSX编译时调用 diff --git a/libs/horizon/src/external/devtools.ts b/libs/horizon/src/external/devtools.ts index e1edf1ff..0cc4d530 100644 --- a/libs/horizon/src/external/devtools.ts +++ b/libs/horizon/src/external/devtools.ts @@ -1,12 +1,5 @@ import { travelVNodeTree } from '../renderer/vnode/VNodeUtils'; -import { - Hook, - Reducer, - Ref, - Effect, - CallBack, - Memo -} from '../renderer/hooks/HookType'; +import { Hook, Reducer, Ref, Effect, CallBack, Memo } from '../renderer/hooks/HookType'; import { VNode } from '../renderer/vnode/VNode'; import { launchUpdateFromVNode } from '../renderer/TreeBuilder'; import { DomComponent } from '../renderer/vnode/VNodeTags'; @@ -26,7 +19,7 @@ const HookName = { MemoHook: 'Memo', RefHook: 'Ref', ReducerHook: 'Reducer', - CallbackHook: 'Callback' + CallbackHook: 'Callback', }; export const helper = { @@ -45,7 +38,8 @@ export const helper = { } else if (isRefHook(state)) { return { name: HookName.RefHook, hIndex, value: (state as Ref).current }; } else if (isEffectHook(state)) { - const name = state.effectConstant == EffectConstant.LayoutEffect ? HookName.LayoutEffectHook : HookName.EffectHook; + const name = + state.effectConstant == EffectConstant.LayoutEffect ? HookName.LayoutEffectHook : HookName.EffectHook; return { name, hIndex, value: (state as Effect).effect }; } else if (isCallbackHook(state)) { return { name: HookName.CallbackHook, hIndex, value: (state as CallBack).func }; @@ -86,7 +80,7 @@ export const helper = { } if (hooks && hooks.length !== 0) { const logHookInfo: any[] = []; - hooks.forEach((hook) => { + hooks.forEach(hook => { const state = hook.state as Reducer; if (state.trigger && state.isUseState) { logHookInfo.push(state.stateValue); @@ -94,20 +88,26 @@ export const helper = { }); info['Hooks'] = logHookInfo; } - travelVNodeTree(vNode, (node: VNode) => { - if (node.tag === DomComponent) { - // 找到组件的第一个dom元素,返回它所在父节点的全部子节点 - const dom = node.realNode; - info['Nodes'] = dom?.parentNode?.childNodes; - return true; - } - return false; - }, null, vNode, null); + travelVNodeTree( + vNode, + (node: VNode) => { + if (node.tag === DomComponent) { + // 找到组件的第一个dom元素,返回它所在父节点的全部子节点 + const dom = node.realNode; + info['Nodes'] = dom?.parentNode?.childNodes; + return true; + } + return false; + }, + null, + vNode, + null + ); return info; }, getElementTag: (element: JSXElement) => { return getElementTag(element); - } + }, }; export function injectUpdater() { diff --git a/libs/horizon/src/renderer/Types.ts b/libs/horizon/src/renderer/Types.ts index 6e1572fe..c6c2390a 100644 --- a/libs/horizon/src/renderer/Types.ts +++ b/libs/horizon/src/renderer/Types.ts @@ -3,20 +3,16 @@ export { VNode } from './vnode/VNode'; type Trigger = (A) => void; export type UseStateHookType = { - useState( - initialState: (() => S) | S - ): [S, Trigger<((S) => S) | S>]; + useState(initialState: (() => S) | S): [S, Trigger<((S) => S) | S>]; }; export type UseReducerHookType = { - useReducer( - reducer: (S, A) => S, - initArg: P, init?: (P) => S, - ): [S, Trigger]; + useReducer(reducer: (S, A) => S, initArg: P, init?: (P) => S): [S, Trigger]; }; -export type UseContextHookType = { useContext(context: ContextType,): T }; +export type UseContextHookType = { useContext(context: ContextType): T }; export type JSXElement = { vtype: any; + source: any; type: any; key: any; ref: any; @@ -50,7 +46,7 @@ export type RefType = { export interface PromiseType { then( onFulfill: (value: R) => void | PromiseType | U, - onReject: (error: any) => void | PromiseType | U, + onReject: (error: any) => void | PromiseType | U ): void | PromiseType; } @@ -61,3 +57,9 @@ export interface SuspenseState { didCapture: boolean; // suspense是否捕获了异常 promiseResolved: boolean; // suspense的promise是否resolve } + +export type Source = { + columnNumber: number; + fileName: string; + lineNumber: number; +}; diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 7c360e47..efb31616 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -18,7 +18,7 @@ import { MemoComponent, } from './VNodeTags'; import type { VNodeTag } from './VNodeTags'; -import type { RefType, ContextType, SuspenseState } from '../Types'; +import type { RefType, ContextType, SuspenseState, Source } from '../Types'; import type { Hook } from '../hooks/HookType'; import { InitFlag } from './VNodeFlags'; @@ -86,6 +86,7 @@ export class VNode { isStoreChange: boolean; observers: Set | null = null; // 记录这个函数组件/类组件依赖哪些Observer classComponentWillUnmount: Function | null; // HorizonX会在classComponentWillUnmount中清除对VNode的引入用 + source: Source | null; // 节点所在代码位置 constructor(tag: VNodeTag, props: any, key: null | string, realNode) { this.tag = tag; // 对应组件的类型,比如ClassComponent等 @@ -116,6 +117,7 @@ export class VNode { this.isStoreChange = false; this.observers = null; this.classComponentWillUnmount = null; + this.source = null; break; case ClassComponent: this.realNode = null; @@ -130,15 +132,18 @@ export class VNode { this.isStoreChange = false; this.observers = null; this.classComponentWillUnmount = null; + this.source = null; break; case DomPortal: this.realNode = null; this.context = null; + this.source = null; break; case DomComponent: this.realNode = null; this.changeList = null; this.context = null; + this.source = null; break; case DomText: this.realNode = null; @@ -152,12 +157,15 @@ export class VNode { oldChildStatus: '', childStatus: '' }; + this.source = null; break; case ContextProvider: + this.source = null; this.context = null; break; case MemoComponent: this.effectList = null; + this.source = null; break; case LazyComponent: this.realNode = null; @@ -165,6 +173,7 @@ export class VNode { this.isLazyComponent = true; this.lazyType = null; this.updates = null; + this.source = null; break; case Fragment: break; diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index c5b4c306..1df766b4 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -17,10 +17,13 @@ import { } from './VNodeTags'; import { TYPE_CONTEXT, - TYPE_FORWARD_REF, TYPE_FRAGMENT, + TYPE_FORWARD_REF, + TYPE_FRAGMENT, TYPE_LAZY, - TYPE_MEMO, TYPE_PROFILER, - TYPE_PROVIDER, TYPE_STRICT_MODE, + TYPE_MEMO, + TYPE_PROFILER, + TYPE_PROVIDER, + TYPE_STRICT_MODE, TYPE_SUSPENSE, } from '../../external/JSXElementType'; import { VNode } from './VNode'; @@ -56,7 +59,7 @@ export function getLazyVNodeTag(lazyComp: any): string { } else if (lazyComp !== undefined && lazyComp !== null && typeLazyMap[lazyComp.vtype]) { return typeLazyMap[lazyComp.vtype]; } - throw Error('Horizon can\'t resolve the content of lazy'); + throw Error("Horizon can't resolve the content of lazy"); } // 创建processing @@ -102,7 +105,7 @@ export function createPortalVNode(portal) { return vNode; } -export function createUndeterminedVNode(type, key, props) { +export function createUndeterminedVNode(type, key, props, source) { let vNodeTag = FunctionComponent; let isLazy = false; const componentType = typeof type; @@ -129,6 +132,7 @@ export function createUndeterminedVNode(type, key, props) { if (isLazy) { vNode.lazyType = type; } + vNode.source = source; return vNode; } @@ -181,14 +185,12 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) { } export function createVNodeFromElement(element: JSXElement): VNode { - const type = element.type; - const key = element.key; - const props = element.props; + const { type, key, props, source } = element; if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) { return createFragmentVNode(key, props.children); } else { - return createUndeterminedVNode(type, key, props); + return createUndeterminedVNode(type, key, props, source); } } @@ -241,4 +243,3 @@ export function onlyUpdateChildVNodes(processing: VNode): VNode | null { // 子树无需工作 return null; } - diff --git a/package.json b/package.json index fe9836de..0517610f 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@babel/plugin-transform-shorthand-properties": "7.16.7", "@babel/plugin-transform-spread": "7.16.7", "@babel/plugin-transform-template-literals": "7.16.7", + "@babel/plugin-transform-react-jsx-source": "^7.18.6", "@babel/preset-env": "7.16.7", "@babel/preset-react": "7.16.7", "@babel/preset-typescript": "7.16.7",