Merge branch 'release'
This commit is contained in:
commit
f224983407
|
|
@ -293,6 +293,11 @@ module.exports = function (webpackEnv) {
|
|||
type: 'javascript/auto',
|
||||
use: [oakFileLoader('wxml')],
|
||||
},
|
||||
...(projectConfiguration &&
|
||||
projectConfiguration.module &&
|
||||
projectConfiguration.module.rules
|
||||
? projectConfiguration.module.rules : []
|
||||
),
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
|
|
@ -415,6 +420,7 @@ module.exports = function (webpackEnv) {
|
|||
aggregateTimeout: 600,
|
||||
ignored: '**/node_modules',
|
||||
followSymlinks: true,
|
||||
...(projectConfiguration?.watchOptions || {}),
|
||||
},
|
||||
performance: {
|
||||
hints: false,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const InjectScriptWebpackPlugin = require('./../../plugins/InjectScriptWebpackPl
|
|||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const CompressionWebpackPlugin = require('compression-webpack-plugin');
|
||||
const WebpackBar = require('webpackbar');
|
||||
|
||||
const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash');
|
||||
|
||||
|
|
@ -390,17 +391,30 @@ module.exports = function (webpackEnv) {
|
|||
net: false,
|
||||
tls: false,
|
||||
};
|
||||
let merged = defaultFb;
|
||||
if (
|
||||
projectConfiguration &&
|
||||
projectConfiguration.resolve &&
|
||||
projectConfiguration.resolve.fallback
|
||||
) {
|
||||
Object.assign(
|
||||
defaultFb,
|
||||
projectConfiguration.resolve.fallback
|
||||
);
|
||||
if(Array.isArray(projectConfiguration.resolve.fallback)) {
|
||||
merged = [...Object.keys(defaultFb).map(key => {
|
||||
// transform to :
|
||||
// {
|
||||
// alias: string | false | string[];
|
||||
// name: string;
|
||||
// onlyModule?: boolean;
|
||||
// }[]
|
||||
return {
|
||||
alias: defaultFb[key],
|
||||
name: key,
|
||||
}
|
||||
}), ...projectConfiguration.resolve.fallback];
|
||||
} else {
|
||||
merged = Object.assign(defaultFb, projectConfiguration.resolve.fallback);
|
||||
}
|
||||
}
|
||||
return defaultFb;
|
||||
return merged;
|
||||
})(),
|
||||
// This allows you to set a fallback for where webpack should look for modules.
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
|
|
@ -432,17 +446,34 @@ module.exports = function (webpackEnv) {
|
|||
'bn.js': require.resolve('bn.js'),
|
||||
assert: require.resolve('browser-assert'),
|
||||
};
|
||||
let merged = defaultAlias;
|
||||
if (
|
||||
projectConfiguration &&
|
||||
projectConfiguration.resolve &&
|
||||
projectConfiguration.resolve.alias
|
||||
) {
|
||||
Object.assign(
|
||||
defaultAlias,
|
||||
projectConfiguration.resolve.alias
|
||||
);
|
||||
// Object.assign(
|
||||
// defaultAlias,
|
||||
// projectConfiguration.resolve.alias
|
||||
// );
|
||||
if (Array.isArray(projectConfiguration.resolve.alias)) {
|
||||
// transform to :
|
||||
//{
|
||||
// alias: string | false | string[];
|
||||
// name: string;
|
||||
// onlyModule?: boolean;
|
||||
// }[]
|
||||
merged = [...Object.keys(defaultAlias).map(key => {
|
||||
return {
|
||||
alias: defaultAlias[key],
|
||||
name: key,
|
||||
}
|
||||
}), ...projectConfiguration.resolve.alias];
|
||||
} else {
|
||||
merged = Object.assign(defaultAlias, projectConfiguration.resolve.alias)
|
||||
}
|
||||
}
|
||||
return defaultAlias;
|
||||
return merged;
|
||||
})(),
|
||||
plugins: [
|
||||
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||
|
|
@ -769,6 +800,9 @@ module.exports = function (webpackEnv) {
|
|||
// Make sure to add the new loader(s) before the "file" loader.
|
||||
],
|
||||
},
|
||||
...(projectConfiguration &&
|
||||
projectConfiguration.module &&
|
||||
projectConfiguration.module.rules ? projectConfiguration.module.rules : []),
|
||||
].filter(Boolean),
|
||||
},
|
||||
plugins: [
|
||||
|
|
@ -1007,6 +1041,12 @@ module.exports = function (webpackEnv) {
|
|||
statsOptions: null,
|
||||
logLevel: 'info',
|
||||
}),
|
||||
new WebpackBar({
|
||||
color: "#85d", // 默认green,进度条颜色支持HEX
|
||||
basic: false, // 默认true,启用一个简单的日志报告器
|
||||
profile:false, // 默认false,启用探查器。
|
||||
}),
|
||||
...(projectConfiguration && projectConfiguration.plugins ? projectConfiguration.plugins : []),
|
||||
].filter(Boolean),
|
||||
// Turn off performance processing because we utilize
|
||||
// our own hints via the FileSizeReporter
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = build;
|
||||
const tslib_1 = require("tslib");
|
||||
const tip_style_1 = require("./tip-style");
|
||||
const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));
|
||||
|
|
@ -76,6 +75,7 @@ async function build(cmd) {
|
|||
`SUB_DIR_NAME=${subdir}`,
|
||||
`COMPILE_ANALYZE=${!!cmd.analyze}`,
|
||||
`GENERATE_SOURCEMAP=${!!cmd.sourcemap}`,
|
||||
!!cmd.open && `OPEN_IN_BROWSER=true`,
|
||||
`PORT=${port || 3000}`,
|
||||
!!cmd.memoryLimit && `MEMORY_LIMIT=${cmd.memoryLimit}`,
|
||||
`node`,
|
||||
|
|
@ -153,3 +153,4 @@ async function build(cmd) {
|
|||
(0, tip_style_1.Error)(`${(0, tip_style_1.error)(`target could only be web or mp(wechatMp) or rn(native)`)}`);
|
||||
}
|
||||
}
|
||||
exports.default = build;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = run;
|
||||
const tslib_1 = require("tslib");
|
||||
const tip_style_1 = require("./tip-style");
|
||||
const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));
|
||||
|
|
@ -49,3 +48,4 @@ async function run(options) {
|
|||
process.exit(-1);
|
||||
}
|
||||
}
|
||||
exports.default = run;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.create = create;
|
||||
exports.update = update;
|
||||
exports.update = exports.create = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
const ts = tslib_1.__importStar(require("typescript"));
|
||||
const fs_1 = require("fs");
|
||||
|
|
@ -241,7 +240,7 @@ async function create(dirName, cmd) {
|
|||
}
|
||||
// 获取package.json内容
|
||||
const packageJson = (0, template_1.packageJsonContent)({
|
||||
name: DEFAULT_PROJECT_NAME, // 后面再统一rename
|
||||
name: DEFAULT_PROJECT_NAME,
|
||||
version,
|
||||
description,
|
||||
cliName: config_1.CLI_NAME,
|
||||
|
|
@ -264,6 +263,7 @@ async function create(dirName, cmd) {
|
|||
(0, tip_style_1.Error)((0, tip_style_1.error)(err));
|
||||
}
|
||||
}
|
||||
exports.create = create;
|
||||
async function update(dirName, subDirName, cmd) {
|
||||
const isDev = cmd.dev ? true : false;
|
||||
try {
|
||||
|
|
@ -290,3 +290,4 @@ async function update(dirName, subDirName, cmd) {
|
|||
console.error((0, tip_style_1.error)(err.message));
|
||||
}
|
||||
}
|
||||
exports.update = update;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
import { Configuration as WebpackConfiguration } from 'webpack';
|
||||
type ResolveType = Required<WebpackConfiguration>['resolve'];
|
||||
type AliasType = Required<ResolveType>['alias'];
|
||||
type FallbackType = Required<ResolveType>['fallback'];
|
||||
type OptimizationType = Required<WebpackConfiguration>['optimization'];
|
||||
type SplitChunks = Required<OptimizationType>['splitChunks'];
|
||||
type CacheGroups = Exclude<SplitChunks, false>["cacheGroups"];
|
||||
type ExternalsType = Required<WebpackConfiguration>['externals'];
|
||||
type ExternalsObjectType = Exclude<ExternalsType, RegExp | string | Function | Array<any>>;
|
||||
type PluginType = Required<WebpackConfiguration>['plugins'];
|
||||
type PluginInstanceType = PluginType extends Array<infer T> ? Exclude<T, false | number | string | null | undefined> : never;
|
||||
type ModuleType = Required<WebpackConfiguration>['module'];
|
||||
type RuleType = Required<ModuleType>['rules'];
|
||||
type RuleObjectType = RuleType extends Array<infer T> ? Exclude<T, false | number | string | null | undefined> : never;
|
||||
type WatchOptionsType = Required<WebpackConfiguration>['watchOptions'];
|
||||
type IgnoreType = Required<WatchOptionsType>['ignored'];
|
||||
type PollType = Required<WatchOptionsType>['poll'];
|
||||
/**
|
||||
* 编译环境配置
|
||||
*/
|
||||
export type CompilerConfiguration = {
|
||||
webpack?: {
|
||||
resolve?: {
|
||||
alias?: AliasType;
|
||||
fallback?: FallbackType;
|
||||
};
|
||||
extraOakModules?: (string | RegExp)[];
|
||||
splitChunks: {
|
||||
cacheGroups: CacheGroups;
|
||||
};
|
||||
externals?: ExternalsObjectType;
|
||||
module: {
|
||||
rules: RuleObjectType[];
|
||||
};
|
||||
plugins?: PluginInstanceType[];
|
||||
watchOptions?: {
|
||||
aggregateTimeout?: number;
|
||||
ignored?: IgnoreType;
|
||||
poll?: PollType;
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* 创建一个oak编译器配置
|
||||
* @param raw 原始配置
|
||||
* @returns 编译器配置
|
||||
* 通过这个函数可以实现对配置文件的预处理,以及在项目中创建配置时提供类型参考
|
||||
*/
|
||||
export declare function CreateCompilerConfig(raw: CompilerConfiguration): CompilerConfiguration;
|
||||
export {};
|
||||
/**
|
||||
* 将compiler.js中的模块导出使用以下形式:
|
||||
* module.exports = CreateComilerConfig({})
|
||||
* 可以在编写时获得类型提示
|
||||
*/
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CreateCompilerConfig = void 0;
|
||||
/**
|
||||
* 创建一个oak编译器配置
|
||||
* @param raw 原始配置
|
||||
* @returns 编译器配置
|
||||
* 通过这个函数可以实现对配置文件的预处理,以及在项目中创建配置时提供类型参考
|
||||
*/
|
||||
function CreateCompilerConfig(raw) {
|
||||
// 在这里可以做配置的预处理
|
||||
return raw;
|
||||
}
|
||||
exports.CreateCompilerConfig = CreateCompilerConfig;
|
||||
/**
|
||||
* 将compiler.js中的模块导出使用以下形式:
|
||||
* module.exports = CreateComilerConfig({})
|
||||
* 可以在编写时获得类型提示
|
||||
*/
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import { PathLike } from 'fs';
|
||||
import { checkFileExistsAndCreateType } from './enum';
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,15 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.readDirPath = readDirPath;
|
||||
exports.readDirGetFile = readDirGetFile;
|
||||
exports.parseJsonFiles = parseJsonFiles;
|
||||
exports.parseJsonFile = parseJsonFile;
|
||||
exports.deleteFolderRecursive = deleteFolderRecursive;
|
||||
exports.writeFile = writeFile;
|
||||
exports.readFile = readFile;
|
||||
exports.copyFolder = copyFolder;
|
||||
exports.checkFileExists = checkFileExists;
|
||||
exports.checkFileExistsAndCreate = checkFileExistsAndCreate;
|
||||
exports.checkFileExistsAndCreate = exports.checkFileExists = exports.copyFolder = exports.readFile = exports.writeFile = exports.deleteFolderRecursive = exports.parseJsonFile = exports.parseJsonFiles = exports.readDirGetFile = exports.readDirPath = void 0;
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = require("path");
|
||||
const enum_1 = require("./enum");
|
||||
|
|
@ -34,6 +25,7 @@ function readDirPath(entry) {
|
|||
}
|
||||
return pathList;
|
||||
}
|
||||
exports.readDirPath = readDirPath;
|
||||
/**
|
||||
* @name 读取指定目录的文件(不进行深度遍历,只获取根目录)
|
||||
* @export
|
||||
|
|
@ -44,6 +36,7 @@ function readDirGetFile(entry) {
|
|||
const dirInfo = (0, fs_1.readdirSync)(entry);
|
||||
return dirInfo;
|
||||
}
|
||||
exports.readDirGetFile = readDirGetFile;
|
||||
/**
|
||||
* @name 解析json文件(数组)
|
||||
* @export
|
||||
|
|
@ -58,6 +51,7 @@ function parseJsonFiles(arr) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
exports.parseJsonFiles = parseJsonFiles;
|
||||
/**
|
||||
* @name 解析单个文件json
|
||||
* @export
|
||||
|
|
@ -73,6 +67,7 @@ function parseJsonFile(file) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
exports.parseJsonFile = parseJsonFile;
|
||||
/**
|
||||
* @name 删除文件夹
|
||||
* @export
|
||||
|
|
@ -102,6 +97,7 @@ function deleteFolderRecursive(entry) {
|
|||
// console.log("文件夹不存在");
|
||||
}
|
||||
}
|
||||
exports.deleteFolderRecursive = deleteFolderRecursive;
|
||||
;
|
||||
function writeFile(path, data) {
|
||||
try {
|
||||
|
|
@ -112,6 +108,7 @@ function writeFile(path, data) {
|
|||
(0, tip_style_1.Error)((0, tip_style_1.error)('文件写入失败'));
|
||||
}
|
||||
}
|
||||
exports.writeFile = writeFile;
|
||||
function readFile(path, options) {
|
||||
try {
|
||||
const data = (0, fs_1.readFileSync)(path, options);
|
||||
|
|
@ -122,6 +119,7 @@ function readFile(path, options) {
|
|||
(0, tip_style_1.Error)((0, tip_style_1.error)('文件读取失败'));
|
||||
}
|
||||
}
|
||||
exports.readFile = readFile;
|
||||
/**
|
||||
* @name 拷贝文件夹
|
||||
* @export
|
||||
|
|
@ -183,6 +181,7 @@ function copyFolder(currentDir, targetDir, overwrite = false) {
|
|||
throw new global.Error(`需要copy的文件夹不存在: ${currentDir}`);
|
||||
}
|
||||
}
|
||||
exports.copyFolder = copyFolder;
|
||||
/**
|
||||
* @name 检测文件/文件夹是否存在
|
||||
* @export
|
||||
|
|
@ -192,6 +191,7 @@ function copyFolder(currentDir, targetDir, overwrite = false) {
|
|||
function checkFileExists(path) {
|
||||
return (0, fs_1.existsSync)(path);
|
||||
}
|
||||
exports.checkFileExists = checkFileExists;
|
||||
/**
|
||||
* @name 检测文件/文件夹是否存在,不存在则创建
|
||||
* @export
|
||||
|
|
@ -217,3 +217,4 @@ function checkFileExistsAndCreate(path, data, type = enum_1.checkFileExistsAndCr
|
|||
throw new global.Error(`${path} already exists!`);
|
||||
}
|
||||
}
|
||||
exports.checkFileExistsAndCreate = checkFileExistsAndCreate;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ commander_1.default
|
|||
.option('--analyze', 'analyze')
|
||||
.option('--memoryLimit <memoryLimit>', 'memoryLimit of node')
|
||||
.option('--stackSize <number>', 'stackSize of node')
|
||||
.option('--open', 'open in browser')
|
||||
.option('-t, --target <target>', 'target')
|
||||
.option('-m, --mode <mode>', 'mode')
|
||||
.option('-d, --subDir <subDirName>', 'subDirName')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = make;
|
||||
const tslib_1 = require("tslib");
|
||||
const tip_style_1 = require("./tip-style");
|
||||
const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));
|
||||
|
|
@ -25,3 +24,4 @@ async function make(cmd, rebuild) {
|
|||
process.exit(-1);
|
||||
}
|
||||
}
|
||||
exports.default = make;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = make;
|
||||
const tslib_1 = require("tslib");
|
||||
const tip_style_1 = require("./tip-style");
|
||||
const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));
|
||||
|
|
@ -21,3 +20,4 @@ async function make() {
|
|||
process.exit(-1);
|
||||
}
|
||||
}
|
||||
exports.default = make;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = make;
|
||||
const tslib_1 = require("tslib");
|
||||
const tip_style_1 = require("./tip-style");
|
||||
const localeBuilder_1 = tslib_1.__importDefault(require("oak-domain/lib/compiler/localeBuilder"));
|
||||
|
|
@ -19,3 +18,4 @@ async function make(cmd) {
|
|||
process.exit(-1);
|
||||
}
|
||||
}
|
||||
exports.default = make;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = make;
|
||||
const tslib_1 = require("tslib");
|
||||
const tip_style_1 = require("./tip-style");
|
||||
const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));
|
||||
|
|
@ -31,3 +30,4 @@ async function make(cmd, watch) {
|
|||
process.exit(-1);
|
||||
}
|
||||
}
|
||||
exports.default = make;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.renameProject = renameProject;
|
||||
exports.rename = rename;
|
||||
exports.rename = exports.renameProject = void 0;
|
||||
const path_1 = require("path");
|
||||
const fs_1 = require("fs");
|
||||
const editTemplate_1 = require("@react-native-community/cli/build/commands/init/editTemplate");
|
||||
|
|
@ -43,10 +42,12 @@ async function renameProject(dir, name, title, placeholderName, placeholderTitle
|
|||
process.chdir(cwd);
|
||||
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Change project name to ${(0, tip_style_1.primary)(name)}, project title to ${(0, tip_style_1.primary)(title)}`)}`);
|
||||
}
|
||||
exports.renameProject = renameProject;
|
||||
async function rename(cmd) {
|
||||
const { projectName, displayName } = cmd;
|
||||
// todo 取native/android下的name和title作为placeholder,再调用renameProject
|
||||
}
|
||||
exports.rename = rename;
|
||||
/* changePlaceholderInTemplate({
|
||||
projectName: 'taicang',
|
||||
projectTitle: '太藏',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = run;
|
||||
const tslib_1 = require("tslib");
|
||||
const tip_style_1 = require("./tip-style");
|
||||
const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));
|
||||
|
|
@ -60,3 +59,4 @@ async function run(options) {
|
|||
process.exit(-1);
|
||||
}
|
||||
}
|
||||
exports.default = run;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/// <reference path="../../src/typings/polyfill.d.ts" />
|
||||
import { EntityDict } from 'oak-domain/lib/types';
|
||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
||||
import { BackendRuntimeContext } from 'oak-frontend-base/lib/context/BackendRuntimeContext';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.initialize = initialize;
|
||||
exports.initialize = void 0;
|
||||
/// <reference path="../typings/polyfill.d.ts" />
|
||||
const oak_backend_base_1 = require("oak-backend-base");
|
||||
async function initialize(path) {
|
||||
|
|
@ -10,3 +10,4 @@ async function initialize(path) {
|
|||
await appLoader.unmount();
|
||||
console.log('data initialized');
|
||||
}
|
||||
exports.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/// <reference path="../../src/typings/polyfill.d.ts" />
|
||||
import './polyfill';
|
||||
import { BackendRuntimeContext } from 'oak-frontend-base/lib/context/BackendRuntimeContext';
|
||||
import { Connector, EntityDict } from 'oak-domain/lib/types';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.startup = startup;
|
||||
exports.startup = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
/// <reference path="../typings/polyfill.d.ts" />
|
||||
require("./polyfill");
|
||||
|
|
@ -9,6 +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"));
|
||||
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");
|
||||
|
|
@ -37,6 +38,8 @@ 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)());
|
||||
// socket
|
||||
const httpServer = (0, http_1.createServer)(koa.callback());
|
||||
const socketOption = {
|
||||
|
|
@ -48,7 +51,7 @@ async function startup(path, connector, omitWatchers, omitTimers, routine) {
|
|||
}
|
||||
: serverConfiguration.cors
|
||||
? {
|
||||
origin: serverConfiguration.cors.origin, //socket.io配置cors origin是支持数组和字符串
|
||||
origin: serverConfiguration.cors.origin,
|
||||
allowedHeaders: [
|
||||
...corsHeaders.concat(connector.getCorsHeader()),
|
||||
...(serverConfiguration.cors.headers || []),
|
||||
|
|
@ -241,3 +244,4 @@ async function startup(path, connector, omitWatchers, omitTimers, routine) {
|
|||
};
|
||||
return shutdown;
|
||||
}
|
||||
exports.startup = startup;
|
||||
|
|
|
|||
|
|
@ -1 +1,72 @@
|
|||
export declare const watch: (projectPath: string) => void;
|
||||
/// <reference types="node" />
|
||||
export type LogFormatterProp = {
|
||||
level: "info" | "warn" | "error";
|
||||
caller: NodeJS.CallSite | null;
|
||||
args: any[];
|
||||
};
|
||||
export type LogFormatter = (props: LogFormatterProp) => any[];
|
||||
export type WatchConfig = {
|
||||
/**
|
||||
* 是否启用polyfill
|
||||
*/
|
||||
polyfill?: {
|
||||
/**
|
||||
* 是否启用console polyfill
|
||||
*/
|
||||
console?: {
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
enable?: boolean;
|
||||
/**
|
||||
* 是否打印调用堆栈信息
|
||||
*/
|
||||
trace?: boolean;
|
||||
/**
|
||||
* 格式化函数
|
||||
*/
|
||||
formatter: LogFormatter;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* 生命周期钩子
|
||||
*/
|
||||
lifecycle?: {
|
||||
/**
|
||||
* 初始化时调用
|
||||
* @returns void
|
||||
*/
|
||||
onInit?: () => void;
|
||||
/**
|
||||
* 服务启动时调用
|
||||
* @returns void
|
||||
*/
|
||||
onServerStart?: () => void;
|
||||
/**
|
||||
* 编译前调用
|
||||
* @returns void
|
||||
*/
|
||||
onBeforeCompile?: () => void;
|
||||
/**
|
||||
* 编译后调用
|
||||
* @returns void
|
||||
*/
|
||||
onAfterCompile?: () => void;
|
||||
/**
|
||||
* 服务关闭时调用
|
||||
* @returns void
|
||||
*/
|
||||
onServerShutdown?: () => void;
|
||||
/**
|
||||
* 销毁监视器时调用
|
||||
* @returns void
|
||||
*/
|
||||
onDispose?: () => void;
|
||||
};
|
||||
};
|
||||
type DeepRequiredIfPresent<T> = {
|
||||
[P in keyof T]-?: NonNullable<T[P]> extends (...args: any) => any ? T[P] : NonNullable<T[P]> extends (infer U)[] ? DeepRequiredIfPresent<U>[] : NonNullable<T[P]> extends object ? DeepRequiredIfPresent<NonNullable<T[P]>> : T[P] extends undefined | null ? T[P] : NonNullable<T[P]>;
|
||||
};
|
||||
export type RealWatchConfig = DeepRequiredIfPresent<WatchConfig>;
|
||||
export declare const watch: (projectPath: string, config?: WatchConfig) => Promise<() => Promise<void>>;
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -3,24 +3,108 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
exports.watch = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
const chokidar_1 = tslib_1.__importDefault(require("chokidar"));
|
||||
const path_1 = require("path");
|
||||
const typescript_1 = tslib_1.__importDefault(require("typescript"));
|
||||
const path_2 = tslib_1.__importDefault(require("path"));
|
||||
const path_1 = tslib_1.__importDefault(require("path"));
|
||||
const start_1 = require("./start");
|
||||
const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
|
||||
const fs_1 = tslib_1.__importDefault(require("fs"));
|
||||
const lodash_1 = require("lodash");
|
||||
const watch = (projectPath) => {
|
||||
const defaultConfig = {
|
||||
polyfill: {
|
||||
console: {
|
||||
enable: true,
|
||||
trace: true,
|
||||
formatter: ({ level, caller, args }) => {
|
||||
const getFileInfo = () => {
|
||||
if (!caller) {
|
||||
return "";
|
||||
}
|
||||
const fileInfo = caller
|
||||
? `${caller.getFileName()}:${caller.getLineNumber()}`
|
||||
: "";
|
||||
return fileInfo.trim();
|
||||
};
|
||||
const getTime = () => (0, dayjs_1.default)().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 = caller ? "]\x1B[0m\n" : "]\x1B[0m";
|
||||
const levelStart = level === "info"
|
||||
? infoStart
|
||||
: level === "warn"
|
||||
? warnStart
|
||||
: errorStart;
|
||||
return [
|
||||
levelStart,
|
||||
getTime(),
|
||||
getFileInfo(),
|
||||
clearColor,
|
||||
...args,
|
||||
];
|
||||
},
|
||||
},
|
||||
},
|
||||
lifecycle: {
|
||||
onInit: () => {
|
||||
console.log("----> Watcher initialized.");
|
||||
},
|
||||
onServerStart: () => {
|
||||
console.log("----> Server started.");
|
||||
},
|
||||
onBeforeCompile: () => {
|
||||
console.log("----> Compiling......");
|
||||
},
|
||||
onAfterCompile: () => {
|
||||
console.log("----> Compile completed.");
|
||||
},
|
||||
onServerShutdown: () => {
|
||||
console.log("----> Server shutdown.");
|
||||
},
|
||||
onDispose: () => {
|
||||
console.log("----> Watcher disposed.");
|
||||
},
|
||||
},
|
||||
};
|
||||
const getOverrideConfig = (config) => {
|
||||
// 遍历default里面的每一个key,如果config里面有,就覆盖,没有就用default的
|
||||
const overrideInner = (obj, dobj) => {
|
||||
const result = {};
|
||||
Object.keys(dobj).forEach((key) => {
|
||||
const value = dobj[key];
|
||||
if (typeof value === "object") {
|
||||
const v = obj[key];
|
||||
if (v === undefined) {
|
||||
result[key] = value;
|
||||
}
|
||||
else {
|
||||
result[key] = overrideInner(v, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (obj && obj[key] !== undefined) {
|
||||
result[key] = obj[key];
|
||||
}
|
||||
else {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
return config
|
||||
? overrideInner(config, defaultConfig)
|
||||
: defaultConfig;
|
||||
};
|
||||
const watch = (projectPath, config) => {
|
||||
const realConfig = getOverrideConfig(config);
|
||||
const enableTrace = !!process.env.ENABLE_TRACE;
|
||||
//polyfill console.log 添加时间
|
||||
const polyfill = (trace) => {
|
||||
const getTime = () => (0, dayjs_1.default)().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 polyfillConsole = (trace) => {
|
||||
// 获取调用堆栈信息
|
||||
const getCallerInfo = () => {
|
||||
if (!trace) {
|
||||
return null;
|
||||
}
|
||||
const originalFunc = Error.prepareStackTrace;
|
||||
let callerInfo = null;
|
||||
try {
|
||||
|
|
@ -43,219 +127,229 @@ const watch = (projectPath) => {
|
|||
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);
|
||||
};
|
||||
["info", "warn", "error"].forEach((level) => {
|
||||
const levelStr = level;
|
||||
const oldFunc = console[levelStr];
|
||||
console[levelStr] = function (...args) {
|
||||
oldFunc(...(defaultConfig.polyfill?.console?.formatter({
|
||||
level: levelStr,
|
||||
caller: getCallerInfo(),
|
||||
args,
|
||||
}) || []));
|
||||
};
|
||||
});
|
||||
};
|
||||
polyfill(enableTrace);
|
||||
let shutdown;
|
||||
const restart = async () => {
|
||||
if (shutdown) {
|
||||
console.log("----> Shutting down service......");
|
||||
await shutdown();
|
||||
realConfig.polyfill.console.enable && polyfillConsole(enableTrace);
|
||||
return new Promise((resolve, reject) => {
|
||||
realConfig.lifecycle.onInit();
|
||||
let shutdown;
|
||||
const restart = async () => {
|
||||
if (shutdown) {
|
||||
console.log("----> Shutting down service......");
|
||||
await shutdown().then(realConfig.lifecycle.onServerShutdown);
|
||||
}
|
||||
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(path_1.default.join(projectPath, "lib/config/connector")).default;
|
||||
console.warn("----> Starting service......");
|
||||
shutdown = await (0, start_1.startup)(pwd, simpleConnector).then((shutdown) => {
|
||||
realConfig.lifecycle.onServerStart();
|
||||
return shutdown;
|
||||
});
|
||||
};
|
||||
const watchSourcePath = path_1.default.join(projectPath, "src");
|
||||
console.log("Watching for changes in", watchSourcePath);
|
||||
// 查找配置文件
|
||||
const configFileName = typescript_1.default.findConfigFile(projectPath, typescript_1.default.sys.fileExists, "tsconfig.build.json");
|
||||
if (!configFileName) {
|
||||
throw new Error("Could not find a valid 'tsconfig.build.json'.");
|
||||
}
|
||||
console.warn("----> Clearing require cache of project......");
|
||||
let deleteCount = 0;
|
||||
// 清空lib以下目录的缓存
|
||||
Object.keys(require.cache).forEach((key) => {
|
||||
// 如果不是项目目录下的文件,不删除
|
||||
if (!key.startsWith(projectPath)) {
|
||||
// 读取配置文件
|
||||
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 watcher = chokidar_1.default.watch(watchSourcePath, {
|
||||
persistent: true,
|
||||
ignored: (file) => file.endsWith(".tsx") ||
|
||||
file.endsWith(".xml") ||
|
||||
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, type) => {
|
||||
// 判断一下是不是以下扩展名:ts
|
||||
if (!path.endsWith(".ts")) {
|
||||
// 如果是json文件,复制或者删除
|
||||
if (path.endsWith(".json")) {
|
||||
const targetPath = path.replace("src", "lib");
|
||||
if (type === "remove") {
|
||||
fs_1.default.unlinkSync(targetPath);
|
||||
console.warn(`File ${targetPath} has been removed.`);
|
||||
}
|
||||
else if (type === "add") {
|
||||
fs_1.default.copyFileSync(path, targetPath, fs_1.default.constants.COPYFILE_FICLONE);
|
||||
console.warn(`File ${path} has been created at ${targetPath}.`);
|
||||
}
|
||||
else if (type === "change") {
|
||||
// 强制覆盖文件
|
||||
if (fs_1.default.existsSync(targetPath)) {
|
||||
fs_1.default.unlinkSync(targetPath);
|
||||
}
|
||||
fs_1.default.copyFileSync(path, targetPath, fs_1.default.constants.COPYFILE_FICLONE);
|
||||
console.warn(`File ${path} has been copied to ${targetPath}.`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn(`File ${path} is not [ts,json] file, skiped.`);
|
||||
}
|
||||
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((0, path_1.join)(projectPath, 'lib/config/connector')).default;
|
||||
console.warn("----> Starting service......");
|
||||
shutdown = await (0, start_1.startup)(pwd, simpleConnector);
|
||||
};
|
||||
const watchSourcePath = (0, path_1.join)(projectPath, "src");
|
||||
console.log("Watching for changes in", watchSourcePath);
|
||||
// 查找配置文件
|
||||
const configFileName = typescript_1.default.findConfigFile(projectPath, typescript_1.default.sys.fileExists, "tsconfig.build.json");
|
||||
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_2.default.dirname(configFileName));
|
||||
const watcher = chokidar_1.default.watch(watchSourcePath, {
|
||||
persistent: true,
|
||||
ignored: (file) => file.endsWith(".tsx") ||
|
||||
file.endsWith(".xml") ||
|
||||
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, type) => {
|
||||
// 判断一下是不是以下扩展名:ts
|
||||
if (!path.endsWith(".ts")) {
|
||||
// 如果是json文件,复制或者删除
|
||||
if (path.endsWith(".json")) {
|
||||
const targetPath = path.replace("src", "lib");
|
||||
// 控制台清空
|
||||
console.clear();
|
||||
console.warn(`File ${path} has been ${type}d`);
|
||||
// 先判断一下这个文件在不在require.cache里面
|
||||
const modulePath = path_1.default.resolve(path);
|
||||
// 将src替换为lib
|
||||
const libPath = modulePath
|
||||
.replace("\\src\\", "\\lib\\")
|
||||
.replace(".ts", ".js");
|
||||
let compileOnly = false;
|
||||
if (!require.cache[libPath]) {
|
||||
// 如果是删除的话,直接尝试删除lib下的文件
|
||||
if (type === "remove") {
|
||||
fs_1.default.unlinkSync(targetPath);
|
||||
console.warn(`File ${targetPath} has been removed.`);
|
||||
}
|
||||
else if (type === "add") {
|
||||
fs_1.default.copyFileSync(path, targetPath, fs_1.default.constants.COPYFILE_FICLONE);
|
||||
console.warn(`File ${path} has been created at ${targetPath}.`);
|
||||
}
|
||||
else if (type === "change") {
|
||||
// 强制覆盖文件
|
||||
if (fs_1.default.existsSync(targetPath)) {
|
||||
fs_1.default.unlinkSync(targetPath);
|
||||
try {
|
||||
fs_1.default.unlinkSync(libPath);
|
||||
}
|
||||
fs_1.default.copyFileSync(path, targetPath, fs_1.default.constants.COPYFILE_FICLONE);
|
||||
console.warn(`File ${path} has been copied to ${targetPath}.`);
|
||||
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 {
|
||||
console.warn(`File ${path} is not [ts,json] file, skiped.`);
|
||||
// 如果是删除,则需要发出警告,文件正在被进程使用
|
||||
if (type === "remove") {
|
||||
console.error(`File ${libPath} is being used, skiped.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 控制台清空
|
||||
console.clear();
|
||||
console.warn(`File ${path} has been ${type}d`);
|
||||
// 先判断一下这个文件在不在require.cache里面
|
||||
const modulePath = (0, path_1.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_1.default.unlinkSync(libPath);
|
||||
const program = typescript_1.default.createProgram({
|
||||
rootNames: [path],
|
||||
options,
|
||||
projectReferences,
|
||||
});
|
||||
const sourceFile = program.getSourceFile(path);
|
||||
// 是否有语法错误
|
||||
const diagnostics = typescript_1.default.getPreEmitDiagnostics(program, sourceFile);
|
||||
if (diagnostics.length) {
|
||||
const syntaxErrors = diagnostics.filter((diagnostic) => diagnostic.category === typescript_1.default.DiagnosticCategory.Error);
|
||||
if (syntaxErrors.length) {
|
||||
console.error(`Error in ${path}`);
|
||||
syntaxErrors.forEach((diagnostic) => {
|
||||
console.error(`${typescript_1.default.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`);
|
||||
});
|
||||
console.error(`文件存在语法错误,请检查修复后重试!`);
|
||||
return;
|
||||
}
|
||||
catch (e) {
|
||||
console.error(`Error in delete ${libPath}`, e);
|
||||
}
|
||||
// 只输出单个文件
|
||||
realConfig.lifecycle.onBeforeCompile();
|
||||
const emitResult = program.emit(sourceFile);
|
||||
// 是否成功
|
||||
const result = emitResult.emitSkipped;
|
||||
if (result) {
|
||||
console.error(`Emit failed for ${path}!`);
|
||||
realConfig.lifecycle.onAfterCompile();
|
||||
}
|
||||
else {
|
||||
console.log(`Emit succeeded. ${compileOnly ? "" : "reload service......"}`);
|
||||
realConfig.lifecycle.onAfterCompile();
|
||||
if (compileOnly) {
|
||||
return;
|
||||
}
|
||||
console.warn(`File ${libPath} has been removed.`);
|
||||
await restart();
|
||||
}
|
||||
};
|
||||
const onChangeDebounced = (0, lodash_1.debounce)(async (path, type) => {
|
||||
if (isProcessing) {
|
||||
console.log("Processing, please wait...");
|
||||
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;
|
||||
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");
|
||||
}
|
||||
}
|
||||
const program = typescript_1.default.createProgram({
|
||||
rootNames: [path],
|
||||
options,
|
||||
projectReferences,
|
||||
});
|
||||
const sourceFile = program.getSourceFile(path);
|
||||
// 是否有语法错误
|
||||
const diagnostics = typescript_1.default.getPreEmitDiagnostics(program, sourceFile);
|
||||
if (diagnostics.length) {
|
||||
const syntaxErrors = diagnostics.filter((diagnostic) => diagnostic.category === typescript_1.default.DiagnosticCategory.Error);
|
||||
if (syntaxErrors.length) {
|
||||
console.error(`Error in ${path}`);
|
||||
syntaxErrors.forEach((diagnostic) => {
|
||||
console.error(`${typescript_1.default.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`);
|
||||
});
|
||||
console.error(`文件存在语法错误,请检查修复后重试!`);
|
||||
return;
|
||||
const dispose = async () => {
|
||||
if (shutdown) {
|
||||
await shutdown();
|
||||
}
|
||||
}
|
||||
// 只输出单个文件
|
||||
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 = (0, lodash_1.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");
|
||||
}
|
||||
await watcher.close();
|
||||
realConfig.lifecycle.onDispose();
|
||||
};
|
||||
restart()
|
||||
.then(() => {
|
||||
resolve(dispose);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
restart();
|
||||
};
|
||||
exports.watch = watch;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.packageJsonContent = packageJsonContent;
|
||||
exports.tsConfigJsonContent = tsConfigJsonContent;
|
||||
exports.tsConfigBuildJsonContent = tsConfigBuildJsonContent;
|
||||
exports.tsConfigBuildPathsJsonContent = tsConfigBuildPathsJsonContent;
|
||||
exports.tsConfigPathsJsonContent = tsConfigPathsJsonContent;
|
||||
exports.tsConfigMpJsonContent = tsConfigMpJsonContent;
|
||||
exports.tsConfigWebJsonContent = tsConfigWebJsonContent;
|
||||
exports.projectConfigContentWithWeChatMp = projectConfigContentWithWeChatMp;
|
||||
exports.appJsonContentWithWeChatMp = appJsonContentWithWeChatMp;
|
||||
exports.oakConfigContentWithWeChatMp = oakConfigContentWithWeChatMp;
|
||||
exports.oakConfigContentWithWeb = oakConfigContentWithWeb;
|
||||
exports.oakConfigContentWithWeb = exports.oakConfigContentWithWeChatMp = exports.appJsonContentWithWeChatMp = exports.projectConfigContentWithWeChatMp = exports.tsConfigWebJsonContent = exports.tsConfigMpJsonContent = exports.tsConfigPathsJsonContent = exports.tsConfigBuildPathsJsonContent = exports.tsConfigBuildJsonContent = exports.tsConfigJsonContent = exports.packageJsonContent = void 0;
|
||||
const child_process_1 = require("child_process");
|
||||
const fs_1 = require("fs");
|
||||
const path_1 = require("path");
|
||||
|
|
@ -60,7 +50,7 @@ function packageJsonContent({ name, version, description, cliName, cliBinName, i
|
|||
oakDevDependencyStr = `"${cliName}": "~${getPackageLatestVersion(cliName)}",`;
|
||||
}
|
||||
const serverInitScript = isDev ? "cross-env NODE_ENV=development cross-env OAK_PLATFORM=server node scripts/initServer.js" : "cross-env OAK_PLATFORM=server node scripts/initServer.js";
|
||||
const serverStartScript = isDev ? "cross-env NODE_ENV=development cross-env OAK_PLATFORM=server node scripts/startServer.js" : "cross-env OAK_PLATFORM=server node scripts/startServer.js";
|
||||
// const serverStartScript = isDev ? "cross-env NODE_ENV=development cross-env OAK_PLATFORM=server node scripts/startServer.js" : "cross-env OAK_PLATFORM=server node scripts/startServer.js";
|
||||
const serverStartWatchScript = isDev ? "cross-env ENABLE_TRACE=true cross-env NODE_ENV=development cross-env OAK_PLATFORM=server node --stack-size=65500 scripts/watchServer.js" : "cross-env OAK_PLATFORM=server node --stack-size=65500 scripts/watchServer.js";
|
||||
return `{
|
||||
"name": "${name}",
|
||||
|
|
@ -97,8 +87,7 @@ function packageJsonContent({ name, version, description, cliName, cliBinName, i
|
|||
"run:ios": "oak-cli run -p ios",
|
||||
"run:android": "oak-cli run -p android",
|
||||
"server:init": "${serverInitScript}",
|
||||
"server:start": "${serverStartScript}",
|
||||
"server:start:watch": "${serverStartWatchScript}",
|
||||
"server:start": "${serverStartWatchScript}",
|
||||
"postinstall": "npm run make:dep"
|
||||
},
|
||||
"keywords": [],
|
||||
|
|
@ -312,6 +301,7 @@ function packageJsonContent({ name, version, description, cliName, cliBinName, i
|
|||
`;
|
||||
// _moduleAliases用于lib内运行时的模块声明,重载之后require的路径还会保留@project,需要这样的方式来进行路径alias
|
||||
}
|
||||
exports.packageJsonContent = packageJsonContent;
|
||||
function tsConfigJsonContent() {
|
||||
return `{
|
||||
"extends": "./tsconfig.paths.json",
|
||||
|
|
@ -363,6 +353,7 @@ function tsConfigJsonContent() {
|
|||
]
|
||||
}`;
|
||||
}
|
||||
exports.tsConfigJsonContent = tsConfigJsonContent;
|
||||
function tsConfigBuildJsonContent() {
|
||||
return `{
|
||||
"extends": "./tsconfig.build.paths.json",
|
||||
|
|
@ -402,6 +393,7 @@ function tsConfigBuildJsonContent() {
|
|||
]
|
||||
}`;
|
||||
}
|
||||
exports.tsConfigBuildJsonContent = tsConfigBuildJsonContent;
|
||||
function tsConfigBuildPathsJsonContent() {
|
||||
return `{
|
||||
"compilerOptions": {
|
||||
|
|
@ -421,6 +413,7 @@ function tsConfigBuildPathsJsonContent() {
|
|||
}
|
||||
}`;
|
||||
}
|
||||
exports.tsConfigBuildPathsJsonContent = tsConfigBuildPathsJsonContent;
|
||||
function tsConfigPathsJsonContent() {
|
||||
return `{
|
||||
"compilerOptions": {
|
||||
|
|
@ -440,6 +433,7 @@ function tsConfigPathsJsonContent() {
|
|||
}
|
||||
}`;
|
||||
}
|
||||
exports.tsConfigPathsJsonContent = tsConfigPathsJsonContent;
|
||||
function tsConfigMpJsonContent() {
|
||||
return `{
|
||||
"extends": "./tsconfig.paths.json",
|
||||
|
|
@ -487,6 +481,7 @@ function tsConfigMpJsonContent() {
|
|||
]
|
||||
}`;
|
||||
}
|
||||
exports.tsConfigMpJsonContent = tsConfigMpJsonContent;
|
||||
function tsConfigWebJsonContent() {
|
||||
return `{
|
||||
"extends": "./tsconfig.paths.json",
|
||||
|
|
@ -536,6 +531,7 @@ function tsConfigWebJsonContent() {
|
|||
]
|
||||
}`;
|
||||
}
|
||||
exports.tsConfigWebJsonContent = tsConfigWebJsonContent;
|
||||
function projectConfigContentWithWeChatMp(oakConfigName, projectname, miniVersion) {
|
||||
return `{
|
||||
"description": "项目配置文件",
|
||||
|
|
@ -611,6 +607,7 @@ function projectConfigContentWithWeChatMp(oakConfigName, projectname, miniVersio
|
|||
}
|
||||
}`;
|
||||
}
|
||||
exports.projectConfigContentWithWeChatMp = projectConfigContentWithWeChatMp;
|
||||
function appJsonContentWithWeChatMp(isDev) {
|
||||
const pages = [
|
||||
'@project/pages/store/list/index',
|
||||
|
|
@ -634,15 +631,18 @@ function appJsonContentWithWeChatMp(isDev) {
|
|||
"sitemapLocation": "sitemap.json"
|
||||
}`;
|
||||
}
|
||||
exports.appJsonContentWithWeChatMp = appJsonContentWithWeChatMp;
|
||||
function oakConfigContentWithWeChatMp() {
|
||||
return `{
|
||||
"theme": {
|
||||
}
|
||||
}`;
|
||||
}
|
||||
exports.oakConfigContentWithWeChatMp = oakConfigContentWithWeChatMp;
|
||||
function oakConfigContentWithWeb() {
|
||||
return `{
|
||||
"theme": {
|
||||
}
|
||||
}`;
|
||||
}
|
||||
exports.oakConfigContentWithWeb = oakConfigContentWithWeb;
|
||||
|
|
|
|||
15
lib/utils.js
15
lib/utils.js
|
|
@ -1,12 +1,6 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.findJson = findJson;
|
||||
exports.getStr = getStr;
|
||||
exports.difference = difference;
|
||||
exports.intersect = intersect;
|
||||
exports.union = union;
|
||||
exports.formatJsonByFile = formatJsonByFile;
|
||||
exports.deWeight = deWeight;
|
||||
exports.deWeight = exports.formatJsonByFile = exports.union = exports.intersect = exports.difference = exports.getStr = exports.findJson = void 0;
|
||||
/**
|
||||
* @name 从一组路径里查找到所有json文件
|
||||
* @export
|
||||
|
|
@ -24,6 +18,7 @@ function findJson(pathArr) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
exports.findJson = findJson;
|
||||
/**
|
||||
* @name 已知前后文取中间文本
|
||||
* @export
|
||||
|
|
@ -37,6 +32,7 @@ function getStr(str, start, end) {
|
|||
let res = str.match(reg);
|
||||
return res ? res[1] : null;
|
||||
}
|
||||
exports.getStr = getStr;
|
||||
/**
|
||||
* @name 差集
|
||||
* @export
|
||||
|
|
@ -48,6 +44,7 @@ function getStr(str, start, end) {
|
|||
function difference(current, target) {
|
||||
return new Set([...target].filter(x => !current.has(x)));
|
||||
}
|
||||
exports.difference = difference;
|
||||
/**
|
||||
* @name 获取交集
|
||||
* @export
|
||||
|
|
@ -59,6 +56,7 @@ function difference(current, target) {
|
|||
function intersect(current, target) {
|
||||
return new Set([...target].filter(x => current.has(x)));
|
||||
}
|
||||
exports.intersect = intersect;
|
||||
/**
|
||||
* @name 获取并集
|
||||
* @export
|
||||
|
|
@ -70,6 +68,7 @@ function intersect(current, target) {
|
|||
function union(current, target) {
|
||||
return new Set([...current, ...target]);
|
||||
}
|
||||
exports.union = union;
|
||||
/**
|
||||
* @name 格式化json
|
||||
* @export
|
||||
|
|
@ -80,6 +79,7 @@ function union(current, target) {
|
|||
function formatJsonByFile(data) {
|
||||
return JSON.stringify(data, null, 2);
|
||||
}
|
||||
exports.formatJsonByFile = formatJsonByFile;
|
||||
/**
|
||||
* @name 数组对象去重
|
||||
* @export
|
||||
|
|
@ -96,3 +96,4 @@ function deWeight(arr, type) {
|
|||
}
|
||||
return new Set([...map.values()]);
|
||||
}
|
||||
exports.deWeight = deWeight;
|
||||
|
|
|
|||
11
package.json
11
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@xuchangzju/oak-cli",
|
||||
"version": "4.0.17",
|
||||
"version": "4.0.18",
|
||||
"description": "client for oak framework",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@types/cross-spawn": "^6.0.2",
|
||||
"@types/inquirer": "^9.0.3",
|
||||
"@types/koa-logger": "^3.1.5",
|
||||
"@types/koa-router": "^7.4.4",
|
||||
"@types/lodash": "^4.17.13",
|
||||
"@types/node": "^20.6.0",
|
||||
|
|
@ -40,7 +41,8 @@
|
|||
"events": "^3.3.0",
|
||||
"fork-ts-checker-webpack-plugin": "^8.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.2.2",
|
||||
"webpackbar": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
|
||||
|
|
@ -93,6 +95,7 @@
|
|||
"jest-watch-typeahead": "^1.0.0",
|
||||
"koa": "^2.13.4",
|
||||
"koa-body": "^5.0.0",
|
||||
"koa-logger": "^3.2.1",
|
||||
"koa-router": "^11.0.1",
|
||||
"less": "^4.1.2",
|
||||
"less-loader": "^10.2.0",
|
||||
|
|
@ -100,8 +103,8 @@
|
|||
"lodash": "^4.17.21",
|
||||
"mini-css-extract-plugin": "^2.5.3",
|
||||
"node-watch": "^0.7.4",
|
||||
"oak-backend-base": "^4.1.11",
|
||||
"oak-domain": "^5.1.11",
|
||||
"oak-backend-base": "^4.1.12",
|
||||
"oak-domain": "^5.1.13",
|
||||
"oak-frontend-base": "^5.3.20",
|
||||
"parse-asn1": "5.1.6",
|
||||
"postcss": "^8.4.4",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
|||
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||
const isInteractive = process.stdout.isTTY;
|
||||
|
||||
const open = !!process.env.OPEN_IN_BROWSER;
|
||||
|
||||
// Warn and crash if required files are missing
|
||||
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||
process.exit(1);
|
||||
|
|
@ -128,8 +130,8 @@ checkBrowsers(paths.appPath, isInteractive)
|
|||
);
|
||||
}
|
||||
|
||||
console.log(chalk.cyan('Starting the development server...\n'));
|
||||
openBrowser(urls.localUrlForBrowser);
|
||||
// console.log(chalk.cyan('Starting the development server...\n'));
|
||||
open && openBrowser(urls.localUrlForBrowser);
|
||||
});
|
||||
|
||||
['SIGINT', 'SIGTERM'].forEach(function (sig) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export default async function build(cmd: any) {
|
|||
const mode = (cmd.mode || 'development') as Mode;
|
||||
const target = cmd.target as Target;
|
||||
const devMode = (cmd.devMode || 'server') as DevMode;
|
||||
|
||||
if (!cmd.target) {
|
||||
Error(
|
||||
`${error(
|
||||
|
|
@ -101,6 +102,7 @@ export default async function build(cmd: any) {
|
|||
`SUB_DIR_NAME=${subdir}`,
|
||||
`COMPILE_ANALYZE=${!!cmd.analyze}`,
|
||||
`GENERATE_SOURCEMAP=${!!cmd.sourcemap}`,
|
||||
!!cmd.open && `OPEN_IN_BROWSER=true`,
|
||||
`PORT=${port || 3000}`,
|
||||
!!cmd.memoryLimit && `MEMORY_LIMIT=${cmd.memoryLimit}`,
|
||||
`node`,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
// webpack config type
|
||||
import { Configuration as WebpackConfiguration } from 'webpack';
|
||||
|
||||
type ResolveType = Required<WebpackConfiguration>['resolve'];
|
||||
type AliasType = Required<ResolveType>['alias'];
|
||||
type FallbackType = Required<ResolveType>['fallback'];
|
||||
type OptimizationType = Required<WebpackConfiguration>['optimization'];
|
||||
type SplitChunks = Required<OptimizationType>['splitChunks'];
|
||||
type CacheGroups = Exclude<SplitChunks, false>["cacheGroups"];
|
||||
type ExternalsType = Required<WebpackConfiguration>['externals'];
|
||||
type ExternalsObjectType = Exclude<ExternalsType, RegExp | string | Function | Array<any>>;
|
||||
type PluginType = Required<WebpackConfiguration>['plugins'];
|
||||
type PluginInstanceType = PluginType extends Array<infer T> ? Exclude<T, false | number | string | null | undefined> : never
|
||||
type ModuleType = Required < WebpackConfiguration > ['module'];
|
||||
type RuleType = Required<ModuleType>['rules'];
|
||||
type RuleObjectType = RuleType extends Array<infer T> ? Exclude<T, false | number | string | null | undefined> : never
|
||||
type WatchOptionsType = Required<WebpackConfiguration>['watchOptions'];
|
||||
type IgnoreType = Required<WatchOptionsType>['ignored'];
|
||||
type PollType = Required<WatchOptionsType>['poll'];
|
||||
|
||||
/**
|
||||
* 编译环境配置
|
||||
*/
|
||||
export type CompilerConfiguration = {
|
||||
webpack?: {
|
||||
resolve?: {
|
||||
alias?: AliasType;
|
||||
fallback?: FallbackType;
|
||||
},
|
||||
extraOakModules?: (string | RegExp)[]; // 被标记的module也会和项目一起被oak编译plugin进行处理(注入getRender,处理i18n等)
|
||||
splitChunks: {
|
||||
cacheGroups: CacheGroups;
|
||||
},
|
||||
externals?: ExternalsObjectType;
|
||||
module: {
|
||||
rules: RuleObjectType[];
|
||||
}
|
||||
plugins?: PluginInstanceType[];
|
||||
watchOptions?: {
|
||||
aggregateTimeout?: number;
|
||||
ignored?: IgnoreType;
|
||||
poll?: PollType;
|
||||
}
|
||||
},
|
||||
// 提供webpack的链式操作(还未完成)
|
||||
// chainWebpack?: (config: WebpackConfiguration) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建一个oak编译器配置
|
||||
* @param raw 原始配置
|
||||
* @returns 编译器配置
|
||||
* 通过这个函数可以实现对配置文件的预处理,以及在项目中创建配置时提供类型参考
|
||||
*/
|
||||
export function CreateCompilerConfig(raw: CompilerConfiguration): CompilerConfiguration {
|
||||
// 在这里可以做配置的预处理
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将compiler.js中的模块导出使用以下形式:
|
||||
* module.exports = CreateComilerConfig({})
|
||||
* 可以在编写时获得类型提示
|
||||
*/
|
||||
|
|
@ -72,6 +72,7 @@ program
|
|||
.option('--analyze', 'analyze')
|
||||
.option('--memoryLimit <memoryLimit>', 'memoryLimit of node')
|
||||
.option('--stackSize <number>', 'stackSize of node')
|
||||
.option('--open' , 'open in browser')
|
||||
.option('-t, --target <target>', 'target')
|
||||
.option('-m, --mode <mode>', 'mode')
|
||||
.option('-d, --subDir <subDirName>', 'subDirName')
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ 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 { AppLoader, getClusterInfo, ClusterAppLoader } from 'oak-backend-base';
|
||||
import { BackendRuntimeContext } from 'oak-frontend-base/lib/context/BackendRuntimeContext';
|
||||
import { OakException, Connector, EntityDict, ClusterInfo } from 'oak-domain/lib/types';
|
||||
|
|
@ -55,6 +57,8 @@ export async function startup<ED extends EntityDict & BaseEntityDict, FrontCxt e
|
|||
const corsMethods = ['PUT', 'POST', 'GET', 'DELETE', 'OPTIONS'];
|
||||
|
||||
const koa = new Koa();
|
||||
// 使用 koa-logger 中间件打印日志
|
||||
koa.use(logger());
|
||||
// socket
|
||||
const httpServer = createServer(koa.callback());
|
||||
const socketOption: Partial<ServerOptions> = {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import chokidar from "chokidar";
|
||||
import { join, resolve } from "path";
|
||||
import ts from "typescript";
|
||||
import path from "path";
|
||||
import pathLib from "path";
|
||||
import { startup } from "./start";
|
||||
import dayjs from "dayjs";
|
||||
import fs from "fs";
|
||||
|
|
@ -10,20 +9,189 @@ import { debounce } from "lodash";
|
|||
declare const require: NodeRequire;
|
||||
declare const process: NodeJS.Process;
|
||||
|
||||
export const watch = (projectPath: string) => {
|
||||
export type LogFormatterProp = {
|
||||
level: "info" | "warn" | "error";
|
||||
caller: NodeJS.CallSite | null;
|
||||
args: any[];
|
||||
};
|
||||
|
||||
export type LogFormatter = (props: LogFormatterProp) => any[];
|
||||
|
||||
export type WatchConfig = {
|
||||
/**
|
||||
* 是否启用polyfill
|
||||
*/
|
||||
polyfill?: {
|
||||
/**
|
||||
* 是否启用console polyfill
|
||||
*/
|
||||
console?: {
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
enable?: boolean;
|
||||
/**
|
||||
* 是否打印调用堆栈信息
|
||||
*/
|
||||
trace?: boolean;
|
||||
/**
|
||||
* 格式化函数
|
||||
*/
|
||||
formatter: LogFormatter;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* 生命周期钩子
|
||||
*/
|
||||
lifecycle?: {
|
||||
/**
|
||||
* 初始化时调用
|
||||
* @returns void
|
||||
*/
|
||||
onInit?: () => void;
|
||||
/**
|
||||
* 服务启动时调用
|
||||
* @returns void
|
||||
*/
|
||||
onServerStart?: () => void;
|
||||
/**
|
||||
* 编译前调用
|
||||
* @returns void
|
||||
*/
|
||||
onBeforeCompile?: () => void;
|
||||
/**
|
||||
* 编译后调用
|
||||
* @returns void
|
||||
*/
|
||||
onAfterCompile?: () => void;
|
||||
/**
|
||||
* 服务关闭时调用
|
||||
* @returns void
|
||||
*/
|
||||
onServerShutdown?: () => void;
|
||||
/**
|
||||
* 销毁监视器时调用
|
||||
* @returns void
|
||||
*/
|
||||
onDispose?: () => void;
|
||||
};
|
||||
};
|
||||
|
||||
// 真实config不会出现?,所以这里新增一个type表示真实的config
|
||||
type DeepRequiredIfPresent<T> = {
|
||||
[P in keyof T]-?: NonNullable<T[P]> extends (...args: any) => any // Check for function type
|
||||
? T[P] // Preserve the original function type
|
||||
: NonNullable<T[P]> extends (infer U)[]
|
||||
? DeepRequiredIfPresent<U>[]
|
||||
: NonNullable<T[P]> extends object
|
||||
? DeepRequiredIfPresent<NonNullable<T[P]>>
|
||||
: T[P] extends undefined | null
|
||||
? T[P]
|
||||
: NonNullable<T[P]>;
|
||||
};
|
||||
|
||||
export type RealWatchConfig = DeepRequiredIfPresent<WatchConfig>;
|
||||
|
||||
const defaultConfig: RealWatchConfig = {
|
||||
polyfill: {
|
||||
console: {
|
||||
enable: true,
|
||||
trace: true,
|
||||
formatter: ({ level, caller, args }) => {
|
||||
const getFileInfo = () => {
|
||||
if (!caller) {
|
||||
return "";
|
||||
}
|
||||
const fileInfo = caller
|
||||
? `${caller.getFileName()}:${caller.getLineNumber()}`
|
||||
: "";
|
||||
return fileInfo.trim();
|
||||
};
|
||||
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 = caller ? "]\x1B[0m\n" : "]\x1B[0m";
|
||||
const levelStart =
|
||||
level === "info"
|
||||
? infoStart
|
||||
: level === "warn"
|
||||
? warnStart
|
||||
: errorStart;
|
||||
return [
|
||||
levelStart,
|
||||
getTime(),
|
||||
getFileInfo(),
|
||||
clearColor,
|
||||
...args,
|
||||
];
|
||||
},
|
||||
},
|
||||
},
|
||||
lifecycle: {
|
||||
onInit: () => {
|
||||
console.log("----> Watcher initialized.");
|
||||
},
|
||||
onServerStart: () => {
|
||||
console.log("----> Server started.");
|
||||
},
|
||||
onBeforeCompile: () => {
|
||||
console.log("----> Compiling......");
|
||||
},
|
||||
onAfterCompile: () => {
|
||||
console.log("----> Compile completed.");
|
||||
},
|
||||
onServerShutdown: () => {
|
||||
console.log("----> Server shutdown.");
|
||||
},
|
||||
onDispose: () => {
|
||||
console.log("----> Watcher disposed.");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const getOverrideConfig = (config?: WatchConfig): RealWatchConfig => {
|
||||
// 遍历default里面的每一个key,如果config里面有,就覆盖,没有就用default的
|
||||
const overrideInner = (obj: any, dobj: any): any => {
|
||||
const result: any = {};
|
||||
Object.keys(dobj).forEach((key) => {
|
||||
const value = dobj[key];
|
||||
if (typeof value === "object") {
|
||||
const v = obj[key];
|
||||
if (v === undefined) {
|
||||
result[key] = value;
|
||||
} else {
|
||||
result[key] = overrideInner(v, value);
|
||||
}
|
||||
} else {
|
||||
if (obj && obj[key] !== undefined) {
|
||||
result[key] = obj[key];
|
||||
} else {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
return config
|
||||
? (overrideInner(config, defaultConfig) as RealWatchConfig)
|
||||
: defaultConfig;
|
||||
};
|
||||
|
||||
export const watch = (
|
||||
projectPath: string,
|
||||
config?: WatchConfig
|
||||
): Promise<() => Promise<void>> => {
|
||||
const realConfig = getOverrideConfig(config);
|
||||
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 polyfillConsole = (trace: boolean) => {
|
||||
// 获取调用堆栈信息
|
||||
const getCallerInfo = (): NodeJS.CallSite | null => {
|
||||
if (!trace) {
|
||||
return null;
|
||||
}
|
||||
const originalFunc = Error.prepareStackTrace;
|
||||
let callerInfo: NodeJS.CallSite | null = null;
|
||||
try {
|
||||
|
|
@ -46,270 +214,288 @@ export const watch = (projectPath: string) => {
|
|||
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);
|
||||
};
|
||||
["info", "warn", "error"].forEach((level: string) => {
|
||||
const levelStr = level as "info" | "warn" | "error";
|
||||
const oldFunc = console[levelStr];
|
||||
console[levelStr] = function (...args) {
|
||||
oldFunc(
|
||||
...(defaultConfig.polyfill?.console?.formatter({
|
||||
level: levelStr,
|
||||
caller: getCallerInfo(),
|
||||
args,
|
||||
}) || [])
|
||||
);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
polyfill(enableTrace);
|
||||
realConfig.polyfill.console.enable && polyfillConsole(enableTrace);
|
||||
|
||||
let shutdown: (() => Promise<void>) | undefined;
|
||||
return new Promise((resolve, reject) => {
|
||||
realConfig.lifecycle.onInit();
|
||||
let shutdown: (() => Promise<void>) | undefined;
|
||||
|
||||
const restart = async () => {
|
||||
if (shutdown) {
|
||||
console.log("----> Shutting down service......");
|
||||
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++;
|
||||
const restart = async () => {
|
||||
if (shutdown) {
|
||||
console.log("----> Shutting down service......");
|
||||
await shutdown().then(realConfig.lifecycle.onServerShutdown);
|
||||
}
|
||||
});
|
||||
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.endsWith(".xml") ||
|
||||
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
|
||||
if (!path.endsWith(".ts")) {
|
||||
// 如果是json文件,复制或者删除
|
||||
if (path.endsWith(".json")) {
|
||||
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}.`
|
||||
);
|
||||
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++;
|
||||
}
|
||||
} else {
|
||||
console.warn(`File ${path} is not [ts,json] 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
|
||||
`----> ${deleteCount} modules has been removed from require.cache.`
|
||||
);
|
||||
const pwd = process.cwd();
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const simpleConnector = require(pathLib.join(
|
||||
projectPath,
|
||||
"lib/config/connector"
|
||||
)).default;
|
||||
console.warn("----> Starting service......");
|
||||
shutdown = await startup(pwd, simpleConnector).then((shutdown) => {
|
||||
realConfig.lifecycle.onServerStart();
|
||||
return shutdown;
|
||||
});
|
||||
};
|
||||
|
||||
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 watchSourcePath = pathLib.join(projectPath, "src");
|
||||
|
||||
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
|
||||
);
|
||||
console.log("Watching for changes in", watchSourcePath);
|
||||
|
||||
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");
|
||||
}
|
||||
// 查找配置文件
|
||||
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,
|
||||
pathLib.dirname(configFileName)
|
||||
);
|
||||
|
||||
const watcher = chokidar.watch(watchSourcePath, {
|
||||
persistent: true,
|
||||
ignored: (file: string) =>
|
||||
file.endsWith(".tsx") ||
|
||||
file.endsWith(".xml") ||
|
||||
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,
|
||||
});
|
||||
|
||||
restart();
|
||||
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
|
||||
if (!path.endsWith(".ts")) {
|
||||
// 如果是json文件,复制或者删除
|
||||
if (path.endsWith(".json")) {
|
||||
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] file, skiped.`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 控制台清空
|
||||
console.clear();
|
||||
console.warn(`File ${path} has been ${type}d`);
|
||||
// 先判断一下这个文件在不在require.cache里面
|
||||
const modulePath = pathLib.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;
|
||||
}
|
||||
}
|
||||
// 只输出单个文件
|
||||
realConfig.lifecycle.onBeforeCompile();
|
||||
const emitResult = program.emit(sourceFile);
|
||||
// 是否成功
|
||||
const result = emitResult.emitSkipped;
|
||||
if (result) {
|
||||
console.error(`Emit failed for ${path}!`);
|
||||
realConfig.lifecycle.onAfterCompile();
|
||||
} else {
|
||||
console.log(
|
||||
`Emit succeeded. ${
|
||||
compileOnly ? "" : "reload service......"
|
||||
}`
|
||||
);
|
||||
realConfig.lifecycle.onAfterCompile();
|
||||
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");
|
||||
}
|
||||
});
|
||||
|
||||
const dispose = async () => {
|
||||
if (shutdown) {
|
||||
await shutdown();
|
||||
}
|
||||
await watcher.close();
|
||||
realConfig.lifecycle.onDispose();
|
||||
};
|
||||
|
||||
restart()
|
||||
.then(() => {
|
||||
resolve(dispose);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// import { CompilerConfiguration } from 'oak-domain/lib/types/Configuration';
|
||||
const path = require('path');
|
||||
const { CreateCompilerConfig } = require('@xuchangzju/oak-cli/lib/createConfig')
|
||||
const oakGeneralBusinessPath = path.resolve(
|
||||
'node_modules/oak-general-business/es'
|
||||
);
|
||||
|
|
@ -7,12 +8,11 @@ const oakFrontendBasePath = path.resolve(
|
|||
'node_modules/oak-frontend-base/es'
|
||||
);
|
||||
|
||||
|
||||
const oakPayBusinessPath = path.resolve(
|
||||
'node_modules/oak-pay-business/es'
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
module.exports = CreateCompilerConfig({
|
||||
webpack: {
|
||||
extraOakModules: [/oak-pay-business/, /oak-general-business/],
|
||||
resolve: {
|
||||
|
|
@ -23,4 +23,4 @@ module.exports = {
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue