add some assets

This commit is contained in:
kangwei 2020-03-16 03:05:21 +08:00
parent b9272d6bab
commit a44120df48
11 changed files with 1290 additions and 95 deletions

View File

@ -4,7 +4,11 @@ import { SimulatorHost } from './host';
import { AssetLevel, AssetLevels, AssetList, isAssetBundle, isAssetItem, AssetType, assetItem } from '../utils/asset';
import { isCSSUrl } from '../../../utils/is-css-url';
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 doc = iframe.contentDocument!;
@ -12,7 +16,7 @@ export function createSimulator(host: SimulatorHost, iframe: HTMLIFrameElement,
const styles: any = {};
const scripts: any = {};
AssetLevels.forEach((lv) => {
AssetLevels.forEach(lv => {
styles[lv] = [];
scripts[lv] = [];
});
@ -36,9 +40,9 @@ export function createSimulator(host: SimulatorHost, iframe: HTMLIFrameElement,
asset = assetItem(isCSSUrl(asset) ? AssetType.CSSUrl : AssetType.JSUrl, asset, level)!;
}
const id = asset.id ? ` data-id="${asset.id}"` : '';
const lv = asset.level || level || AssetLevel.BaseDepends;
const lv = asset.level || level || AssetLevel.Environment;
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 === AssetType.JSText) {
(scripts[lv] || scripts[AssetLevel.App]).push(`<script${id}>${asset.content}</script>`);
} else if (asset.type === AssetType.CSSUrl) {
@ -51,12 +55,16 @@ export function createSimulator(host: SimulatorHost, iframe: HTMLIFrameElement,
parseAssetList(vendors);
const styleFrags = Object.keys(styles).map(key => {
const styleFrags = Object.keys(styles)
.map(key => {
return styles[key].join('\n') + `<meta level="${key}" />`;
}).join('');
const scriptFrags = Object.keys(scripts).map(key => {
})
.join('');
const scriptFrags = Object.keys(scripts)
.map(key => {
return scripts[key].join('\n');
}).join('');
})
.join('');
doc.open();
doc.write(`<!doctype html><html><head><meta charset="utf-8"/>

View File

@ -6,7 +6,7 @@ import { SimulatorRenderer } from '../renderer/renderer';
import Node, { NodeParent, isNodeParent, isNode, contains } from '../../../designer/document/node/node';
import DocumentModel from '../../../designer/document/document-model';
import ResourceConsumer from './resource-consumer';
import { AssetLevel, Asset, assetBundle, assetItem, AssetType } from '../utils/asset';
import { AssetLevel, Asset, AssetList, assetBundle, assetItem, AssetType } from '../utils/asset';
import {
DragObjectType,
isShaken,
@ -34,6 +34,12 @@ import { ReactInstance } from 'react';
import { isRootNode } from '../../../designer/document/node/root-node';
import { parseProps } from '../utils/parse-props';
export interface LibraryItem {
package: string;
library: string;
urls: Asset;
}
export interface SimulatorProps {
// 从 documentModel 上获取
// suspended?: boolean;
@ -41,8 +47,9 @@ export interface SimulatorProps {
device?: 'mobile' | 'iphone' | string;
deviceClassName?: string;
simulatorUrl?: Asset;
dependsAsset?: Asset;
themesAsset?: Asset;
environment?: Asset;
library?: LibraryItem[];
theme?: Asset;
componentsAsset?: Asset;
[key: string]: any;
}
@ -59,14 +66,13 @@ const defaultSimulatorUrl = (() => {
return urls;
})();
const defaultDepends = [
const defaultEnvironment = [
// 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
assetItem(AssetType.JSText, 'window.React=parent.React;window.ReactDOM=parent.ReactDOM;', undefined, 'react'),
assetItem(
AssetType.JSText,
'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',
),
// assetItem(AssetType.JSUrl, 'https://g.alicdn.com/mylib/@ali/recore/1.5.7/umd/recore.min.js'),
assetItem(AssetType.JSUrl, '/statics/lowcode-renderer.js'),
];
@ -97,8 +103,8 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
return this.get('componentsAsset');
}
@computed get themesAsset(): Asset | undefined {
return this.get('themesAsset');
@computed get theme(): Asset | undefined {
return this.get('theme');
}
@computed get componentsMap() {
@ -166,6 +172,8 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
return {};
});
readonly libraryMap: { [key: string]: string } = {};
async mountContentFrame(iframe: HTMLIFrameElement | null) {
if (!iframe) {
return;
@ -173,11 +181,22 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
this._contentWindow = iframe.contentWindow!;
const library = this.get('library') as LibraryItem[];
const libraryAsset: AssetList = [];
if (library) {
library.forEach(item => {
this.libraryMap[item.package] = item.library;
libraryAsset.push(item.urls);
});
}
const vendors = [
// required & use once
assetBundle(this.get('dependsAsset') || defaultDepends, AssetLevel.BaseDepends),
assetBundle(this.get('environment') || defaultEnvironment, AssetLevel.Environment),
// required & use once
assetBundle(libraryAsset, AssetLevel.Library),
// required & TODO: think of update
assetBundle(this.themesAsset, AssetLevel.Theme),
assetBundle(this.theme, AssetLevel.Theme),
// required & use once
assetBundle(this.get('simulatorUrl') || defaultSimulatorUrl, AssetLevel.Runtime),
];

View File

@ -40,11 +40,11 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> {
}
render() {
const { renderer } = this.props;
const { components, schemas } = LowCodeRenderer.others;
// const { components, schemas } = LowCodeRenderer.others;
return (
<LowCodeRenderer
schema={renderer.schema}
components={components /*renderer.components*/}
components={renderer.components}
appHelper={renderer.context}
// context={renderer.context}
designMode={renderer.designMode}

View File

@ -27,8 +27,12 @@ export class SimulatorRenderer {
// sync schema
this._schema = host.document.schema;
// todo: split with others, not all should recompute
if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) {
this._libraryMap = host.libraryMap || {};
this._componentsMap = host.designer.componentsMap;
this.buildComponents();
}
// sync designMode
@ -64,8 +68,9 @@ export class SimulatorRenderer {
@computed get schema(): any {
return this._schema;
}
private _libraryMap: { [key: string]: string } = {};
private buildComponents() {
this._components = buildComponents(this._componentsMap);
this._components = buildComponents(this._libraryMap, this._componentsMap);
}
@obx.ref private _components: any = {};
@computed get components(): object {
@ -280,7 +285,7 @@ function getSubComponent(library: any, paths: string[]) {
return component;
}
function findComponent(componentName: string, npm?: NpmInfo) {
function findComponent(libraryMap: LibraryMap, componentName: string, npm?: NpmInfo) {
if (!npm) {
return accessLibrary(componentName);
}
@ -290,21 +295,26 @@ function findComponent(componentName: string, npm?: NpmInfo) {
// export { exportName as componentName } from package
// if exportName == null exportName === componentName;
// const componentName = exportName.subName, if exportName empty subName donot use
const libraryName = npm.exportName || npm.componentName || componentName;
const exportName = npm.exportName || npm.componentName || componentName;
const libraryName = libraryMap[npm.package] || exportName;
const library = accessLibrary(libraryName);
const paths = npm.exportName && npm.subName ? npm.subName.split('.') : [];
if (npm.destructuring) {
paths.unshift(libraryName);
paths.unshift(exportName);
} else if (isESModule(library)) {
paths.unshift('default');
}
return getSubComponent(library, paths);
}
function buildComponents(componentsMap: { [componentName: string]: NpmInfo }) {
export interface LibraryMap {
[key: string]: string;
}
function buildComponents(libraryMap: LibraryMap, componentsMap: { [componentName: string]: NpmInfo }) {
const components: any = {};
Object.keys(componentsMap).forEach(componentName => {
components[componentName] = findComponent(componentName, componentsMap[componentName]);
components[componentName] = findComponent(libraryMap, componentName, componentsMap[componentName]);
});
return components;
}

View File

@ -6,11 +6,11 @@ export interface AssetItem {
}
export enum AssetLevel {
// 基础依赖库
BaseDepends = 1,
// 基础组件库
BaseComponents = 2,
// 主题
// 环境依赖库 比如 react, react-dom
Environment = 1,
// 基础类库,比如 lodash deep fusion antd
Library = 2,
// 主题
Theme = 3,
// 运行时
Runtime = 4,
@ -21,8 +21,8 @@ export enum AssetLevel {
}
export const AssetLevels = [
AssetLevel.BaseDepends,
AssetLevel.BaseComponents,
AssetLevel.Environment,
AssetLevel.Library,
AssetLevel.Theme,
AssetLevel.Runtime,
AssetLevel.Components,

View File

@ -1,10 +1,20 @@
import { load, evaluate } from './script';
import StylePoint from './style';
import { Asset, AssetLevel, AssetLevels, AssetType, AssetList, isAssetBundle, isAssetItem, assetItem, AssetItem } from './asset';
import {
Asset,
AssetLevel,
AssetLevels,
AssetType,
AssetList,
isAssetBundle,
isAssetItem,
assetItem,
AssetItem,
} from './asset';
import { isCSSUrl } from '../../../utils/is-css-url';
function parseAssetList(scripts: any, styles: any, assets: AssetList, level?: AssetLevel) {
for (let asset of assets) {
for (const asset of assets) {
parseAsset(scripts, styles, asset, level);
}
}
@ -36,7 +46,7 @@ function parseAsset(scripts: any, styles: any, asset: Asset | undefined | null,
let lv = asset.level || level;
if (!lv || AssetLevel[lv] == null) {
lv = AssetLevel.App
lv = AssetLevel.App;
}
asset.level = lv;
@ -51,19 +61,19 @@ export class AssetLoader {
async load(asset: Asset) {
const styles: any = {};
const scripts: any = {};
AssetLevels.forEach((lv) => {
AssetLevels.forEach(lv => {
styles[lv] = [];
scripts[lv] = [];
});
parseAsset(scripts, styles, asset);
const styleQueue: AssetItem[] = styles[AssetLevel.BaseDepends].concat(
styles[AssetLevel.BaseComponents],
const styleQueue: AssetItem[] = styles[AssetLevel.Environment].concat(
styles[AssetLevel.Library],
styles[AssetLevel.Theme],
styles[AssetLevel.Runtime],
styles[AssetLevel.App],
);
const scriptQueue: AssetItem[] = scripts[AssetLevel.BaseDepends].concat(
scripts[AssetLevel.BaseComponents],
const scriptQueue: AssetItem[] = scripts[AssetLevel.Environment].concat(
scripts[AssetLevel.Library],
scripts[AssetLevel.Theme],
scripts[AssetLevel.Runtime],
scripts[AssetLevel.App],
@ -71,9 +81,7 @@ export class AssetLoader {
await Promise.all(
styleQueue.map(({ content, level, type, id }) => this.loadStyle(content, level!, type === AssetType.CSSUrl, id)),
);
await Promise.all(
scriptQueue.map(({ content, type }) => this.loadScript(content, type === AssetType.JSUrl)),
);
await Promise.all(scriptQueue.map(({ content, type }) => this.loadScript(content, type === AssetType.JSUrl)));
}
private stylePoints = new Map<string, StylePoint>();

View File

@ -330,7 +330,7 @@ export default class Designer {
return meta;
}
get componentsMap(): { [key: string]: NpmInfo } {
@computed get componentsMap(): { [key: string]: NpmInfo } {
const maps: any = {};
this._componentMetasMap.forEach((config, key) => {
maps[key] = config.metadata.npm;

View File

@ -325,7 +325,7 @@ export default class Node {
*/
export(serialize = false): NodeSchema {
const baseSchema: any = {
componentName: this.componentName,
componentName: this.componentName === 'Leaf' ? 'Fragment' : this.componentName,
};
if (serialize) {
@ -334,10 +334,11 @@ export default class Node {
if (!isNodeParent(this)) {
baseSchema.children = this.props.get('children')?.export(serialize);
return baseSchema;
// FIXME!
return baseSchema.children;
}
const { props, extras } = this.props.export(serialize) || {};
const { props = {}, extras } = this.props.export(serialize) || {};
const schema: any = {
...baseSchema,
props,

View File

@ -33,22 +33,24 @@ export default {
propType: 'string'
}
],
configure: {
},
'Button.Group': {
componentName: 'Button.Group',
title: '按钮组',
devMode: 'proCode',
npm: {
package: '@alifd/next',
version: '1.19.18',
destructuring: true,
exportName: 'Button',
subName: 'Group'
},
props: [
{
name: 'type',
setter: {
componentName: 'Input'
}
},
{
name: 'children',
setter: {
componentName: 'Input'
}
}
]
name: 'size',
propType: 'string'
}
],
},
Input: {
componentName: 'Input',
@ -66,16 +68,91 @@ export default {
propType: 'string'
}
],
configure: {
},
Form: {
componentName: 'Form',
title: '表单容器',
devMode: 'proCode',
npm: {
package: '@alifd/next',
version: '1.19.18',
destructuring: true,
exportName: 'Form'
},
props: [
{
name: 'device',
propType: 'string'
}
],
},
'Form.Item': {
componentName: 'Form.Item',
title: '表单项',
devMode: 'proCode',
npm: {
package: '@alifd/next',
version: '1.19.18',
destructuring: true,
exportName: 'Form',
subName: 'Item'
},
props: [
{
name: 'label',
propType: 'string',
},
{
name: 'device',
propType: 'string'
}
],
},
NumberPicker: {
componentName: 'NumberPicker',
title: '数字输入',
devMode: 'proCode',
npm: {
package: '@alifd/next',
version: '1.19.18',
destructuring: true,
exportName: 'NumberPicker',
},
props: [
{
name: 'size',
propType: 'string',
},
{
name: 'defaultValue',
propType: 'number'
}
],
},
Select: {
componentName: 'Select',
title: '下拉',
devMode: 'proCode',
npm: {
package: '@alifd/next',
version: '1.19.18',
destructuring: true,
exportName: 'Select',
},
props: [
{
name: 'size',
propType: 'string',
},
{
name: 'defaultValue',
propType: 'number'
},
{
name: 'placeholder',
setter: {
componentName: 'Input'
}
}
]
propType: 'string'
}
],
}
},
componentList: [

View File

@ -6,6 +6,8 @@ import { PluginConfig } from '../../framework/definitions';
// @ts-ignore
import Designer from '../../../../designer';
import assets from '../../config/assets';
import './index.scss';
export interface PluginProps {
@ -53,7 +55,7 @@ const SCHEMA = {
},
children: [
{
componentName: 'FormItem',
componentName: 'Form.Item',
props: {
label: '姓名:',
name: 'name',
@ -73,7 +75,7 @@ const SCHEMA = {
]
},
{
componentName: 'FormItem',
componentName: 'Form.Item',
props: {
label: '年龄:',
name: 'age',
@ -90,7 +92,7 @@ const SCHEMA = {
]
},
{
componentName: 'FormItem',
componentName: 'Form.Item',
props: {
label: '职业:',
name: 'profession'
@ -126,7 +128,7 @@ const SCHEMA = {
},
children: [
{
componentName: 'ButtonGroup',
componentName: 'Button.Group',
props: {},
children: [
{
@ -179,21 +181,9 @@ export default class DesignerPlugin extends PureComponent<PluginProps> {
className="lowcode-plugin-designer"
defaultSchema={SCHEMA as any}
eventPipe={editor as any}
componentsDescription={Object.values(assets.components) as any}
simulatorProps={{
componentsAsset: [
{
type: 'jsUrl',
content: 'https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js',
id: 'next',
level: 2
},
{
type: 'cssUrl',
content: 'https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.css',
id: 'next',
level: 2
}
]
library: Object.values(assets.packages),
}}
/>
);

File diff suppressed because it is too large Load Diff