UNPKG

@lcap/builder

Version:
300 lines (299 loc) 13.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getBuildConfig = void 0; const vite_1 = require("vite"); const chokidar_1 = __importDefault(require("chokidar")); const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const dayjs_1 = __importDefault(require("dayjs")); const logger_1 = __importDefault(require("../utils/logger")); const build_ide_1 = require("../build/build-ide"); const build_1 = require("../build"); const build_css_info_1 = __importDefault(require("../build/build-css-info")); const build_extension_1 = require("../build/build-extension"); const build_theme_1 = require("../build/build-theme"); const build_declaration_1 = __importDefault(require("../build/build-declaration")); const exec_1 = require("../utils/exec"); const server_1 = __importDefault(require("../utils/server")); function getBuildConfig(mode = 'production') { var _a; return __awaiter(this, void 0, void 0, function* () { const loadResult = yield (0, vite_1.loadConfigFromFile)({ command: 'build', mode }); if (!loadResult || !loadResult.config) { throw new Error('未找到 vite 配置文件'); } const { config } = loadResult; if (config.plugins) { config.plugins = config.plugins.flat(); } else { config.plugins = []; } const index = (_a = config.plugins) === null || _a === void 0 ? void 0 : _a.findIndex((p) => p && p.name === 'vite:lcap-build'); let lcapBuildPlugin; if (index && index !== -1) { lcapBuildPlugin = config.plugins[index]; config.plugins.splice(index, 1); } return { viteConfig: config, // eslint-disable-next-line no-underscore-dangle buildOptions: lcapBuildPlugin === null || lcapBuildPlugin === void 0 ? void 0 : lcapBuildPlugin._options, }; }); } exports.getBuildConfig = getBuildConfig; function getWatcherTasks(options, pkgInfo) { return __awaiter(this, void 0, void 0, function* () { const NaslUIWatcher = { name: 'nasl.ui', check(filePath) { return filePath.endsWith('api.ts') || filePath.includes('block.stories'); }, build: () => __awaiter(this, void 0, void 0, function* () { yield (0, build_1.buildNaslUI)(options); yield (0, build_declaration_1.default)(options); yield (0, build_css_info_1.default)(options); yield (0, build_1.buildManifest)(options); if (pkgInfo && pkgInfo.scripts && pkgInfo.scripts.lowcode) { yield (0, exec_1.exec)('npm run lowcode'); } }), }; const ThemeWatcher = { name: 'nasl.theme', check(filePath) { return filePath.includes('src/') && filePath.includes('/theme/'); }, build: () => __awaiter(this, void 0, void 0, function* () { yield (0, build_theme_1.buildTheme)(options, 'watch'); }), }; const I18nWatcher = { name: 'nasl.ui.i18n', check(filePath) { const list = Object.keys(options.i18n || {}).map((k) => (options.i18n ? path_1.default.resolve(options.rootPath, options.i18n[k]) : '')); const relativePath = path_1.default.resolve(options.rootPath, filePath); return list.length > 0 && list.includes(relativePath); }, build: () => __awaiter(this, void 0, void 0, function* () { yield (0, build_1.buildI18N)(options); }), }; const NaslExtensionWatcher = { name: 'nasl.extension', check(filePath) { return filePath.includes('src/') && (filePath.endsWith('api.ts') || filePath.includes('src/logics') || filePath.includes('block.stories')); }, build: () => __awaiter(this, void 0, void 0, function* () { yield (0, build_extension_1.buildNaslExtensionConfig)(options); yield (0, build_declaration_1.default)(options); yield (0, build_extension_1.buildNaslExtensionManifest)(options); }), }; if (options.type === 'extension') { return [ NaslExtensionWatcher, ThemeWatcher, ]; } return [ NaslUIWatcher, ThemeWatcher, I18nWatcher, ]; }); } function startWatcher(options, pkgInfo, send) { return __awaiter(this, void 0, void 0, function* () { let enabledBuild = false; const watcher = chokidar_1.default.watch(['./src', './src-vusion', options.destDir], { ignoreInitial: true, }); const watcherTasks = yield getWatcherTasks(options, pkgInfo); const taskQueue = []; let executing = false; function executeTask(tasks) { return __awaiter(this, void 0, void 0, function* () { tasks.forEach((task) => { if (taskQueue.includes(task)) { return; } taskQueue.push(task); }); if (executing) { return; } executing = true; while (taskQueue.length > 0) { const task = taskQueue.shift(); try { logger_1.default.start(`start ${task.name} task build`); send(`${task.name} building`); // eslint-disable-next-line no-await-in-loop yield task.build(); logger_1.default.success(`${task.name} task build successed!`); send(task.name); } catch (e) { logger_1.default.error(`${task.name} task build error!`); logger_1.default.error(e); } } executing = false; }); } const handleFileChange = (filePath, action) => __awaiter(this, void 0, void 0, function* () { if (!enabledBuild) { return; } const tasks = watcherTasks.filter((task) => task.check((0, vite_1.normalizePath)(filePath))); if (tasks.length > 0) { console.clear(); logger_1.default.info(`${action} file, filePath: ${filePath} `); executeTask(tasks); } }); watcher.on('add', (filePath) => handleFileChange(filePath, 'add')) .on('change', (filePath) => handleFileChange(filePath, 'change')) .on('unlink', (filePath) => handleFileChange(filePath, 'unlink')); logger_1.default.info('start files watcher'); return { start: () => { enabledBuild = true; }, close: () => watcher.close(), }; }); } function createProxyLibrarySchema(options, { port, https }) { return (req, res, next) => { var _a; if ((_a = req.url) === null || _a === void 0 ? void 0 : _a.startsWith('/api/library/schema')) { res.setHeader('content-type', 'application/json;charset=UTF-8'); const naslConfigPath = path_1.default.resolve(options.rootPath, 'nasl.extension.json'); let naslConfig; if (fs_extra_1.default.existsSync(naslConfigPath)) { naslConfig = fs_extra_1.default.readJSONSync(naslConfigPath); } if (!naslConfig) { next(); return; } res.write(JSON.stringify({ code: 200, msg: '调用成功', result: { category: 'LIBRARY', symbol: naslConfig.name, name: naslConfig.name, ideVersion: naslConfig.ideVersion, version: naslConfig.version, id: 77777, description: `${naslConfig.description} 调试使用`, picture: '', tenantId: '00000000000000000000000000000000', jsonSchema: JSON.stringify(naslConfig), origin: '手动上传', dependencies: [], tags: [], hasAuth: null, hasUserCenter: null, publisher: 'Develop Debuging', publishTime: (0, dayjs_1.default)().format('YYYY-MM-DD HH:mm:ss'), url: `${https ? 'https' : 'http'}://127.0.0.1:${port}/${naslConfig.name}@${naslConfig.version}.zip`, }, success: true, })); res.end(); } next(); }; } function startServer(options, { port = 8080, https, middlewares = [], openURL = '' }) { return server_1.default.start({ port, https, cors: true, middlewares: [ createProxyLibrarySchema(options, { port, https }), ...middlewares, ], openURL, }); } exports.default = (rootPath, { port, https, middlewares, onFirstBuilded, openURL }, buildConfigs) => __awaiter(void 0, void 0, void 0, function* () { if (!buildConfigs) { buildConfigs = yield getBuildConfig(); } const { viteConfig, buildOptions } = buildConfigs; const pkgInfo = fs_extra_1.default.readJSONSync(path_1.default.join(rootPath, 'package.json')); let onceBuilded = false; let server; // eslint-disable-next-line no-inner-declarations function send(msg) { if (!server) { return; } server.send(msg); } const watcher = yield startWatcher(buildOptions, pkgInfo, send); if (fs_extra_1.default.existsSync(buildOptions.destDir)) { yield fs_extra_1.default.remove(buildOptions.destDir); } let buildError = false; // 构建 ide 和 运行时文件, watch; yield Promise.all([ (0, build_ide_1.buildIDE)(buildOptions, true, send), (0, vite_1.build)(Object.assign(Object.assign({ configFile: false, envFile: false }, viteConfig), { mode: 'staging', plugins: [ ...viteConfig.plugins, { buildEnd(error) { if (error) { buildError = true; } }, closeBundle() { return __awaiter(this, void 0, void 0, function* () { if (buildError) { return; } if (onceBuilded) { send('update.runtime'); return; } onceBuilded = true; try { yield (0, build_1.lcapBuild)(buildOptions, 'watch'); if (pkgInfo && pkgInfo.scripts && pkgInfo.scripts.lowcode) { yield (0, exec_1.exec)('npm run lowcode'); } logger_1.default.success('build successed! starting file watching...'); watcher.start(); if (typeof onFirstBuilded === 'function') { onFirstBuilded(); } server = yield startServer(buildOptions, { port, https, middlewares, openURL }); } catch (e) { logger_1.default.error(e); process.exit(1); } }); }, }, ], build: Object.assign(Object.assign({}, viteConfig.build), { watch: {}, emptyOutDir: false }) })), ]); });