"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; } require("regenerator-runtime/runtime"); function _assert() { const data = _interopRequireDefault(require("assert")); _assert = function _assert() { return data; }; return data; } function _chalk() { const data = _interopRequireDefault(require("chalk")); _chalk = function _chalk() { return data; }; return data; } function _emptyDir() { const data = _interopRequireDefault(require("empty-dir")); _emptyDir = function _emptyDir() { return data; }; return data; } function _clearModule() { const data = _interopRequireDefault(require("clear-module")); _clearModule = function _clearModule() { return data; }; return data; } function _path() { const data = require("path"); _path = function _path() { return data; }; return data; } function _launchEditor() { const data = _interopRequireDefault(require("@umijs/launch-editor")); _launchEditor = function _launchEditor() { return data; }; return data; } function _openBrowser() { const data = _interopRequireDefault(require("react-dev-utils/openBrowser")); _openBrowser = function _openBrowser() { return data; }; return data; } function _fs() { const data = require("fs"); _fs = function _fs() { return data; }; return data; } function _child_process() { const data = require("child_process"); _child_process = function _child_process() { return data; }; return data; } function _got() { const data = _interopRequireDefault(require("got")); _got = function _got() { return data; }; return data; } function _lodash() { const data = require("lodash"); _lodash = function _lodash() { return data; }; return data; } function _rimraf() { const data = _interopRequireDefault(require("rimraf")); _rimraf = function _rimraf() { return data; }; return data; } function _portfinder() { const data = _interopRequireDefault(require("portfinder")); _portfinder = function _portfinder() { return data; }; return data; } function _resolveFrom() { const data = _interopRequireDefault(require("resolve-from")); _resolveFrom = function _resolveFrom() { return data; }; return data; } function _semver() { const data = _interopRequireDefault(require("semver")); _semver = function _semver() { return data; }; return data; } var _Config = _interopRequireDefault(require("./Config")); var _getClientScript = _interopRequireWildcard(require("./getClientScript")); var _listDirectory = _interopRequireDefault(require("./listDirectory")); var _installCreator = _interopRequireDefault(require("./installCreator")); var _npmClient = require("./npmClient"); var _ActiveProjectError = _interopRequireDefault(require("./ActiveProjectError")); var _Actions = require("./Actions"); var _checkProject = require("./checkProject"); var _scripts = _interopRequireDefault(require("./scripts")); var _isDepFileExists = _interopRequireDefault(require("./utils/isDepFileExists")); var _terminal = _interopRequireWildcard(require("./terminal")); var _detectLanguage = _interopRequireDefault(require("./detectLanguage")); var _detectNpmClients = _interopRequireDefault(require("./detectNpmClients")); var _debug = _interopRequireWildcard(require("./debug")); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } 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); }); }; } process.env.UMI_UI = 'true'; class UmiUI { constructor() { this.cwd = void 0; this.servicesByKey = void 0; this.server = void 0; this.socketServer = void 0; this.logs = void 0; this.config = void 0; this.send = void 0; this.developMode = false; this.npmClients = []; this.basicUIPath = void 0; this.basicConfigPath = void 0; this.getService = cwd => { const serviceModule = process.env.BIGFISH_COMPAT ? '@alipay/bigfish/_Service.js' : 'umi/_Service.js'; const servicePath = process.env.LOCAL_DEBUG ? 'umi-build-dev/lib/Service' : _resolveFrom().default.silent(cwd, serviceModule) || 'umi-build-dev/lib/Service'; (0, _debug.default)(`Service path: ${servicePath}`); // eslint-disable-next-line import/no-dynamic-require const Service = require(servicePath).default; return new Service({ cwd }); }; this.cwd = process.cwd(); // 兼容旧版 Bigfish const defaultBaseUI = process.env.BIGFISH_COMPAT ? (0, _path().join)(__dirname, '../ui/dist/ui.umd.js') : ''; this.basicUIPath = process.env.BASIC_UI_PATH || defaultBaseUI; // export default { serices, ... } this.basicConfigPath = process.env.BASIC_CONFIG_PATH || ''; this.servicesByKey = {}; this.server = null; this.socketServer = null; this.config = new _Config.default({ onSave: data => { if (this.send) { this.send({ type: '@@project/list/progress', payload: data }); } } }); this.logs = []; this.developMode = !!process.env.DEVELOP_MODE; if (process.env.CURRENT_PROJECT) { const key = this.config.addProjectWithPath((0, _path().join)(process.cwd(), process.env.CURRENT_PROJECT)); this.config.setCurrentProject(key); } process.nextTick(() => { this.initNpmClients(); }); } openProject(key, service, opts) { const _ref = opts || {}, lang = _ref.lang; const project = this.config.data.projectsByKey[key]; (0, _assert().default)(project, `project of key ${key} not exists`); // Check exists. if (!(0, _fs().existsSync)(project.path)) { throw new _ActiveProjectError.default({ title: { 'zh-CN': `项目 ${project.path} 路径不存在。`, 'en-US': `Project ${project.path} not exists.` }, lang, actions: [_Actions.BackToHomeAction] }); } // Check umi valid. if (!(0, _checkProject.isUmiProject)(project.path)) { throw new _ActiveProjectError.default({ title: { 'zh-CN': `项目 ${project.path} 不是 Umi 项目。`, 'en-US': `Project ${project.path} is not a valid Umi project.` }, lang, actions: [_Actions.BackToHomeAction] }); } if (process.env.BIGFISH_COMPAT && (0, _checkProject.isUsingUmi)(project.path)) { throw new _ActiveProjectError.default({ title: { 'zh-CN': `项目 ${project.path} 是 Umi 项目,不能使用 Bigfish 打开。`, 'en-US': `Project ${project.path} is Umi Project, don't open it with Bigfish.` }, lang, actions: [_Actions.BackToHomeAction] }); } if (!process.env.BIGFISH_COMPAT && (0, _checkProject.isUsingBigfish)(project.path)) { throw new _ActiveProjectError.default({ title: { 'zh-CN': `项目 ${project.path} 是 Bigfish 项目,不能使用 Umi 打开。`, 'en-US': `Project ${project.path} is Bigfish Project, don't open it with Umi.` }, lang, actions: [_Actions.BackToHomeAction] }); } if (!this.developMode && service) { this.servicesByKey[key] = service; } else if (!this.servicesByKey[key]) { // Attach Service (0, _debug.default)(`Attach service for ${key}`); // Use local service and detect version compatibility const binModule = process.env.BIGFISH_COMPAT ? '@alipay/bigfish/bin/bigfish.js' : 'umi/bin/umi.js'; const pkgModule = process.env.BIGFISH_COMPAT ? '@alipay/bigfish/package.json' : 'umi/package.json'; const cwd = project.path; const localBin = (0, _isDepFileExists.default)(cwd, binModule); if (process.env.UI_CHECK_LOCAL !== 'none' && localBin) { const _JSON$parse = JSON.parse((0, _fs().readFileSync)((0, _path().join)(cwd, 'node_modules', pkgModule), 'utf-8')), version = _JSON$parse.version; if (!_semver().default.gt(version, process.env.BIGFISH_COMPAT ? '2.23.0' : '2.12.0-beta.2')) { throw new _ActiveProjectError.default({ title: process.env.BIGFISH_COMPAT ? `本地项目的 Bigfish 版本(${version})过低,请升级到 @alipay/bigfish@2.23 或以上,查看详情。` : { 'zh-CN': `本地项目的 Umi 版本(${version})过低,请升级到 umi@2.12 或以上,查看详情。`, 'en-US': `Umi version (${version}) of the project is too low, please upgrade to umi@2.12 or above, view details.` }, lang, actions: [_Actions.ReInstallDependencyAction, _Actions.OpenProjectAction, _Actions.BackToHomeAction] }); } } try { const service = this.getService(cwd); (0, _debug.default)(`Attach service for ${key} after new and before init()`); service.init(); (0, _debug.default)(`Attach service for ${key} ${_chalk().default.green('SUCCESS')}`); this.servicesByKey[key] = service; } catch (e) { if ((0, _checkProject.isDepLost)(e) || (0, _checkProject.isPluginLost)(e)) { throw new _ActiveProjectError.default({ title: { 'zh-CN': `依赖文件没找到。`, 'en-US': 'Dependency file not found.' }, message: e.message, stack: e.stack, lang, actions: [_Actions.ReInstallDependencyAction, _Actions.BackToHomeAction] }); } else { throw new _ActiveProjectError.default({ title: { 'zh-CN': '其他错误', 'en-US': 'Other Errors' }, message: e.message, stack: e.stack, lang, // exception tag exception: true, actions: [_Actions.BackToHomeAction] }); } } } this.config.editProject(key, { opened_at: +new Date() }); } openProjectInEditor(key, callback = {}, lang = 'zh-CN') { var _this = this; return _asyncToGenerator(function* () { let launchPath = key; if (!(key.startsWith('/') && (0, _fs().existsSync)(key))) { const project = _this.config.data.projectsByKey[key]; (0, _assert().default)(project, `project of key ${key} not exists`); launchPath = project.path; } if (!(0, _fs().existsSync)(launchPath)) { if (callback.failure) { const msg = { 'zh-CN': `打开编辑器失败 ${launchPath},项目不存在`, 'en-US': `Open Editor Failure, ${launchPath}, project does not exist` }; console.error(_chalk().default.red(msg[lang])); callback.failure({ message: msg[lang] }); } if (callback.success) { callback.success(); } } else { try { const res = yield (0, _launchEditor().default)(launchPath); if (res && res.success) { callback.success(res); } else { callback.failure(res); } } catch (e) { callback.failure(e); } } })(); } openConfigFileInEditor(projectPath, { success, failure, lang }) { return _asyncToGenerator(function* () { let configFile; const configFiles = ['.umirc.js', '.umirc.ts', 'config/config.js', 'config/config.ts']; for (var _i = 0, _configFiles = configFiles; _i < _configFiles.length; _i++) { const file = _configFiles[_i]; if ((0, _fs().existsSync)((0, _path().join)(projectPath, file))) { configFile = (0, _path().join)(projectPath, file); break; } } try { (0, _assert().default)(configFile, lang === 'zh-CN' ? '在编辑器中打开失败,因为配置文件不存在。' : `Open failed with editor, since configFile not exists.`); const res = yield (0, _launchEditor().default)(configFile); if (res && res.success) { success(res); } else { failure(res); } } catch (e) { console.error(e); failure({ message: e.message }); } })(); } getExtraAssets({ key }) { const service = this.servicesByKey[key]; const uiPlugins = service.applyPlugins('addUIPlugin', { initialValue: [] }); const script = (0, _getClientScript.default)(uiPlugins); return { script }; } getBasicAssets() { const script = this.basicUIPath ? (0, _getClientScript.getBasicScriptContent)(this.basicUIPath) : ''; return { script }; } installDeps(npmClient, projectPath, { onProgress, onSuccess, taobaoSpeedUp }) { return _asyncToGenerator(function* () { yield (0, _npmClient.installDeps)(npmClient, projectPath, { taobaoSpeedUp, onData(data) { onProgress({ install: data }); } }); onSuccess(); })(); } createProject(opts = {}, { onSuccess, onFailure, onProgress, lang }) { var _this2 = this; return _asyncToGenerator(function* () { let key = opts.key; let retryFrom = opts.retryFrom; let createOpts = opts; if (key) { (0, _assert().default)('retryFrom' in opts, `key 和 retryFrom 必须同时提供。`); // eslint-disable-next-line prefer-destructuring createOpts = _this2.config.data.projectsByKey[key].createOpts; } const setProgress = args => { (0, _assert().default)(key, `key is not initialized.`); _this2.config.setCreatingProgress(key, args); }; const sigintHandler = () => { if (key) { _this2.config.setCreatingProgress(key, { stepStatus: 3, failure: { message: 'exit UmiUi server' } }); } process.exit(); }; try { (0, _assert().default)(createOpts.baseDir, `baseDir must be supplied`); (0, _assert().default)(createOpts.name, `name must be supplied`); (0, _assert().default)(createOpts.type, `type must be supplied`); const targetDir = (0, _path().join)(createOpts.baseDir, createOpts.name); if (!retryFrom) { // 步骤: // // 1. 校验 // a) 比如检查目标目录是否为空或不存在 // 2. 添加项目状态到本地存储,后面每一步都更新状态到存储 // 3. 安装 create-umi 或更新他 // 4. create-umi 创建 // 如果是 ant-design-pro,还需要拆几步出来,比如 git clone // 5. 安装依赖 // // 项目步骤: // 1. 校验参数 // 2. 安装/更新 create-umi // 3. 使用 create-umi 初始化项目 // 4. 安装依赖 // // 结束后打开项目。 // 0 (0, _assert().default)(!(0, _fs().existsSync)(targetDir) || _emptyDir().default.sync(targetDir), `target dir ${targetDir} exists and not empty`); // 1 key = _this2.config.addProject({ path: targetDir, name: createOpts.name, npmClient: createOpts.npmClient, createOpts }); // get create key onSuccess({ key }); setProgress({ // 表示第几个 step,从 0 开始 step: 1, // 0: 未开始 // 1: 执行中 // 2: 执行完成 // 3: 执行失败 stepStatus: 0, steps: { 'zh-CN': ['校验参数', '安装或更新 create-umi', '初始化项目', '安装依赖'], 'en-US': ['Validate Params', 'Install or Update create-umi', 'Initialize Project', 'Install Dependency'] } }); } // catch exit process.on('SIGINT', sigintHandler); // 1 let creatorPath; // step 2 依赖 step 1 if (retryFrom === 2) { retryFrom = 1; } if (!retryFrom || retryFrom <= 1) { setProgress({ step: 1, stepStatus: 1 }); creatorPath = yield (0, _installCreator.default)({ // npmClient: createOpts.npmClient, onData(data) { onProgress({ install: data }); } }); setProgress({ stepStatus: 2 }); } // 2 if (!retryFrom || retryFrom <= 2) { setProgress({ step: 2, stepStatus: 1 }); (0, _clearModule().default)(creatorPath); yield require(creatorPath).run({ cwd: targetDir, type: createOpts.type, args: createOpts.args }); setProgress({ stepStatus: 2 }); } // 3 if (!retryFrom || retryFrom <= 3) { setProgress({ step: 3, stepStatus: 1 }); // 重装 node_modules 时先清空,否则可能会失败 if (retryFrom === 3) { _rimraf().default.sync((0, _path().join)(targetDir, 'node_modules')); } yield (0, _npmClient.installDeps)(createOpts.npmClient, targetDir, { taobaoSpeedUp: _this2.hasTaobaoSpeedUp(), onData(data) { onProgress({ install: data }); } }); setProgress({ stepStatus: 2 }); setProgress({ success: true }); } } catch (e) { if (key) { _this2.config.setCreatingProgress(key, { stepStatus: 3, failure: e }); } onFailure(e); } finally { process.removeListener('SIGINT', sigintHandler); } })(); } checkDirValid({ dir }, { onSuccess, onFailure }) { try { // 入参校验 (0, _assert().default)(dir, `payload.dir must be supplied`); if (!(0, _fs().existsSync)(dir)) { return onSuccess(); } // 非目录判断和权限校验 const stat = (0, _fs().statSync)(dir); (0, _assert().default)(stat.isDirectory(), `target directory must be a directory`); // 费空目录判断 (0, _assert().default)(_emptyDir().default.sync(dir), `target directory must be empty`); } catch (e) { onFailure(e); } } initNpmClients() { const ret = []; try { (0, _child_process().execSync)('tnpm --version', { stdio: 'ignore' }); ret.push('tnpm'); } catch (e) {} try { (0, _child_process().execSync)('cnpm --version', { stdio: 'ignore' }); ret.push('cnpm'); } catch (e) {} try { (0, _child_process().execSync)('npm --version', { stdio: 'ignore' }); ret.push('npm'); } catch (e) {} try { (0, _child_process().execSync)('ayarn --version', { stdio: 'ignore' }); ret.push('ayarn'); } catch (e) {} try { (0, _child_process().execSync)('tyarn --version', { stdio: 'ignore' }); ret.push('tyarn'); } catch (e) {} try { (0, _child_process().execSync)('yarn --version', { stdio: 'ignore' }); ret.push('yarn'); } catch (e) {} try { (0, _child_process().execSync)('pnpm --version', { stdio: 'ignore' }); ret.push('pnpm'); } catch (e) {} this.npmClients = ret; } getNpmClients() { return this.npmClients; } reloadProject(key) {} handleCoreData({ type, payload, lang, key }, { log, send, success, failure, progress }) { switch (type) { case '@@project/getBasicAssets': success(this.getBasicAssets()); break; case '@@project/getExtraAssets': success(this.getExtraAssets({ key })); break; case '@@project/list': this.config.checkValid(); this.config.load(); success({ data: this.config.data }); break; case '@@project/detail': success({ data: this.config.data.projectsByKey[payload.key] }); break; case '@@project/add': // TODO: 检验是否 umi 项目,不是则抛错给客户端 try { (0, _assert().default)((0, _fs().existsSync)(payload.path), `Add project failed, since path ${payload.path} don't exists.`); log('info', `Add project ${payload.path} with name ${payload.name}`); this.config.addProject({ path: payload.path, name: payload.name }); success(); } catch (e) { console.error(_chalk().default.red(`Error: Add project FAILED`)); console.error(e); failure({ message: e.message }); } break; case '@@project/delete': if (this.config.data.projectsByKey[payload.key]) { log('info', `Delete project: ${this.getProjectName(payload.key)}`); this.config.deleteProject(payload.key); success(); } break; case '@@project/getKeyOrAddWithPath': success({ key: this.config.getKeyOrAddWithPath(payload.path) }); break; case '@@project/open': try { log('info', `Open project: ${this.getProjectName(payload.key)}`); this.openProject(payload.key, null, { lang }); success(); } catch (e) { console.error(_chalk().default.red(`Error: Attach Project of key ${payload.key} FAILED`)); console.error(e); failure((0, _lodash().pick)(e, ['title', 'message', 'stack', 'actions', 'exception'])); } break; case '@@project/openInEditor': log('info', `Open in editor: ${this.getProjectName(payload.key)}`); this.openProjectInEditor(payload.key, { success, failure }, lang); break; case '@@project/edit': log('info', `Edit project: ${this.getProjectName(payload.key)}`); this.config.editProject(payload.key, { name: payload.name, cloudUrl: payload.cloudUrl }); success(); break; case '@@project/setCurrentProject': this.config.load(); // 重新 load this.config.setCurrentProject(payload.key); success(); break; case '@@project/clearCurrentProject': this.config.clearCurrentProject(); success(); break; case '@@project/create': log('info', `Create project: ${this.getProjectName(payload.key)}`); this.createProject(payload, { onSuccess: success, onFailure(e) { failure({ message: e.message }); }, onProgress: progress, lang }); break; case '@@project/checkDirValid': this.checkDirValid(payload, { onSuccess: success, onFailure(e) { failure({ message: e.message }); } }); break; case '@@project/createTemplateList': success({ data: [{ title: 'Ant Design Pro', description: 'A layout-only ant-design-pro boilerplate, use together with umi block', url: 'https://preview.pro.ant.design/' }, { title: 'Basic Template', description: 'A simple boilerplate, support typescript.' }] }); break; case '@@project/getNpmClients': success({ data: this.getNpmClients() }); break; case '@@project/getSharedDataDir': success({ tmpDir: (0, _path().join)((0, _path().dirname)(this.config.dbPath), 'shared-data', key) }); break; case '@@project/detectLanguage': try { (0, _assert().default)(key && this.servicesByKey[key], `Detect language failed, key must be supplied.`); const service = this.servicesByKey[key]; success({ language: (0, _detectLanguage.default)(service.cwd, { routeComponents: service.getRouteComponents() }) }); } catch (e) { console.error(e); failure({ message: e.message }); } break; case '@@project/detectNpmClients': try { (0, _assert().default)(key && this.servicesByKey[key], `Detect language failed, key must be supplied.`); const service = this.servicesByKey[key]; success({ npmClients: (0, _detectNpmClients.default)(service.cwd) }); } catch (e) { console.error(e); failure({ message: e.message }); } break; case '@@fs/getCwd': success({ cwd: this.cwd }); break; case '@@fs/listDirectory': { try { const data = (0, _listDirectory.default)(payload.dirPath, { directoryOnly: true }); success({ data }); } catch (e) { failure({ message: e.message }); } break; } case '@@log/getHistory': success({ data: this.logs }); break; case '@@log/clear': this.logs = []; success(); break; case '@@actions/installDependencies': this.config.setProjectNpmClient({ key: payload.key, npmClient: payload.npmClient }); this.installDeps(payload.npmClient, payload.projectPath, { taobaoSpeedUp: this.hasTaobaoSpeedUp(), onProgress: progress, onSuccess: success }); break; case '@@actions/reInstallDependencies': this.config.setProjectNpmClient({ key: payload.key, npmClient: payload.npmClient }); _rimraf().default.sync((0, _path().join)(payload.projectPath, 'node_modules')); this.installDeps(payload.npmClient, payload.projectPath, { taobaoSpeedUp: this.hasTaobaoSpeedUp(), onProgress: progress, onSuccess: success }); break; case '@@actions/openConfigFile': this.openConfigFileInEditor(payload.projectPath, { success, failure, lang }); break; case '@@actions/openProjectInEditor': this.openProjectInEditor(payload.projectPath, { success, failure }, lang); break; case '@@app/notify': try { const notifier = require('node-notifier'); const buildInImages = { error: (0, _path().resolve)(__dirname, 'assets', 'error.png'), info: (0, _path().resolve)(__dirname, 'assets', 'info.png'), success: (0, _path().resolve)(__dirname, 'assets', 'success.png'), warning: (0, _path().resolve)(__dirname, 'assets', 'warning.png') }; const type = payload.type, restPayload = _objectWithoutProperties(payload, ["type"]); const noticeConfig = _objectSpread({}, restPayload, { contentImage: buildInImages[type] || buildInImages.info, icon: (0, _path().resolve)(__dirname, 'assets', 'umi.png'), sound: true }); notifier.notify(noticeConfig); success(); } catch (e) { console.error(_chalk().default.red(`Error: Notify for ${e.message} FAILED`)); failure(e); } break; default: log('error', _chalk().default.red(`Unhandled message type ${type}`)); failure(); break; } } start() { var _this3 = this; return _asyncToGenerator(function* () { return new Promise( /*#__PURE__*/function () { var _ref2 = _asyncToGenerator(function* (resolve, reject) { console.log(`🚀 Starting Umi UI using umi@${process.env.UMI_VERSION}...`); const url = require('url'); const express = require('express'); const compression = require('compression'); const sockjs = require('sockjs'); const app = express(); app.use(compression()); // Index Page let content = null; // Serve Static (Production Only) if (!process.env.LOCAL_DEBUG) { app.use(express.static((0, _path().join)(__dirname, '../client/dist'), { index: false })); } /** * Terminal shell resize server */ app.get('/terminal/resize', /*#__PURE__*/function () { var _ref3 = _asyncToGenerator(function* (req, res) { const rows = parseInt(req.query.rows || 30); const cols = parseInt(req.query.cols || 180); try { (0, _terminal.resizeTerminal)({ rows, cols }); res.send({ success: true, rows, cols }); } catch (_) {} }); return function (_x3, _x4) { return _ref3.apply(this, arguments); }; }()); app.get('/', /*#__PURE__*/function () { var _ref4 = _asyncToGenerator(function* (req, res) { const isMini = ('mini' in req.query); (0, _debug.default)('isMini', isMini); const data = _this3.config.data; if (isMini || data.currentProject) { return res.status(302).redirect(url.format({ pathname: isMini ? '/blocks' : '/dashboard', query: req.query })); } else { return res.status(302).redirect(url.format({ pathname: '/project/select', query: req.query })); } }); return function (_x5, _x6) { return _ref4.apply(this, arguments); }; }()); app.use('/*', /*#__PURE__*/function () { var _ref5 = _asyncToGenerator(function* (req, res) { const scripts = yield (0, _scripts.default)(); if (process.env.LOCAL_DEBUG) { try { const _yield$got = yield (0, _got().default)(`http://localhost:8002${req.path}`), body = _yield$got.body; res.set('Content-Type', 'text/html'); res.send(normalizeHtml(body, scripts)); } catch (e) { console.error(e); } } else { if (!content) { content = (0, _fs().readFileSync)((0, _path().join)(__dirname, '../client/dist/index.html'), 'utf-8'); } res.send(normalizeHtml(content, scripts)); } }); return function (_x7, _x8) { return _ref5.apply(this, arguments); }; }()); // 添加埋点脚本 function normalizeHtml(html, scripts) { const bigfishScripts = scripts.bigfishScripts, umiScripts = scripts.umiScripts; // basementMonitor html = html.replace('', ''); html = html.replace('', `\n`); if (process.env.BIGFISH_COMPAT) { html = html.replace('', `\n`); } // not local dev and not test env if (!process.env.LOCAL_DEBUG && !process.env.UMI_UI_TEST) { const headScript = process.env.BIGFISH_COMPAT ? bigfishScripts.head.join('\n') : umiScripts.head.join('\n'); html = html.replace('', `${headScript}`); const footScript = process.env.BIGFISH_COMPAT ? bigfishScripts.foot.join('\n') : umiScripts.foot.join('\n'); html = html.replace('', `${footScript}`); } return html; } const ss = sockjs.createServer(); const conns = {}; function send(action) { const message = JSON.stringify(action); (0, _debug.debugSocket)(_chalk().default.green.bold('>>>>'), formatLogMessage(message)); Object.keys(conns).forEach(id => { conns[id].write(message); }); } function formatLogMessage(message) { let ret = message.length > 500 ? `${message.slice(0, 500)} ${_chalk().default.gray('...')}` : message; ret = ret.replace(/{"type":"(.+?)"/, `{"type":"${_chalk().default.magenta.bold('$1')}"`); return ret; } ss.on('connection', conn => { conns[conn.id] = conn; (0, _debug.debugSocket)(`🔗 ${_chalk().default.green('Connected to')}: ${conn.id}`); function success(type, payload) { send({ type: `${type}/success`, payload }); } function failure(type, payload) { send({ type: `${type}/failure`, payload }); } function progress(type, payload) { send({ type: `${type}/progress`, payload }); } _this3.send = send; // 给 packages/umi/src/scripts/dev.js 用 global.g_send = send; const log = (type, message) => { const payload = { date: +new Date(), type, message }; const msg = `${_chalk().default.gray(`[${type}]`)} ${message}`; const logFunc = type === 'error' ? console.error : _debug.debugSocket; logFunc(msg); _this3.logs.push(payload); send({ type: '@@log/message', payload }); }; conn.on('close', () => { (0, _debug.debugSocket)(`😿 ${_chalk().default.red('Disconnected to')}: ${conn.id}`); delete conns[conn.id]; }); conn.on('data', message => { try { const _JSON$parse2 = JSON.parse(message), type = _JSON$parse2.type, payload = _JSON$parse2.payload, lang = _JSON$parse2.$lang, key = _JSON$parse2.$key; (0, _debug.debugSocket)(_chalk().default.blue.bold('<<<<'), formatLogMessage(message)); const serviceArgs = { action: { type, payload, lang }, log, send, success: success.bind(_this3, type), failure: failure.bind(_this3, type), progress: progress.bind(_this3, type) }; if (type.startsWith('@@')) { _this3.handleCoreData({ type, payload, lang, key }, { log, send, success: success.bind(_this3, type), failure: failure.bind(_this3, type), progress: progress.bind(_this3, type) }); } else { (0, _assert().default)(_this3.servicesByKey[key], `service of key ${key} not exists.`); const service = _this3.servicesByKey[key]; service.applyPlugins('onUISocket', { args: serviceArgs }); } // Bigfish extend service if (_this3.basicConfigPath) { const _ref6 = // eslint-disable-next-line import/no-dynamic-require require(_this3.basicConfigPath).default || require(_this3.basicConfigPath) || {}, services = _ref6.services; if (Array.isArray(services) && services.length > 0) { // register framework services services.forEach(baseUIService => { baseUIService(serviceArgs); }); } } // eslint-disable-next-line no-empty } catch (e) { console.error(_chalk().default.red(e.stack)); } }); }); const port = process.env.UMI_UI_PORT || process.env.UMI_PORT || (yield _portfinder().default.getPortPromise({ port: 3000 })); const server = app.listen(port, process.env.HOST || '127.0.0.1', err => { if (err) { reject(err); } else { const url = `http://localhost:${port}/`; console.log(`⛽️ Ready on ${url}`); if (process.env.UMI_UI_BROWSER !== 'none') { (0, _openBrowser().default)(url); } resolve({ port }); // just TEST or ALL ? if (process.send) { const message = { type: 'UI_SERVER_DONE', data: { port, url } }; (0, _debug.default)(`send ${JSON.stringify(message)}`); process.send(message); } } }); ss.installHandlers(server, { prefix: '/umiui', log: () => {} }); _terminal.default.call(_this3, server); _this3.socketServer = ss; _this3.server = server; }); return function (_x, _x2) { return _ref2.apply(this, arguments); }; }()); })(); } /** * 返回 projcet name,如果 project 不存在,则返回 key * @param key project key */ getProjectName(key) { if (!key) { return ''; } const project = this.config.data.projectsByKey[key]; if (!project) { return key; } return project.name; } /** * 是否使用淘宝加速 * @param key project key */ hasTaobaoSpeedUp() { // 一期默认开启,二期走全局配置。 return true; } } exports.default = UmiUI;