@lcap/builder
Version:
lcap builder utils
300 lines (299 loc) • 13.1 kB
JavaScript
;
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 }) })),
]);
});