Skip to content

Commit 9e8e40f

Browse files
committed
feat: 添加 AppRouter 编译器
1 parent d6c1e46 commit 9e8e40f

File tree

14 files changed

+465
-138
lines changed

14 files changed

+465
-138
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,4 @@ typings/
6363
test/fixtures/*/project
6464
*.zip
6565
.vscode
66+
lib/app-plugin

lib/compiler/config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import path from "path";
2-
import UIPlugin from "./ui-plugin.js";
2+
import AppPlugin from "../app-plugin/index.js";
33

44
export default {
55
module: {
@@ -70,6 +70,6 @@ export default {
7070
extensions: [".ts", ".tsx", ".mjs", ".js", ".jsx"],
7171
},
7272
plugins: [
73-
new UIPlugin()
73+
new AppPlugin()
7474
]
7575
};

lib/compiler/index.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ function getDirs() {
3333
};
3434
return {
3535
rootContext,
36-
appDirPath: mkdir(path.join(rootContext, "app")),
37-
buildDirPath: mkdir(path.join(rootContext, ".lcui/build")),
38-
sourceDirPath: mkdir(path.join(rootContext, "src")),
39-
modulesDirPath: path.join(rootContext, "node_modules"),
40-
modulesOutputDirPath: mkdir(path.join(rootContext, "vendor.node_modules")),
36+
distDir: mkdir(path.join(rootContext, "dist")),
37+
buildDir: mkdir(path.join(rootContext, ".lcui/build")),
38+
appDir: mkdir(path.join(rootContext, "app")),
39+
modulesDir: path.join(rootContext, "node_modules"),
40+
modulesOutputDir: mkdir(path.join(rootContext, "vendor.node_modules")),
4141
};
4242
}
4343

@@ -101,7 +101,7 @@ function resolveModuleImportPath(name, context) {
101101
if (!dir || !ext) {
102102
return name;
103103
}
104-
return path.join(context.modulesDirPath, name);
104+
return path.join(context.modulesDir, name);
105105
}
106106
return path.resolve(context.context, name);
107107
}
@@ -119,7 +119,7 @@ function resolveModuleOutputPath(name, context) {
119119
if (!dir || !ext) {
120120
return name;
121121
}
122-
fullPath = path.join(context.modulesDirPath, name);
122+
fullPath = path.join(context.modulesDir, name);
123123
} else {
124124
fullPath = path.resolve(context.context, name);
125125
}
@@ -129,17 +129,17 @@ function resolveModuleOutputPath(name, context) {
129129
if (!resolvedPath) {
130130
throw new Error(`${name}: File does not exist`);
131131
}
132-
const modulesPath = path.join(context.buildDirPath, "node_modules");
132+
const modulesPath = path.join(context.buildDir, "node_modules");
133133
const outputPath = resolveModuleExt(
134134
path.join(
135-
context.buildDirPath,
135+
context.buildDir,
136136
path.relative(context.rootContext, resolvedPath)
137137
)
138138
);
139139
// 更改路径,避免 import 语句中的模块路径被解析到构建目录中的 node_modules
140140
if (outputPath.startsWith(modulesPath)) {
141141
return path.join(
142-
context.buildDirPath,
142+
context.buildDir,
143143
"[modules]",
144144
outputPath.substring(modulesPath.length)
145145
);
@@ -181,7 +181,7 @@ export default async function compile(file, compilerOptions) {
181181
...getDirs(),
182182
...compilerOptions,
183183
};
184-
const logFile = path.join(options.buildDirPath, "compile.log");
184+
const logFile = path.join(options.buildDir, "compile.log");
185185
const logger = createLogger(logFile, options.verbose);
186186

187187
function createHook() {
@@ -251,7 +251,7 @@ export default async function compile(file, compilerOptions) {
251251
return cache;
252252
}
253253
if (
254-
outputDirPath.startsWith(context.buildDirPath) &&
254+
outputDirPath.startsWith(context.buildDir) &&
255255
!fs.existsSync(outputDirPath)
256256
) {
257257
fs.mkdirpSync(outputDirPath);
@@ -372,10 +372,10 @@ export default async function compile(file, compilerOptions) {
372372

373373
function createCompilerContext(resourcePath) {
374374
let outputPath = resourcePath;
375-
if (resourcePath.startsWith(options.modulesDirPath)) {
375+
if (resourcePath.startsWith(options.modulesDir)) {
376376
outputPath = path.join(
377-
options.modulesOutputDirPath,
378-
resourcePath.substring(options.modulesDirPath.length + 1)
377+
options.modulesOutputDir,
378+
resourcePath.substring(options.modulesDir.length + 1)
379379
);
380380
if (!fs.existsSync(path.dirname(outputPath))) {
381381
fs.mkdirpSync(path.dirname(outputPath));
@@ -389,7 +389,7 @@ export default async function compile(file, compilerOptions) {
389389
resourceOutputPath: `${outputPath}.h`,
390390
context: path.dirname(resourcePath),
391391
emitFile(name, content) {
392-
const outputPath = path.resolve(options.appDirPath, name);
392+
const outputPath = path.resolve(options.distDir, name);
393393
const outputDir = path.dirname(outputPath);
394394
if (!fs.existsSync(outputDir)) {
395395
fs.mkdirpSync(outputDir);
@@ -401,7 +401,7 @@ export default async function compile(file, compilerOptions) {
401401
printError(resourcePath, error);
402402
},
403403
resolveOutput(name) {
404-
// TODO: 引入项目目录外的文件时,将路径转换成 buildDirPath
404+
// TODO: 引入项目目录外的文件时,将路径转换成 buildDir
405405
return path.resolve(context.context, `${name}.h`);
406406
},
407407
resolveModule(name) {

lib/compiler/ts-loader.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default async function TsLoader(content) {
2828
.slice(1, -1);
2929
let modulePath = loader.resolveModule(importPath);
3030
modules.push(loader.importModule(importPath));
31-
if (modulePath.startsWith(loader.buildDirPath)) {
31+
if (modulePath.startsWith(loader.buildDir)) {
3232
modulePath = path.relative(outputDirPath, modulePath);
3333
modulePath = `.${path.sep}${modulePath}`;
3434
}
@@ -74,7 +74,7 @@ export default async function TsLoader(content) {
7474

7575
const { compile } = await import(
7676
`file://${path.join(
77-
loader.modulesDirPath,
77+
loader.modulesDir,
7878
"@lcui",
7979
"react",
8080
"lib",

lib/compiler/ui-plugin.js

Lines changed: 0 additions & 92 deletions
This file was deleted.

lib/types.d.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/// <reference types="node" resolution-mode="require"/>
2+
export interface ModuleMetadata {
3+
type: "javascript" | "asset";
4+
/** 资源文件所在路径 */
5+
path: string;
6+
/** 资源文件输出路径 */
7+
outputPath: string;
8+
/** 加载该资源时需要包含的 C 头文件 */
9+
headerFiles: string[];
10+
/**
11+
* 初始化代码
12+
* 加载该资源所需要执行的 C 代码
13+
**/
14+
initCode: string;
15+
}
16+
export interface Module extends Record<string, any> {
17+
default: any;
18+
metadata: ModuleMetadata;
19+
}
20+
export interface CompilerOptions {
21+
verbose?: boolean;
22+
/**
23+
* 模块所在的目录
24+
* 可以用作解析其他模块成员的上下文
25+
**/
26+
context: string;
27+
/** 根目录 */
28+
rootContext: string;
29+
distDir: string;
30+
appDir: string;
31+
buildDir: string;
32+
modulesDir: string;
33+
modulesOutputDir: string;
34+
}
35+
export interface Hook<T = (...args: any[]) => any> {
36+
tap(name: string, fn: T): void;
37+
call: T;
38+
}
39+
export interface CompilerContext extends CompilerOptions {
40+
/** 资源文件的路径 */
41+
resourcePath: string;
42+
/** 资源文件的输出路径 */
43+
resourceOutputPath: string;
44+
emitError(err: Error): void;
45+
/** 确定资源文件的输出路径 */
46+
resolveOutput(name: string): string;
47+
/** 确定资源文件的模块路径 */
48+
resolveModule(name: string): string;
49+
/** 引入与资源文件对应的模块 */
50+
importModule(name: string): Promise<Module>;
51+
/** 输出文件 */
52+
emitFile(name: string, content: string | Buffer): void;
53+
/** 生成模块 */
54+
generateModule(name: string, generator: () => Promise<string | Buffer>): Promise<void>;
55+
logger: import("winston").Logger;
56+
}
57+
export interface LoaderContext extends CompilerContext {
58+
data: Record<string, any>;
59+
/** 获取配置选项 */
60+
getOptions(): any;
61+
}
62+
export interface CompilerInstance {
63+
options: CompilerOptions;
64+
logger: import("winston").Logger;
65+
hooks: {
66+
loadModule: Hook<(file: string, data: Record<string, any>) => void>;
67+
done: Hook;
68+
};
69+
}
70+
export interface ComponentConfig {
71+
headerFilePath: string;
72+
resourceLoaderName: string;
73+
assets: Module[];
74+
components: string[];
75+
}
76+
export interface ResourceNode {
77+
name: string;
78+
text?: string;
79+
attributes?: Record<string, any>;
80+
children?: ResourceNode[];
81+
}
82+
type LoaderOptions = Record<string, any>;
83+
export interface UILoaderOptions extends LoaderOptions {
84+
indent?: number;
85+
}
86+
type LoaderInput = string | Buffer | ResourceNode;
87+
type Loader = (this: LoaderContext, content: LoaderInput) => LoaderInput | Promise<undefined>;
88+
type LoaderRule = {
89+
loader: string | Loader;
90+
options: LoaderOptions;
91+
};
92+
type ModuleRuleUseConfig = string | (LoaderRule | string)[];
93+
export interface ModuleRule {
94+
test: RegExp | ((path: string) => boolean);
95+
use: ModuleRuleUseConfig;
96+
}
97+
export interface ModuleCacheItem {
98+
state: "pending" | "loading" | "loaded";
99+
outputPath: string;
100+
exports: Promise<Module>;
101+
resolve: (exports: Module) => void;
102+
reject: (err: Error) => void;
103+
}
104+
export type ModuleCacheMap = Record<string, ModuleCacheItem>;
105+
export {};

lib/types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"bin": {
88
"lcui": "bin/lcui.js"
99
},
10+
"types": "./lib/types.d.ts",
1011
"scripts": {
1112
"test": "nyc mocha",
1213
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
@@ -37,14 +38,16 @@
3738
"react-dom": "^18.2.0",
3839
"sass": "^1.64.2",
3940
"simple-git": "^3.3.0",
40-
"typescript": "^5.1.6",
41+
"typescript": "^5.4.5",
4142
"winston": "^3.10.0",
4243
"xml-js": "^1.6.11",
4344
"yaml": "^2.3.1"
4445
},
4546
"devDependencies": {
4647
"@commitlint/cli": "^12.1.1",
4748
"@commitlint/config-conventional": "^12.1.1",
49+
"@types/fs-extra": "^11.0.4",
50+
"@types/react": "^18.2.64",
4851
"codecov": "^3.8.2",
4952
"eslint": "^8.50.0",
5053
"husky": "^6.0.0",

0 commit comments

Comments
 (0)