debug start

This commit is contained in:
kangwei 2020-02-18 05:14:12 +08:00
parent a127fc8d5f
commit 5f0ac69595
13 changed files with 127 additions and 74 deletions

View File

@ -1,7 +1,7 @@
// NOTE: 仅用作类型标注,切勿作为实体使用 // NOTE: 仅用作类型标注,切勿作为实体使用
import { SimulatorRenderer } from '../renderer/renderer'; import { SimulatorRenderer } from '../renderer/renderer';
import { SimulatorHost } from './host'; import { SimulatorHost } from './host';
import { AssetLevel, AssetList, isAssetBundle, isAssetItem, isCSSUrl, AssetType, assetItem } from '../utils/asset'; import { AssetLevel, AssetLevels, AssetList, isAssetBundle, isAssetItem, isCSSUrl, AssetType, assetItem } from '../utils/asset';
export function createSimulator(host: SimulatorHost, iframe: HTMLIFrameElement, vendors: AssetList = []): Promise<SimulatorRenderer> { export function createSimulator(host: SimulatorHost, iframe: HTMLIFrameElement, vendors: AssetList = []): Promise<SimulatorRenderer> {
const win: any = iframe.contentWindow; const win: any = iframe.contentWindow;
@ -11,10 +11,9 @@ export function createSimulator(host: SimulatorHost, iframe: HTMLIFrameElement,
const styles: any = {}; const styles: any = {};
const scripts: any = {}; const scripts: any = {};
Object.keys(AssetLevel).forEach((key) => { AssetLevels.forEach((lv) => {
const v = (AssetLevel as any)[key]; styles[lv] = [];
styles[v] = []; scripts[lv] = [];
scripts[v] = [];
}); });
function parseAssetList(assets: AssetList, level?: AssetLevel) { function parseAssetList(assets: AssetList, level?: AssetLevel) {
@ -37,13 +36,13 @@ export function createSimulator(host: SimulatorHost, iframe: HTMLIFrameElement,
} }
const id = asset.id ? ` data-id="${asset.id}"` : ''; const id = asset.id ? ` data-id="${asset.id}"` : '';
const lv = asset.level || level || AssetLevel.BaseDepends; const lv = asset.level || level || AssetLevel.BaseDepends;
if (asset.type === 'jsUrl') { if (asset.type === AssetType.JSUrl) {
(scripts[lv] || scripts[AssetLevel.App]).push(`<script src="${asset.content}"${id}></script>`) (scripts[lv] || scripts[AssetLevel.App]).push(`<script src="${asset.content}"${id}></script>`)
} else if (asset.type === 'jsText') { } else if (asset.type === AssetType.JSText) {
(scripts[lv] || scripts[AssetLevel.App]).push(`<script${id}>${asset.content}</script>`); (scripts[lv] || scripts[AssetLevel.App]).push(`<script${id}>${asset.content}</script>`);
} else if (asset.type === 'cssUrl') { } else if (asset.type === AssetType.CSSUrl) {
(styles[lv] || styles[AssetLevel.App]).push(`<link rel="stylesheet" href="${asset.content}"${id} />`); (styles[lv] || styles[AssetLevel.App]).push(`<link rel="stylesheet" href="${asset.content}"${id} />`);
} else if (asset.type === 'cssText') { } else if (asset.type === AssetType.CSSText) {
(styles[lv] || styles[AssetLevel.App]).push(`<style type="text/css"${id}>${asset.content}</style>`); (styles[lv] || styles[AssetLevel.App]).push(`<style type="text/css"${id}>${asset.content}</style>`);
} }
} }
@ -53,10 +52,10 @@ export function createSimulator(host: SimulatorHost, iframe: HTMLIFrameElement,
const styleFrags = Object.keys(styles).map(key => { const styleFrags = Object.keys(styles).map(key => {
return styles[key].join('\n') + `<meta level="${key}" />`; return styles[key].join('\n') + `<meta level="${key}" />`;
}); }).join('');
const scriptFrags = Object.keys(scripts).map(key => { const scriptFrags = Object.keys(scripts).map(key => {
return styles[key].join('\n') + `<meta level="${key}" />`; return scripts[key].join('\n');
}); }).join('');
doc.open(); doc.open();
doc.write(`<!doctype html><html><head><meta charset="utf-8"/> doc.write(`<!doctype html><html><head><meta charset="utf-8"/>

View File

@ -25,6 +25,7 @@ export class SimulatorHostView extends Component<SimulatorProps & {
super(props); super(props);
const { documentContext } = this.props; const { documentContext } = this.props;
this.host = (documentContext.simulator as SimulatorHost) || new SimulatorHost(documentContext); this.host = (documentContext.simulator as SimulatorHost) || new SimulatorHost(documentContext);
this.host.setProps(this.props);
} }
shouldComponentUpdate(nextProps: SimulatorProps) { shouldComponentUpdate(nextProps: SimulatorProps) {
this.host.setProps(nextProps); this.host.setProps(nextProps);

View File

@ -6,7 +6,7 @@ import { SimulatorRenderer } from '../renderer/renderer';
import Node, { NodeParent } from '../../../designer/document/node/node'; import Node, { NodeParent } from '../../../designer/document/node/node';
import DocumentModel from '../../../designer/document/document-model'; import DocumentModel from '../../../designer/document/document-model';
import ResourceConsumer from './resource-consumer'; import ResourceConsumer from './resource-consumer';
import { AssetLevel, Asset, assetBundle } from '../utils/asset'; import { AssetLevel, Asset, assetBundle, assetItem, AssetType } from '../utils/asset';
import { DragObjectType, isShaken, LocateEvent, DragNodeObject, DragNodeDataObject } from '../../../designer/dragon'; import { DragObjectType, isShaken, LocateEvent, DragNodeObject, DragNodeDataObject } from '../../../designer/dragon';
import { LocationData } from '../../../designer/location'; import { LocationData } from '../../../designer/location';
import { NodeData } from '../../../designer/schema'; import { NodeData } from '../../../designer/schema';
@ -32,23 +32,19 @@ const defaultSimulatorUrl = (() => {
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
urls = [`${publicPath}simulator-renderer.min.css`, `${publicPath}simulator-renderer.min.js`]; urls = [`${publicPath}simulator-renderer.min.css`, `${publicPath}simulator-renderer.min.js`];
} else { } else {
urls = [`${publicPath}simulator-renderer.js`]; urls = [`${publicPath}simulator-renderer.css`, `${publicPath}simulator-renderer.js`];
} }
return urls; return urls;
})(); })();
const defaultDepends = [ const defaultDepends = [
{ // https://g.alicdn.com/mylib/??react/16.11.0/umd/react.production.min.js,react-dom/16.8.6/umd/react-dom.production.min.js,prop-types/15.7.2/prop-types.min.js
type: 'jsUrl', assetItem(AssetType.JSText, 'window.React=parent.React;window.ReactDOM=parent.ReactDOM;', undefined, 'react'),
content: assetItem(
'https://g.alicdn.com/mylib/??react/16.11.0/umd/react.production.min.js,react-dom/16.8.6/umd/react-dom.production.min.js,prop-types/15.7.2/prop-types.min.js', AssetType.JSText,
id: 'rect', 'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',
}, ),
{ assetItem(AssetType.JSUrl, 'http://localhost:4444/js/index.js'),
type: 'jsText',
content:
'React.PropTypes=window.PropTypes;window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',
},
]; ];
export class SimulatorHost implements ISimulator<SimulatorProps> { export class SimulatorHost implements ISimulator<SimulatorProps> {
@ -138,15 +134,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
return this._renderer; return this._renderer;
} }
readonly componentsConsumer = new ResourceConsumer<{ readonly componentsConsumer = new ResourceConsumer<Asset | undefined>(() => this.componentsAsset);
componentsAsset?: Asset;
componentsMap: object;
}>(() => {
return {
componentsAsset: this.componentsAsset,
componentsMap: this.componentsMap,
};
});
readonly injectionConsumer = new ResourceConsumer(() => { readonly injectionConsumer = new ResourceConsumer(() => {
return {}; return {};
@ -350,8 +338,8 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
getClosestNodeId(elem: Element): string { getClosestNodeId(elem: Element): string | null {
throw new Error('Method not implemented.'); return this.renderer?.getClosestNodeId(elem) || null;
} }
findDOMNodes(instance: ComponentInstance): (Element | Text)[] | null { findDOMNodes(instance: ComponentInstance): (Element | Text)[] | null {

View File

@ -58,7 +58,11 @@ export default class ResourceConsumer<T = any> {
} }
await consumer(this._data); await consumer(this._data);
// TODO: catch error and report // TODO: catch error and report
this.emitter.emit('consume'); if (this.resovleFirst) {
this.resovleFirst();
} else {
this._firstConsumed = true;
}
}); });
} }
@ -72,9 +76,15 @@ export default class ResourceConsumer<T = any> {
this.emitter.removeAllListeners(); this.emitter.removeAllListeners();
} }
private _firstConsumed: boolean = false;
private resovleFirst?: () => void;
waitFirstConsume(): Promise<any> { waitFirstConsume(): Promise<any> {
if (this._firstConsumed) {
return Promise.resolve();
}
return new Promise((resolve) => { return new Promise((resolve) => {
this.emitter.once('consume', resolve); this.resovleFirst = resolve;
}); });
} }
} }

View File

@ -1,4 +1,4 @@
// import { Engine as LowCodeRenderer } from '@ali/iceluna-sdk'; import LowCodeRenderer from '@ali/iceluna-sdk';
import { ReactInstance, Fragment, Component } from 'react'; import { ReactInstance, Fragment, Component } from 'react';
import { observer } from '@recore/core-obx'; import { observer } from '@recore/core-obx';
import { SimulatorRenderer } from './renderer'; import { SimulatorRenderer } from './renderer';
@ -50,20 +50,21 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> {
componentsMap={renderer.componentsMap} componentsMap={renderer.componentsMap}
suspended={renderer.suspended} suspended={renderer.suspended}
self={renderer.scope} self={renderer.scope}
onComponentGetRef={(schema: any, ref: ReactInstance | null) => { onCompGetRef={(schema: any, ref: ReactInstance | null) => {
renderer.mountInstance(schema.id, ref); renderer.mountInstance(schema.id, ref);
}} }}
onComponentGetCtx={(schema: any, ctx: object) => { //onCompGetCtx={(schema: any, ctx: object) => {
renderer.mountContext(schema.id, ctx); // renderer.mountContext(schema.id, ctx);
}} //}}
/> />
); );
} }
} }
/*
class LowCodeRenderer extends Component<any> { class LowCodeRenderer extends Component<any> {
render() { render() {
const { schema } = this.props;
return <div>{JSON.stringify(this.props.schema)}</div> return <div>{JSON.stringify(this.props.schema)}</div>
} }
} }*/

View File

@ -67,6 +67,9 @@ export class SimulatorRenderer {
// sync schema // sync schema
this._schema = host.document.schema; this._schema = host.document.schema;
this._componentsMap = host.designer.componentsMap;
this.buildComponents();
// sync designMode // sync designMode
// sync suspended // sync suspended
@ -75,13 +78,11 @@ export class SimulatorRenderer {
// sync device // sync device
}); });
host.componentsConsumer.consume(async (data) => { host.componentsConsumer.consume(async (componentsAsset) => {
if (data.componentsAsset) { if (componentsAsset) {
await this.load(data.componentsAsset); await this.load(componentsAsset);
this.buildComponents();
} }
// sync componetsMap
this._componentsMap = data.componentsMap;
}); });
host.injectionConsumer.consume((data) => { host.injectionConsumer.consume((data) => {
// sync utils, i18n, contants,... config // sync utils, i18n, contants,... config
@ -103,11 +104,14 @@ export class SimulatorRenderer {
@computed get schema(): any { @computed get schema(): any {
return this._schema; return this._schema;
} }
@obx.ref private _componentsMap = {}; private buildComponents() {
this._components = buildComponents(this._componentsMap);
}
@obx.ref private _components = {};
@computed get components(): object { @computed get components(): object {
// 根据 device 选择不同组件,进行响应式 // 根据 device 选择不同组件,进行响应式
// 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl
return buildComponents(this._componentsMap); return this._components;
} }
// context from: utils、constants、history、location、match // context from: utils、constants、history、location、match
@obx.ref private _appContext = {}; @obx.ref private _appContext = {};
@ -118,6 +122,7 @@ export class SimulatorRenderer {
@computed get designMode(): any { @computed get designMode(): any {
return 'border'; return 'border';
} }
@obx.ref private _componentsMap = {};
@computed get componentsMap(): any { @computed get componentsMap(): any {
return this._componentsMap; return this._componentsMap;
} }

View File

@ -20,6 +20,15 @@ export enum AssetLevel {
App = 6, App = 6,
} }
export const AssetLevels = [
AssetLevel.BaseDepends,
AssetLevel.BaseComponents,
AssetLevel.Theme,
AssetLevel.Runtime,
AssetLevel.Components,
AssetLevel.App,
];
export type URL = string; export type URL = string;
export enum AssetType { export enum AssetType {
@ -27,7 +36,7 @@ export enum AssetType {
CSSUrl = 'cssUrl', CSSUrl = 'cssUrl',
CSSText = 'cssText', CSSText = 'cssText',
JSText = 'jsText', JSText = 'jsText',
Bundle = 'bundel', Bundle = 'bundle',
} }
export interface AssetBundle { export interface AssetBundle {
@ -64,7 +73,7 @@ export function assetBundle(assets?: Asset | AssetList | null, level?: AssetLeve
} }
export function assetItem(type: AssetType, content?: string | null, level?: AssetLevel, id?: string): AssetItem | null { export function assetItem(type: AssetType, content?: string | null, level?: AssetLevel, id?: string): AssetItem | null {
if (content) { if (!content) {
return null; return null;
} }
return { return {

View File

@ -1,6 +1,6 @@
import { load, evaluate } from './script'; import { load, evaluate } from './script';
import StylePoint from './style'; import StylePoint from './style';
import { Asset, AssetLevel, AssetType, AssetList, isAssetBundle, isAssetItem, assetItem, isCSSUrl, AssetItem } from './asset'; import { Asset, AssetLevel, AssetLevels, AssetType, AssetList, isAssetBundle, isAssetItem, assetItem, isCSSUrl, AssetItem } from './asset';
function parseAssetList(scripts: any, styles: any, assets: AssetList, level?: AssetLevel) { function parseAssetList(scripts: any, styles: any, assets: AssetList, level?: AssetLevel) {
for (let asset of assets) { for (let asset of assets) {
@ -50,10 +50,9 @@ export class AssetLoader {
async load(asset: Asset) { async load(asset: Asset) {
const styles: any = {}; const styles: any = {};
const scripts: any = {}; const scripts: any = {};
Object.keys(AssetLevel).forEach((key) => { AssetLevels.forEach((lv) => {
const v = (AssetLevel as any)[key]; styles[lv] = [];
styles[v] = []; scripts[lv] = [];
scripts[v] = [];
}); });
parseAsset(scripts, styles, asset); parseAsset(scripts, styles, asset);
const styleQueue: AssetItem[] = styles[AssetLevel.BaseDepends].concat( const styleQueue: AssetItem[] = styles[AssetLevel.BaseDepends].concat(

View File

@ -0,0 +1,28 @@
.lc-designer {
position: relative;
min-width: 500px;
min-height: 500px;
.lc-project {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
.lc-document {
width: 100%;
height: 100%;
&&-hidden {
// todo:
display: none;
}
.lc-simulator-shell {
width: 100%;
height: 100%;
}
}
}
}

View File

@ -93,7 +93,7 @@ export default class Node {
this._directives = new Props(this, {}); this._directives = new Props(this, {});
Object.keys(extras).forEach(key => { Object.keys(extras).forEach(key => {
if (DIRECTIVES.indexOf(key) > -1) { if (DIRECTIVES.indexOf(key) > -1) {
this.directives!.add((extras as any)[key], key); this._directives!.add((extras as any)[key], key);
delete (extras as any)[key]; delete (extras as any)[key];
} }
}); });
@ -295,9 +295,9 @@ export default class Node {
// TODO... // TODO...
const schema: any = { const schema: any = {
componentName: this.componentName, componentName: this.componentName,
...this.extras, ...this.extras?.value,
props: this.props, props: this.props?.value || {},
...this.directives, ...this.directives?.value,
}; };
if (serialize) { if (serialize) {
schema.id = this.id; schema.id = this.id;

View File

@ -65,9 +65,10 @@ export default class Props<O = any> implements IPropParent {
constructor(readonly owner: O, value?: PropsMap | PropsList | null) { constructor(readonly owner: O, value?: PropsMap | PropsList | null) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
this.type = 'list'; this.type = 'list';
value.forEach(item => {}); this.items = value.map(item => new Prop(this, item.value, item.name, item.spread));
} else if (value != null) { } else if (value != null) {
this.type = 'map'; this.type = 'map';
this.items = Object.keys(value).map(key => new Prop(this, value[key], key));
} }
} }

View File

@ -35,12 +35,24 @@ import Props from './props/props';
*/ */
export default class RootNode extends Node implements NodeParent { export default class RootNode extends Node implements NodeParent {
readonly isRootNode = true; readonly isRootNode = true;
readonly isNodeParent = true; get isNodeParent() {
readonly index = 0; return true;
readonly nextSibling = null; }
readonly prevSibling = null; get index() {
readonly zLevel = 0; return 0;
readonly parent = null; }
get nextSibling() {
return null
}
get prevSibling() {
return null
}
get zLevel() {
return 0;
}
get parent() {
return null
}
get children(): NodeChildren { get children(): NodeChildren {
return this._children as NodeChildren; return this._children as NodeChildren;
} }
@ -51,7 +63,7 @@ export default class RootNode extends Node implements NodeParent {
return this._extras as any; return this._extras as any;
} }
get directives(): Props<RootNode> { get directives(): Props<RootNode> {
return this._props as any; return this._directives as any;
} }
internalSetParent(parent: null) {} internalSetParent(parent: null) {}

View File

@ -132,9 +132,9 @@ export interface ISimulator<P = object> extends ISensor {
/** /**
* *
*/ */
getComponentContext(node: Node): object; getComponentContext(node: Node): object | null;
getClosestNodeId(elem: Element): string; getClosestNodeId(elem: Element): string | null;
findDOMNodes(instance: ComponentInstance): Array<Element | Text> | null; findDOMNodes(instance: ComponentInstance): Array<Element | Text> | null;