From 3f3981bb9db874b738a67fd449c579c35c58d08b Mon Sep 17 00:00:00 2001 From: Wells Date: Fri, 31 May 2024 14:54:12 +0800 Subject: [PATCH] fix: parse app entry file & pass correct routerType to sandbox (#168) * fix: parse app entry file & pass correct routerType to sandbox * fix: export entry module --- packages/core/src/helpers/ast/traverse.ts | 19 +++++++++++++++++++ packages/core/src/models/entry-module.ts | 18 ++++++++++++++++++ packages/core/src/models/index.ts | 1 + packages/core/src/models/interfaces.ts | 5 +++++ packages/core/src/models/workspace.ts | 13 +++++++++++++ packages/core/src/types.ts | 1 + packages/designer/src/sandbox/sandbox.tsx | 11 +++++++++-- 7 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 packages/core/src/models/entry-module.ts diff --git a/packages/core/src/helpers/ast/traverse.ts b/packages/core/src/helpers/ast/traverse.ts index 1d190ba..37c010f 100644 --- a/packages/core/src/helpers/ast/traverse.ts +++ b/packages/core/src/helpers/ast/traverse.ts @@ -1425,3 +1425,22 @@ export function traverseFile(ast: t.File) { imports, }; } + +/** + * app.js 入口文件解析 + * @param ast + */ +export function traverseEntryFile(ast: t.File) { + let appConfig: any; + traverse(ast, { + CallExpression(path) { + const { node } = path; + const calleeName = keyNode2value(node.callee) as string; + if (calleeName === 'runApp') { + appConfig = node2value(node.arguments[0]); + path.stop(); + } + }, + }); + return appConfig; +} diff --git a/packages/core/src/models/entry-module.ts b/packages/core/src/models/entry-module.ts new file mode 100644 index 0000000..efa844e --- /dev/null +++ b/packages/core/src/models/entry-module.ts @@ -0,0 +1,18 @@ +import { traverseEntryFile } from '../helpers'; +import { IFileConfig } from '../types'; +import { IWorkspace } from './interfaces'; +import { TangoModule } from './module'; + +export class AppEntryModule extends TangoModule { + routerType: string; + + constructor(workspace: IWorkspace, props: IFileConfig) { + super(workspace, props, false); + this.update(props.code, true, false); + } + + _analysisAst() { + const config = traverseEntryFile(this.ast); + this.routerType = config?.router?.type; + } +} diff --git a/packages/core/src/models/index.ts b/packages/core/src/models/index.ts index 69fbe8c..92bdb05 100644 --- a/packages/core/src/models/index.ts +++ b/packages/core/src/models/index.ts @@ -7,6 +7,7 @@ export * from './drag-source'; export * from './history'; export * from './file'; export * from './module'; +export * from './entry-module'; export * from './route-module'; export * from './service-module'; export * from './store-module'; diff --git a/packages/core/src/models/interfaces.ts b/packages/core/src/models/interfaces.ts index 2923072..b40371c 100644 --- a/packages/core/src/models/interfaces.ts +++ b/packages/core/src/models/interfaces.ts @@ -16,6 +16,7 @@ import { TangoRouteModule } from './route-module'; import { TangoStoreModule } from './store-module'; import { TangoServiceModule } from './service-module'; import { IdGenerator } from '../helpers'; +import { AppEntryModule } from './entry-module'; export interface IViewFile { readonly workspace: IWorkspace; @@ -152,6 +153,10 @@ export interface IWorkspace { * 解析后的 tango.config.json 文件,如果要获取项目配置,推荐使用 projectConfig 获取 */ tangoConfigJson: TangoJsonFile; + /** + * app.js 入口文件解析后的模块 + */ + appEntryModule: AppEntryModule; /** * 解析后的路由模块 */ diff --git a/packages/core/src/models/workspace.ts b/packages/core/src/models/workspace.ts index 058bfbc..6ba38b8 100644 --- a/packages/core/src/models/workspace.ts +++ b/packages/core/src/models/workspace.ts @@ -35,6 +35,7 @@ import { TangoStoreEntryModule, TangoStoreModule } from './store-module'; import { TangoServiceModule } from './service-module'; import { TangoViewModule } from './view-module'; import { TangoComponentsEntryModule } from './component-module'; +import { AppEntryModule } from './entry-module'; export interface IWorkspaceOptions { /** @@ -97,6 +98,11 @@ export class Workspace extends EventTarget implements IWorkspace { */ activeViewFile: string; + /** + * 应用入口模块 + */ + appEntryModule: AppEntryModule; + /** * 路由配置模块 */ @@ -329,6 +335,9 @@ export class Workspace extends EventTarget implements IWorkspace { * @param fileType 模块类型 */ addFile(filename: string, code: string, fileType?: FileType) { + if (!fileType && filename === this.entry) { + fileType = FileType.AppEntryModule; + } const moduleType = fileType || inferFileType(filename); const props = { filename, @@ -338,6 +347,10 @@ export class Workspace extends EventTarget implements IWorkspace { let module; switch (moduleType) { + case FileType.AppEntryModule: + module = new AppEntryModule(this, props); + this.appEntryModule = module; + break; case FileType.StoreEntryModule: module = new TangoStoreEntryModule(this, props); this.storeEntryModule = module; diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index e59680a..9af6892 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -8,6 +8,7 @@ export type SimulatorMode = 'desktop' | 'tablet' | 'phone'; export enum FileType { // js 文件 Module = 'module', + AppEntryModule = 'appEntryModule', StoreEntryModule = 'storeEntryModule', RouteModule = 'routeModule', ServiceModule = 'serviceModule', diff --git a/packages/designer/src/sandbox/sandbox.tsx b/packages/designer/src/sandbox/sandbox.tsx index 21f7a50..c3665ba 100644 --- a/packages/designer/src/sandbox/sandbox.tsx +++ b/packages/designer/src/sandbox/sandbox.tsx @@ -49,6 +49,10 @@ export interface CombinedSandboxRef { const LANDING_PAGE_PATH = '/__background_landing_page__'; +function fixRouterMode(routerType: string): CodeSandboxProps['routerMode'] { + return routerType === 'hash' ? 'hash' : undefined; +} + function useSandbox({ isPreview: isPreviewProp, configFormatter, @@ -105,23 +109,26 @@ function useSandbox({ // 根据当前 workspace 状态与组件传入的状态是否一致,控制是否需要切换到空白路由 const display = isActive ? 'block' : 'none'; const routePath = isActive ? startRoute || workspace.activeRoute : LANDING_PAGE_PATH; + const routerMode = fixRouterMode(workspace.appEntryModule?.routerType); const sandboxProps = isPreview ? { files, eventHandlers: pick(dndHandlers, ['onTango']), onMessage, + onLoad, display, startRoute: routePath, - onLoad, + routerMode, } : { files, eventHandlers: dndHandlers as any, onMessage, + onLoad, display, startRoute: routePath, - onLoad, + routerMode, }; return sandboxProps;