From 7b181521b98f47f26a19d161df03c80a44effcf8 Mon Sep 17 00:00:00 2001 From: "liujuping.liujupin" Date: Wed, 3 Nov 2021 11:38:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=EF=BC=8C=E6=8F=92=E6=A7=BD=E7=AD=89=E4=BD=9C=E7=94=A8=E5=9F=9F?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98=20&=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9C=80=E5=B0=8F=E6=B8=B2=E6=9F=93=E5=8D=95?= =?UTF-8?q?=E5=85=83=E5=8A=9F=E8=83=BD=EF=BC=8C=E8=A7=A3=E5=86=B3=E5=A2=9E?= =?UTF-8?q?=E9=87=8F=E6=9B=B4=E6=96=B0=E6=9C=BA=E5=88=B6=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/component-meta.ts | 7 ++ packages/renderer-core/src/hoc/leaf.tsx | 115 ++++++++++++++---- packages/renderer-core/src/renderer/base.tsx | 100 +++++++-------- packages/types/src/metadata.ts | 2 + .../src/bundle/upgrade-metadata.ts | 6 + 5 files changed, 154 insertions(+), 76 deletions(-) diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 9baa5726d..fec7eedf6 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -85,6 +85,10 @@ export class ComponentMeta { return this._isContainer! || this.isRootComponent(); } + get isMinimalRenderUnit(): boolean { + return this._isMinimalRenderUnit || false; + } + private _isModal?: boolean; get isModal(): boolean { @@ -128,6 +132,8 @@ export class ComponentMeta { private _title?: TitleContent; + private _isMinimalRenderUnit?: boolean; + get title(): string | I18nData | ReactElement { // TODO: 标记下。这块需要康师傅加一下API,页面正常渲染。 // string | i18nData | ReactElement @@ -220,6 +226,7 @@ export class ComponentMeta { this._isModal = !!component.isModal; this._descriptor = component.descriptor; this._rootSelector = component.rootSelector; + this._isMinimalRenderUnit = component.isMinimalRenderUnit; if (component.nestingRule) { const { parentWhitelist, childWhitelist } = component.nestingRule; this.parentWhitelist = buildFilter(parentWhitelist); diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 41b3b22ff..aaa15de4d 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -16,6 +16,7 @@ export interface IComponentHocInfo { schema: any; baseRenderer: types.IBaseRendererInstance; componentInfo: any; + scope: any; } type DesignMode = Pick['designMode']; @@ -45,6 +46,7 @@ enum RerenderType { ChildChanged = 'ChildChanged', PropsChanged = 'PropsChanged', VisibleChanged = 'VisibleChanged', + MinimalRenderUnit = 'MinimalRenderUnit', } // 缓存 Leaf 层组件,防止重新渲染问题 @@ -63,6 +65,8 @@ class LeafCache { * 订阅事件缓存,导致 rerender 的订阅事件 */ event = new Map(); + + ref = new Map(); } let cache: LeafCache; @@ -119,6 +123,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, { schema, baseRenderer, componentInfo, + scope, }: IComponentHocInfo) { const { __debug, @@ -152,8 +157,8 @@ export function leafWrapper(Comp: types.IBaseRenderer, { getNode, }); - if (curDocumentId && cache.component.has(schema.componentName)) { - return cache.component.get(schema.componentName); + if (curDocumentId && cache.component.has(schema.id)) { + return cache.component.get(schema.id); } class LeafHoc extends Component { @@ -259,9 +264,71 @@ export function leafWrapper(Comp: types.IBaseRenderer, { setSchemaChangedSymbol?.(true); } - // get isInWhitelist() { - // return whitelist.includes(schema.componentName); - // } + renderUnitInfo: { + minimalUnitId?: string, + minimalUnitName?: string; + singleRender?: boolean, + }; + + shouldRenderSingleNode(): boolean { + if (!this.renderUnitInfo) { + this.getRenderUnitInfo(); + } + + const renderUnitInfo = this.renderUnitInfo; + + if (renderUnitInfo.singleRender) { + return true; + } + + const ref = cache.ref.get(renderUnitInfo.minimalUnitId); + + if (!ref) { + __debug('Cant find minimalRenderUnit ref! This make rerender!'); + container.rerender(); + return false; + } + __debug(`${this.leaf?.componentName}(${this.props.componentId}) need render, make its minimalRenderUnit ${renderUnitInfo.minimalUnitName}(${renderUnitInfo.minimalUnitId})`); + ref.makeUnitRender(); + + return false; + } + + getRenderUnitInfo(leaf = this.leaf) { + if (leaf?.isRoot()) { + this.renderUnitInfo = { + singleRender: true, + ...(this.renderUnitInfo || {}), + }; + } + if (leaf?.componentMeta.isMinimalRenderUnit) { + this.renderUnitInfo = { + minimalUnitId: leaf.id, + minimalUnitName: leaf.componentName, + singleRender: false, + }; + } + if (leaf?.parent) { + this.getRenderUnitInfo(leaf.parent); + } + } + + makeUnitRender() { + this.beforeRender(RerenderType.MinimalRenderUnit); + const nextProps = getProps(this.leaf?.export?.(TransformStage.Render) as types.ISchema, Comp, componentInfo); + const children = getChildren(this.leaf?.export?.(TransformStage.Render) as types.ISchema, Comp); + const nextState = { + nextProps, + nodeChildren: children, + childrenInState: true, + }; + if ('children' in nextProps) { + nextState.nodeChildren = nextProps.children; + } + + __debug(`${this.leaf?.componentName}(${this.props.componentId}) MinimalRenderUnit Render!`); + this.setState(nextState); + } componentWillReceiveProps(nextProps: any) { let { _leaf, componentId } = nextProps; @@ -294,11 +361,6 @@ export function leafWrapper(Comp: types.IBaseRenderer, { } = propChangeInfo; const node = leaf; - // if (this.isInWhitelist) { - // container.rerender(); - // return; - // } - // 如果循坏条件变化,从根节点重新渲染 // 目前多层循坏无法判断需要从哪一层开始渲染,故先粗暴解决 if (key === '___loop___') { @@ -307,9 +369,12 @@ export function leafWrapper(Comp: types.IBaseRenderer, { return; } - this.beforeRender(RerenderType.PropsChanged); __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onPropsChange event`); - const nextProps = getProps(node?.export?.(TransformStage.Render) as types.ISchema, Comp, componentInfo); + if (!this.shouldRenderSingleNode()) { + return; + } + this.beforeRender(RerenderType.PropsChanged); + const nextProps = getProps(node?.export?.(TransformStage.Render) as types.ISchema, scope, Comp, componentInfo); this.setState(nextProps.children ? { nodeChildren: nextProps.children, nodeProps: nextProps, @@ -330,12 +395,11 @@ export function leafWrapper(Comp: types.IBaseRenderer, { return; } - // if (this.isInWhitelist) { - // container.rerender(); - // return; - // } - __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onVisibleChange event`); + if (!this.shouldRenderSingleNode()) { + return; + } + this.beforeRender(RerenderType.VisibleChanged); this.setState({ visible: flag, @@ -354,16 +418,15 @@ export function leafWrapper(Comp: types.IBaseRenderer, { type, node, } = param || {}; - // if (this.isInWhitelist) { - // container.rerender(); - // return; - // } - this.beforeRender(`${RerenderType.ChildChanged}-${type}`, node); __debug(`${schema.componentName}[${this.props.componentId}] component trigger onChildrenChange event`); + if (!this.shouldRenderSingleNode()) { + return; + } + this.beforeRender(`${RerenderType.ChildChanged}-${type}`, node); // TODO: 缓存同级其他元素的 children。 // 缓存二级 children Next 查询筛选组件有问题 // 缓存一级 children Next Tab 组件有问题 - const nextChild = getChildren(leaf?.export?.(TransformStage.Render) as types.ISchema, Comp); // this.childrenMap + const nextChild = getChildren(leaf?.export?.(TransformStage.Render) as types.ISchema, scope, Comp); // this.childrenMap this.setState({ nodeChildren: nextChild, childrenInState: true, @@ -431,7 +494,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, { const LeafWrapper = forwardRef((props: any, ref: any) => ( // @ts-ignore - + cache.ref.set(props.componentId, ref)} /> )); if (typeof Comp === 'object') { @@ -446,9 +509,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, { LeafWrapper.displayName = (Comp as any).displayName; - if (curDocumentId) { - cache.component.set(schema.componentName, LeafWrapper); - } + cache.component.set(schema.id, LeafWrapper); return LeafWrapper; } \ No newline at end of file diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 8fcbf8e86..f75b51385 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -347,34 +347,31 @@ export default function baseRenererFactory() { __createDom = () => { const { __schema, __ctx, __components = {} } = this.props; - const self: any = {}; - self.__proto__ = __ctx || this; + const scope: any = {}; + scope.__proto__ = __ctx || this; if (!this._self) { - this._self = self; + this._self = scope; } const _children = this.getSchemaChildren(__schema); let Comp = __components[__schema.componentName]; - return this.__createVirtualDom(_children, self, ({ + if (!Comp) { + console.error(`${__schema.componentName} is invalid!`); + } + + return this.__createVirtualDom(_children, scope, ({ schema: __schema, - Comp: this.__getHocComp(Comp, __schema), + Comp: this.__getHocComp(Comp, __schema, scope), } as IInfo)); }; - private get self() { - const { __ctx } = this.props; - const self: any = {}; - self.__proto__ = __ctx || this; - - return self; - } // 将模型结构转换成react Element // schema 模型结构 // self 为每个渲染组件构造的上下文,self是自上而下继承的 // parentInfo 父组件的信息,包含schema和Comp // idx 若为循环渲染的循环Index - __createVirtualDom = (schema: ISchema, self: any, parentInfo: IInfo, idx: string | number = ''): any => { + __createVirtualDom = (schema: ISchema, scope: any, parentInfo: IInfo, idx: string | number = ''): any => { const { engine } = this.context || {}; try { if (!schema) return null; @@ -388,28 +385,28 @@ export default function baseRenererFactory() { const { __appHelper: appHelper, __components: components = {} } = this.props || {}; if (isJSExpression(schema)) { - return parseExpression(schema, self); + return parseExpression(schema, scope); } if (isI18n(schema)) { - return parseI18n(schema, self); + return parseI18n(schema, scope); } if (isJSSlot(schema)) { - return this.__createVirtualDom(schema.value, self, parentInfo); + return this.__createVirtualDom(schema.value, scope, parentInfo); } if (typeof schema === 'string') return schema; if (typeof schema === 'number' || typeof schema === 'boolean') { return String(schema); } if (Array.isArray(schema)) { - if (schema.length === 1) return this.__createVirtualDom(schema[0], self, parentInfo); - return schema.map((item, idy) => this.__createVirtualDom(item, self, parentInfo, item?.__ctx?.lceKey ? '' : String(idy))); + if (schema.length === 1) return this.__createVirtualDom(schema[0], scope, parentInfo); + return schema.map((item, idy) => this.__createVirtualDom(item, scope, parentInfo, item?.__ctx?.lceKey ? '' : String(idy))); } // FIXME const _children = this.getSchemaChildren(schema); // 解析占位组件 if (schema.componentName === 'Flagment' && _children) { - const tarChildren = isJSExpression(_children) ? parseExpression(_children, self) : _children; - return this.__createVirtualDom(tarChildren, self, parentInfo); + const tarChildren = isJSExpression(_children) ? parseExpression(_children, scope) : _children; + return this.__createVirtualDom(tarChildren, scope, parentInfo); } if (schema.$$typeof) { @@ -429,26 +426,26 @@ export default function baseRenererFactory() { } if (schema.loop != null) { - const loop = parseData(schema.loop, self); + const loop = parseData(schema.loop, scope); if ((Array.isArray(loop) && loop.length > 0) || isJSExpression(loop)) { return this.__createLoopVirtualDom( { ...schema, loop, }, - self, + scope, parentInfo, idx, ); } } - const condition = schema.condition == null ? true : parseData(schema.condition, self); + const condition = schema.condition == null ? true : parseData(schema.condition, scope); if (!condition) return null; let scopeKey = ''; // 判断组件是否需要生成scope,且只生成一次,挂在this.__compScopes上 if (Comp.generateScope) { - const key = parseExpression(schema.props.key, self); + const key = parseExpression(schema.props.key, scope); if (key) { // 如果组件自己设置key则使用组件自己的key scopeKey = key; @@ -469,8 +466,8 @@ export default function baseRenererFactory() { // 如果组件有设置scope,需要为组件生成一个新的scope上下文 if (scopeKey && this.__compScopes[scopeKey]) { const compSelf = { ...this.__compScopes[scopeKey] }; - compSelf.__proto__ = self; - self = compSelf; + compSelf.__proto__ = scope; + scope = compSelf; } // 容器类组件的上下文通过props传递,避免context传递带来的嵌套问题 @@ -488,7 +485,7 @@ export default function baseRenererFactory() { otherProps.__tag = Math.random(); } const componentInfo: any = {}; - const props: any = this.__getComponentProps(schema, Comp, { + const props: any = this.__getComponentProps(schema, scope, Comp, { ...componentInfo, props: transformArrayToMap(componentInfo.props, 'name'), }) || {}; @@ -498,6 +495,7 @@ export default function baseRenererFactory() { schema, componentInfo, baseRenderer: this, + scope, }); }); @@ -522,7 +520,7 @@ export default function baseRenererFactory() { } if (schema?.__ctx?.lceKey) { if (!isFileSchema(schema)) { - engine?.props?.onCompGetCtx(schema, self); + engine?.props?.onCompGetCtx(schema, scope); } props.key = props.key || `${schema.__ctx.lceKey}_${schema.__ctx.idx || 0}_${idx !== undefined ? idx : ''}`; } else if (typeof idx === 'number' && !props.key) { @@ -535,7 +533,7 @@ export default function baseRenererFactory() { props.key = props.__id; } - let child: any = parentInfo.componentChildren || this.__getSchemaChildrenVirtualDom(schema, Comp); + let child: any = parentInfo.componentChildren || this.__getSchemaChildrenVirtualDom(schema, scope, Comp); const renderComp = (props: any) => engine.createElement(Comp, props, child); // 设计模式下的特殊处理 if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) { @@ -568,7 +566,7 @@ export default function baseRenererFactory() { return engine.createElement(engine.getFaultComponent(), { error: e, schema, - self, + self: scope, parentInfo, idx, }); @@ -594,7 +592,7 @@ export default function baseRenererFactory() { .map((d: IComponentHoc) => d.hoc); } - __getSchemaChildrenVirtualDom = (schema: ISchema, Comp: any, childrenMap?: Map) => { + __getSchemaChildrenVirtualDom = (schema: ISchema, scope: any, Comp: any, childrenMap?: Map) => { let _children = this.getSchemaChildren(schema); let children: any = []; @@ -605,8 +603,8 @@ export default function baseRenererFactory() { _children.forEach((_child: any) => { const _childVirtualDom = this.__createVirtualDom( - isJSExpression(_child) ? parseExpression(_child, this.self) : _child, - this.self, + isJSExpression(_child) ? parseExpression(_child, scope) : _child, + scope, { schema, Comp, @@ -625,11 +623,11 @@ export default function baseRenererFactory() { return null; }; - __getComponentProps = (schema: ISchema, Comp: any, componentInfo?: any) => { + __getComponentProps = (schema: ISchema, scope: any, Comp: any, componentInfo?: any) => { if (!schema) { return {}; } - return this.__parseProps(schema?.props, this.self, '', { + return this.__parseProps(schema?.props, scope, '', { schema, Comp, componentInfo: { @@ -639,7 +637,7 @@ export default function baseRenererFactory() { }) || {}; }; - __createLoopVirtualDom = (schema: ISchema, self: any, parentInfo: IInfo, idx: number | string) => { + __createLoopVirtualDom = (schema: ISchema, scope: any, parentInfo: IInfo, idx: number | string) => { if (isFileSchema(schema)) { console.warn('file type not support Loop'); return null; @@ -652,7 +650,7 @@ export default function baseRenererFactory() { [itemArg]: item, [indexArg]: i, }; - loopSelf.__proto__ = self; + loopSelf.__proto__ = scope; return this.__createVirtualDom( { ...schema, @@ -670,7 +668,7 @@ export default function baseRenererFactory() { return engine?.props?.designMode === 'design'; } - __parseProps = (props: any, self: any, path: string, info: IInfo): any => { + __parseProps = (props: any, scope: any, path: string, info: IInfo): any => { const { schema, Comp, componentInfo = {} } = info; const propInfo = getValue(componentInfo.props, path); // FIXME! 将这行逻辑外置,解耦,线上环境不要验证参数,调试环境可以有,通过传参自定义 @@ -683,7 +681,7 @@ export default function baseRenererFactory() { const parseReactNode = (data: any, params: any) => { if (isEmpty(params)) { - return checkProps(this.__createVirtualDom(data, self, ({ schema, Comp } as IInfo))); + return checkProps(this.__createVirtualDom(data, scope, ({ schema, Comp } as IInfo))); } return checkProps(function () { const args: any = {}; @@ -696,8 +694,8 @@ export default function baseRenererFactory() { } }); } - args.__proto__ = self; - return self.__createVirtualDom(data, args, { schema, Comp }); + args.__proto__ = scope; + return scope.__createVirtualDom(data, args, { schema, Comp }); }); }; @@ -713,7 +711,7 @@ export default function baseRenererFactory() { return checkProps(props); } if (isJSExpression(props)) { - props = parseExpression(props, self); + props = parseExpression(props, scope); // 只有当变量解析出来为模型结构的时候才会继续解析 if (!isSchema(props) && !isJSSlot(props)) return checkProps(props); } @@ -726,7 +724,7 @@ export default function baseRenererFactory() { if (i18nProp) { props = i18nProp; } else { - return parseI18n(props, self); + return parseI18n(props, scope); } } @@ -768,10 +766,10 @@ export default function baseRenererFactory() { ); } if (Array.isArray(props)) { - return checkProps(props.map((item, idx) => this.__parseProps(item, self, path ? `${path}.${idx}` : `${idx}`, info))); + return checkProps(props.map((item, idx) => this.__parseProps(item, scope, path ? `${path}.${idx}` : `${idx}`, info))); } if (typeof props === 'function') { - return checkProps(props.bind(self)); + return checkProps(props.bind(scope)); } if (props && typeof props === 'object') { if (props.$$typeof) return checkProps(props); @@ -781,7 +779,7 @@ export default function baseRenererFactory() { res[key] = val; return; } - res[key] = this.__parseProps(val, self, path ? `${path}.${key}` : key, info); + res[key] = this.__parseProps(val, scope, path ? `${path}.${key}` : key, info); }); return checkProps(res); } @@ -829,12 +827,13 @@ export default function baseRenererFactory() { return createElement(AppContext.Consumer, {}, children); }; - __getHocComp(Comp: any, schema: any) { + __getHocComp(Comp: any, schema: any, scope: any) { this.componentHoc.forEach((ComponentConstruct: IComponentConstruct) => { Comp = ComponentConstruct(Comp || Div, { schema, componentInfo: {}, baseRenderer: this, + scope, }); }); @@ -843,8 +842,11 @@ export default function baseRenererFactory() { __renderComp(Comp: any, ctxProps: object) { const { __schema } = this.props; - Comp = this.__getHocComp(Comp, __schema); - const data = this.__parseProps(__schema?.props, this.self, '', { + const { __ctx } = this.props; + const scope: any = {}; + scope.__proto__ = __ctx || this; + Comp = this.__getHocComp(Comp, __schema, scope); + const data = this.__parseProps(__schema?.props, scope, '', { schema: __schema, Comp, componentInfo: {}, diff --git a/packages/types/src/metadata.ts b/packages/types/src/metadata.ts index 77476d758..c266755a1 100644 --- a/packages/types/src/metadata.ts +++ b/packages/types/src/metadata.ts @@ -29,6 +29,8 @@ export interface ComponentConfigure { descriptor?: string; nestingRule?: NestingRule; + isMinimalRenderUnit?: boolean; + rootSelector?: string; // copy, move, remove | * disableBehaviors?: string[] | string; diff --git a/packages/vision-polyfill/src/bundle/upgrade-metadata.ts b/packages/vision-polyfill/src/bundle/upgrade-metadata.ts index 5817a7b5d..89487ac73 100644 --- a/packages/vision-polyfill/src/bundle/upgrade-metadata.ts +++ b/packages/vision-polyfill/src/bundle/upgrade-metadata.ts @@ -132,6 +132,7 @@ export interface OldPrototypeConfig { componentName: string; // => docUrl?: string; // => defaultProps?: any; // => ? + isMinimalRenderUnit?: boolean; // => false /** * extra actions on the outline of current selected node * by default we have: remove / clone @@ -702,6 +703,9 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) { devMode, schema, isTopFixed, + + // render + isMinimalRenderUnit, } = oldConfig; let { canResizing, // resizing @@ -714,6 +718,7 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) { docUrl, devMode: devMode || 'procode', schema: schema?.componentsTree[0], + // isMinimalRenderUnit, }; if (category) { @@ -732,6 +737,7 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) { isModal, isFloating, descriptor, + isMinimalRenderUnit, }; if (canOperating === false) { From a652b1f6f26b14e64ec5eb7af6c04b3605c88f95 Mon Sep 17 00:00:00 2001 From: "liujuping.liujupin" Date: Thu, 4 Nov 2021 09:22:09 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E7=94=B1=E4=BA=8E=E6=B8=85=E7=A9=BA=EF=BC=8C?= =?UTF-8?q?=E4=B8=A2=E5=A4=B1=E9=97=AE=E9=A2=98=20&=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20function=20=E7=BB=84=E4=BB=B6=E9=9D=99=E6=80=81=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E4=B8=A2=E5=A4=B1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ignitor/public/favicon.png | Bin 3612 -> 0 bytes packages/ignitor/public/index.html | 87 ------------------ packages/ignitor/public/preview.html | 21 ----- packages/renderer-core/package.json | 3 +- packages/renderer-core/src/hoc/index.tsx | 10 +- packages/renderer-core/src/hoc/leaf.tsx | 61 ++++++------ packages/renderer-core/src/renderer/base.tsx | 24 ++--- packages/renderer-core/src/types/index.ts | 2 +- packages/renderer-core/src/utils/common.ts | 4 +- packages/renderer-core/src/utils/logger.ts | 2 + .../utils/src/clone-enumerable-property.ts | 22 +++++ packages/utils/src/index.ts | 1 + packages/utils/src/is-react.ts | 4 +- .../src/bundle/upgrade-metadata.ts | 1 - 14 files changed, 75 insertions(+), 167 deletions(-) delete mode 100644 packages/ignitor/public/favicon.png delete mode 100644 packages/ignitor/public/index.html delete mode 100644 packages/ignitor/public/preview.html create mode 100644 packages/renderer-core/src/utils/logger.ts create mode 100644 packages/utils/src/clone-enumerable-property.ts diff --git a/packages/ignitor/public/favicon.png b/packages/ignitor/public/favicon.png deleted file mode 100644 index 307ffbd82dba398d6db6459102bff331eef7df6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3612 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 - - - - - - LowCodeEngine Editor DEMO - - - - - - - - - - - - - - - - - - - - - - -
- - - - - diff --git a/packages/ignitor/public/preview.html b/packages/ignitor/public/preview.html deleted file mode 100644 index c8f2cfdcb..000000000 --- a/packages/ignitor/public/preview.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - LowCodeEngine DEMO - - - - - - - - - - - -
- - diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 41fe3cbe6..d2562e16e 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -29,7 +29,8 @@ "react-is": "^16.10.1", "serialize-javascript": "^1.7.0", "socket.io-client": "^2.2.0", - "whatwg-fetch": "^3.0.0" + "whatwg-fetch": "^3.0.0", + "zen-logger": "^1.1.4" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/renderer-core/src/hoc/index.tsx b/packages/renderer-core/src/hoc/index.tsx index e8745f5e9..b8ab424c5 100644 --- a/packages/renderer-core/src/hoc/index.tsx +++ b/packages/renderer-core/src/hoc/index.tsx @@ -1,3 +1,4 @@ +import { cloneEnumerableProperty } from '@ali/lowcode-utils'; import adapter from '../adapter'; export function compWrapper(Comp: any) { @@ -8,15 +9,16 @@ export function compWrapper(Comp: any) { // } render() { - const { forwardRef } = this.props; + const { forwardRef, ...rest } = this.props; + return createElement(Comp, { - ...this.props, + ...rest, ref: forwardRef, }); } } - return forwardRef((props: any, ref: any) => { + return cloneEnumerableProperty(forwardRef((props: any, ref: any) => { return createElement(Wrapper, { ...props, forwardRef: ref }); - }); + }), Comp); } diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index aaa15de4d..951ceea27 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -1,16 +1,10 @@ import { BuiltinSimulatorHost, Node, PropChangeOptions } from '@ali/lowcode-designer'; import { GlobalEvent, TransformStage } from '@ali/lowcode-types'; -import { isReactComponent } from '@ali/lowcode-utils'; +import { isReactComponent, cloneEnumerableProperty } from '@ali/lowcode-utils'; import { EngineOptions } from '@ali/lowcode-editor-core'; import adapter from '../adapter'; import * as types from '../types/index'; -const compDefaultPropertyNames = [ - '$$typeof', - 'render', - 'defaultProps', - 'props', -]; export interface IComponentHocInfo { schema: any; @@ -315,8 +309,8 @@ export function leafWrapper(Comp: types.IBaseRenderer, { makeUnitRender() { this.beforeRender(RerenderType.MinimalRenderUnit); - const nextProps = getProps(this.leaf?.export?.(TransformStage.Render) as types.ISchema, Comp, componentInfo); - const children = getChildren(this.leaf?.export?.(TransformStage.Render) as types.ISchema, Comp); + const nextProps = getProps(this.leaf?.export?.(TransformStage.Render) as types.ISchema, scope, Comp, componentInfo); + const children = getChildren(this.leaf?.export?.(TransformStage.Render) as types.ISchema, scope, Comp); const nextState = { nextProps, nodeChildren: children, @@ -358,6 +352,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, { const dispose = leaf?.onPropChange?.((propChangeInfo: PropChangeOptions) => { const { key, + newValue = null, } = propChangeInfo; const node = leaf; @@ -368,18 +363,24 @@ export function leafWrapper(Comp: types.IBaseRenderer, { container.rerender(); return; } - - __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onPropsChange event`); if (!this.shouldRenderSingleNode()) { return; } this.beforeRender(RerenderType.PropsChanged); - const nextProps = getProps(node?.export?.(TransformStage.Render) as types.ISchema, scope, Comp, componentInfo); - this.setState(nextProps.children ? { - nodeChildren: nextProps.children, - nodeProps: nextProps, + const nodeProps = getProps(node?.export?.(TransformStage.Render) as types.ISchema, scope, Comp, componentInfo); + const preNodeProps = this.state.nodeProps; + const newNodeProps = { + ...preNodeProps, + [key as string]: newValue, + ...nodeProps, + }; + __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onPropsChange event`, newNodeProps); + this.setState('children' in nodeProps ? { + nodeChildren: nodeProps.children, + nodeProps: newNodeProps, + childrenInState: true, } : { - nodeProps: nextProps, + nodeProps: newNodeProps, }); }); @@ -395,11 +396,11 @@ export function leafWrapper(Comp: types.IBaseRenderer, { return; } - __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onVisibleChange event`); if (!this.shouldRenderSingleNode()) { return; } + __debug(`${leaf?.componentName}[${this.props.componentId}] component trigger onVisibleChange(${flag}) event`); this.beforeRender(RerenderType.VisibleChanged); this.setState({ visible: flag, @@ -418,7 +419,6 @@ export function leafWrapper(Comp: types.IBaseRenderer, { type, node, } = param || {}; - __debug(`${schema.componentName}[${this.props.componentId}] component trigger onChildrenChange event`); if (!this.shouldRenderSingleNode()) { return; } @@ -427,6 +427,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, { // 缓存二级 children Next 查询筛选组件有问题 // 缓存一级 children Next Tab 组件有问题 const nextChild = getChildren(leaf?.export?.(TransformStage.Render) as types.ISchema, scope, Comp); // this.childrenMap + __debug(`${schema.componentName}[${this.props.componentId}] component trigger onChildrenChange event`, nextChild); this.setState({ nodeChildren: nextChild, childrenInState: true, @@ -454,7 +455,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, { } get children(): any { - if (this.state.nodeChildren) { + if (this.state.childrenInState) { return this.state.nodeChildren; } if (this.props.children && !Array.isArray(this.props.children)) { @@ -476,7 +477,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, { } const { - ref, + forwardedRef, ...rest } = this.props; @@ -485,27 +486,23 @@ export function leafWrapper(Comp: types.IBaseRenderer, { ...(this.state.nodeProps || {}), children: [], __id: this.props.componentId, - ref: this.props.forwardedRef, + ref: forwardedRef, }; return engine.createElement(Comp, compProps, this.hasChildren ? this.children : null); } } - const LeafWrapper = forwardRef((props: any, ref: any) => ( + let LeafWrapper = forwardRef((props: any, ref: any) => ( // @ts-ignore - cache.ref.set(props.componentId, ref)} /> + cache.ref.set(props.componentId, _ref)} + /> )); - if (typeof Comp === 'object') { - const compExtraPropertyNames = Object.getOwnPropertyNames(Comp).filter(d => !compDefaultPropertyNames.includes(d)); - - __debug(`${schema.componentName} extra property names: ${compExtraPropertyNames.join(',')}`); - - compExtraPropertyNames.forEach((d: string) => { - (LeafWrapper as any)[d] = Comp[d]; - }); - } + LeafWrapper = cloneEnumerableProperty(LeafWrapper, Comp); LeafWrapper.displayName = (Comp as any).displayName; diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index f75b51385..67a0d7542 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -1,5 +1,4 @@ import classnames from 'classnames'; -import Debug from 'debug'; import { create as createDataSourceEngine } from '@ali/lowcode-datasource-engine/interpret'; import adapter from '../adapter'; import divFactory from '../components/Div'; @@ -21,7 +20,7 @@ import { transformStringToFunction, checkPropTypes, getI18n, - acceptsRef, + canAcceptsRef, getFileCssName, capitalizeFirstLetter, DataHelper, @@ -31,6 +30,7 @@ import { import { IRendererProps, ISchema, IInfo, ComponentModel, IRenderer } from '../types'; import { compWrapper } from '../hoc'; import { IComponentConstruct, IComponentHoc, leafWrapper } from '../hoc/leaf'; +import logger from '../utils/logger'; export default function baseRenererFactory() { const { BaseRenderer: customBaseRenderer } = adapter.getRenderers(); @@ -44,7 +44,6 @@ export default function baseRenererFactory() { const VisualDom = visualDomFactory(); const AppContext = contextFactory(); - const debug = Debug('renderer:base'); const DESIGN_MODE = { EXTEND: 'extend', BORDER: 'border', @@ -71,7 +70,6 @@ export default function baseRenererFactory() { this.__beforeInit(props); this.__init(props); this.__afterInit(props); - this.__initDebug(); this.__debug(`constructor - ${props?.__schema?.fileName}`); } @@ -88,7 +86,7 @@ export default function baseRenererFactory() { __afterInit(/* props: IRendererProps */) { } static getDerivedStateFromProps(props: IRendererProps, state: any) { - debug('getDerivedStateFromProps'); + logger.log('getDerivedStateFromProps'); const func = props?.__schema?.lifeCycles?.getDerivedStateFromProps; if (func) { @@ -356,7 +354,7 @@ export default function baseRenererFactory() { let Comp = __components[__schema.componentName]; if (!Comp) { - console.error(`${__schema.componentName} is invalid!`); + this.__debug(`${__schema.componentName} is invalid!`); } return this.__createVirtualDom(_children, scope, ({ @@ -499,8 +497,8 @@ export default function baseRenererFactory() { }); }); - // 对于可以获取到ref的组件做特殊处理 - if (!acceptsRef(Comp)) { + // 对于不可以接收到 ref 的组件需要做特殊处理 + if (!canAcceptsRef(Comp)) { Comp = compWrapper(Comp); components[schema.componentName] = Comp; } @@ -800,15 +798,7 @@ export default function baseRenererFactory() { return this.__instanceMap[filedId]; } - __initDebug = () => { - this.__logger = Debug(`renderer:${this.__namespace || 'base'}`); - }; - - __debug = (msg = '') => { - if (this.__logger) { - this.__logger(`${this.__namespace}.${msg}`); - } - }; + __debug = logger.log; __renderContextProvider = (customProps?: object, children?: any) => { customProps = customProps || {}; diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts index 49b8c895d..8bee549f9 100644 --- a/packages/renderer-core/src/types/index.ts +++ b/packages/renderer-core/src/types/index.ts @@ -141,7 +141,7 @@ export interface IRenderer { __createLoopVirtualDom: (schema: any, self: any, parentInfo: IInfo, idx: number | string) => any; __parseProps: (props: any, self: any, path: string, info: IInfo) => any; __initDebug: () => void; - __debug: (msg: string) => void; + __debug: (...args: any[]) => void; __renderContextProvider: (customProps?: object, children?: any) => any; __renderContextConsumer: (children: any) => any; __renderContent: (children: any) => any; diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 928ddbfd8..78bead5ac 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -202,8 +202,8 @@ export function getI18n(key: string, values = {}, locale = 'zh-CN', messages = { * 判断当前组件是否能够设置ref * @param {*} Comp 需要判断的组件 */ -export function acceptsRef(Comp: any) { - return Comp?.$$typeof === REACT_FORWARD_REF_TYPE || Comp?.prototype?.isReactComponent || Comp?.prototype?.setState; +export function canAcceptsRef(Comp: any) { + return Comp?.$$typeof === REACT_FORWARD_REF_TYPE || Comp?.prototype?.isReactComponent || Comp?.prototype?.setState || Comp._forwardRef; } /** diff --git a/packages/renderer-core/src/utils/logger.ts b/packages/renderer-core/src/utils/logger.ts new file mode 100644 index 000000000..1feb9f6c8 --- /dev/null +++ b/packages/renderer-core/src/utils/logger.ts @@ -0,0 +1,2 @@ +import Logger from 'zen-logger'; +export default new Logger({ level: 'warn', bizName: 'renderer' }); \ No newline at end of file diff --git a/packages/utils/src/clone-enumerable-property.ts b/packages/utils/src/clone-enumerable-property.ts new file mode 100644 index 000000000..414f8dccd --- /dev/null +++ b/packages/utils/src/clone-enumerable-property.ts @@ -0,0 +1,22 @@ +const excludePropertyNames = [ + '$$typeof', + 'render', + 'defaultProps', + 'props', + 'length', + 'prototype', + 'name', + 'caller', + 'callee', + 'arguments', +]; + +export function cloneEnumerableProperty(target: any, origin: any) { + const compExtraPropertyNames = Object.keys(origin).filter(d => !excludePropertyNames.includes(d)); + + compExtraPropertyNames.forEach((d: string) => { + (target as any)[d] = origin[d]; + }); + + return target; +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 891c1c54f..087591d99 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -23,3 +23,4 @@ export * from './app-helper'; export * from './misc'; export * from './schema'; export * from './node-helper'; +export * from './clone-enumerable-property'; diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index 7261b6a07..02ef50fa6 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -1,4 +1,5 @@ import { ComponentClass, Component, FunctionComponent, ComponentType, createElement } from 'react'; +import { cloneEnumerableProperty } from './clone-enumerable-property'; const hasSymbol = typeof Symbol === 'function' && Symbol.for; const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; @@ -20,11 +21,12 @@ export function isReactComponent(obj: any): obj is ComponentType { } export function wrapReactClass(view: FunctionComponent) { - const ViewComponentClass = class extends Component { + let ViewComponentClass = class extends Component { render() { return createElement(view, this.props); } } as any; + ViewComponentClass = cloneEnumerableProperty(ViewComponentClass, view); ViewComponentClass.displayName = view.displayName; return ViewComponentClass; } diff --git a/packages/vision-polyfill/src/bundle/upgrade-metadata.ts b/packages/vision-polyfill/src/bundle/upgrade-metadata.ts index 89487ac73..953e85062 100644 --- a/packages/vision-polyfill/src/bundle/upgrade-metadata.ts +++ b/packages/vision-polyfill/src/bundle/upgrade-metadata.ts @@ -718,7 +718,6 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) { docUrl, devMode: devMode || 'procode', schema: schema?.componentsTree[0], - // isMinimalRenderUnit, }; if (category) {