server watch移至cli中
This commit is contained in:
parent
84993373d7
commit
712964f288
|
|
@ -0,0 +1,314 @@
|
||||||
|
import chokidar from "chokidar";
|
||||||
|
import { join, resolve } from "path";
|
||||||
|
import ts from "typescript";
|
||||||
|
import path from "path";
|
||||||
|
import { startup } from "./start";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import fs from "fs";
|
||||||
|
import { debounce } from "lodash";
|
||||||
|
|
||||||
|
declare const require: NodeRequire;
|
||||||
|
declare const process: NodeJS.Process;
|
||||||
|
|
||||||
|
export const watch = (projectPath: string) => {
|
||||||
|
const enableTrace = !!process.env.ENABLE_TRACE;
|
||||||
|
|
||||||
|
//polyfill console.log 添加时间
|
||||||
|
const polyfill = (trace: boolean) => {
|
||||||
|
const getTime = () => dayjs().format("YYYY-MM-DD HH:mm:ss.SSS");
|
||||||
|
|
||||||
|
const infoStart = "\x1B[36m[ Info";
|
||||||
|
const warnStart = "\x1B[33m[ Warn";
|
||||||
|
const errorStart = "\x1B[31m[ Error";
|
||||||
|
const clearColor = trace ? "]\x1B[0m\n" : "]\x1B[0m";
|
||||||
|
|
||||||
|
// 获取调用堆栈信息
|
||||||
|
const getCallerInfo = (): NodeJS.CallSite | null => {
|
||||||
|
const originalFunc = Error.prepareStackTrace;
|
||||||
|
let callerInfo: NodeJS.CallSite | null = null;
|
||||||
|
try {
|
||||||
|
const err = new Error();
|
||||||
|
Error.prepareStackTrace = (err, stack) => stack;
|
||||||
|
const stack = err.stack as unknown as NodeJS.CallSite[]; // Type assertion here
|
||||||
|
const currentFile = stack[0].getFileName();
|
||||||
|
|
||||||
|
for (let i = 1; i < stack.length; i++) {
|
||||||
|
// Start from index 1
|
||||||
|
const callSite = stack[i];
|
||||||
|
if (currentFile !== callSite.getFileName()) {
|
||||||
|
callerInfo = callSite;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
Error.prepareStackTrace = originalFunc;
|
||||||
|
return callerInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFileInfo = () => {
|
||||||
|
if (!trace) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const callerInfo = getCallerInfo();
|
||||||
|
const fileInfo = callerInfo
|
||||||
|
? `${callerInfo.getFileName()}:${callerInfo.getLineNumber()}`
|
||||||
|
: "";
|
||||||
|
return fileInfo.trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
// polyfill console.log 添加时间和文件位置
|
||||||
|
const oldLog = console.log;
|
||||||
|
console.log = function (...args) {
|
||||||
|
oldLog(infoStart, getTime(), getFileInfo(), clearColor, ...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
const oldWarn = console.warn;
|
||||||
|
console.warn = function (...args) {
|
||||||
|
oldWarn(warnStart, getTime(), getFileInfo(), clearColor, ...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
const oldError = console.error;
|
||||||
|
console.error = function (...args) {
|
||||||
|
oldError(errorStart, getTime(), getFileInfo(), clearColor, ...args);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
polyfill(enableTrace);
|
||||||
|
|
||||||
|
let shutdown: (() => Promise<void>) | undefined;
|
||||||
|
|
||||||
|
|
||||||
|
const restart = async () => {
|
||||||
|
if (shutdown) {
|
||||||
|
await shutdown();
|
||||||
|
}
|
||||||
|
console.warn("----> Clearing require cache of project......");
|
||||||
|
let deleteCount = 0;
|
||||||
|
// 清空lib以下目录的缓存
|
||||||
|
Object.keys(require.cache).forEach((key) => {
|
||||||
|
// 如果不是项目目录下的文件,不删除
|
||||||
|
if (!key.startsWith(projectPath)) {
|
||||||
|
return;
|
||||||
|
} else if (key.includes("lib") && !key.includes("node_modules")) {
|
||||||
|
delete require.cache[key];
|
||||||
|
deleteCount++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.warn(`----> ${deleteCount} modules has been removed from require.cache.`);
|
||||||
|
const pwd = process.cwd();
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const simpleConnector = require(join(projectPath, 'lib/config/connector')).default;
|
||||||
|
console.warn("----> Starting service......");
|
||||||
|
shutdown = await startup(pwd, simpleConnector);
|
||||||
|
};
|
||||||
|
|
||||||
|
const watchSourcePath = join(projectPath, "src");
|
||||||
|
|
||||||
|
console.log("Watching for changes in", watchSourcePath);
|
||||||
|
|
||||||
|
// 查找配置文件
|
||||||
|
const configFileName = ts.findConfigFile(
|
||||||
|
projectPath,
|
||||||
|
ts.sys.fileExists,
|
||||||
|
"tsconfig.build.json"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!configFileName) {
|
||||||
|
throw new Error("Could not find a valid 'tsconfig.build.json'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取配置文件
|
||||||
|
const configFile = ts.readConfigFile(configFileName, ts.sys.readFile);
|
||||||
|
|
||||||
|
// 解析配置文件内容
|
||||||
|
const { options, projectReferences } = ts.parseJsonConfigFileContent(
|
||||||
|
configFile.config,
|
||||||
|
ts.sys,
|
||||||
|
path.dirname(configFileName)
|
||||||
|
);
|
||||||
|
|
||||||
|
const watcher = chokidar.watch(watchSourcePath, {
|
||||||
|
persistent: true,
|
||||||
|
ignored: (file: string) =>
|
||||||
|
file.endsWith(".tsx") ||
|
||||||
|
file.includes("components") ||
|
||||||
|
file.includes("pages") ||
|
||||||
|
file.includes("hooks"),
|
||||||
|
interval: 100,
|
||||||
|
binaryInterval: 100,
|
||||||
|
cwd: projectPath,
|
||||||
|
depth: 99,
|
||||||
|
followSymlinks: true,
|
||||||
|
ignoreInitial: false,
|
||||||
|
ignorePermissionErrors: false,
|
||||||
|
usePolling: false,
|
||||||
|
alwaysStat: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let startWatching = false;
|
||||||
|
|
||||||
|
watcher.on("ready", () => {
|
||||||
|
console.warn("Initial scan complete. Ready for changes");
|
||||||
|
startWatching = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
watcher.on("error", (error) => console.log(`Watcher error: ${error}`));
|
||||||
|
|
||||||
|
let isProcessing = false;
|
||||||
|
const fileChangeHandler = async (
|
||||||
|
path: string,
|
||||||
|
type: "add" | "remove" | "change"
|
||||||
|
) => {
|
||||||
|
// 判断一下是不是以下扩展名:ts,tsx
|
||||||
|
if (!path.endsWith(".ts")) {
|
||||||
|
// 如果是json或者xml文件,复制或者删除
|
||||||
|
if (path.endsWith(".json") || path.endsWith(".xml")) {
|
||||||
|
const targetPath = path.replace("src", "lib");
|
||||||
|
if (type === "remove") {
|
||||||
|
fs.unlinkSync(targetPath);
|
||||||
|
console.warn(`File ${targetPath} has been removed.`);
|
||||||
|
} else if (type === "add") {
|
||||||
|
fs.copyFileSync(
|
||||||
|
path,
|
||||||
|
targetPath,
|
||||||
|
fs.constants.COPYFILE_FICLONE
|
||||||
|
);
|
||||||
|
console.warn(
|
||||||
|
`File ${path} has been created at ${targetPath}.`
|
||||||
|
);
|
||||||
|
} else if (type === "change") {
|
||||||
|
// 强制覆盖文件
|
||||||
|
if (fs.existsSync(targetPath)) {
|
||||||
|
fs.unlinkSync(targetPath);
|
||||||
|
}
|
||||||
|
fs.copyFileSync(
|
||||||
|
path,
|
||||||
|
targetPath,
|
||||||
|
fs.constants.COPYFILE_FICLONE
|
||||||
|
);
|
||||||
|
console.warn(
|
||||||
|
`File ${path} has been copied to ${targetPath}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn(`File ${path} is not [ts,json,xml] file, skiped.`);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 控制台清空
|
||||||
|
console.clear();
|
||||||
|
console.warn(`File ${path} has been ${type}d`);
|
||||||
|
// 先判断一下这个文件在不在require.cache里面
|
||||||
|
const modulePath = resolve(path);
|
||||||
|
// 将src替换为lib
|
||||||
|
const libPath = modulePath
|
||||||
|
.replace("\\src\\", "\\lib\\")
|
||||||
|
.replace(".ts", ".js");
|
||||||
|
let compileOnly = false;
|
||||||
|
if (!require.cache[libPath]) {
|
||||||
|
// 如果是删除的话,直接尝试删除lib下的文件
|
||||||
|
if (type === "remove") {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(libPath);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Error in delete ${libPath}`, e);
|
||||||
|
}
|
||||||
|
console.warn(`File ${libPath} has been removed.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.warn(
|
||||||
|
`File ${libPath} is not in module cache, will compile only.`
|
||||||
|
);
|
||||||
|
compileOnly = true;
|
||||||
|
} else {
|
||||||
|
// 如果是删除,则需要发出警告,文件正在被进程使用
|
||||||
|
if (type === "remove") {
|
||||||
|
console.error(`File ${libPath} is being used, skiped.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const program = ts.createProgram({
|
||||||
|
rootNames: [path],
|
||||||
|
options,
|
||||||
|
projectReferences,
|
||||||
|
});
|
||||||
|
const sourceFile = program.getSourceFile(path);
|
||||||
|
// 是否有语法错误
|
||||||
|
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
|
||||||
|
if (diagnostics.length) {
|
||||||
|
const syntaxErrors = diagnostics.filter(
|
||||||
|
(diagnostic) =>
|
||||||
|
diagnostic.category === ts.DiagnosticCategory.Error
|
||||||
|
);
|
||||||
|
|
||||||
|
if (syntaxErrors.length) {
|
||||||
|
console.error(`Error in ${path}`);
|
||||||
|
syntaxErrors.forEach((diagnostic) => {
|
||||||
|
console.error(
|
||||||
|
`${ts.flattenDiagnosticMessageText(
|
||||||
|
diagnostic.messageText,
|
||||||
|
"\n"
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
console.error(`文件存在语法错误,请检查修复后重试!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 只输出单个文件
|
||||||
|
const emitResult = program.emit(sourceFile);
|
||||||
|
// 是否成功
|
||||||
|
const result = emitResult.emitSkipped;
|
||||||
|
if (result) {
|
||||||
|
console.error(`Emit failed for ${path}!`);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`Emit succeeded. ${compileOnly ? "" : "reload service......"}`
|
||||||
|
);
|
||||||
|
if (compileOnly) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await restart();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeDebounced = debounce(
|
||||||
|
async (path: string, type: "add" | "remove" | "change") => {
|
||||||
|
if (isProcessing) {
|
||||||
|
console.log("Processing, please wait...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
isProcessing = true;
|
||||||
|
await fileChangeHandler(path, type);
|
||||||
|
} catch (e) {
|
||||||
|
console.clear();
|
||||||
|
console.error(e);
|
||||||
|
} finally {
|
||||||
|
isProcessing = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
100
|
||||||
|
);
|
||||||
|
|
||||||
|
watcher
|
||||||
|
.on("add", (path) => {
|
||||||
|
if (startWatching) {
|
||||||
|
onChangeDebounced(path, "add");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on("change", (path) => {
|
||||||
|
if (startWatching) {
|
||||||
|
onChangeDebounced(path, "change");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on("unlink", (path) => {
|
||||||
|
if (startWatching) {
|
||||||
|
onChangeDebounced(path, "remove");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
restart();
|
||||||
|
};
|
||||||
|
|
@ -1,309 +1,6 @@
|
||||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||||
require('module-alias/register');
|
require('module-alias/register');
|
||||||
const chokidar = require('chokidar');
|
const { watch } = require('@xuchangzju/oak-cli/lib/server/watch');
|
||||||
const { join } = require('path');
|
|
||||||
const ts = require('typescript');
|
|
||||||
const path = require('path');
|
|
||||||
const { resolve } = require('path');
|
|
||||||
const _ = require('lodash');
|
|
||||||
const { startup } = require('@xuchangzju/oak-cli/lib/server/start');
|
|
||||||
const projectPath = join(__dirname, '..');
|
|
||||||
const dayjs = require('dayjs');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const enableTrace = !!process.env.ENABLE_TRACE;
|
|
||||||
|
|
||||||
//polyfill console.log 添加时间
|
|
||||||
const polyfill = (trace) => {
|
|
||||||
const getTime = () => {
|
|
||||||
return dayjs().format('YYYY-MM-DD HH:mm:ss.SSS');
|
|
||||||
};
|
|
||||||
|
|
||||||
const infoStart = '\x1B[36m[ Info';
|
|
||||||
const warnStart = '\x1B[33m[ Warn';
|
|
||||||
const errorStart = '\x1B[31m[ Error';
|
|
||||||
const clearColor = trace ? ']\x1B[0m\n' : ']\x1B[0m';
|
|
||||||
// 获取调用堆栈信息
|
|
||||||
const getCallerInfo = () => {
|
|
||||||
const originalFunc = Error.prepareStackTrace;
|
|
||||||
let callerInfo = null;
|
|
||||||
try {
|
|
||||||
const err = new Error();
|
|
||||||
Error.prepareStackTrace = (err, stack) => {
|
|
||||||
return stack;
|
|
||||||
};
|
|
||||||
const currentFile = err.stack.shift().getFileName();
|
|
||||||
while (err.stack.length) {
|
|
||||||
callerInfo = err.stack.shift();
|
|
||||||
if (currentFile !== callerInfo.getFileName()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
Error.prepareStackTrace = originalFunc;
|
|
||||||
return callerInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getFileInfo = () => {
|
|
||||||
if (!trace) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
const callerInfo = getCallerInfo();
|
|
||||||
const fileInfo = callerInfo
|
|
||||||
? `${callerInfo.getFileName()}:${callerInfo.getLineNumber()}`
|
|
||||||
: '';
|
|
||||||
return fileInfo.trim();
|
|
||||||
};
|
|
||||||
|
|
||||||
// polyfill console.log 添加时间和文件位置
|
|
||||||
const oldLog = console.log;
|
|
||||||
console.log = function () {
|
|
||||||
oldLog(infoStart, getTime(), getFileInfo(), clearColor, ...arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
const oldWarn = console.warn;
|
|
||||||
console.warn = function () {
|
|
||||||
oldWarn(warnStart, getTime(), getFileInfo(), clearColor, ...arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
const oldError = console.error;
|
|
||||||
console.error = function () {
|
|
||||||
oldError(
|
|
||||||
errorStart,
|
|
||||||
getTime(),
|
|
||||||
getFileInfo(),
|
|
||||||
clearColor,
|
|
||||||
...arguments
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
polyfill(enableTrace);
|
|
||||||
|
|
||||||
let shutdown;
|
|
||||||
|
|
||||||
const restart = async () => {
|
|
||||||
if (shutdown) {
|
|
||||||
await shutdown();
|
|
||||||
}
|
|
||||||
// 清空lib以下目录的缓存
|
|
||||||
// 删除所有模块的缓存
|
|
||||||
Object.keys(require.cache).forEach(function (key) {
|
|
||||||
// 如果不是项目目录下的文件,不删除
|
|
||||||
if (!key.startsWith(projectPath)) {
|
|
||||||
return;
|
|
||||||
} else if (key.includes('lib') && !key.includes('node_modules')) {
|
|
||||||
console.log('delete module cache:', key);
|
|
||||||
delete require.cache[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const pwd = process.cwd();
|
const pwd = process.cwd();
|
||||||
const simpleConnector = require('../lib/config/connector').default;
|
|
||||||
console.warn('----> Starting service......');
|
|
||||||
shutdown = await startup(pwd, simpleConnector);
|
|
||||||
};
|
|
||||||
|
|
||||||
const watchSourcePath = join(projectPath, 'src');
|
watch(pwd);
|
||||||
|
|
||||||
console.log('Watching for changes in', watchSourcePath);
|
|
||||||
|
|
||||||
// 查找配置文件
|
|
||||||
const configFileName = ts.findConfigFile(
|
|
||||||
/*searchPath*/ projectPath,
|
|
||||||
ts.sys.fileExists,
|
|
||||||
'tsconfig.build.json'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!configFileName) {
|
|
||||||
throw new Error("Could not find a valid 'tsconfig.build.json'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取配置文件
|
|
||||||
const configFile = ts.readConfigFile(configFileName, ts.sys.readFile);
|
|
||||||
|
|
||||||
// 解析配置文件内容
|
|
||||||
const { options, projectReferences } = ts.parseJsonConfigFileContent(
|
|
||||||
configFile.config,
|
|
||||||
ts.sys,
|
|
||||||
path.dirname(configFileName)
|
|
||||||
);
|
|
||||||
|
|
||||||
const watcher = chokidar.watch(watchSourcePath, {
|
|
||||||
persistent: true,
|
|
||||||
// ignore render and i18n files
|
|
||||||
ignored: (file) => {
|
|
||||||
return (
|
|
||||||
file.endsWith('.tsx') ||
|
|
||||||
file.includes('components') ||
|
|
||||||
file.includes('pages') ||
|
|
||||||
file.includes('hooks')
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// awaitWriteFinish: true, // emit single event when chunked writes are completed
|
|
||||||
// atomic: true, // emit proper events when "atomic writes" (mv _tmp file) are used
|
|
||||||
interval: 100,
|
|
||||||
binaryInterval: 100,
|
|
||||||
cwd: projectPath,
|
|
||||||
depth: 99,
|
|
||||||
followSymlinks: true,
|
|
||||||
ignoreInitial: false,
|
|
||||||
ignorePermissionErrors: false,
|
|
||||||
usePolling: false,
|
|
||||||
alwaysStat: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
let startWatching = false;
|
|
||||||
|
|
||||||
watcher.on('ready', () => {
|
|
||||||
console.warn('Initial scan complete. Ready for changes');
|
|
||||||
startWatching = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
watcher.on('error', (error) => console.log(`Watcher error: ${error}`));
|
|
||||||
|
|
||||||
let isProcessing = false;
|
|
||||||
const fileChangeHandler = async (path, type) => {
|
|
||||||
// 判断一下是不是以下扩展名:ts,tsx
|
|
||||||
if (!path.endsWith('.ts')) {
|
|
||||||
// 如果是json或者xml文件,复制或者删除
|
|
||||||
if (path.endsWith('.json') || path.endsWith('.xml')) {
|
|
||||||
const targetPath = path.replace('src', 'lib');
|
|
||||||
if (type === 'remove') {
|
|
||||||
fs.unlinkSync(targetPath);
|
|
||||||
console.warn(`File ${targetPath} has been removed.`);
|
|
||||||
} else if (type === 'add') {
|
|
||||||
fs.copyFileSync(
|
|
||||||
path,
|
|
||||||
targetPath,
|
|
||||||
fs.constants.COPYFILE_FICLONE
|
|
||||||
);
|
|
||||||
console.warn(`File ${path} has been created at ${targetPath}.`);
|
|
||||||
} else if (type === 'change') {
|
|
||||||
// 强制覆盖文件
|
|
||||||
if (fs.existsSync(targetPath)) {
|
|
||||||
fs.unlinkSync(targetPath);
|
|
||||||
}
|
|
||||||
fs.copyFileSync(
|
|
||||||
path,
|
|
||||||
targetPath,
|
|
||||||
fs.constants.COPYFILE_FICLONE
|
|
||||||
);
|
|
||||||
console.warn(`File ${path} has been copied to ${targetPath}.`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn(`File ${path} is not [ts,json,xml] file, skiped.`);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 控制台清空
|
|
||||||
console.clear();
|
|
||||||
console.warn(`File ${path} has been ${type}d`);
|
|
||||||
// 先判断一下这个文件在不在require.cache里面
|
|
||||||
const modulePath = resolve(path);
|
|
||||||
// 将src替换为lib
|
|
||||||
const libPath = modulePath
|
|
||||||
.replace('\\src\\', '\\lib\\')
|
|
||||||
.replace('.ts', '.js');
|
|
||||||
let compileOnly = false;
|
|
||||||
if (!require.cache[libPath]) {
|
|
||||||
// 如果是删除的话,直接尝试删除lib下的文件
|
|
||||||
if (type === 'remove') {
|
|
||||||
try {
|
|
||||||
fs.unlinkSync(libPath);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Error in delete ${libPath}`, e);
|
|
||||||
}
|
|
||||||
console.warn(`File ${libPath} has been removed.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.warn(
|
|
||||||
`File ${libPath} is not in module cache, will compile only.`
|
|
||||||
);
|
|
||||||
compileOnly = true;
|
|
||||||
} else {
|
|
||||||
// 如果是删除,则需要发出警告,文件正在被进程使用
|
|
||||||
if (type === 'remove') {
|
|
||||||
console.error(`File ${libPath} is being used, skiped.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const program = ts.createProgram({
|
|
||||||
rootNames: [path],
|
|
||||||
options,
|
|
||||||
projectReferences,
|
|
||||||
});
|
|
||||||
const sourceFile = program.getSourceFile(path);
|
|
||||||
// 是否有语法错误
|
|
||||||
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
|
|
||||||
if (diagnostics.length) {
|
|
||||||
const syntaxErrors = diagnostics.filter(
|
|
||||||
(diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error
|
|
||||||
);
|
|
||||||
|
|
||||||
if (syntaxErrors.length) {
|
|
||||||
console.error(`Error in ${path}`);
|
|
||||||
syntaxErrors.forEach((diagnostic) => {
|
|
||||||
console.error(
|
|
||||||
`${ts.flattenDiagnosticMessageText(
|
|
||||||
diagnostic.messageText,
|
|
||||||
'\n'
|
|
||||||
)}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
console.error(`文件存在语法错误,请检查修复后重试!`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 只输出单个文件
|
|
||||||
const emitResult = program.emit(sourceFile);
|
|
||||||
// 是否成功
|
|
||||||
const result = emitResult.emitSkipped;
|
|
||||||
if (result) {
|
|
||||||
console.error(`Emit failed for ${path}!`);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
`Emit succeeded. ${compileOnly ? '' : 'reload service......'}`
|
|
||||||
);
|
|
||||||
if (compileOnly) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await restart();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChangeDebounced = _.debounce(async (path, type) => {
|
|
||||||
if (isProcessing) {
|
|
||||||
console.log('Processing, please wait...');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
isProcessing = true;
|
|
||||||
await fileChangeHandler(path, type);
|
|
||||||
} catch (e) {
|
|
||||||
console.clear();
|
|
||||||
console.error(e);
|
|
||||||
} finally {
|
|
||||||
isProcessing = false;
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
watcher
|
|
||||||
.on('add', (path) => {
|
|
||||||
if (startWatching) {
|
|
||||||
onChangeDebounced(path, 'add');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on('change', (path) => {
|
|
||||||
if (startWatching) {
|
|
||||||
onChangeDebounced(path, 'change');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on('unlink', (path) => {
|
|
||||||
if (startWatching) {
|
|
||||||
onChangeDebounced(path, 'remove');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
restart();
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue