Skip to content

Commit 03f7c76

Browse files
committed
feat: add router
1 parent fb5de64 commit 03f7c76

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1143
-1426
lines changed

docs/docs/specs/lowcode-spec.md

-1
Original file line numberDiff line numberDiff line change
@@ -1513,7 +1513,6 @@ webpack.config.js # 项目工程配置,包含插件配置及自定义 webpack
15131513
| -------------- | ---------------------------------- | ------ | ------ | ------ | ---------------------------------------------- |
15141514
| path | 当前解析后的路径 | String | - | - | 必填 |
15151515
| hash | 当前路径的 hash 值,以 # 开头 | String | - | - | 必填 |
1516-
| href | 当前的全部路径 | String | - | - | 必填 |
15171516
| params | 匹配到的路径参数 | Object | - | - | 必填 |
15181517
| query | 当前的路径 query 对象 | Object | - | - | 必填,代表当前地址的 search 属性的对象 |
15191518
| name | 匹配到的路由记录名 | String | - | - | 选填 |

runtime/renderer-core/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
"bugs": "https://github.com/alibaba/lowcode-engine/issues",
77
"homepage": "https://github.com/alibaba/lowcode-engine/#readme",
88
"license": "MIT",
9+
"module": "./dist/index.js",
10+
"types": "./dist/index.d.ts",
911
"scripts": {
10-
"build": "",
12+
"build": "tsc",
1113
"test": "vitest --run",
1214
"test:watch": "vitest"
1315
},

runtime/renderer-core/src/api/app.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface AppBase {
2222
*/
2323
export interface AppContext {
2424
schema: AppSchema;
25-
config: Map<string, any>;
25+
config: PlainObject;
2626
appScope: CodeScope;
2727
packageManager: PackageManager;
2828
boosts: AppBoostsManager;
@@ -35,14 +35,14 @@ type AppCreator<O, T extends AppBase> = (
3535

3636
export type App<T extends AppBase = AppBase> = {
3737
schema: Project;
38-
config: Map<string, any>;
38+
config: PlainObject;
3939
readonly boosts: AppBoosts;
4040

4141
use(plugin: Plugin): Promise<void>;
4242
} & T;
4343

4444
/**
45-
* 创建应用
45+
* 创建 createApp 的辅助函数
4646
* @param schema
4747
* @param options
4848
* @returns
@@ -55,9 +55,9 @@ export function createAppFunction<O extends AppOptionsBase, T extends AppBase =
5555
}
5656

5757
return async (options) => {
58-
const { schema, appScopeValue = {} } = options;
58+
const { schema, appScopeValue } = options;
5959
const appSchema = createAppSchema(schema);
60-
const appConfig = new Map<string, any>();
60+
const appConfig = {};
6161
const packageManager = createPackageManager();
6262
const appScope = createScope({
6363
...appScopeValue,

runtime/renderer-core/src/api/component.ts

+38-132
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,42 @@
1-
import { CreateContainerOptions, createContainer } from '../container';
2-
import { createCodeRuntime, createScope } from '../code-runtime';
3-
import { throwRuntimeError } from '../utils/error';
4-
import { validateContainerSchema } from '../validator/schema';
5-
6-
export interface ComponentOptionsBase<C> {
7-
componentsTree: RootSchema;
8-
componentsRecord: Record<string, C | Package>;
9-
dataSourceCreator: DataSourceCreator;
10-
}
11-
12-
export function createComponentFunction<C, O extends ComponentOptionsBase<C>>(options: {
13-
stateCreator: (initState: AnyObject) => StateContext;
14-
componentCreator: (container: Container, componentOptions: O) => C;
15-
defaultOptions?: Partial<O>;
16-
}): (componentOptions: O) => C {
17-
const { stateCreator, componentCreator, defaultOptions = {} } = options;
18-
1+
import { type CreateContainerOptions, createContainer, type Container } from '../container';
2+
import type { PlainObject, InstanceStateApi } from '../types';
3+
4+
export type CreateComponentBaseOptions<T extends string> = Omit<
5+
CreateContainerOptions<T>,
6+
'stateCreator'
7+
>;
8+
9+
/**
10+
* 创建 createComponent 的辅助函数
11+
* createComponent = createComponentFunction(() => component)
12+
*/
13+
export function createComponentFunction<
14+
ComponentT,
15+
InstanceT,
16+
LifeCycleNameT extends string,
17+
O extends CreateComponentBaseOptions<LifeCycleNameT>,
18+
>(
19+
stateCreator: (initState: PlainObject) => InstanceStateApi,
20+
componentCreator: (
21+
container: Container<InstanceT, LifeCycleNameT>,
22+
componentOptions: O,
23+
) => ComponentT,
24+
): (componentOptions: O) => ComponentT {
1925
return (componentOptions) => {
20-
const finalOptions = Object.assign({}, defaultOptions, componentOptions);
21-
const { supCodeScope, initScopeValue = {}, dataSourceCreator } = finalOptions;
22-
23-
const codeRuntimeScope =
24-
supCodeScope?.createSubScope(initScopeValue) ?? createScope(initScopeValue);
25-
const codeRuntime = createCodeRuntime(codeRuntimeScope);
26-
27-
const container: Container = {
28-
get codeScope() {
29-
return codeRuntimeScope;
30-
},
31-
get codeRuntime() {
32-
return codeRuntime;
33-
},
34-
35-
createInstance(componentsTree, extraProps = {}) {
36-
if (!validateContainerSchema(componentsTree)) {
37-
throwRuntimeError('createComponent', 'componentsTree is not valid!');
38-
}
39-
40-
const mapRefToComponentInstance: Map<string, C> = new Map();
41-
42-
const initialState = codeRuntime.parseExprOrFn(componentsTree.state ?? {});
43-
const stateContext = stateCreator(initialState);
44-
45-
codeRuntimeScope.setValue(
46-
Object.assign(
47-
{
48-
props: codeRuntime.parseExprOrFn({
49-
...componentsTree.defaultProps,
50-
...componentsTree.props,
51-
...extraProps,
52-
}),
53-
$(ref: string) {
54-
return mapRefToComponentInstance.get(ref);
55-
},
56-
},
57-
stateContext,
58-
dataSourceCreator
59-
? dataSourceCreator(componentsTree.dataSource ?? ({ list: [] } as any), stateContext)
60-
: {},
61-
) as ContainerInstanceScope<C>,
62-
true,
63-
);
64-
65-
if (componentsTree.methods) {
66-
for (const [key, fn] of Object.entries(componentsTree.methods)) {
67-
const customMethod = codeRuntime.createFnBoundScope(fn.value);
68-
if (customMethod) {
69-
codeRuntimeScope.inject(key, customMethod);
70-
}
71-
}
72-
}
73-
74-
triggerLifeCycle('constructor');
75-
76-
function triggerLifeCycle(lifeCycleName: LifeCycleNameT, ...args: any[]) {
77-
// keys 用来判断 lifeCycleName 存在于 schema 对象上,不获取原型链上的对象
78-
if (
79-
!componentsTree.lifeCycles ||
80-
!Object.keys(componentsTree.lifeCycles).includes(lifeCycleName)
81-
) {
82-
return;
83-
}
84-
85-
const lifeCycleSchema = componentsTree.lifeCycles[lifeCycleName];
86-
if (isJsFunction(lifeCycleSchema)) {
87-
const lifeCycleFn = codeRuntime.createFnBoundScope(lifeCycleSchema.value);
88-
if (lifeCycleFn) {
89-
lifeCycleFn.apply(codeRuntime.getScope().value, args);
90-
}
91-
}
92-
}
93-
94-
const instance: ContainerInstance<C> = {
95-
get id() {
96-
return componentsTree.id;
97-
},
98-
get cssText() {
99-
return componentsTree.css;
100-
},
101-
get codeScope() {
102-
return codeRuntimeScope;
103-
},
104-
105-
triggerLifeCycle,
106-
setRefInstance(ref, instance) {
107-
mapRefToComponentInstance.set(ref, instance);
108-
},
109-
removeRefInstance(ref) {
110-
mapRefToComponentInstance.delete(ref);
111-
},
112-
getComponentTreeNodes() {
113-
const childNodes = componentsTree.children
114-
? Array.isArray(componentsTree.children)
115-
? componentsTree.children
116-
: [componentsTree.children]
117-
: [];
118-
const treeNodes = childNodes.map((item) => {
119-
return createComponentTreeNode(item, undefined);
120-
});
121-
122-
return treeNodes;
123-
},
124-
125-
destory() {
126-
mapRefToComponentInstance.clear();
127-
codeRuntimeScope.setValue({});
128-
},
129-
};
130-
131-
return instance;
132-
},
133-
};
26+
const {
27+
supCodeScope,
28+
initScopeValue = {},
29+
dataSourceCreator,
30+
componentsTree,
31+
} = componentOptions;
32+
33+
const container = createContainer<InstanceT, LifeCycleNameT>({
34+
supCodeScope,
35+
initScopeValue,
36+
stateCreator,
37+
dataSourceCreator,
38+
componentsTree,
39+
});
13440

13541
return componentCreator(container, componentOptions);
13642
};

runtime/renderer-core/src/code-runtime.ts

+24-27
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,20 @@ export function createCodeRuntime(scopeOrValue: PlainObject = {}): CodeRuntime {
7676
};
7777
}
7878

79-
export interface CodeScope {
80-
readonly value: PlainObject;
79+
export interface CodeScope<T extends PlainObject = PlainObject, K extends keyof T = keyof T> {
80+
readonly value: T;
8181

82-
inject(name: string, value: any, force?: boolean): void;
83-
setValue(value: PlainObject, replace?: boolean): void;
84-
createSubScope(initValue?: PlainObject): CodeScope;
82+
inject(name: K, value: T[K], force?: boolean): void;
83+
setValue(value: T, replace?: boolean): void;
84+
createSubScope<O extends PlainObject = PlainObject>(initValue: O): CodeScope<T & O>;
8585
}
8686

87-
export function createScope(initValue: PlainObject = {}): CodeScope {
87+
export function createScope<T extends PlainObject = PlainObject, K extends keyof T = keyof T>(
88+
initValue: T,
89+
): CodeScope<T, K> {
8890
const innerScope = { value: initValue };
89-
const proxyValue = new Proxy(Object.create(null), {
91+
92+
const proxyValue: T = new Proxy(Object.create(null), {
9093
set(target, p, newValue, receiver) {
9194
return Reflect.set(target, p, newValue, receiver);
9295
},
@@ -104,37 +107,31 @@ export function createScope(initValue: PlainObject = {}): CodeScope {
104107
},
105108
});
106109

107-
function inject(name: string, value: any, force = false): void {
108-
if (innerScope.value[name] && !force) {
109-
console.warn(`${name} 已存在值`);
110-
return;
111-
}
112-
113-
innerScope.value[name] = value;
114-
}
115-
116-
function createSubScope(initValue: PlainObject = {}) {
117-
const childScope = createScope(initValue);
118-
119-
(childScope as any).__raw.__parent = innerScope;
120-
121-
return childScope;
122-
}
123-
124-
const scope: CodeScope = {
110+
const scope: CodeScope<T, K> = {
125111
get value() {
126112
// dev return value
127113
return proxyValue;
128114
},
129-
inject,
115+
inject(name, value, force = false): void {
116+
if (innerScope.value[name] && !force) {
117+
return;
118+
}
119+
innerScope.value[name] = value;
120+
},
130121
setValue(value, replace = false) {
131122
if (replace) {
132123
innerScope.value = { ...value };
133124
} else {
134125
innerScope.value = Object.assign({}, innerScope.value, value);
135126
}
136127
},
137-
createSubScope,
128+
createSubScope<O extends PlainObject = PlainObject>(initValue: O) {
129+
const childScope = createScope<O & T>(initValue);
130+
131+
(childScope as any).__raw.__parent = innerScope;
132+
133+
return childScope;
134+
},
138135
};
139136

140137
Object.defineProperty(scope, Symbol.for(SYMBOL_SIGN), { get: () => true });

runtime/renderer-core/src/container.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
ComponentTree,
55
InstanceDataSourceApi,
66
InstanceStateApi,
7+
NodeType,
78
} from './types';
89
import { type CodeScope, type CodeRuntime, createCodeRuntime, createScope } from './code-runtime';
910
import { isJSFunction } from './utils/type-guard';
@@ -48,7 +49,13 @@ export interface CreateContainerOptions<LifeCycleNameT extends string> {
4849
export function createContainer<InstanceT, LifeCycleNameT extends string>(
4950
options: CreateContainerOptions<LifeCycleNameT>,
5051
): Container<InstanceT, LifeCycleNameT> {
51-
const { componentsTree, supCodeScope, initScopeValue, stateCreator, dataSourceCreator } = options;
52+
const {
53+
componentsTree,
54+
supCodeScope,
55+
initScopeValue = {},
56+
stateCreator,
57+
dataSourceCreator,
58+
} = options;
5259

5360
validContainerSchema(componentsTree);
5461

@@ -151,7 +158,6 @@ export function createContainer<InstanceT, LifeCycleNameT extends string>(
151158

152159
createWidgets<Element>() {
153160
if (!componentsTree.children) return [];
154-
155161
return componentsTree.children.map((item) => createWidget<Element>(item));
156162
},
157163
};

runtime/renderer-core/src/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ export { createCodeRuntime, createScope } from './code-runtime';
55
export { definePlugin } from './plugin';
66
export { createWidget } from './widget';
77
export { createContainer } from './container';
8+
export { createHookStore, useEvent } from './utils/hook';
9+
export * from './utils/type-guard';
10+
export * from './utils/value';
11+
export * from './widget';
812

913
/* --------------- types ---------------- */
1014
export * from './types';
1115
export type { CodeRuntime, CodeScope } from './code-runtime';
1216
export type { Plugin, PluginSetupContext } from './plugin';
1317
export type { PackageManager, PackageLoader } from './package';
14-
export type { Container } from './container';
15-
export type { Widget, TextWidget, ComponentWidget } from './widget';
18+
export type { Container, CreateContainerOptions } from './container';

runtime/renderer-core/src/package.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ export interface PackageManager {
2424
/** 解析组件映射 */
2525
resolveComponentMaps(componentMaps: ComponentMap[]): void;
2626
/** 获取组件映射对象,key = componentName value = component */
27-
getComponentsNameRecord<C = unknown>(componentMaps?: ComponentMap[]): Record<string, C>;
27+
getComponentsNameRecord<C = unknown>(
28+
componentMaps?: ComponentMap[],
29+
): Record<string, C | LowCodeComponent>;
2830
/** 通过组件名获取对应的组件 */
29-
getComponent<C = unknown>(componentName: string): C | undefined;
31+
getComponent<C = unknown>(componentName: string): C | LowCodeComponent | undefined;
3032
/** 注册组件 */
3133
registerComponentByName(componentName: string, Component: unknown): void;
3234
}

0 commit comments

Comments
 (0)