fix: 🐛 bugs about deps

This commit is contained in:
春希 2020-07-21 13:38:02 +08:00
parent 84da70d9db
commit 1eabd506e3
7 changed files with 70 additions and 36 deletions

View File

@ -6,6 +6,7 @@
import { SUPPORT_SCHEMA_VERSION_LIST } from '../const'; import { SUPPORT_SCHEMA_VERSION_LIST } from '../const';
import { handleChildren } from '../utils/nodeToJSX'; import { handleChildren } from '../utils/nodeToJSX';
import { uniqueArray } from '../utils/common';
import { import {
ChildNodeType, ChildNodeType,
@ -24,6 +25,7 @@ import {
IProjectSchema, IProjectSchema,
ISchemaParser, ISchemaParser,
IUtilItem, IUtilItem,
INpmPackage,
} from '../types'; } from '../types';
const defaultContainer: IContainerInfo = { const defaultContainer: IContainerInfo = {
@ -36,17 +38,15 @@ const defaultContainer: IContainerInfo = {
}; };
class SchemaParser implements ISchemaParser { class SchemaParser implements ISchemaParser {
public validate(schema: IBasicSchema): boolean { validate(schema: IBasicSchema): boolean {
if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) { if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) {
throw new CompatibilityError( throw new CompatibilityError(`Not support schema with version [${schema.version}]`);
`Not support schema with version [${schema.version}]`,
);
} }
return true; return true;
} }
public parse(schemaSrc: IProjectSchema | string): IParseResult { parse(schemaSrc: IProjectSchema | string): IParseResult {
// TODO: collect utils depends in JSExpression // TODO: collect utils depends in JSExpression
const compDeps: Record<string, IExternalDependency> = {}; const compDeps: Record<string, IExternalDependency> = {};
const internalDeps: Record<string, IInternalDependency> = {}; const internalDeps: Record<string, IInternalDependency> = {};
@ -64,7 +64,7 @@ class SchemaParser implements ISchemaParser {
} }
// 解析三方组件依赖 // 解析三方组件依赖
schema.componentsMap.forEach(info => { schema.componentsMap.forEach((info) => {
info.dependencyType = DependencyType.External; info.dependencyType = DependencyType.External;
info.importName = info.componentName; info.importName = info.componentName;
compDeps[info.componentName] = info; compDeps[info.componentName] = info;
@ -73,8 +73,7 @@ class SchemaParser implements ISchemaParser {
let containers: IContainerInfo[]; let containers: IContainerInfo[];
// Test if this is a lowcode component without container // Test if this is a lowcode component without container
if (schema.componentsTree.length > 0) { if (schema.componentsTree.length > 0) {
const firstRoot: IContainerNodeItem = schema const firstRoot: IContainerNodeItem = schema.componentsTree[0] as IContainerNodeItem;
.componentsTree[0] as IContainerNodeItem;
if (!firstRoot.fileName) { if (!firstRoot.fileName) {
// 整个 schema 描述一个容器,且无根节点定义 // 整个 schema 描述一个容器,且无根节点定义
@ -85,7 +84,7 @@ class SchemaParser implements ISchemaParser {
containers = [container]; containers = [container];
} else { } else {
// 普通带 1 到多个容器的 schema // 普通带 1 到多个容器的 schema
containers = schema.componentsTree.map(n => { containers = schema.componentsTree.map((n) => {
const subRoot = n as IContainerNodeItem; const subRoot = n as IContainerNodeItem;
const container: IContainerInfo = { const container: IContainerInfo = {
...subRoot, ...subRoot,
@ -100,7 +99,7 @@ class SchemaParser implements ISchemaParser {
} }
// 建立所有容器的内部依赖索引 // 建立所有容器的内部依赖索引
containers.forEach(container => { containers.forEach((container) => {
let type; let type;
switch (container.containerType) { switch (container.containerType) {
case 'Page': case 'Page':
@ -126,22 +125,20 @@ class SchemaParser implements ISchemaParser {
}); });
// 分析容器内部组件依赖 // 分析容器内部组件依赖
containers.forEach(container => { containers.forEach((container) => {
if (container.children) { if (container.children) {
// const depNames = this.getComponentNames(container.children); const depNames = this.getComponentNames(container.children);
// container.deps = uniqueArray<string>(depNames) container.deps = uniqueArray<string>(depNames, (i: string) => i)
// .map(depName => internalDeps[depName] || compDeps[depName]) .map((depName) => internalDeps[depName] || compDeps[depName])
// .filter(dep => !!dep); .filter((dep) => !!dep);
container.deps = Object.keys(compDeps).map( // container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]);
depName => compDeps[depName],
);
} }
}); });
// 分析路由配置 // 分析路由配置
const routes = containers const routes = containers
.filter(container => container.containerType === 'Page') .filter((container) => container.containerType === 'Page')
.map(page => { .map((page) => {
const meta = page.meta as IPageMeta; const meta = page.meta as IPageMeta;
if (meta) { if (meta) {
return { return {
@ -156,20 +153,28 @@ class SchemaParser implements ISchemaParser {
}); });
const routerDeps = routes const routerDeps = routes
.map(r => internalDeps[r.componentName] || compDeps[r.componentName]) .map((r) => internalDeps[r.componentName] || compDeps[r.componentName])
.filter(dep => !!dep); .filter((dep) => !!dep);
// 分析 Utils 依赖 // 分析 Utils 依赖
let utils: IUtilItem[]; let utils: IUtilItem[];
if (schema.utils) { if (schema.utils) {
utils = schema.utils; utils = schema.utils;
utilsDeps = schema.utils utilsDeps = schema.utils.filter((u) => u.type !== 'function').map((u) => u.content as IExternalDependency);
.filter(u => u.type !== 'function')
.map(u => u.content as IExternalDependency);
} else { } else {
utils = []; utils = [];
} }
// 分析项目 npm 依赖
let npms: INpmPackage[] = [];
containers.forEach((con) => {
const p = (con.deps || [])
.map((dep) => (dep.dependencyType === DependencyType.External ? dep : null))
.filter((dep) => dep !== null);
npms.push(...((p as unknown) as INpmPackage[]));
});
npms = uniqueArray<INpmPackage>(npms, (i) => i.package);
return { return {
containers, containers,
globalUtils: { globalUtils: {
@ -187,13 +192,16 @@ class SchemaParser implements ISchemaParser {
css: schema.css, css: schema.css,
constants: schema.constants, constants: schema.constants,
i18n: schema.i18n, i18n: schema.i18n,
packages: npms,
}, },
}; };
} }
public getComponentNames(children: ChildNodeType): string[] { getComponentNames(children: ChildNodeType): string[] {
return handleChildren<string>(children, { return handleChildren<string>(children, {
node: (i: IComponentNodeItem) => [i.componentName], node: (i: IComponentNodeItem) => [i.componentName],
}, {
rerun: true,
}); });
} }
} }

View File

@ -28,11 +28,11 @@ function groupDepsByPack(deps: IDependency[]): Record<string, IDependency[]> {
deps.forEach(dep => { deps.forEach(dep => {
if (dep.dependencyType === DependencyType.Internal) { if (dep.dependencyType === DependencyType.Internal) {
addDep( addDep(
`${(dep as IInternalDependency).moduleName}${dep.main || ''}`, `${(dep as IInternalDependency).moduleName}${`/${dep.main}` || ''}`,
dep, dep,
); );
} else { } else {
addDep(`${(dep as IExternalDependency).package}${dep.main || ''}`, dep); addDep(`${(dep as IExternalDependency).package}${`/${dep.main}` || ''}`, dep);
} }
}); });

View File

@ -73,6 +73,8 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
originTemplate: '@alifd/scaffold-lite-js', originTemplate: '@alifd/scaffold-lite-js',
}; };
ir.packages.forEach((packageInfo) => (packageJson.dependencies[packageInfo.package] = packageInfo.version));
next.chunks.push({ next.chunks.push({
type: ChunkType.JSON, type: ChunkType.JSON,
fileType: FileType.JSON, fileType: FileType.JSON,

View File

@ -1,13 +1,15 @@
export interface INpmPackage {
package: string; // 组件包的名称
version: string; // 组件包的版本
}
/** /**
* *
* *
* @export * @export
* @interface IExternalDependency * @interface IExternalDependency
*/ */
export interface IExternalDependency extends IDependency { export interface IExternalDependency extends INpmPackage, IDependency {}
package: string; // 组件包的名称
version: string; // 组件包的版本
}
export enum InternalDependencyType { export enum InternalDependencyType {
PAGE = 'pages', PAGE = 'pages',

View File

@ -5,6 +5,7 @@ import {
IDependency, IDependency,
II18nMap, II18nMap,
IInternalDependency, IInternalDependency,
INpmPackage,
IUtilItem, IUtilItem,
} from './index'; } from './index';
@ -42,6 +43,7 @@ export interface IProjectInfo {
css?: string; css?: string;
constants?: Record<string, string>; constants?: Record<string, string>;
i18n?: II18nMap; i18n?: II18nMap;
packages: INpmPackage[];
} }
/** /**

View File

@ -22,7 +22,10 @@ export function upperCaseFirst(inputValue: string): string {
return changeCase.upperCaseFirst(inputValue); return changeCase.upperCaseFirst(inputValue);
} }
export function uniqueArray<T>(arr: T[]) { export function uniqueArray<T>(arr: T[], by: (i: T) => string) {
const uniqueItems = [...new Set<T>(arr)]; const map: Record<string, T> = {};
arr.forEach((item) => (map[by(item)] = item));
const uniqueKeys = [...new Set<string>(Object.keys(map))];
const uniqueItems = uniqueKeys.map((key) => map[key]);
return uniqueItems; return uniqueItems;
} }

View File

@ -16,14 +16,26 @@ import { generateExpression } from './jsExpression';
// tslint:disable-next-line: no-empty // tslint:disable-next-line: no-empty
const noop = () => []; const noop = () => [];
const handleChildrenDefaultOptions = {
rerun: false,
};
export function handleChildren<T>( export function handleChildren<T>(
children: ChildNodeType, children: ChildNodeType,
handlers: HandlerSet<T>, handlers: HandlerSet<T>,
options?: {
rerun?: boolean,
},
): T[] { ): T[] {
const opt = {
...handleChildrenDefaultOptions,
...(options || {}),
};
if (Array.isArray(children)) { if (Array.isArray(children)) {
const list: ChildNodeItem[] = children as ChildNodeItem[]; const list: ChildNodeItem[] = children as ChildNodeItem[];
return list return list
.map(child => handleChildren(child, handlers)) .map(child => handleChildren(child, handlers, opt))
.reduce((p, c) => p.concat(c), []); .reduce((p, c) => p.concat(c), []);
} else if (typeof children === 'string') { } else if (typeof children === 'string') {
const handler = handlers.string || handlers.common || noop; const handler = handlers.string || handlers.common || noop;
@ -33,7 +45,12 @@ export function handleChildren<T>(
return handler(children as IJSExpression); return handler(children as IJSExpression);
} else { } else {
const handler = handlers.node || handlers.common || noop; const handler = handlers.node || handlers.common || noop;
return handler(children as IComponentNodeItem); let curRes = handler(children as IComponentNodeItem);
if (opt.rerun && children.children) {
const childRes = handleChildren(children.children, handlers, opt);
curRes = curRes.concat(childRes || []);
}
return curRes;
} }
} }