esa-cli
Version:
A CLI for operating Alibaba Cloud ESA EdgeRoutine (Edge Functions).
173 lines (172 loc) • 7.06 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());
});
};
import path from 'path';
import fs from 'fs';
import logger from '../../../libs/logger.js';
import devBuild from '../build.js';
import t from '../../../i18n/index.js';
import { getDevConf } from '../../../utils/fileUtils/index.js';
import { getRoot, getDirName } from '../../../utils/fileUtils/base.js';
import { checkPort } from '../../../utils/checkDevPort.js';
import { EW2Path } from '../../../utils/installEw2.js';
// 生成可用的Ew2端口
const generateEw2Port = () => __awaiter(void 0, void 0, void 0, function* () {
let ew2port = 3322;
let portAvailable = yield checkPort(ew2port);
while (!portAvailable) {
ew2port += 1;
portAvailable = yield checkPort(ew2port);
}
// @ts-ignore
global.ew2Port = ew2port;
return ew2port;
});
const writeEw2config = (id, port, userRoot) => {
const devDir = path.resolve(userRoot, '.dev');
const devIndex = path.resolve(devDir, `index-${id}.js`);
const devConfPath = path.resolve(devDir, `config-${id}.toml`);
const erConfPath = path.resolve(EW2Path, `er.conf`);
const config = `
port = ${port}
[debugger_cli_options]
enable = true
code_path = "${devIndex}"
conf_path = "${erConfPath}"
`;
const erConf = JSON.stringify({
Ttl: 301,
ServiceOptions: {
service_status: 'active'
},
InstanceOptions: {
allow_node_module: true
},
ContextOptions: {
vm_max_cpu_time: 100
},
ServiceOptionsMd5: '1',
InstanceOptionsMd5: '2',
ContextOptionsMd5: '3'
});
return Promise.all([
fs.promises.writeFile(devConfPath, config),
fs.promises.writeFile(erConfPath, erConf)
]);
};
// 生成入口文件
const generateEntry = (id, projectEntry, userRoot, port) => __awaiter(void 0, void 0, void 0, function* () {
const __dirname = getDirName(import.meta.url);
const devDir = path.resolve(userRoot, '.dev');
const devEntry = path.resolve(devDir, `devEntry-${id}.js`);
const devEntryTemp = path.resolve(__dirname, './devEntry.js');
const devEntryTempFile = fs.readFileSync(devEntryTemp, 'utf-8');
const mockDevDir = path.resolve(userRoot, '.dev/mock');
const mockDir = path.resolve(__dirname, './mock');
if (!fs.existsSync(devDir)) {
yield fs.promises.mkdir(devDir);
}
if (!fs.existsSync(mockDevDir)) {
yield fs.promises.mkdir(mockDevDir);
}
const entries = yield fs.promises.readdir(mockDir);
for (const file of entries) {
const srcPath = path.resolve(mockDir, file);
const destPath = path.resolve(mockDevDir, file);
yield fs.promises.copyFile(srcPath, destPath);
}
return fs.promises.writeFile(devEntry, devEntryTempFile
.replace(/'\$userPath'/g, `'${projectEntry.replace(/\\/g, '/')}'`)
.replace(/\$userPort/g, `${port}`));
});
// 前期准备
const prepare = (configPath, entry, port, localUpstream, userRoot) => __awaiter(void 0, void 0, void 0, function* () {
const options = {};
const currentOptions = { entry, port, localUpstream };
// 支持同时跑多个 worker
const id = new Date().getTime().toString();
// @ts-ignore
global.id = id;
// 生成入口文件
yield generateEntry(id, entry, userRoot, port);
// 生成 Ew2 配置
const ew2port = yield generateEw2Port();
yield writeEw2config(id, ew2port, userRoot);
// 给每一次 dev 的配置项,在一个文件中通过 id 区分
if (fs.existsSync(configPath)) {
const currentConfig = fs
.readFileSync(configPath, 'utf-8')
.replace('export default ', '');
const currentConfigObj = JSON.parse(currentConfig);
const currentIds = Object.keys(currentConfigObj);
if (currentIds[0] && /^\d+$/.test(currentIds[0])) {
// 删除没有用到的入口
for (let currentId of currentIds) {
const unused = yield checkPort(currentConfigObj[currentId].port);
if (unused) {
const devDir = path.resolve(userRoot, '.dev');
const files = fs.readdirSync(devDir);
const filesToDelete = files.filter((file) => file.includes(currentId));
for (const file of filesToDelete) {
fs.rmSync(path.resolve(devDir, file), {
force: true,
recursive: true,
maxRetries: 5
});
}
}
else {
options[currentId] = currentConfigObj[currentId];
}
}
}
}
return fs.promises.writeFile(configPath, `export default ${JSON.stringify(Object.assign(options, { [id]: currentOptions }))}`);
});
const devPack = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (restarting = false) {
logger.ora.start('Processing...\n');
const userRoot = getRoot();
const configPath = path.resolve(userRoot, 'esa.toml');
let port, minify, localUpstream, entry;
let projectEntry = path.resolve(userRoot, 'src/index.js');
if (fs.existsSync(configPath)) {
port = getDevConf('port', 'dev', 18080);
minify = getDevConf('minify', 'dev', false);
localUpstream = getDevConf('localUpstream', 'dev', '');
entry = getDevConf('entry', '', '');
if (entry) {
projectEntry = path.resolve(userRoot, entry);
}
}
else {
logger.notInProject();
process.exit(0);
}
return prepare(path.resolve(userRoot, '.dev/devConfig.js'), projectEntry, port, localUpstream, userRoot)
.then(() => {
logger.ora.succeed(t('dev_pack_config_success').d('Config created successfully'));
return devBuild({
minify
});
})
.then(() => {
logger.ora.succeed(t('dev_pack_success').d('Build finished successfully'));
logger.ora.stop();
logger.block();
})
.catch((err) => {
logger.ora.fail('Build Failed');
logger.error(`${t('common_error_occurred').d('An error occurred')}: ${err}`);
if (err.toString().includes('EACCES')) {
logger.pathEacces(getDirName(import.meta.url));
}
process.exit(1);
});
});
export default devPack;