feat: 完善watch编译器,现编译完成之后会自动进行alias替换,防止运行时问题,并修复server启动失败导致整体进程退出的问题
This commit is contained in:
parent
1440147f3e
commit
ef0d846f0a
|
|
@ -7,8 +7,8 @@ const typescript_1 = tslib_1.__importDefault(require("typescript"));
|
||||||
const path_1 = tslib_1.__importDefault(require("path"));
|
const path_1 = tslib_1.__importDefault(require("path"));
|
||||||
const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
|
const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
|
||||||
const fs_1 = tslib_1.__importDefault(require("fs"));
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
||||||
const lodash_1 = require("lodash");
|
|
||||||
const polyfill_1 = require("./polyfill");
|
const polyfill_1 = require("./polyfill");
|
||||||
|
const tsc_alias_1 = require("tsc-alias");
|
||||||
// 创建事件发射器
|
// 创建事件发射器
|
||||||
const createEventEmitter = () => {
|
const createEventEmitter = () => {
|
||||||
const listeners = new Map();
|
const listeners = new Map();
|
||||||
|
|
@ -227,12 +227,19 @@ const createServerManager = (projectPath, eventEmitter, config) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const simpleConnector = require(path_1.default.join(projectPath, "lib/config/connector")).default;
|
const simpleConnector = require(path_1.default.join(projectPath, "lib/config/connector")).default;
|
||||||
console.warn("----> Starting service......");
|
console.warn("----> Starting service......");
|
||||||
// 这里注意要在require之前,因为require会触发编译
|
try {
|
||||||
const { startup } = require('./start');
|
// 这里注意要在require之前,因为require会触发编译
|
||||||
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
const { startup } = require('./start');
|
||||||
config.lifecycle.onServerStart(config);
|
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
||||||
return shutdown;
|
config.lifecycle.onServerStart(config);
|
||||||
});
|
return shutdown;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("----> Failed to start service:", error);
|
||||||
|
isRestarting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
isRestarting = false;
|
isRestarting = false;
|
||||||
await eventEmitter.emit("server-restarted", {});
|
await eventEmitter.emit("server-restarted", {});
|
||||||
};
|
};
|
||||||
|
|
@ -248,7 +255,7 @@ const createServerManager = (projectPath, eventEmitter, config) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// 创建编译器
|
// 创建编译器
|
||||||
const createCompiler = (projectPath, options, projectReferences, aliasConfig, config) => {
|
const createCompiler = async (projectPath, options, projectReferences, treatFile, config) => {
|
||||||
const createProgramAndSourceFile = (path) => {
|
const createProgramAndSourceFile = (path) => {
|
||||||
const program = typescript_1.default.createProgram({
|
const program = typescript_1.default.createProgram({
|
||||||
rootNames: [path],
|
rootNames: [path],
|
||||||
|
|
@ -375,6 +382,8 @@ const createCompiler = (projectPath, options, projectReferences, aliasConfig, co
|
||||||
else {
|
else {
|
||||||
console.log(`Emit succeeded for ${filePath}.`);
|
console.log(`Emit succeeded for ${filePath}.`);
|
||||||
config.lifecycle.onAfterCompile(config);
|
config.lifecycle.onAfterCompile(config);
|
||||||
|
const jsFilePath = libPath;
|
||||||
|
treatFile(jsFilePath);
|
||||||
return {
|
return {
|
||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -445,40 +454,39 @@ const createFileWatcher = (projectPath, eventEmitter) => {
|
||||||
const generateTaskId = () => {
|
const generateTaskId = () => {
|
||||||
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
};
|
};
|
||||||
/**
|
// /**
|
||||||
* 根据 alias 配置表将路径中的别名替换为真实路径
|
// * 根据 alias 配置表将路径中的别名替换为真实路径
|
||||||
* @param path - 输入的路径字符串,例如 "@project/file" 或 "@oak-app-domain/some-module"
|
// * @param path - 输入的路径字符串,例如 "@project/file" 或 "@oak-app-domain/some-module"
|
||||||
* @param aliasConfig - alias 配置表,key 为别名,value 为对应的真实路径或路径数组
|
// * @param aliasConfig - alias 配置表,key 为别名,value 为对应的真实路径或路径数组
|
||||||
* @returns 替换后的路径,如果没有匹配到 alias,则返回原始路径
|
// * @returns 替换后的路径,如果没有匹配到 alias,则返回原始路径
|
||||||
*/
|
// */
|
||||||
const replaceAliasWithPath = (path, aliasConfig) => {
|
// const replaceAliasWithPath = (path: string, aliasConfig: Record<string, string | string[]>): string => {
|
||||||
for (const [alias, targets] of Object.entries(aliasConfig)) {
|
// for (const [alias, targets] of Object.entries(aliasConfig)) {
|
||||||
// If alias ends with "*", handle it as a dynamic alias.
|
// // If alias ends with "*", handle it as a dynamic alias.
|
||||||
if (alias.endsWith('*')) {
|
// if (alias.endsWith('*')) {
|
||||||
// Create a regex pattern that matches paths starting with the alias, followed by any characters
|
// // Create a regex pattern that matches paths starting with the alias, followed by any characters
|
||||||
const aliasPattern = new RegExp(`^${alias.replace(/\*$/, "")}(.*)`); // e.g., '@project/*' becomes '@project/(.*)'
|
// const aliasPattern = new RegExp(`^${alias.replace(/\*$/, "")}(.*)`); // e.g., '@project/*' becomes '@project/(.*)'
|
||||||
const match = path.match(aliasPattern);
|
// const match = path.match(aliasPattern);
|
||||||
if (match) {
|
// if (match) {
|
||||||
// Replace the alias with the target path, appending the matched part from the original path
|
// // Replace the alias with the target path, appending the matched part from the original path
|
||||||
const target = Array.isArray(targets) ? targets[0] : targets; // Take the first target (if it's an array)
|
// const target = Array.isArray(targets) ? targets[0] : targets; // Take the first target (if it's an array)
|
||||||
// Ensure that the target path ends with a slash if it's not already
|
// // Ensure that the target path ends with a slash if it's not already
|
||||||
const replacedPath = target.replace(/\/\*$/, "/") + match[1];
|
// const replacedPath = target.replace(/\/\*$/, "/") + match[1];
|
||||||
return replacedPath;
|
// return replacedPath;
|
||||||
}
|
// }
|
||||||
}
|
// } else {
|
||||||
else {
|
// // Handle static alias without "*" by directly matching the path
|
||||||
// Handle static alias without "*" by directly matching the path
|
// if (path.startsWith(alias)) {
|
||||||
if (path.startsWith(alias)) {
|
// const target = Array.isArray(targets) ? targets[0] : targets; // Take the first target (if it's an array)
|
||||||
const target = Array.isArray(targets) ? targets[0] : targets; // Take the first target (if it's an array)
|
// // Replace the alias part with the target path
|
||||||
// Replace the alias part with the target path
|
// return path.replace(alias, target);
|
||||||
return path.replace(alias, target);
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// // If no alias matches, return the original path
|
||||||
// If no alias matches, return the original path
|
// return path;
|
||||||
return path;
|
// };
|
||||||
};
|
const watch = async (projectPath, config) => {
|
||||||
const watch = (projectPath, config) => {
|
|
||||||
const realConfig = getOverrideConfig(config);
|
const realConfig = getOverrideConfig(config);
|
||||||
const enableTrace = !!process.env.ENABLE_TRACE;
|
const enableTrace = !!process.env.ENABLE_TRACE;
|
||||||
// 查找配置文件
|
// 查找配置文件
|
||||||
|
|
@ -486,20 +494,30 @@ const watch = (projectPath, config) => {
|
||||||
if (!configFileName) {
|
if (!configFileName) {
|
||||||
throw new Error("Could not find a valid 'tsconfig.build.json'.");
|
throw new Error("Could not find a valid 'tsconfig.build.json'.");
|
||||||
}
|
}
|
||||||
// 读取配置文件
|
const runFile = await (0, tsc_alias_1.prepareSingleFileReplaceTscAliasPaths)({
|
||||||
const configFile = typescript_1.default.readConfigFile(configFileName, typescript_1.default.sys.readFile);
|
configFile: path_1.default.join(projectPath, "tsconfig.build.json"),
|
||||||
// 解析配置文件内容
|
resolveFullPaths: true,
|
||||||
const { options, projectReferences } = typescript_1.default.parseJsonConfigFileContent(configFile.config, typescript_1.default.sys, path_1.default.dirname(configFileName));
|
|
||||||
const aliasConfig = (0, lodash_1.cloneDeep)(options.paths) || {};
|
|
||||||
// 输出原始配置
|
|
||||||
// console.log("[DEBUG] Original alias config:", aliasConfig);
|
|
||||||
Object.keys(aliasConfig).forEach((key) => {
|
|
||||||
const value = aliasConfig[key];
|
|
||||||
// 替换src
|
|
||||||
aliasConfig[key] = typeof value === "string" ? value.replace("src", "lib") : value.map((v) => v.replace("src", "lib"));
|
|
||||||
});
|
});
|
||||||
|
function treatFile(filePath) {
|
||||||
|
const fileContents = fs_1.default.readFileSync(filePath, 'utf8');
|
||||||
|
const newContents = runFile({ fileContents, filePath });
|
||||||
|
// do stuff with newContents
|
||||||
|
fs_1.default.writeFileSync(filePath, newContents, 'utf8');
|
||||||
|
}
|
||||||
|
// // 读取配置文件
|
||||||
|
const configFile = typescript_1.default.readConfigFile(configFileName, typescript_1.default.sys.readFile);
|
||||||
|
// // 解析配置文件内容
|
||||||
|
const { options, projectReferences } = typescript_1.default.parseJsonConfigFileContent(configFile.config, typescript_1.default.sys, path_1.default.dirname(configFileName));
|
||||||
|
// const aliasConfig: AliasConfig = cloneDeep(options.paths) || {};
|
||||||
|
// // 输出原始配置
|
||||||
|
// // console.log("[DEBUG] Original alias config:", aliasConfig);
|
||||||
|
// Object.keys(aliasConfig).forEach((key) => {
|
||||||
|
// const value = aliasConfig[key];
|
||||||
|
// // 替换src
|
||||||
|
// aliasConfig[key] = typeof value === "string" ? value.replace("src", "lib") : value.map((v: string) => v.replace("src", "lib"));
|
||||||
|
// });
|
||||||
// 输出真实的alias配置
|
// 输出真实的alias配置
|
||||||
console.debug("[DEBUG] Running Alias config:", aliasConfig);
|
// console.debug("[DEBUG] Running Alias config:", aliasConfig);
|
||||||
// 初始化polyfill
|
// 初始化polyfill
|
||||||
const polyfillLoader = () => {
|
const polyfillLoader = () => {
|
||||||
const BuiltinModule = require("module");
|
const BuiltinModule = require("module");
|
||||||
|
|
@ -530,6 +548,9 @@ const watch = (projectPath, config) => {
|
||||||
console.error(`[resolve] Emit skipped for: ${tsPath}`);
|
console.error(`[resolve] Emit skipped for: ${tsPath}`);
|
||||||
throw new Error("TypeScript emit skipped");
|
throw new Error("TypeScript emit skipped");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
treatFile(jsPath);
|
||||||
|
}
|
||||||
console.log(`[resolve] Successfully compiled: ${tsPath}`);
|
console.log(`[resolve] Successfully compiled: ${tsPath}`);
|
||||||
return jsPath;
|
return jsPath;
|
||||||
}
|
}
|
||||||
|
|
@ -559,11 +580,11 @@ const watch = (projectPath, config) => {
|
||||||
rFoptions // 解析选项
|
rFoptions // 解析选项
|
||||||
) {
|
) {
|
||||||
let resolvedRequest = request;
|
let resolvedRequest = request;
|
||||||
const replacedPath = replaceAliasWithPath(request, aliasConfig);
|
// const replacedPath = replaceAliasWithPath(request, aliasConfig);
|
||||||
if (replacedPath !== request) {
|
// if (replacedPath !== request) {
|
||||||
console.log(`[resolve] Alias resolved: ${request} -> ${replacedPath}`);
|
// console.log(`[resolve] Alias resolved: ${request} -> ${replacedPath}`);
|
||||||
resolvedRequest = path_1.default.join(projectPath, replacedPath);
|
// resolvedRequest = pathLib.join(projectPath, replacedPath);
|
||||||
}
|
// }
|
||||||
try {
|
try {
|
||||||
return oldResolveFilename.call(this, resolvedRequest, parent, isMain, rFoptions);
|
return oldResolveFilename.call(this, resolvedRequest, parent, isMain, rFoptions);
|
||||||
}
|
}
|
||||||
|
|
@ -631,14 +652,34 @@ const watch = (projectPath, config) => {
|
||||||
"src/ports/index.ts",
|
"src/ports/index.ts",
|
||||||
];
|
];
|
||||||
compileFiles.forEach(tryCompile);
|
compileFiles.forEach(tryCompile);
|
||||||
|
// 最后替换lib目录下所有的路径别名
|
||||||
|
console.log(`[watch] Replacing path aliases in lib directory......`);
|
||||||
|
const libDir = path_1.default.join(projectPath, "lib");
|
||||||
|
const walkDir = (dir) => {
|
||||||
|
const files = fs_1.default.readdirSync(dir);
|
||||||
|
files.forEach((file) => {
|
||||||
|
const fullPath = path_1.default.join(dir, file);
|
||||||
|
const stat = fs_1.default.statSync(fullPath);
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
walkDir(fullPath);
|
||||||
|
}
|
||||||
|
else if (stat.isFile() && fullPath.endsWith(".js")) {
|
||||||
|
const fileContents = fs_1.default.readFileSync(fullPath, 'utf8');
|
||||||
|
const newContents = runFile({ fileContents, filePath: fullPath });
|
||||||
|
fs_1.default.writeFileSync(fullPath, newContents, 'utf8');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
walkDir(libDir);
|
||||||
|
console.log(`[watch] Path alias replacement completed.`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
// 创建事件系统
|
// 创建事件系统
|
||||||
const eventEmitter = createEventEmitter();
|
const eventEmitter = createEventEmitter();
|
||||||
// 创建各个组件
|
// 创建各个组件
|
||||||
const compileQueue = createCompileQueue(eventEmitter);
|
const compileQueue = createCompileQueue(eventEmitter);
|
||||||
const compiler = createCompiler(projectPath, options, projectReferences, aliasConfig, realConfig);
|
const compiler = await createCompiler(projectPath, options, projectReferences, treatFile, realConfig);
|
||||||
const serverManager = createServerManager(projectPath, eventEmitter, realConfig);
|
const serverManager = createServerManager(projectPath, eventEmitter, realConfig);
|
||||||
const fileWatcher = createFileWatcher(projectPath, eventEmitter);
|
const fileWatcher = createFileWatcher(projectPath, eventEmitter);
|
||||||
// 设置编译器处理器
|
// 设置编译器处理器
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@
|
||||||
"stylelint-webpack-plugin": "^3.2.0",
|
"stylelint-webpack-plugin": "^3.2.0",
|
||||||
"tailwindcss": "^3.0.2",
|
"tailwindcss": "^3.0.2",
|
||||||
"terser-webpack-plugin": "^5.2.5",
|
"terser-webpack-plugin": "^5.2.5",
|
||||||
|
"tsc-alias": "^1.8.16",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"ui-extract-webpack-plugin": "^1.0.0",
|
"ui-extract-webpack-plugin": "^1.0.0",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ import ts, { CompilerOptions, ProjectReference } from "typescript";
|
||||||
import pathLib from "path";
|
import pathLib from "path";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { cloneDeep } from "lodash";
|
// import { cloneDeep } from "lodash";
|
||||||
import { AsyncContext } from "oak-domain/lib/store/AsyncRowStore";
|
import { AsyncContext } from "oak-domain/lib/store/AsyncRowStore";
|
||||||
import { LogFormatter, LogFormatterProp, polyfillConsole } from "./polyfill";
|
import { LogFormatter, LogFormatterProp, polyfillConsole } from "./polyfill";
|
||||||
|
import { prepareSingleFileReplaceTscAliasPaths, SingleFileReplacer } from 'tsc-alias';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 工作流程
|
* 工作流程
|
||||||
|
|
@ -397,15 +398,22 @@ const createServerManager = (
|
||||||
|
|
||||||
console.warn("----> Starting service......");
|
console.warn("----> Starting service......");
|
||||||
|
|
||||||
// 这里注意要在require之前,因为require会触发编译
|
try {
|
||||||
const { startup } = require('./start') as {
|
// 这里注意要在require之前,因为require会触发编译
|
||||||
startup: (pwd: string, connector: any) => Promise<() => Promise<void>>;
|
const { startup } = require('./start') as {
|
||||||
}
|
startup: (pwd: string, connector: any) => Promise<() => Promise<void>>;
|
||||||
|
}
|
||||||
|
|
||||||
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
||||||
config.lifecycle.onServerStart(config);
|
config.lifecycle.onServerStart(config);
|
||||||
return shutdown;
|
return shutdown;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("----> Failed to start service:", error);
|
||||||
|
isRestarting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
isRestarting = false;
|
isRestarting = false;
|
||||||
await eventEmitter.emit("server-restarted", {});
|
await eventEmitter.emit("server-restarted", {});
|
||||||
|
|
@ -425,13 +433,14 @@ const createServerManager = (
|
||||||
};
|
};
|
||||||
|
|
||||||
// 创建编译器
|
// 创建编译器
|
||||||
const createCompiler = (
|
const createCompiler = async (
|
||||||
projectPath: string,
|
projectPath: string,
|
||||||
options: CompilerOptions,
|
options: CompilerOptions,
|
||||||
projectReferences: readonly ProjectReference[] | undefined,
|
projectReferences: readonly ProjectReference[] | undefined,
|
||||||
aliasConfig: Record<string, string | string[]>,
|
treatFile: (filePath: string) => void,
|
||||||
config: RealWatchConfig
|
config: RealWatchConfig
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
const createProgramAndSourceFile = (path: string) => {
|
const createProgramAndSourceFile = (path: string) => {
|
||||||
const program = ts.createProgram({
|
const program = ts.createProgram({
|
||||||
rootNames: [path],
|
rootNames: [path],
|
||||||
|
|
@ -578,6 +587,8 @@ const createCompiler = (
|
||||||
} else {
|
} else {
|
||||||
console.log(`Emit succeeded for ${filePath}.`);
|
console.log(`Emit succeeded for ${filePath}.`);
|
||||||
config.lifecycle.onAfterCompile(config);
|
config.lifecycle.onAfterCompile(config);
|
||||||
|
const jsFilePath = libPath;
|
||||||
|
treatFile(jsFilePath);
|
||||||
return {
|
return {
|
||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -666,42 +677,42 @@ const generateTaskId = (): string => {
|
||||||
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* 根据 alias 配置表将路径中的别名替换为真实路径
|
// * 根据 alias 配置表将路径中的别名替换为真实路径
|
||||||
* @param path - 输入的路径字符串,例如 "@project/file" 或 "@oak-app-domain/some-module"
|
// * @param path - 输入的路径字符串,例如 "@project/file" 或 "@oak-app-domain/some-module"
|
||||||
* @param aliasConfig - alias 配置表,key 为别名,value 为对应的真实路径或路径数组
|
// * @param aliasConfig - alias 配置表,key 为别名,value 为对应的真实路径或路径数组
|
||||||
* @returns 替换后的路径,如果没有匹配到 alias,则返回原始路径
|
// * @returns 替换后的路径,如果没有匹配到 alias,则返回原始路径
|
||||||
*/
|
// */
|
||||||
const replaceAliasWithPath = (path: string, aliasConfig: Record<string, string | string[]>): string => {
|
// const replaceAliasWithPath = (path: string, aliasConfig: Record<string, string | string[]>): string => {
|
||||||
for (const [alias, targets] of Object.entries(aliasConfig)) {
|
// for (const [alias, targets] of Object.entries(aliasConfig)) {
|
||||||
// If alias ends with "*", handle it as a dynamic alias.
|
// // If alias ends with "*", handle it as a dynamic alias.
|
||||||
if (alias.endsWith('*')) {
|
// if (alias.endsWith('*')) {
|
||||||
// Create a regex pattern that matches paths starting with the alias, followed by any characters
|
// // Create a regex pattern that matches paths starting with the alias, followed by any characters
|
||||||
const aliasPattern = new RegExp(`^${alias.replace(/\*$/, "")}(.*)`); // e.g., '@project/*' becomes '@project/(.*)'
|
// const aliasPattern = new RegExp(`^${alias.replace(/\*$/, "")}(.*)`); // e.g., '@project/*' becomes '@project/(.*)'
|
||||||
|
|
||||||
const match = path.match(aliasPattern);
|
// const match = path.match(aliasPattern);
|
||||||
if (match) {
|
// if (match) {
|
||||||
// Replace the alias with the target path, appending the matched part from the original path
|
// // Replace the alias with the target path, appending the matched part from the original path
|
||||||
const target = Array.isArray(targets) ? targets[0] : targets; // Take the first target (if it's an array)
|
// const target = Array.isArray(targets) ? targets[0] : targets; // Take the first target (if it's an array)
|
||||||
// Ensure that the target path ends with a slash if it's not already
|
// // Ensure that the target path ends with a slash if it's not already
|
||||||
const replacedPath = target.replace(/\/\*$/, "/") + match[1];
|
// const replacedPath = target.replace(/\/\*$/, "/") + match[1];
|
||||||
return replacedPath;
|
// return replacedPath;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
// Handle static alias without "*" by directly matching the path
|
// // Handle static alias without "*" by directly matching the path
|
||||||
if (path.startsWith(alias)) {
|
// if (path.startsWith(alias)) {
|
||||||
const target = Array.isArray(targets) ? targets[0] : targets; // Take the first target (if it's an array)
|
// const target = Array.isArray(targets) ? targets[0] : targets; // Take the first target (if it's an array)
|
||||||
// Replace the alias part with the target path
|
// // Replace the alias part with the target path
|
||||||
return path.replace(alias, target);
|
// return path.replace(alias, target);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// If no alias matches, return the original path
|
// // If no alias matches, return the original path
|
||||||
return path;
|
// return path;
|
||||||
};
|
// };
|
||||||
|
|
||||||
export const watch = (
|
export const watch = async (
|
||||||
projectPath: string,
|
projectPath: string,
|
||||||
config?: WatchConfig
|
config?: WatchConfig
|
||||||
): Promise<() => Promise<void>> => {
|
): Promise<() => Promise<void>> => {
|
||||||
|
|
@ -719,29 +730,42 @@ export const watch = (
|
||||||
throw new Error("Could not find a valid 'tsconfig.build.json'.");
|
throw new Error("Could not find a valid 'tsconfig.build.json'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取配置文件
|
const runFile: SingleFileReplacer = await prepareSingleFileReplaceTscAliasPaths({
|
||||||
|
configFile: pathLib.join(projectPath, "tsconfig.build.json"),
|
||||||
|
resolveFullPaths: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
function treatFile(filePath: string) {
|
||||||
|
console.log(`Processing file for alias replacement: ${filePath}`);
|
||||||
|
const fileContents = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const newContents = runFile({ fileContents, filePath });
|
||||||
|
// do stuff with newContents
|
||||||
|
fs.writeFileSync(filePath, newContents, 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 读取配置文件
|
||||||
const configFile = ts.readConfigFile(configFileName, ts.sys.readFile);
|
const configFile = ts.readConfigFile(configFileName, ts.sys.readFile);
|
||||||
|
|
||||||
// 解析配置文件内容
|
// // 解析配置文件内容
|
||||||
const { options, projectReferences } = ts.parseJsonConfigFileContent(
|
const { options, projectReferences } = ts.parseJsonConfigFileContent(
|
||||||
configFile.config,
|
configFile.config,
|
||||||
ts.sys,
|
ts.sys,
|
||||||
pathLib.dirname(configFileName)
|
pathLib.dirname(configFileName)
|
||||||
);
|
);
|
||||||
|
|
||||||
const aliasConfig: AliasConfig = cloneDeep(options.paths) || {};
|
// const aliasConfig: AliasConfig = cloneDeep(options.paths) || {};
|
||||||
|
|
||||||
// 输出原始配置
|
// // 输出原始配置
|
||||||
// console.log("[DEBUG] Original alias config:", aliasConfig);
|
// // console.log("[DEBUG] Original alias config:", aliasConfig);
|
||||||
|
|
||||||
Object.keys(aliasConfig).forEach((key) => {
|
// Object.keys(aliasConfig).forEach((key) => {
|
||||||
const value = aliasConfig[key];
|
// const value = aliasConfig[key];
|
||||||
// 替换src
|
// // 替换src
|
||||||
aliasConfig[key] = typeof value === "string" ? value.replace("src", "lib") : value.map((v: string) => v.replace("src", "lib"));
|
// aliasConfig[key] = typeof value === "string" ? value.replace("src", "lib") : value.map((v: string) => v.replace("src", "lib"));
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 输出真实的alias配置
|
// 输出真实的alias配置
|
||||||
console.debug("[DEBUG] Running Alias config:", aliasConfig);
|
// console.debug("[DEBUG] Running Alias config:", aliasConfig);
|
||||||
|
|
||||||
// 初始化polyfill
|
// 初始化polyfill
|
||||||
const polyfillLoader = () => {
|
const polyfillLoader = () => {
|
||||||
|
|
@ -781,6 +805,8 @@ export const watch = (
|
||||||
if (emitResult.emitSkipped) {
|
if (emitResult.emitSkipped) {
|
||||||
console.error(`[resolve] Emit skipped for: ${tsPath}`);
|
console.error(`[resolve] Emit skipped for: ${tsPath}`);
|
||||||
throw new Error("TypeScript emit skipped");
|
throw new Error("TypeScript emit skipped");
|
||||||
|
} else {
|
||||||
|
treatFile(jsPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[resolve] Successfully compiled: ${tsPath}`);
|
console.log(`[resolve] Successfully compiled: ${tsPath}`);
|
||||||
|
|
@ -823,13 +849,12 @@ export const watch = (
|
||||||
rFoptions: object | undefined // 解析选项
|
rFoptions: object | undefined // 解析选项
|
||||||
) {
|
) {
|
||||||
let resolvedRequest = request;
|
let resolvedRequest = request;
|
||||||
const replacedPath = replaceAliasWithPath(request, aliasConfig);
|
// const replacedPath = replaceAliasWithPath(request, aliasConfig);
|
||||||
|
|
||||||
if (replacedPath !== request) {
|
|
||||||
console.log(`[resolve] Alias resolved: ${request} -> ${replacedPath}`);
|
|
||||||
resolvedRequest = pathLib.join(projectPath, replacedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// if (replacedPath !== request) {
|
||||||
|
// console.log(`[resolve] Alias resolved: ${request} -> ${replacedPath}`);
|
||||||
|
// resolvedRequest = pathLib.join(projectPath, replacedPath);
|
||||||
|
// }
|
||||||
try {
|
try {
|
||||||
return oldResolveFilename.call(this, resolvedRequest, parent, isMain, rFoptions);
|
return oldResolveFilename.call(this, resolvedRequest, parent, isMain, rFoptions);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|
@ -908,16 +933,36 @@ export const watch = (
|
||||||
"src/ports/index.ts",
|
"src/ports/index.ts",
|
||||||
];
|
];
|
||||||
compileFiles.forEach(tryCompile);
|
compileFiles.forEach(tryCompile);
|
||||||
|
// 最后替换lib目录下所有的路径别名
|
||||||
|
console.log(`[watch] Replacing path aliases in lib directory......`);
|
||||||
|
const libDir = pathLib.join(projectPath, "lib");
|
||||||
|
const walkDir = (dir: string) => {
|
||||||
|
const files = fs.readdirSync(dir);
|
||||||
|
files.forEach((file) => {
|
||||||
|
const fullPath = pathLib.join(dir, file);
|
||||||
|
const stat = fs.statSync(fullPath);
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
walkDir(fullPath);
|
||||||
|
}
|
||||||
|
else if (stat.isFile() && fullPath.endsWith(".js")) {
|
||||||
|
const fileContents = fs.readFileSync(fullPath, 'utf8');
|
||||||
|
const newContents = runFile({ fileContents, filePath: fullPath });
|
||||||
|
fs.writeFileSync(fullPath, newContents, 'utf8');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
walkDir(libDir);
|
||||||
|
console.log(`[watch] Path alias replacement completed.`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
// 创建事件系统
|
// 创建事件系统
|
||||||
const eventEmitter = createEventEmitter();
|
const eventEmitter = createEventEmitter();
|
||||||
|
|
||||||
// 创建各个组件
|
// 创建各个组件
|
||||||
const compileQueue = createCompileQueue(eventEmitter);
|
const compileQueue = createCompileQueue(eventEmitter);
|
||||||
const compiler = createCompiler(projectPath, options, projectReferences, aliasConfig, realConfig);
|
const compiler = await createCompiler(projectPath, options, projectReferences, treatFile, realConfig);
|
||||||
const serverManager = createServerManager(projectPath, eventEmitter, realConfig);
|
const serverManager = createServerManager(projectPath, eventEmitter, realConfig);
|
||||||
const fileWatcher = createFileWatcher(projectPath, eventEmitter);
|
const fileWatcher = createFileWatcher(projectPath, eventEmitter);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue