"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; function _react() { const data = _interopRequireDefault(require("react")); _react = function _react() { return data; }; return data; } function _chalk() { const data = _interopRequireDefault(require("chalk")); _chalk = function _chalk() { return data; }; return data; } function _path() { const data = require("path"); _path = function _path() { return data; }; return data; } function _assert() { const data = _interopRequireDefault(require("assert")); _assert = function _assert() { return data; }; return data; } function _mkdirp() { const data = _interopRequireDefault(require("mkdirp")); _mkdirp = function _mkdirp() { return data; }; return data; } function _lodash() { const data = require("lodash"); _lodash = function _lodash() { return data; }; return data; } function _signale() { const data = _interopRequireDefault(require("signale")); _signale = function _signale() { return data; }; return data; } function _umiUtils() { const data = require("umi-utils"); _umiUtils = function _umiUtils() { return data; }; return data; } function _error() { const data = require("umi-core/lib/error"); _error = function _error() { return data; }; return data; } var _getPaths = _interopRequireDefault(require("./getPaths")); var _getPlugins = _interopRequireDefault(require("./getPlugins")); var _PluginAPI = _interopRequireDefault(require("./PluginAPI")); var _UserConfig = _interopRequireDefault(require("./UserConfig")); var _registerBabel = _interopRequireDefault(require("./registerBabel")); var _getCodeFrame = _interopRequireDefault(require("./utils/getCodeFrame")); var _writeContent = _interopRequireDefault(require("./utils/writeContent")); var _getRouteManager = _interopRequireDefault(require("./plugins/commands/getRouteManager")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _createForOfIteratorHelper(o) { if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) { var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var it, normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } const debug = require('debug')('umi-build-dev:Service'); class Service { constructor({ cwd }) { // 用户传入的 cmd 不可信任 转化一下 this.cwd = cwd || process.cwd(); try { this.pkg = require((0, _path().join)(this.cwd, 'package.json')); // eslint-disable-line } catch (e) { this.pkg = {}; } (0, _registerBabel.default)({ cwd: this.cwd }); this.commands = {}; this.pluginHooks = {}; this.pluginMethods = {}; this.generators = {}; this.UmiError = _error().UmiError; // resolve user config this.config = _UserConfig.default.getConfig({ cwd: this.cwd, service: this }); debug(`user config: ${JSON.stringify(this.config)}`); // resolve plugins this.plugins = this.resolvePlugins(); this.extraPlugins = []; debug(`plugins: ${this.plugins.map(p => p.id).join(' | ')}`); // resolve paths this.paths = (0, _getPaths.default)(this); } printUmiError(error, opts) { this.applyPlugins('onPrintUmiError', { args: { error, opts } }); (0, _error().printUmiError)(error, opts); } resolvePlugins() { try { (0, _assert().default)(Array.isArray(this.config.plugins || []), `Configure item ${_chalk().default.underline.cyan('plugins')} should be Array, but got ${_chalk().default.red(typeof this.config.plugins)}`); return (0, _getPlugins.default)({ cwd: (0, _umiUtils().winPath)(this.cwd), plugins: this.config.plugins || [] }); } catch (e) { if (process.env.UMI_TEST || process.env.UMI_UI) { throw new Error(e); } else { this.printUmiError(e); process.exit(1); } } } initPlugin(plugin) { const id = plugin.id, apply = plugin.apply, opts = plugin.opts; try { (0, _assert().default)(typeof apply === 'function', ` plugin must export a function, e.g. export default function(api) { // Implement functions via api } `.trim()); const api = new Proxy(new _PluginAPI.default(id, this), { get: (target, prop) => { if (this.pluginMethods[prop]) { return this.pluginMethods[prop]; } if ([// methods 'changePluginOption', 'applyPlugins', '_applyPluginsAsync', 'writeTmpFile', 'getRoutes', 'getRouteComponents', // properties 'cwd', 'config', 'webpackConfig', 'pkg', 'paths', 'routes', // error handler 'UmiError', 'printUmiError', // dev methods 'restart', 'printError', 'printWarn', 'refreshBrowser', 'rebuildTmpFiles', 'rebuildHTML'].includes(prop)) { if (typeof this[prop] === 'function') { return this[prop].bind(this); } else { return this[prop]; } } else { return target[prop]; } } }); api.onOptionChange = fn => { (0, _assert().default)(typeof fn === 'function', `The first argument for api.onOptionChange should be function in ${id}.`); plugin.onOptionChange = fn; }; apply(api, opts); plugin._api = api; } catch (e) { if (process.env.UMI_TEST) { throw new Error(e); } else { _signale().default.error(` Plugin ${_chalk().default.cyan.underline(id)} initialize failed ${(0, _getCodeFrame.default)(e, { cwd: this.cwd })} `.trim()); console.error(e); process.exit(1); } } } initPlugins() { // Plugin depth let count = 0; const initExtraPlugins = () => { if (!this.extraPlugins.length) { return; } const extraPlugins = (0, _lodash().cloneDeep)(this.extraPlugins); this.extraPlugins = []; extraPlugins.forEach(plugin => { this.initPlugin(plugin); this.plugins.push(plugin); initExtraPlugins(); }); count += 1; (0, _assert().default)(count <= 10, `插件注册死循环?`); }; const plugins = (0, _lodash().cloneDeep)(this.plugins); this.plugins = []; plugins.forEach(plugin => { this.initPlugin(plugin); this.plugins.push(plugin); // reset count count = 0; initExtraPlugins(); }); // Throw error for methods that can't be called after plugins is initialized this.plugins.forEach(plugin => { ['onOptionChange', 'register', 'registerMethod', 'registerPlugin'].forEach(method => { plugin._api[method] = () => { throw new Error(`api.${method}() should not be called after plugin is initialized.`); }; }); }); } changePluginOption(id, newOpts) { (0, _assert().default)(id, `id must supplied`); const plugin = this.plugins.filter(p => p.id === id)[0]; (0, _assert().default)(plugin, `plugin ${id} not found`); plugin.opts = newOpts; if (plugin.onOptionChange) { plugin.onOptionChange(newOpts); } else { this.restart(`plugin ${id}'s option changed`); } } applyPlugins(key, opts = {}) { debug(`apply plugins ${key}`); return (this.pluginHooks[key] || []).reduce((memo, { fn }) => { try { return fn({ memo, args: opts.args }); } catch (e) { console.error(_chalk().default.red(`Plugin apply failed: ${e.message}`)); throw e; } }, opts.initialValue); } _applyPluginsAsync(key, opts = {}) { var _this = this; return _asyncToGenerator(function* () { debug(`apply plugins async ${key}`); const hooks = _this.pluginHooks[key] || []; let memo = opts.initialValue; var _iterator = _createForOfIteratorHelper(hooks), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { const hook = _step.value; const fn = hook.fn; // eslint-disable-next-line no-await-in-loop memo = yield fn({ memo, args: opts.args }); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return memo; })(); } loadEnv() { const basePath = (0, _path().join)(this.cwd, '.env'); const localPath = `${basePath}.local`; (0, _umiUtils().loadDotEnv)(basePath); (0, _umiUtils().loadDotEnv)(localPath); } writeTmpFile(file, content) { const paths = this.paths; const path = (0, _path().join)(paths.absTmpDirPath, file); _mkdirp().default.sync((0, _path().dirname)(path)); (0, _writeContent.default)(path, content); } getRoutes() { const RoutesManager = (0, _getRouteManager.default)(this); RoutesManager.fetchRoutes(); return RoutesManager.routes; } getRouteComponents() { const routes = this.getRoutes(); const getComponents = routes => { return routes.reduce((memo, route) => { if (route.component && !route.component.startsWith('()')) { const component = (0, _path().isAbsolute)(route.component) ? route.component : require.resolve((0, _path().join)(this.cwd, route.component)); memo.push((0, _umiUtils().winPath)(component)); } if (route.routes) { memo = memo.concat(getComponents(route.routes)); } return memo; }, []); }; return (0, _lodash().uniq)(getComponents(routes)); } init() { // load env this.loadEnv(); // init plugins this.initPlugins(); // reload user config const userConfig = new _UserConfig.default(this); const config = userConfig.getConfig({ force: true }); mergeConfig(this.config, config); this.userConfig = userConfig; if (config.browserslist) { (0, _umiUtils().deprecate)('config.browserslist', 'use config.targets instead'); } debug('got user config'); debug(this.config); // assign user's outputPath config to paths object if (config.outputPath) { const paths = this.paths; paths.outputPath = config.outputPath; paths.absOutputPath = (0, _path().join)(paths.cwd, config.outputPath); } debug('got paths'); debug(this.paths); } registerCommand(name, opts, fn) { if (typeof opts === 'function') { fn = opts; opts = null; } opts = opts || {}; (0, _assert().default)(!(name in this.commands), `Command ${name} exists, please select another one.`); this.commands[name] = { fn, opts }; } run(name = 'help', args) { this.init(); return this.runCommand(name, args); } runCommand(rawName, rawArgs = {}, remoteLog) { debug(`raw command name: ${rawName}, args: ${JSON.stringify(rawArgs)}`); const _this$applyPlugins = this.applyPlugins('_modifyCommand', { initialValue: { name: rawName, args: rawArgs } }), name = _this$applyPlugins.name, args = _this$applyPlugins.args; debug(`run ${name} with args ${JSON.stringify(args)}`); const command = this.commands[name]; if (!command) { _signale().default.error(`Command ${_chalk().default.underline.cyan(name)} does not exists`); process.exit(1); } const fn = command.fn, opts = command.opts; if (opts.webpack) { // webpack config this.webpackConfig = require('./getWebpackConfig').default(this, { watch: rawArgs.w || rawArgs.watch }); if (this.config.ssr) { // when use ssr, push client-manifest plugin into client webpackConfig this.webpackConfig.plugins.push(new (require('./plugins/commands/getChunkMapPlugin').default(this))()); // server webpack config this.ssrWebpackConfig = require('./getWebpackConfig').default(this, { ssr: this.config.ssr }); } } return fn(args, { remoteLog }); } } exports.default = Service; function mergeConfig(oldConfig, newConfig) { Object.keys(oldConfig).forEach(key => { if (!(key in newConfig)) { delete oldConfig[key]; } }); (0, _lodash().assign)(oldConfig, newConfig); return oldConfig; }