Merge branch 'release'
This commit is contained in:
commit
c9b3284f49
|
|
@ -191,8 +191,22 @@ async function create(dirName, cmd) {
|
|||
(0, file_handle_1.checkFileExistsAndCreate)(rootPath);
|
||||
// 复制项目文件
|
||||
if (isModule) {
|
||||
// 模块化的项目,只拷贝src和typings目录
|
||||
(0, file_handle_1.copyFolder)((0, path_1.join)(emptyTemplatePath, 'src'), (0, path_1.join)(rootPath, 'src'));
|
||||
// 模块化的项目,只拷贝 src 下的内容,但跳过 pages 目录;同时拷贝 typings
|
||||
const templateSrc = (0, path_1.join)(emptyTemplatePath, 'src');
|
||||
const destSrc = (0, path_1.join)(rootPath, 'src');
|
||||
// 确保目标 src 目录存在
|
||||
if (!(0, fs_1.existsSync)(destSrc)) {
|
||||
(0, fs_1.mkdirSync)(destSrc, { recursive: true });
|
||||
}
|
||||
const entries = (0, fs_1.readdirSync)(templateSrc, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (entry.name === 'pages') {
|
||||
continue; // 模块模式下跳过 pages
|
||||
}
|
||||
const from = (0, path_1.join)(templateSrc, entry.name);
|
||||
const to = (0, path_1.join)(destSrc, entry.name);
|
||||
(0, file_handle_1.copyFolder)(from, to);
|
||||
}
|
||||
(0, file_handle_1.copyFolder)((0, path_1.join)(emptyTemplatePath, 'typings'), (0, path_1.join)(rootPath, 'typings'));
|
||||
}
|
||||
else {
|
||||
|
|
@ -234,8 +248,16 @@ async function create(dirName, cmd) {
|
|||
(0, file_handle_1.checkFileExistsAndCreate)(tsConfigMpJsonPath, tsConfigMpJson, enum_1.checkFileExistsAndCreateType.FILE);
|
||||
// 创建tsconfig.web.json
|
||||
(0, file_handle_1.checkFileExistsAndCreate)(tsConfigWebJsonPath, tsConfigWebJson, enum_1.checkFileExistsAndCreateType.FILE);
|
||||
// 更新configuration/compiler.js
|
||||
(0, template_1.updateCompilerJsContent)(rootPath, deps);
|
||||
// 复制.gitignore
|
||||
const gitignoreContent = (0, file_handle_1.readFile)((0, path_1.join)(__dirname, '..', 'template', '.gitignore'));
|
||||
(0, file_handle_1.checkFileExistsAndCreate)((0, path_1.join)(rootPath, '.gitignore'), gitignoreContent, enum_1.checkFileExistsAndCreateType.FILE);
|
||||
// 复制oak.config.json
|
||||
const oakConfigContent = (0, file_handle_1.readFile)((0, path_1.join)(__dirname, '..', 'template', config_1.USER_CONFIG_FILE_NAME));
|
||||
(0, file_handle_1.checkFileExistsAndCreate)((0, path_1.join)(rootPath, config_1.USER_CONFIG_FILE_NAME), oakConfigContent, enum_1.checkFileExistsAndCreateType.FILE);
|
||||
// 更新configuration/compiler.js (仅在非模块化模式下)
|
||||
if (!isModule) {
|
||||
(0, template_1.updateCompilerJsContent)(rootPath, deps);
|
||||
}
|
||||
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Successfully created project ${(0, tip_style_1.primary)(name)}, directory name is ${(0, tip_style_1.primary)(dirName)}`)}`);
|
||||
shelljs_1.default.cd(dirName);
|
||||
if (deps.length > 0) {
|
||||
|
|
@ -254,8 +276,21 @@ async function create(dirName, cmd) {
|
|||
});
|
||||
// 创建package.json
|
||||
(0, file_handle_1.checkFileExistsAndCreate)(packageJsonPath, packageJson, enum_1.checkFileExistsAndCreateType.FILE);
|
||||
(0, rename_1.renameProject)(rootPath, name, title, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_TITLE);
|
||||
if (example) {
|
||||
// 只在非模块化模式下重命名整个项目(包括web、wechatMp等)
|
||||
if (!isModule) {
|
||||
(0, rename_1.renameProject)(rootPath, name, title, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_TITLE);
|
||||
}
|
||||
else {
|
||||
// 模块化模式下只更新 package.json 的 name
|
||||
const packageJsonFilePath = (0, path_1.join)(rootPath, 'package.json');
|
||||
const packageJsonContent = (0, fs_1.readFileSync)(packageJsonFilePath, 'utf-8');
|
||||
const packageJsonJson = JSON.parse(packageJsonContent);
|
||||
packageJsonJson.name = name;
|
||||
const newPackageJsonContent = JSON.stringify(packageJsonJson, undefined, 4);
|
||||
(0, fs_1.writeFileSync)(packageJsonFilePath, newPackageJsonContent);
|
||||
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Change project name to ${(0, tip_style_1.primary)(name)}`)}`);
|
||||
}
|
||||
if (example && !isModule) {
|
||||
// todo: copy template example files
|
||||
(0, file_handle_1.copyFolder)(examplePath, rootPath, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export declare function writeFile(path: string | PathLike, data: any): void;
|
|||
export declare function readFile(path: string | PathLike, options?: {
|
||||
encoding?: null | undefined;
|
||||
flag?: string | undefined;
|
||||
} | null): Buffer<ArrayBufferLike> | undefined;
|
||||
} | null): NonSharedBuffer | undefined;
|
||||
/**
|
||||
* @name 拷贝文件夹
|
||||
* @export
|
||||
|
|
|
|||
|
|
@ -149,9 +149,8 @@ function copyFolder(currentDir, targetDir, overwrite = false) {
|
|||
}
|
||||
else {
|
||||
if (file.isFile()) {
|
||||
const readStream = (0, fs_1.createReadStream)(copyCurrentFileInfo);
|
||||
const writeStream = (0, fs_1.createWriteStream)(copyTargetFileInfo);
|
||||
readStream.pipe(writeStream);
|
||||
// 使用同步复制确保文件完全写入
|
||||
(0, fs_1.copyFileSync)(copyCurrentFileInfo, copyTargetFileInfo);
|
||||
// console.log(`复制文件: ${copyCurrentFileInfo} -> ${copyTargetFileInfo}`);
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const path_1 = require("path");
|
|||
const koa_1 = tslib_1.__importDefault(require("koa"));
|
||||
const koa_router_1 = tslib_1.__importDefault(require("koa-router"));
|
||||
const koa_body_1 = tslib_1.__importDefault(require("koa-body"));
|
||||
const koa_logger_1 = tslib_1.__importDefault(require("koa-logger"));
|
||||
// import logger from 'koa-logger';
|
||||
const oak_backend_base_1 = require("oak-backend-base");
|
||||
const types_1 = require("oak-domain/lib/types");
|
||||
const cluster_adapter_1 = require("@socket.io/cluster-adapter");
|
||||
|
|
@ -39,13 +39,17 @@ function concat(...paths) {
|
|||
});
|
||||
}
|
||||
async function startup(path, connector, omitWatchers, omitTimers, routine) {
|
||||
let errorHandler = undefined;
|
||||
try {
|
||||
errorHandler = require((0, path_1.join)(path, 'lib', 'configuration', 'errors')).default;
|
||||
}
|
||||
catch (err) {
|
||||
// 不存在errors配置
|
||||
}
|
||||
// let errorHandler: InternalErrorHandler<ED, Cxt> | undefined = undefined;
|
||||
// try {
|
||||
// errorHandler = require(join(
|
||||
// path,
|
||||
// 'lib',
|
||||
// 'configuration',
|
||||
// 'exception'
|
||||
// )).default;
|
||||
// } catch (err) {
|
||||
// // 不存在exception配置
|
||||
// }
|
||||
const serverConfiguration = require((0, path_1.join)(path, 'lib', 'configuration', 'server')).default;
|
||||
// 拿到package.json,用作项目的唯一标识,否则无法区分不同项目的Redis+socketIO连接
|
||||
const packageJson = require((0, path_1.join)(path, 'package.json'));
|
||||
|
|
@ -59,7 +63,7 @@ async function startup(path, connector, omitWatchers, omitTimers, routine) {
|
|||
const corsMethods = ['PUT', 'POST', 'GET', 'DELETE', 'OPTIONS'];
|
||||
const koa = new koa_1.default();
|
||||
// 使用 koa-logger 中间件打印日志
|
||||
koa.use((0, koa_logger_1.default)());
|
||||
// koa.use(logger());
|
||||
// socket
|
||||
const httpServer = (0, http_1.createServer)(koa.callback());
|
||||
const socketPath = connector.getSocketPath();
|
||||
|
|
@ -172,18 +176,22 @@ async function startup(path, connector, omitWatchers, omitTimers, routine) {
|
|||
await appLoader.unmount();
|
||||
return result;
|
||||
}
|
||||
if (errorHandler && typeof errorHandler === 'function') {
|
||||
(0, polyfill_1.polyfillConsole)("startup", true, (props) => {
|
||||
if (props.level === "error") {
|
||||
appLoader.execRoutine(async (ctx) => {
|
||||
await errorHandler(props.caller, props.args, ctx);
|
||||
}).catch((err) => {
|
||||
console.warn('执行全局错误处理失败:', err);
|
||||
});
|
||||
}
|
||||
return props.args;
|
||||
});
|
||||
}
|
||||
// if (errorHandler && typeof errorHandler === 'function') {
|
||||
// // polyfillConsole("startup", true, (props) => {
|
||||
// // if (props.level === "error") {
|
||||
// // appLoader.execRoutine(async (ctx) => {
|
||||
// // await errorHandler(props.caller, props.args, ctx);
|
||||
// // }).catch((err) => {
|
||||
// // console.warn('执行全局错误处理失败:', err);
|
||||
// // });
|
||||
// // }
|
||||
// // return props.args;
|
||||
// // });
|
||||
// // appLoader.registerInternalErrorHandler(async (ctx, type, msg, err) => {
|
||||
// // await errorHandler(ctx, type, msg, err);
|
||||
// // });
|
||||
// }
|
||||
appLoader.regAllExceptionHandler();
|
||||
// 否则启动服务器模式
|
||||
koa.use(async (ctx, next) => {
|
||||
try {
|
||||
|
|
@ -204,6 +212,23 @@ async function startup(path, connector, omitWatchers, omitTimers, routine) {
|
|||
koa.use((0, koa_body_1.default)(Object.assign({
|
||||
multipart: true,
|
||||
}, serverConfiguration.koaBody)));
|
||||
// 注册自定义中间件
|
||||
if (serverConfiguration.middleware) {
|
||||
if (Array.isArray(serverConfiguration.middleware)) {
|
||||
serverConfiguration.middleware.forEach((mw) => {
|
||||
koa.use(mw);
|
||||
});
|
||||
}
|
||||
else if (typeof serverConfiguration.middleware === 'function') {
|
||||
const mws = serverConfiguration.middleware(koa);
|
||||
if (!Array.isArray(mws)) {
|
||||
throw new Error('middleware 配置函数必须返回 Koa.Middleware 数组');
|
||||
}
|
||||
mws.forEach((mw) => {
|
||||
koa.use(mw);
|
||||
});
|
||||
}
|
||||
}
|
||||
const router = new koa_router_1.default();
|
||||
// 如果是开发环境,允许options
|
||||
if (['development', 'staging'].includes(process.env.NODE_ENV)) {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ const typescript_1 = tslib_1.__importDefault(require("typescript"));
|
|||
const path_1 = tslib_1.__importDefault(require("path"));
|
||||
const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
|
||||
const fs_1 = tslib_1.__importDefault(require("fs"));
|
||||
const lodash_1 = require("lodash");
|
||||
const polyfill_1 = require("./polyfill");
|
||||
const tsc_alias_1 = require("tsc-alias");
|
||||
// 创建事件发射器
|
||||
const createEventEmitter = () => {
|
||||
const listeners = new Map();
|
||||
|
|
@ -227,12 +227,19 @@ const createServerManager = (projectPath, eventEmitter, config) => {
|
|||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const simpleConnector = require(path_1.default.join(projectPath, "lib/config/connector")).default;
|
||||
console.warn("----> Starting service......");
|
||||
// 这里注意要在require之前,因为require会触发编译
|
||||
const { startup } = require('./start');
|
||||
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
||||
config.lifecycle.onServerStart(config);
|
||||
return shutdown;
|
||||
});
|
||||
try {
|
||||
// 这里注意要在require之前,因为require会触发编译
|
||||
const { startup } = require('./start');
|
||||
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
||||
config.lifecycle.onServerStart(config);
|
||||
return shutdown;
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error("----> Failed to start service:", error);
|
||||
isRestarting = false;
|
||||
return;
|
||||
}
|
||||
isRestarting = false;
|
||||
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 program = typescript_1.default.createProgram({
|
||||
rootNames: [path],
|
||||
|
|
@ -375,6 +382,8 @@ const createCompiler = (projectPath, options, projectReferences, aliasConfig, co
|
|||
else {
|
||||
console.log(`Emit succeeded for ${filePath}.`);
|
||||
config.lifecycle.onAfterCompile(config);
|
||||
const jsFilePath = libPath;
|
||||
treatFile(jsFilePath);
|
||||
return {
|
||||
taskId: task.id,
|
||||
success: true,
|
||||
|
|
@ -445,40 +454,39 @@ const createFileWatcher = (projectPath, eventEmitter) => {
|
|||
const generateTaskId = () => {
|
||||
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
};
|
||||
/**
|
||||
* 根据 alias 配置表将路径中的别名替换为真实路径
|
||||
* @param path - 输入的路径字符串,例如 "@project/file" 或 "@oak-app-domain/some-module"
|
||||
* @param aliasConfig - alias 配置表,key 为别名,value 为对应的真实路径或路径数组
|
||||
* @returns 替换后的路径,如果没有匹配到 alias,则返回原始路径
|
||||
*/
|
||||
const replaceAliasWithPath = (path, aliasConfig) => {
|
||||
for (const [alias, targets] of Object.entries(aliasConfig)) {
|
||||
// If alias ends with "*", handle it as a dynamic alias.
|
||||
if (alias.endsWith('*')) {
|
||||
// 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 match = path.match(aliasPattern);
|
||||
if (match) {
|
||||
// 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)
|
||||
// Ensure that the target path ends with a slash if it's not already
|
||||
const replacedPath = target.replace(/\/\*$/, "/") + match[1];
|
||||
return replacedPath;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Handle static alias without "*" by directly matching the path
|
||||
if (path.startsWith(alias)) {
|
||||
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
|
||||
return path.replace(alias, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If no alias matches, return the original path
|
||||
return path;
|
||||
};
|
||||
const watch = (projectPath, config) => {
|
||||
// /**
|
||||
// * 根据 alias 配置表将路径中的别名替换为真实路径
|
||||
// * @param path - 输入的路径字符串,例如 "@project/file" 或 "@oak-app-domain/some-module"
|
||||
// * @param aliasConfig - alias 配置表,key 为别名,value 为对应的真实路径或路径数组
|
||||
// * @returns 替换后的路径,如果没有匹配到 alias,则返回原始路径
|
||||
// */
|
||||
// const replaceAliasWithPath = (path: string, aliasConfig: Record<string, string | string[]>): string => {
|
||||
// for (const [alias, targets] of Object.entries(aliasConfig)) {
|
||||
// // If alias ends with "*", handle it as a dynamic alias.
|
||||
// if (alias.endsWith('*')) {
|
||||
// // 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 match = path.match(aliasPattern);
|
||||
// if (match) {
|
||||
// // 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)
|
||||
// // Ensure that the target path ends with a slash if it's not already
|
||||
// const replacedPath = target.replace(/\/\*$/, "/") + match[1];
|
||||
// return replacedPath;
|
||||
// }
|
||||
// } else {
|
||||
// // Handle static alias without "*" by directly matching the path
|
||||
// if (path.startsWith(alias)) {
|
||||
// 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
|
||||
// return path.replace(alias, target);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // If no alias matches, return the original path
|
||||
// return path;
|
||||
// };
|
||||
const watch = async (projectPath, config) => {
|
||||
const realConfig = getOverrideConfig(config);
|
||||
const enableTrace = !!process.env.ENABLE_TRACE;
|
||||
// 查找配置文件
|
||||
|
|
@ -486,20 +494,30 @@ const watch = (projectPath, config) => {
|
|||
if (!configFileName) {
|
||||
throw new Error("Could not find a valid 'tsconfig.build.json'.");
|
||||
}
|
||||
// 读取配置文件
|
||||
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 = (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"));
|
||||
const runFile = await (0, tsc_alias_1.prepareSingleFileReplaceTscAliasPaths)({
|
||||
configFile: path_1.default.join(projectPath, "tsconfig.build.json"),
|
||||
resolveFullPaths: true,
|
||||
});
|
||||
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配置
|
||||
console.debug("[DEBUG] Running Alias config:", aliasConfig);
|
||||
// console.debug("[DEBUG] Running Alias config:", aliasConfig);
|
||||
// 初始化polyfill
|
||||
const polyfillLoader = () => {
|
||||
const BuiltinModule = require("module");
|
||||
|
|
@ -530,6 +548,9 @@ const watch = (projectPath, config) => {
|
|||
console.error(`[resolve] Emit skipped for: ${tsPath}`);
|
||||
throw new Error("TypeScript emit skipped");
|
||||
}
|
||||
else {
|
||||
treatFile(jsPath);
|
||||
}
|
||||
console.log(`[resolve] Successfully compiled: ${tsPath}`);
|
||||
return jsPath;
|
||||
}
|
||||
|
|
@ -559,11 +580,11 @@ const watch = (projectPath, config) => {
|
|||
rFoptions // 解析选项
|
||||
) {
|
||||
let resolvedRequest = request;
|
||||
const replacedPath = replaceAliasWithPath(request, aliasConfig);
|
||||
if (replacedPath !== request) {
|
||||
console.log(`[resolve] Alias resolved: ${request} -> ${replacedPath}`);
|
||||
resolvedRequest = path_1.default.join(projectPath, replacedPath);
|
||||
}
|
||||
// const replacedPath = replaceAliasWithPath(request, aliasConfig);
|
||||
// if (replacedPath !== request) {
|
||||
// console.log(`[resolve] Alias resolved: ${request} -> ${replacedPath}`);
|
||||
// resolvedRequest = pathLib.join(projectPath, replacedPath);
|
||||
// }
|
||||
try {
|
||||
return oldResolveFilename.call(this, resolvedRequest, parent, isMain, rFoptions);
|
||||
}
|
||||
|
|
@ -631,14 +652,34 @@ const watch = (projectPath, config) => {
|
|||
"src/ports/index.ts",
|
||||
];
|
||||
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 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 fileWatcher = createFileWatcher(projectPath, eventEmitter);
|
||||
// 设置编译器处理器
|
||||
|
|
|
|||
|
|
@ -636,8 +636,13 @@ function oakConfigContentWithWeb() {
|
|||
}
|
||||
function updateCompilerJsContent(directory, deps) {
|
||||
const compilerJsPath = (0, path_1.join)(directory, 'configuration', 'compiler.js');
|
||||
(0, assert_1.default)((0, fs_1.existsSync)(compilerJsPath));
|
||||
// 只有在有依赖项时才需要修改 compiler.js
|
||||
if (deps.length > 0) {
|
||||
// 检查文件是否存在
|
||||
if (!(0, fs_1.existsSync)(compilerJsPath)) {
|
||||
console.warn(`Warning: ${compilerJsPath} does not exist, skipping compiler.js update`);
|
||||
return;
|
||||
}
|
||||
const { ast } = (0, core_1.transformFileSync)(compilerJsPath, { ast: true });
|
||||
const { program } = ast;
|
||||
const { body } = program;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { BaseEntityDict } from "oak-domain";
|
||||
import { AsyncContext } from "oak-domain/lib/store/AsyncRowStore";
|
||||
import { EntityDict } from "oak-domain/lib/types";
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
export type ErrorHandler<ED extends EntityDict & BaseEntityDict> = (caller: NodeJS.CallSite | null, args: any[], ctx: AsyncContext<ED>) => Promise<void>;
|
||||
export type InternalErrorType = 'aspect' | 'trigger' | 'watcher' | 'timer' | 'checkpoint';
|
||||
export type InternalErrorHandler<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> = (ctx: Cxt, type: InternalErrorType, message: string, err: Error) => Promise<void>;
|
||||
export type ExceptionPublisher = (type: string, message: string, err: any) => Promise<void>;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@xuchangzju/oak-cli",
|
||||
"version": "4.0.28",
|
||||
"version": "4.0.29",
|
||||
"description": "client for oak framework",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
|
@ -112,9 +112,9 @@
|
|||
"lodash": "^4.17.21",
|
||||
"mini-css-extract-plugin": "^2.5.3",
|
||||
"node-watch": "^0.7.4",
|
||||
"oak-backend-base": "^4.1.23",
|
||||
"oak-domain": "^5.1.28",
|
||||
"oak-frontend-base": "^5.3.38",
|
||||
"oak-backend-base": "^4.1.24",
|
||||
"oak-domain": "^5.1.30",
|
||||
"oak-frontend-base": "^5.3.43",
|
||||
"parse-asn1": "5.1.6",
|
||||
"postcss": "^8.4.4",
|
||||
"postcss-flexbugs-fixes": "^5.0.2",
|
||||
|
|
@ -145,6 +145,7 @@
|
|||
"stylelint-webpack-plugin": "^3.2.0",
|
||||
"tailwindcss": "^3.0.2",
|
||||
"terser-webpack-plugin": "^5.2.5",
|
||||
"tsc-alias": "^1.8.16",
|
||||
"tslib": "^2.4.0",
|
||||
"ui-extract-webpack-plugin": "^1.0.0",
|
||||
"uuid": "^8.3.2",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ dependencies.forEach(
|
|||
}
|
||||
);
|
||||
|
||||
analyzeEntities(join(process.cwd(), 'src', 'entities'));
|
||||
const projectEntitiesPath = join(process.cwd(), 'src', 'entities');
|
||||
if (existsSync(projectEntitiesPath)) {
|
||||
analyzeEntities(projectEntitiesPath, 'src/entities');
|
||||
} else {
|
||||
console.warn('no project entities found');
|
||||
}
|
||||
|
||||
removeSync(join(process.cwd(), 'src', 'oak-app-domain'));
|
||||
buildSchema(join(process.cwd(), 'src', 'oak-app-domain'));
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import * as ts from 'typescript';
|
||||
import { writeFileSync } from 'fs';
|
||||
import { writeFileSync, readFileSync, readdirSync, existsSync, mkdirSync } from 'fs';
|
||||
const { factory } = ts;
|
||||
|
||||
import {
|
||||
|
|
@ -279,8 +279,22 @@ export async function create(dirName: string, cmd: any) {
|
|||
checkFileExistsAndCreate(rootPath);
|
||||
// 复制项目文件
|
||||
if (isModule) {
|
||||
// 模块化的项目,只拷贝src和typings目录
|
||||
copyFolder(join(emptyTemplatePath, 'src'), join(rootPath, 'src'));
|
||||
// 模块化的项目,只拷贝 src 下的内容,但跳过 pages 目录;同时拷贝 typings
|
||||
const templateSrc = join(emptyTemplatePath, 'src');
|
||||
const destSrc = join(rootPath, 'src');
|
||||
// 确保目标 src 目录存在
|
||||
if (!existsSync(destSrc)) {
|
||||
mkdirSync(destSrc, { recursive: true });
|
||||
}
|
||||
const entries = readdirSync(templateSrc, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (entry.name === 'pages') {
|
||||
continue; // 模块模式下跳过 pages
|
||||
}
|
||||
const from = join(templateSrc, entry.name);
|
||||
const to = join(destSrc, entry.name);
|
||||
copyFolder(from, to);
|
||||
}
|
||||
copyFolder(join(emptyTemplatePath, 'typings'), join(rootPath, 'typings'));
|
||||
}
|
||||
else {
|
||||
|
|
@ -356,8 +370,24 @@ export async function create(dirName: string, cmd: any) {
|
|||
tsConfigWebJson,
|
||||
checkFileExistsAndCreateType.FILE
|
||||
);
|
||||
// 更新configuration/compiler.js
|
||||
updateCompilerJsContent(rootPath, deps);
|
||||
// 复制.gitignore
|
||||
const gitignoreContent = readFile(join(__dirname, '..', 'template', '.gitignore'));
|
||||
checkFileExistsAndCreate(
|
||||
join(rootPath, '.gitignore'),
|
||||
gitignoreContent,
|
||||
checkFileExistsAndCreateType.FILE
|
||||
);
|
||||
// 复制oak.config.json
|
||||
const oakConfigContent = readFile(join(__dirname, '..', 'template', USER_CONFIG_FILE_NAME));
|
||||
checkFileExistsAndCreate(
|
||||
join(rootPath, USER_CONFIG_FILE_NAME),
|
||||
oakConfigContent,
|
||||
checkFileExistsAndCreateType.FILE
|
||||
);
|
||||
// 更新configuration/compiler.js (仅在非模块化模式下)
|
||||
if (!isModule) {
|
||||
updateCompilerJsContent(rootPath, deps);
|
||||
}
|
||||
Success(
|
||||
`${success(
|
||||
`Successfully created project ${primary(
|
||||
|
|
@ -390,9 +420,25 @@ export async function create(dirName: string, cmd: any) {
|
|||
checkFileExistsAndCreateType.FILE
|
||||
);
|
||||
|
||||
renameProject(rootPath, name, title, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_TITLE);
|
||||
// 只在非模块化模式下重命名整个项目(包括web、wechatMp等)
|
||||
if (!isModule) {
|
||||
renameProject(rootPath, name, title, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_TITLE);
|
||||
} else {
|
||||
// 模块化模式下只更新 package.json 的 name
|
||||
const packageJsonFilePath = join(rootPath, 'package.json');
|
||||
const packageJsonContent = readFileSync(packageJsonFilePath, 'utf-8');
|
||||
const packageJsonJson = JSON.parse(packageJsonContent);
|
||||
packageJsonJson.name = name;
|
||||
const newPackageJsonContent = JSON.stringify(packageJsonJson, undefined, 4);
|
||||
writeFileSync(packageJsonFilePath, newPackageJsonContent);
|
||||
Success(
|
||||
`${success(
|
||||
`Change project name to ${primary(name)}`
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
if (example) {
|
||||
if (example && !isModule) {
|
||||
// todo: copy template example files
|
||||
copyFolder(examplePath, rootPath, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { readdirSync, statSync, writeFileSync, PathLike, existsSync, unlinkSync, mkdirSync, rmdirSync, createReadStream, accessSync, createWriteStream, constants, readFileSync } from 'fs'
|
||||
import { readdirSync, statSync, writeFileSync, PathLike, existsSync, unlinkSync, mkdirSync, rmdirSync, createReadStream, accessSync, createWriteStream, constants, readFileSync, copyFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import { checkFileExistsAndCreateType } from './enum'
|
||||
import { Error, error, Warn, warn } from './tip-style'
|
||||
|
|
@ -141,9 +141,8 @@ export function copyFolder(currentDir: PathLike, targetDir: PathLike, overwrite:
|
|||
}
|
||||
else {
|
||||
if (file.isFile()) {
|
||||
const readStream = createReadStream(copyCurrentFileInfo);
|
||||
const writeStream = createWriteStream(copyTargetFileInfo);
|
||||
readStream.pipe(writeStream);
|
||||
// 使用同步复制确保文件完全写入
|
||||
copyFileSync(copyCurrentFileInfo, copyTargetFileInfo);
|
||||
// console.log(`复制文件: ${copyCurrentFileInfo} -> ${copyTargetFileInfo}`);
|
||||
} else {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import PathLib, { join } from 'path';
|
|||
import Koa from 'koa';
|
||||
import KoaRouter from 'koa-router';
|
||||
import KoaBody from 'koa-body';
|
||||
import logger from 'koa-logger';
|
||||
// import logger from 'koa-logger';
|
||||
|
||||
import { AppLoader, getClusterInfo, ClusterAppLoader } from 'oak-backend-base';
|
||||
import { BackendRuntimeContext } from 'oak-frontend-base/lib/context/BackendRuntimeContext';
|
||||
|
|
@ -26,7 +26,6 @@ import chalk from 'chalk';
|
|||
import { checkNodeVersion, randomString } from '../utils';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { LogFormatter, polyfillConsole, removePolyfill } from './polyfill';
|
||||
import { ErrorHandler } from '../types';
|
||||
|
||||
checkNodeVersion()
|
||||
|
||||
|
|
@ -57,18 +56,18 @@ export async function startup<ED extends EntityDict & BaseEntityDict, FrontCxt e
|
|||
routine?: (context: AsyncContext<ED>) => Promise<void>,
|
||||
): Promise<(() => Promise<any>) | any> {
|
||||
|
||||
let errorHandler: ErrorHandler<ED> | undefined = undefined;
|
||||
// let errorHandler: InternalErrorHandler<ED, Cxt> | undefined = undefined;
|
||||
|
||||
try {
|
||||
errorHandler = require(join(
|
||||
path,
|
||||
'lib',
|
||||
'configuration',
|
||||
'errors'
|
||||
)).default;
|
||||
} catch (err) {
|
||||
// 不存在errors配置
|
||||
}
|
||||
// try {
|
||||
// errorHandler = require(join(
|
||||
// path,
|
||||
// 'lib',
|
||||
// 'configuration',
|
||||
// 'exception'
|
||||
// )).default;
|
||||
// } catch (err) {
|
||||
// // 不存在exception配置
|
||||
// }
|
||||
|
||||
const serverConfiguration: ServerConfiguration = require(join(
|
||||
path,
|
||||
|
|
@ -89,7 +88,8 @@ export async function startup<ED extends EntityDict & BaseEntityDict, FrontCxt e
|
|||
|
||||
const koa = new Koa();
|
||||
// 使用 koa-logger 中间件打印日志
|
||||
koa.use(logger());
|
||||
// koa.use(logger());
|
||||
|
||||
// socket
|
||||
const httpServer = createServer(koa.callback());
|
||||
const socketPath = connector.getSocketPath();
|
||||
|
|
@ -220,18 +220,22 @@ export async function startup<ED extends EntityDict & BaseEntityDict, FrontCxt e
|
|||
return result;
|
||||
}
|
||||
|
||||
if (errorHandler && typeof errorHandler === 'function') {
|
||||
polyfillConsole("startup", true, (props) => {
|
||||
if (props.level === "error") {
|
||||
appLoader.execRoutine(async (ctx) => {
|
||||
await errorHandler(props.caller, props.args, ctx);
|
||||
}).catch((err) => {
|
||||
console.warn('执行全局错误处理失败:', err);
|
||||
});
|
||||
}
|
||||
return props.args;
|
||||
});
|
||||
}
|
||||
// if (errorHandler && typeof errorHandler === 'function') {
|
||||
// // polyfillConsole("startup", true, (props) => {
|
||||
// // if (props.level === "error") {
|
||||
// // appLoader.execRoutine(async (ctx) => {
|
||||
// // await errorHandler(props.caller, props.args, ctx);
|
||||
// // }).catch((err) => {
|
||||
// // console.warn('执行全局错误处理失败:', err);
|
||||
// // });
|
||||
// // }
|
||||
// // return props.args;
|
||||
// // });
|
||||
// // appLoader.registerInternalErrorHandler(async (ctx, type, msg, err) => {
|
||||
// // await errorHandler(ctx, type, msg, err);
|
||||
// // });
|
||||
// }
|
||||
appLoader.regAllExceptionHandler()
|
||||
|
||||
// 否则启动服务器模式
|
||||
koa.use(async (ctx, next) => {
|
||||
|
|
@ -261,6 +265,23 @@ export async function startup<ED extends EntityDict & BaseEntityDict, FrontCxt e
|
|||
multipart: true,
|
||||
}, serverConfiguration.koaBody))
|
||||
);
|
||||
// 注册自定义中间件
|
||||
if (serverConfiguration.middleware) {
|
||||
if (Array.isArray(serverConfiguration.middleware)) {
|
||||
serverConfiguration.middleware.forEach((mw) => {
|
||||
koa.use(mw);
|
||||
});
|
||||
}
|
||||
else if (typeof serverConfiguration.middleware === 'function') {
|
||||
const mws = serverConfiguration.middleware(koa);
|
||||
if (!Array.isArray(mws)) {
|
||||
throw new Error('middleware 配置函数必须返回 Koa.Middleware 数组');
|
||||
}
|
||||
mws.forEach((mw) => {
|
||||
koa.use(mw);
|
||||
});
|
||||
}
|
||||
}
|
||||
const router = new KoaRouter();
|
||||
|
||||
// 如果是开发环境,允许options
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ import ts, { CompilerOptions, ProjectReference } from "typescript";
|
|||
import pathLib from "path";
|
||||
import dayjs from "dayjs";
|
||||
import fs from "fs";
|
||||
import { cloneDeep } from "lodash";
|
||||
// import { cloneDeep } from "lodash";
|
||||
import { AsyncContext } from "oak-domain/lib/store/AsyncRowStore";
|
||||
import { LogFormatter, LogFormatterProp, polyfillConsole } from "./polyfill";
|
||||
import { prepareSingleFileReplaceTscAliasPaths, SingleFileReplacer } from 'tsc-alias';
|
||||
|
||||
/*
|
||||
* 工作流程
|
||||
|
|
@ -397,15 +398,22 @@ const createServerManager = (
|
|||
|
||||
console.warn("----> Starting service......");
|
||||
|
||||
// 这里注意要在require之前,因为require会触发编译
|
||||
const { startup } = require('./start') as {
|
||||
startup: (pwd: string, connector: any) => Promise<() => Promise<void>>;
|
||||
}
|
||||
try {
|
||||
// 这里注意要在require之前,因为require会触发编译
|
||||
const { startup } = require('./start') as {
|
||||
startup: (pwd: string, connector: any) => Promise<() => Promise<void>>;
|
||||
}
|
||||
|
||||
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
||||
config.lifecycle.onServerStart(config);
|
||||
return shutdown;
|
||||
});
|
||||
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
||||
config.lifecycle.onServerStart(config);
|
||||
return shutdown;
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("----> Failed to start service:", error);
|
||||
isRestarting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
isRestarting = false;
|
||||
await eventEmitter.emit("server-restarted", {});
|
||||
|
|
@ -425,13 +433,14 @@ const createServerManager = (
|
|||
};
|
||||
|
||||
// 创建编译器
|
||||
const createCompiler = (
|
||||
const createCompiler = async (
|
||||
projectPath: string,
|
||||
options: CompilerOptions,
|
||||
projectReferences: readonly ProjectReference[] | undefined,
|
||||
aliasConfig: Record<string, string | string[]>,
|
||||
treatFile: (filePath: string) => void,
|
||||
config: RealWatchConfig
|
||||
) => {
|
||||
|
||||
const createProgramAndSourceFile = (path: string) => {
|
||||
const program = ts.createProgram({
|
||||
rootNames: [path],
|
||||
|
|
@ -578,6 +587,8 @@ const createCompiler = (
|
|||
} else {
|
||||
console.log(`Emit succeeded for ${filePath}.`);
|
||||
config.lifecycle.onAfterCompile(config);
|
||||
const jsFilePath = libPath;
|
||||
treatFile(jsFilePath);
|
||||
return {
|
||||
taskId: task.id,
|
||||
success: true,
|
||||
|
|
@ -666,42 +677,42 @@ const generateTaskId = (): string => {
|
|||
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据 alias 配置表将路径中的别名替换为真实路径
|
||||
* @param path - 输入的路径字符串,例如 "@project/file" 或 "@oak-app-domain/some-module"
|
||||
* @param aliasConfig - alias 配置表,key 为别名,value 为对应的真实路径或路径数组
|
||||
* @returns 替换后的路径,如果没有匹配到 alias,则返回原始路径
|
||||
*/
|
||||
const replaceAliasWithPath = (path: string, aliasConfig: Record<string, string | string[]>): string => {
|
||||
for (const [alias, targets] of Object.entries(aliasConfig)) {
|
||||
// If alias ends with "*", handle it as a dynamic alias.
|
||||
if (alias.endsWith('*')) {
|
||||
// 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/(.*)'
|
||||
// /**
|
||||
// * 根据 alias 配置表将路径中的别名替换为真实路径
|
||||
// * @param path - 输入的路径字符串,例如 "@project/file" 或 "@oak-app-domain/some-module"
|
||||
// * @param aliasConfig - alias 配置表,key 为别名,value 为对应的真实路径或路径数组
|
||||
// * @returns 替换后的路径,如果没有匹配到 alias,则返回原始路径
|
||||
// */
|
||||
// const replaceAliasWithPath = (path: string, aliasConfig: Record<string, string | string[]>): string => {
|
||||
// for (const [alias, targets] of Object.entries(aliasConfig)) {
|
||||
// // If alias ends with "*", handle it as a dynamic alias.
|
||||
// if (alias.endsWith('*')) {
|
||||
// // 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 match = path.match(aliasPattern);
|
||||
if (match) {
|
||||
// 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)
|
||||
// Ensure that the target path ends with a slash if it's not already
|
||||
const replacedPath = target.replace(/\/\*$/, "/") + match[1];
|
||||
return replacedPath;
|
||||
}
|
||||
} else {
|
||||
// Handle static alias without "*" by directly matching the path
|
||||
if (path.startsWith(alias)) {
|
||||
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
|
||||
return path.replace(alias, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
// const match = path.match(aliasPattern);
|
||||
// if (match) {
|
||||
// // 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)
|
||||
// // Ensure that the target path ends with a slash if it's not already
|
||||
// const replacedPath = target.replace(/\/\*$/, "/") + match[1];
|
||||
// return replacedPath;
|
||||
// }
|
||||
// } else {
|
||||
// // Handle static alias without "*" by directly matching the path
|
||||
// if (path.startsWith(alias)) {
|
||||
// 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
|
||||
// return path.replace(alias, target);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// If no alias matches, return the original path
|
||||
return path;
|
||||
};
|
||||
// // If no alias matches, return the original path
|
||||
// return path;
|
||||
// };
|
||||
|
||||
export const watch = (
|
||||
export const watch = async (
|
||||
projectPath: string,
|
||||
config?: WatchConfig
|
||||
): Promise<() => Promise<void>> => {
|
||||
|
|
@ -719,29 +730,42 @@ export const watch = (
|
|||
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 { options, projectReferences } = ts.parseJsonConfigFileContent(
|
||||
configFile.config,
|
||||
ts.sys,
|
||||
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) => {
|
||||
const value = aliasConfig[key];
|
||||
// 替换src
|
||||
aliasConfig[key] = typeof value === "string" ? value.replace("src", "lib") : value.map((v: string) => v.replace("src", "lib"));
|
||||
});
|
||||
// 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配置
|
||||
console.debug("[DEBUG] Running Alias config:", aliasConfig);
|
||||
// console.debug("[DEBUG] Running Alias config:", aliasConfig);
|
||||
|
||||
// 初始化polyfill
|
||||
const polyfillLoader = () => {
|
||||
|
|
@ -781,6 +805,8 @@ export const watch = (
|
|||
if (emitResult.emitSkipped) {
|
||||
console.error(`[resolve] Emit skipped for: ${tsPath}`);
|
||||
throw new Error("TypeScript emit skipped");
|
||||
} else {
|
||||
treatFile(jsPath)
|
||||
}
|
||||
|
||||
console.log(`[resolve] Successfully compiled: ${tsPath}`);
|
||||
|
|
@ -823,13 +849,12 @@ export const watch = (
|
|||
rFoptions: object | undefined // 解析选项
|
||||
) {
|
||||
let resolvedRequest = request;
|
||||
const replacedPath = replaceAliasWithPath(request, aliasConfig);
|
||||
|
||||
if (replacedPath !== request) {
|
||||
console.log(`[resolve] Alias resolved: ${request} -> ${replacedPath}`);
|
||||
resolvedRequest = pathLib.join(projectPath, replacedPath);
|
||||
}
|
||||
// const replacedPath = replaceAliasWithPath(request, aliasConfig);
|
||||
|
||||
// if (replacedPath !== request) {
|
||||
// console.log(`[resolve] Alias resolved: ${request} -> ${replacedPath}`);
|
||||
// resolvedRequest = pathLib.join(projectPath, replacedPath);
|
||||
// }
|
||||
try {
|
||||
return oldResolveFilename.call(this, resolvedRequest, parent, isMain, rFoptions);
|
||||
} catch (error: any) {
|
||||
|
|
@ -908,16 +933,36 @@ export const watch = (
|
|||
"src/ports/index.ts",
|
||||
];
|
||||
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 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 fileWatcher = createFileWatcher(projectPath, eventEmitter);
|
||||
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ export function tsConfigPathsJsonContent(deps: string[]) {
|
|||
compilerOptions: {
|
||||
baseUrl: "./",
|
||||
paths,
|
||||
typeRoots: ["./typings"]
|
||||
typeRoots: ["./typings", "node_modules/@types"]
|
||||
}
|
||||
}, null, '\t');
|
||||
}
|
||||
|
|
@ -663,9 +663,14 @@ export function oakConfigContentWithWeb() {
|
|||
|
||||
export function updateCompilerJsContent(directory: string, deps: string[]) {
|
||||
const compilerJsPath = join(directory, 'configuration', 'compiler.js');
|
||||
assert(existsSync(compilerJsPath));
|
||||
|
||||
|
||||
// 只有在有依赖项时才需要修改 compiler.js
|
||||
if (deps.length > 0) {
|
||||
// 检查文件是否存在
|
||||
if (!existsSync(compilerJsPath)) {
|
||||
console.warn(`Warning: ${compilerJsPath} does not exist, skipping compiler.js update`);
|
||||
return;
|
||||
}
|
||||
const { ast } = transformFileSync(compilerJsPath, { ast: true })!;
|
||||
const { program } = ast!;
|
||||
const { body } = program!;
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
import { EntityDict } from "oak-domain/lib/types";
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
|
||||
export type ErrorHandler<ED extends EntityDict & BaseEntityDict> = ( caller: NodeJS.CallSite | null, args: any[], ctx: AsyncContext<ED>) => Promise<void>;
|
||||
Loading…
Reference in New Issue