UNPKG

takin

Version:

Front end engineering base toolchain and scaffold

191 lines 7.56 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Takin = void 0; const lodash_1 = require("lodash"); const tapable_1 = require("tapable"); const config_1 = require("./config"); const constants_1 = require("./constants"); const logger_1 = require("./logger"); const ChangeCwdPlugin_1 = __importDefault(require("./plugins/ChangeCwdPlugin")); const CustomConfigPlugin_1 = __importDefault(require("./plugins/CustomConfigPlugin")); const LoadEnvPlugin_1 = __importDefault(require("./plugins/LoadEnvPlugin")); const MultiConfigPlugin_1 = __importDefault(require("./plugins/MultiConfigPlugin")); const PluginConfigPlugin_1 = __importDefault(require("./plugins/PluginConfigPlugin")); const StopRunPlugin_1 = __importDefault(require("./plugins/StopRunPlugin")); const runner_1 = require("./runner"); /** * 命令行扩展内核,基于 Runner 和 Plugin * 提供各类 Utils 方法 */ class Takin extends config_1.Config { constructor(name = constants_1.DEFAULT_NAME) { super(name); // 重新初始化默认 logger // 以传入的 name 为准 logger_1.logger.init('info', { debugPrefix: name, prefix: `[${name}]` }); this.currentRunners = new Set(); // 旧版兼容 this.config = this; this.isConfigLoaded = false; this.isReloading = false; this.hooks = { initialize: new tapable_1.AsyncSeriesHook(['takin']), prepare: new tapable_1.AsyncSeriesHook(['runnerOptions']), extendRunner: new tapable_1.SyncWaterfallHook(['Runner', 'runnerOptions']), configLoaded: new tapable_1.AsyncSeriesHook(['takin', 'commandOptions']), configFiltered: new tapable_1.AsyncSeriesWaterfallHook([ 'UserConfigs', 'commandOptions' ]) }; // 内部插件 this.use([ new ChangeCwdPlugin_1.default(), new CustomConfigPlugin_1.default(), new MultiConfigPlugin_1.default(), new PluginConfigPlugin_1.default() ]); } /** * 应用 Runner 插件 */ use(plugins) { this.usePlugins(plugins, config_1.PluginTypes.use); } /** * 执行命令, 分为如下几个步骤 * 1. 执行初始化 hook * 2. 尝试载入配置文件, 只执行一次 * 3. 基于多配置的设定,获取 filters * 4. 基于 filters 筛选 用户配置 * 5. 基于不同的用户配置分别运行 Runner * @param command - 命令参数, 可选, 如不填写则自动从命令行读取 * @param userConfigs - 用户配置, 可选, 如不填写则使用 config 中载入的用户配置 * @param context - Runner 上下文, 可用于初始化时候传入 Runner * @returns 返回命令执行的结果 */ async run(command, userConfigs, context) { // 保存当前参数 this.lastRunState = (0, lodash_1.cloneDeep)({ command, userConfigs, context }); // 执行初始化 hook await this.hooks.initialize.promise(this); const results = []; const baseOptions = { config: this, command, userConfig: {}, context }; const configs = await this.prepare(command, userConfigs); // 基于多配置逐一运行 runner for await (const userConfig of configs.length ? configs : [{}]) { if (this.isReloading) { logger_1.logger.debug(`正在 reloading, 跳过 Runner 执行`); continue; } const runner = await this.runExtendedRunner({ ...baseOptions, userConfig }); results.push(runner.getResult()); } return results; } /** * 基于最近一次命令传入参数重新运行命令 * @returns 返回命令执行的结果 */ async reload() { // 避免重复 reloading if (this.isReloading) return []; // 清理配置项 this.pkg = undefined; this.pkgPath = ''; this.userConfig = undefined; this.userConfigFilePath = undefined; // 标记配置未载入 this.isConfigLoaded = false; // 标记为正在 reloading this.isReloading = true; // 逐个关闭 runner for await (const runner of this.currentRunners) { logger_1.logger.debug(`关闭 Runner#${runner.runnerId} 中...`); await runner.hooks.shutdown.promise(runner); logger_1.logger.debug(`关闭 Runner#${runner.runnerId} 完成`); } this.currentRunners.clear(); // 获取上次运行时传入的参数 const { command, userConfigs, context } = this.lastRunState || {}; this.lastRunState = undefined; // 标记 reloading 结束 this.isReloading = false; // 重新执行命令 return await this.run(command, userConfigs, context); } /** * 执行扩展 Runner 方法 */ async runExtendedRunner(options) { const RunnerExtended = this.hooks.extendRunner.call(runner_1.Runner, options); const runner = new RunnerExtended(options.config, options.userConfig, options.context); this.currentRunners.add(runner); await runner.run(options.command, options.plugins); return runner; } /** * 利用 Runner 的能力完成一些前置准备工作 * - 修改 cwd * - 载入用户配置文件 * - 过滤用户配置 * @param command - 通过接口传入的命令选项 * @param userConfigs - 通过接口传入的用户配置 * @returns 过滤后的用户配置数组 */ async prepare(command, userConfigs) { let filteredConfigs = []; const plugins = [ new ChangeCwdPlugin_1.default(), new LoadEnvPlugin_1.default(), new MultiConfigPlugin_1.default(false, async (runner, filters) => { // 过滤用户配置 filteredConfigs = this.filterBy(filters, userConfigs); // 过滤用户配置 if (this.hooks.configFiltered.isUsed()) { filteredConfigs = await this.hooks.configFiltered.promise(filteredConfigs, runner.getCommandOptions()); } }), new PluginConfigPlugin_1.default({ registerPluginSchema: false, loadCliOrEnvPlugins: true }), new StopRunPlugin_1.default() ]; // 如果未传入用户配置,则尝试自动载入配置 if (!(userConfigs === null || userConfigs === void 0 ? void 0 : userConfigs.length) && !this.isConfigLoaded) { plugins.push(new CustomConfigPlugin_1.default(true, async (runner) => { await this.hooks.configLoaded.promise(this, runner.getCommandOptions()); this.isConfigLoaded = true; })); } const options = { command, config: this, userConfig: {}, plugins }; // 触发前置准备 Hook await this.hooks.prepare.promise(options); await runner_1.Runner.run(options); return filteredConfigs; } } exports.Takin = Takin; //# sourceMappingURL=takin.js.map