UNPKG

astroboy

Version:

Astroboy(阿童木)is a Nodejs SFB(Separation of Front and Back ends) framework, built on koa2.

296 lines 8.57 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // @ts-ignore no types matched const pathMatching = require("path-matching"); const path = require("path"); const lodash = require("lodash"); const util_1 = require("./lib/util"); const Loader_1 = require("./Loader"); /** * ## Core Loader * - decide how to build application. * * @author Big Mogician * @export * @class CoreLoader * @extends {Loader<F, A>} * @template F * @template A */ class CoreLoader extends Loader_1.Loader { constructor(options = {}) { super(options); this.options = options || {}; this.astroboy = this.options.astroboy; this.app = this.options.app || this.app; this.NODE_ENV = this.app.NODE_ENV || 'development'; this.patterns = Object.assign({}, this.defaultPatterns); this.init(); } get defaultPatterns() { return { loaderPattern: `/loader/*.(js|ts)`, pluginPattern: `/config/plugin.(default|${this.NODE_ENV}).(js|ts)`, loaderConfigPattern: `/config/loader.(default|${this.NODE_ENV}).(js|ts)`, }; } /** * ### `init` hook * * @virtual * @author Big Mogician * @protected * @memberof CoreLoader */ init() { this.loadCoreDirs(this.app.ROOT_PATH); this.loadPluginConfig(); this.loadFullDirs(); this.loadLoaderQueue(); this.loadLoaders(); this.runLoaders(); this.useMiddlewares(); } /** * ### `load` hook * * @virtual * @author Big Mogician * @memberof CoreLoader */ load() { } /** * ### 加载核心目录,包括 app、framework,但不包括 plugin * * @author Big Mogician * @protected * @param {string} baseDir * @memberof CoreLoader */ loadCoreDirs(baseDir) { const coreDirs = [ { baseDir: baseDir, type: 'app', name: path.basename(baseDir), }, ]; let proto = this.astroboy; while (proto) { proto = Object.getPrototypeOf(proto); if (proto) { const newBaseDir = proto[Symbol.for('BASE_DIR')]; if (newBaseDir) { coreDirs.push({ baseDir: newBaseDir, type: 'framework', name: path.basename(newBaseDir), }); } } } this.coreDirs = coreDirs.reverse(); util_1.outputJsonSync(`${this.app.ROOT_PATH}/run/coreDirs.json`, this.coreDirs); } /** * ### 获取插件配置 * * @author Big Mogician * @protected * @memberof CoreLoader */ loadPluginConfig() { let pluginConfig = {}; this.coreDirs.forEach(item => { this.globDir(item.baseDir, this.patterns.pluginPattern, entries => { pluginConfig = entries.reduce((a, b) => { const content = require(b); return lodash.merge(a, content); }, pluginConfig); }); }); this.pluginConfig = pluginConfig; util_1.outputJsonSync(`${this.app.ROOT_PATH}/run/pluginConfig.json`, pluginConfig); } /** * ### 获取遍历目录 * * @author Big Mogician * @protected * @memberof CoreLoader */ loadFullDirs() { let dirs = []; this.coreDirs.forEach(item => { dirs = dirs.concat(this.getPluginDirs(item.baseDir).reverse()); dirs.push(item); }); this.dirs = dirs; util_1.outputJsonSync(`${this.app.ROOT_PATH}/run/dirs.json`, dirs); } /** * ### 获取需要遍历的插件目录 * * @author Big Mogician * @protected * @param {string} baseDir * @returns * @memberof CoreLoader */ getPluginDirs(baseDir) { const config = this.getPluginConfig(baseDir); const ret = []; if (lodash.isPlainObject(config)) { for (let name in config) { if (this.pluginConfig[name].enable) { const baseDir = this.getPluginPath(config[name]); ret.push({ baseDir: baseDir, type: 'plugin', name: path.basename(baseDir), }); } } } return ret; } /** * ### 获取需要遍历的插件配置 * * @author Big Mogician * @protected * @param {string} baseDir * @returns * @memberof CoreLoader */ getPluginConfig(baseDir) { let config = {}; this.globDir(baseDir, this.patterns.pluginPattern, entries => { config = entries.reduce((a, b) => { return lodash.merge(a, require(b)); }, {}); }); return config; } /** * ### 获取加载器执行队列 * * @author Big Mogician * @protected * @memberof CoreLoader */ loadLoaderQueue() { let loaderConfig = {}; this.globDirs(this.patterns.loaderConfigPattern, entries => { loaderConfig = entries.reduce((previousValue, currentValue) => { return lodash.merge(previousValue, require(currentValue)); }, loaderConfig); }); let queue = []; Object.keys(loaderConfig).forEach(item => { queue.push(Object.assign({ priority: 300, name: item, }, loaderConfig[item])); }); queue = queue.sort((a, b) => { return a.priority - b.priority; }); this.loaderQueue = queue; } /** * ### 获取加载器 * * @author Big Mogician * @protected * @memberof CoreLoader */ loadLoaders() { let loaders = {}; this.globDirs(this.patterns.loaderPattern, entries => { entries.forEach(entry => { const key = this.resolveExtensions(path.basename(entry)); loaders[key] = require(entry); }); }); this.loaders = loaders; } /** * ### 执行加载器 * * @author Big Mogician * @protected * @memberof CoreLoader */ runLoaders() { const app = this.app; const loaders = this.loaders; this.loaderQueue.forEach(item => { if (loaders[item.name]) { const loader = new loaders[item.name]({ dirs: this.dirs, config: item.options, app, }); if (!(loader instanceof Loader_1.Loader)) { throw new Error(`Loader ${item.name} must extend Loader.`); } loader.load(); } else { throw new Error(`Loader ${item.name} is not found.`); } }); } /** * ### Use Middlewares * * @author Big Mogician * @protected * @memberof CoreLoader */ useMiddlewares() { const app = this.app; const middlewares = app.middlewares; app.middlewareQueue.forEach(item => { if (middlewares[item.name]) { let fn = middlewares[item.name](item.options, app); // 定义扩宽,match和ignore实际上只有一个存在并生效 if (item.match || item.ignore) { fn = this.wrapMiddleware(fn, item); } if (fn) { app.use(fn); } } else { throw new Error(`middleware ${item.name} is not found.`); } }); } /** * ### Wrap Middlewares * * @author Big Mogician * @protected * @param {NormalizedMiddleware} middleware * @param {IPriority} options * @returns * @memberof CoreLoader */ wrapMiddleware(middleware, options) { const match = pathMatching(options); let fn = async function (ctx, next) { if (match(ctx)) { await middleware(ctx, next); } else { await next(); } }; fn._name = `wrap-${middleware.name || middleware._name}`; return fn; } } exports.CoreLoader = CoreLoader; //# sourceMappingURL=CoreLoader.js.map