Compare commits

...

3 Commits

Author SHA1 Message Date
涂旭辉 06458da6db
!33 [inula]<feat> 新增 reconciler 模块
Merge pull request !33 from 涂旭辉/reconciler
2023-10-09 09:04:31 +00:00
13659257719 61ad99bdb1 Merge branch 'master' of https://gitee.com/openInula/inula into reconciler 2023-10-09 16:59:44 +08:00
13659257719 f8c5cb0bbe [inula]<feat> 新增 reconciler 模块 2023-10-09 16:53:51 +08:00
10 changed files with 132 additions and 31 deletions

View File

@ -4,7 +4,7 @@
"keywords": [ "keywords": [
"openinula" "openinula"
], ],
"version": "0.0.1", "version": "0.0.1-beta-reconciler-20231009-2",
"homepage": "", "homepage": "",
"bugs": "", "bugs": "",
"license": "MulanPSL2", "license": "MulanPSL2",

View File

@ -22,7 +22,7 @@ import { listenSimulatedDelegatedEvents } from '../event/EventBinding';
import { Callback } from '../renderer/Types'; import { Callback } from '../renderer/Types';
import { InulaNode } from '../types'; import { InulaNode } from '../types';
function createRoot(children: any, container: Container, callback?: Callback) { export function createTreeRoot(children: any, container: Container, callback?: Callback) {
// 清空容器 // 清空容器
let child = container.lastChild; let child = container.lastChild;
while (child) { while (child) {
@ -56,7 +56,7 @@ function executeRender(children: any, container: Container, callback?: Callback)
let treeRoot = container._treeRoot; let treeRoot = container._treeRoot;
if (!treeRoot) { if (!treeRoot) {
treeRoot = createRoot(children, container, callback); treeRoot = createTreeRoot(children, container, callback);
} else { } else {
// container被render过 // container被render过
if (typeof callback === 'function') { if (typeof callback === 'function') {

View File

@ -21,12 +21,12 @@ import { NSS } from './utils/DomCreator';
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler'; import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
import type { VNode } from '../renderer/Types'; import type { VNode } from '../renderer/Types';
import { setInitValue, getPropsWithoutValue, updateValue } from './valueHandler'; import { setInitValue, getPropsWithoutValue, updateValue } from './valueHandler';
import { compareProps, setDomProps } from './DOMPropertiesHandler/DOMPropertiesHandler';
import { isNativeElement, validateProps } from './validators/ValidateProps'; import { isNativeElement, validateProps } from './validators/ValidateProps';
import { watchValueChange } from './valueHandler/ValueChangeHandler'; import { watchValueChange } from './valueHandler/ValueChangeHandler';
import { DomComponent, DomText } from '../renderer/vnode/VNodeTags'; import { DomComponent, DomText } from '../renderer/vnode/VNodeTags';
import { updateCommonProp } from './DOMPropertiesHandler/UpdateCommonProp'; import { updateCommonProp } from './DOMPropertiesHandler/UpdateCommonProp';
import { getCurrentRoot } from '../renderer/RootStack'; import { getCurrentRoot } from '../renderer/RootStack';
import hostConfig from '../reconciler/hostConfig';
export type Props = Record<string, any> & { export type Props = Record<string, any> & {
autoFocus?: boolean; autoFocus?: boolean;
@ -94,7 +94,7 @@ export function initDomProps(dom: Element, tagName: string, rawProps: Props): bo
// 初始化DOM属性不包括valuedefaultValue // 初始化DOM属性不包括valuedefaultValue
const isNativeTag = isNativeElement(tagName, props); const isNativeTag = isNativeElement(tagName, props);
setDomProps(dom, props, isNativeTag, true); hostConfig.setDomProps(dom, props, isNativeTag, true);
if (tagName === 'input' || tagName === 'textarea') { if (tagName === 'input' || tagName === 'textarea') {
// 增加监听value和checked的set、get方法 // 增加监听value和checked的set、get方法
@ -121,7 +121,7 @@ export function getPropChangeList(
const oldProps: Record<string, any> = getPropsWithoutValue(type, dom, lastRawProps); const oldProps: Record<string, any> = getPropsWithoutValue(type, dom, lastRawProps);
const newProps: Record<string, any> = getPropsWithoutValue(type, dom, nextRawProps); const newProps: Record<string, any> = getPropsWithoutValue(type, dom, nextRawProps);
return compareProps(oldProps, newProps); return hostConfig.compareProps(oldProps, newProps);
} }
export function isTextChild(type: string, props: Props): boolean { export function isTextChild(type: string, props: Props): boolean {
@ -175,7 +175,7 @@ export function submitDomUpdate(tag: string, vNode: VNode) {
updateCommonProp(element, 'checked', newProps.checked, true); updateCommonProp(element, 'checked', newProps.checked, true);
} }
const isNativeTag = isNativeElement(type, newProps); const isNativeTag = isNativeElement(type, newProps);
setDomProps(element, changeList, isNativeTag, false); hostConfig.setDomProps(element, changeList, isNativeTag, false);
updateValue(type, element, newProps); updateValue(type, element, newProps);
} }
} }

View File

@ -71,6 +71,7 @@ import {
import { syncUpdates as flushSync } from './renderer/TreeBuilder'; import { syncUpdates as flushSync } from './renderer/TreeBuilder';
import { toRaw } from './inulax/proxy/ProxyHandler'; import { toRaw } from './inulax/proxy/ProxyHandler';
import inulaReconciler from './reconciler';
const Inula = { const Inula = {
Children, Children,
@ -122,6 +123,7 @@ const Inula = {
Profiler, Profiler,
StrictMode, StrictMode,
Suspense, Suspense,
inulaReconciler,
}; };
export const version = __VERSION__; export const version = __VERSION__;
@ -178,6 +180,7 @@ export {
Profiler, Profiler,
StrictMode, StrictMode,
Suspense, Suspense,
inulaReconciler,
}; };
export * from './types'; export * from './types';

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
import { setDomProps, compareProps } from '../dom/DOMPropertiesHandler/DOMPropertiesHandler';
import {
appendChildElement,
clearText,
hideDom,
unHideDom,
initDomProps,
insertDomBefore,
newDom,
newTextDom,
removeChildDom,
submitDomUpdate
} from '../dom/DOMOperator';
const hostConfig = {
setDomProps,
compareProps,
newDom,
initDomProps,
newTextDom,
submitDomUpdate,
clearText,
appendChildElement,
insertDomBefore,
removeChildDom,
hideDom,
unHideDom,
};
export default hostConfig;

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
import { createTreeRoot as createContainer } from '../dom/DOMExternal';
import { getPublicRootInstance } from '../renderer/getPublicRootInstance';
import { startUpdate as updateContainer } from '../renderer/Renderer';
import hostConfig from './hostConfig';
const inulaReconciler = {
hostConfig,
createContainer,
updateContainer,
getPublicRootInstance
};
export default inulaReconciler;

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
import {VNode} from './vnode/VNode';
import {DomComponent, TreeRoot} from './vnode/VNodeTags';
export function getPublicRootInstance(container: VNode): any {
const realNode = container.realNode;
if (!realNode.child) {
return null;
}
switch (realNode.child.tag) {
case TreeRoot:
case DomComponent:
return realNode.child.realNode;
default:
return realNode.child.stateNode;
}
}

View File

@ -17,12 +17,13 @@ import type { VNode } from '../Types';
import type { Props } from '../../dom/DOMOperator'; import type { Props } from '../../dom/DOMOperator';
import { getNamespaceCtx, setNamespaceCtx, resetNamespaceCtx } from '../ContextSaver'; import { getNamespaceCtx, setNamespaceCtx, resetNamespaceCtx } from '../ContextSaver';
import { appendChildElement, newDom, initDomProps, getPropChangeList, isTextChild } from '../../dom/DOMOperator'; import { getPropChangeList, isTextChild } from '../../dom/DOMOperator';
import { FlagUtils } from '../vnode/VNodeFlags'; import { FlagUtils } from '../vnode/VNodeFlags';
import { markRef } from './BaseComponent'; import { markRef } from './BaseComponent';
import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags'; import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags';
import { travelVNodeTree } from '../vnode/VNodeUtils'; import { travelVNodeTree } from '../vnode/VNodeUtils';
import { createChildrenByDiff } from '../diff/nodeDiffComparator'; import { createChildrenByDiff } from '../diff/nodeDiffComparator';
import hostConfig from '../../reconciler/hostConfig';
function updateDom(processing: VNode, type: any, newProps: Props) { function updateDom(processing: VNode, type: any, newProps: Props) {
// 如果oldProps !== newProps意味着存在更新并且需要处理其相关的副作用 // 如果oldProps !== newProps意味着存在更新并且需要处理其相关的副作用
@ -65,7 +66,7 @@ export function bubbleRender(processing: VNode) {
const parentNamespace = getNamespaceCtx(); const parentNamespace = getNamespaceCtx();
// 创建dom // 创建dom
const dom = newDom(type, newProps, parentNamespace, processing); const dom = hostConfig.newDom(type, newProps, parentNamespace, processing);
// 把dom类型的子节点append到parent dom中 // 把dom类型的子节点append到parent dom中
const vNode = processing.child; const vNode = processing.child;
@ -75,7 +76,7 @@ export function bubbleRender(processing: VNode) {
vNode, vNode,
node => { node => {
if (node.tag === DomComponent || node.tag === DomText) { if (node.tag === DomComponent || node.tag === DomText) {
appendChildElement(dom, node.realNode); hostConfig.appendChildElement(dom, node.realNode);
} }
}, },
node => node =>
@ -88,7 +89,7 @@ export function bubbleRender(processing: VNode) {
processing.realNode = dom; processing.realNode = dom;
if (initDomProps(dom, type, newProps)) { if (hostConfig.initDomProps(dom, type, newProps)) {
FlagUtils.markUpdate(processing); FlagUtils.markUpdate(processing);
} }

View File

@ -16,8 +16,8 @@
import type { VNode } from '../Types'; import type { VNode } from '../Types';
import { throwIfTrue } from '../utils/throwIfTrue'; import { throwIfTrue } from '../utils/throwIfTrue';
import { newTextDom } from '../../dom/DOMOperator';
import { FlagUtils } from '../vnode/VNodeFlags'; import { FlagUtils } from '../vnode/VNodeFlags';
import hostConfig from '../../reconciler/hostConfig';
export function captureRender(): VNode | null { export function captureRender(): VNode | null {
return null; return null;
@ -44,6 +44,6 @@ export function bubbleRender(processing: VNode) {
); );
} }
// 获得对应节点 // 获得对应节点
processing.realNode = newTextDom(newText, processing); processing.realNode = hostConfig.newTextDom(newText, processing);
} }
} }

View File

@ -34,15 +34,6 @@ import {
} from '../vnode/VNodeTags'; } from '../vnode/VNodeTags';
import { FlagUtils, ResetText, Clear, Update, DirectAddition } from '../vnode/VNodeFlags'; import { FlagUtils, ResetText, Clear, Update, DirectAddition } from '../vnode/VNodeFlags';
import { mergeDefaultProps } from '../render/LazyComponent'; import { mergeDefaultProps } from '../render/LazyComponent';
import {
submitDomUpdate,
clearText,
appendChildElement,
insertDomBefore,
removeChildDom,
hideDom,
unHideDom,
} from '../../dom/DOMOperator';
import { import {
callEffectRemove, callEffectRemove,
callUseEffects, callUseEffects,
@ -53,6 +44,7 @@ import { handleSubmitError } from '../ErrorHandler';
import { travelVNodeTree, clearVNode, isDomVNode, getSiblingDom } from '../vnode/VNodeUtils'; import { travelVNodeTree, clearVNode, isDomVNode, getSiblingDom } from '../vnode/VNodeUtils';
import { shouldAutoFocus } from '../../dom/utils/Common'; import { shouldAutoFocus } from '../../dom/utils/Common';
import { BELONG_CLASS_VNODE_KEY } from '../vnode/VNode'; import { BELONG_CLASS_VNODE_KEY } from '../vnode/VNode';
import hostConfig from '../../reconciler/hostConfig';
function callComponentWillUnmount(vNode: VNode, instance: any) { function callComponentWillUnmount(vNode: VNode, instance: any) {
try { try {
@ -143,9 +135,9 @@ function hideOrUnhideAllChildren(vNode, isHidden) {
if (node.tag === DomComponent || node.tag === DomText) { if (node.tag === DomComponent || node.tag === DomText) {
if (isHidden) { if (isHidden) {
hideDom(node.tag, instance); hostConfig.hideDom(node.tag, instance);
} else { } else {
unHideDom(node.tag, instance, node.props); hostConfig.unHideDom(node.tag, instance, node.props);
} }
} }
}, },
@ -227,7 +219,7 @@ function unmountDomComponents(vNode: VNode): void {
unmountNestedVNodes(node); unmountNestedVNodes(node);
// 在所有子项都卸载后删除dom树中的节点 // 在所有子项都卸载后删除dom树中的节点
removeChildDom(currentParent, node.realNode); hostConfig.removeChildDom(currentParent, node.realNode);
} else if (node.tag === DomPortal) { } else if (node.tag === DomPortal) {
if (node.child !== null) { if (node.child !== null) {
currentParent = node.realNode; currentParent = node.realNode;
@ -292,9 +284,9 @@ function unmountVNode(vNode: VNode): void {
function insertDom(parent, realNode, beforeDom) { function insertDom(parent, realNode, beforeDom) {
if (beforeDom) { if (beforeDom) {
insertDomBefore(parent, realNode, beforeDom); hostConfig.insertDomBefore(parent, realNode, beforeDom);
} else { } else {
appendChildElement(parent, realNode); hostConfig.appendChildElement(parent, realNode);
} }
} }
@ -330,7 +322,7 @@ function submitAddition(vNode: VNode): void {
if ((parent!.flags & ResetText) === ResetText) { if ((parent!.flags & ResetText) === ResetText) {
// 在insert之前先reset // 在insert之前先reset
clearText(parentDom); hostConfig.clearText(parentDom);
FlagUtils.removeFlag(parent!, ResetText); FlagUtils.removeFlag(parent!, ResetText);
} }
@ -381,7 +373,7 @@ function submitClear(vNode: VNode): void {
} }
// 在所有子项都卸载后删除dom树中的节点 // 在所有子项都卸载后删除dom树中的节点
removeChildDom(parentDom, vNode.realNode); hostConfig.removeChildDom(parentDom, vNode.realNode);
const realNodeNext = getSiblingDom(vNode); const realNodeNext = getSiblingDom(vNode);
insertDom(parentDom, cloneDom, realNodeNext); insertDom(parentDom, cloneDom, realNodeNext);
vNode.realNode = cloneDom; vNode.realNode = cloneDom;
@ -416,7 +408,7 @@ function submitUpdate(vNode: VNode): void {
} }
case DomComponent: case DomComponent:
case DomText: { case DomText: {
submitDomUpdate(vNode.tag, vNode); hostConfig.submitDomUpdate(vNode.tag, vNode);
break; break;
} }
case SuspenseComponent: { case SuspenseComponent: {
@ -431,7 +423,7 @@ function submitUpdate(vNode: VNode): void {
} }
function submitResetTextContent(vNode: VNode) { function submitResetTextContent(vNode: VNode) {
clearText(vNode.realNode); hostConfig.clearText(vNode.realNode);
} }
export { export {