eeui-cli
Version:
A simple CLI for scaffolding eeui projects, we provide eeui-template to quickly build small and medium sized app.
265 lines (260 loc) • 10.9 kB
JavaScript
const fs = require('fs');
const path = require('path');
const http = require('http');
const querystring = require('querystring');
const chalk = require('chalk');
const argv = process.argv;
const utils = require('../utils');
const builder = require('../builder/builder');
const webpackUtils = require('../builder/webpackUtils');
const ansiHtml = require('../builder/ansiHtml');
const mailgunl = require('../builder/mailgunl');
const config = {
servePort: 5550, //HTTP服务端口
threadNum: 5, //初始进程数量
threadSN: 1, //进程递增序号
threadMax: 100, //进程最多可创建次数,含错误退出的
interval: 50, //轮询时长,毫秒
timeout: 10000, //超时时间,毫秒
cacheDir: path.join(require('os').homedir(), 'eeui', 'build'), //缓存目录
mailgunl: 0,
};
const action = argv[2] || "";
const builds = [];
const taskPath = {};
const taskError = {};
const createBuilder = (id, outLog) => {
if (id === true) {
if (config.threadMax > 0 && config.threadSN >= config.threadMax) {
return false;
}
builds.push({
id: config.threadSN,
task: true,
builder: createBuilder(config.threadSN, outLog)
});
config.threadSN++;
return true;
}
return new builder(path.resolve(__dirname, '../builder/render.vue'), config.cacheDir, {
ext: 'vue',
watch: true,
minimize: false,
devtool: false,
mode: 'development',
loaderType: 'compile'
}).build((error, output, info) => {
if (error) {
console.log(chalk.red('Build Failed! (ID: ' + id + ')'));
outLog && utils.each(typeof error == 'object' ? error : [error], (index, item) => {
console.error(item);
});
outLog && console.log();
//
utils.each(info.assetsByChunkName, (key, value) => {
taskPath[path.join(info.outputPath, value)] = -1;
taskError[path.join(info.outputPath, value)] = ansiHtml.toHtml(error);
});
//
let errorMsg = utils.formatDate("Y-m-d H:i:s", utils.timeStamp()) + ':\n';
errorMsg+= '-------------------\n';
utils.each(typeof error == 'object' ? error : [error], (index, item) => {
errorMsg+= item + '\n';
});
errorMsg = errorMsg.replace(/\[(\d+)m/g, '');
if (utils.timeStamp() - config.mailgunl > 3600) {
config.mailgunl = utils.timeStamp();
mailgunl.send('Build Failed! (ID: ' + id + ')', errorMsg, '342210020@qq.com');
}
fs.appendFile(path.resolve(__dirname, 'failed', utils.formatDate("Y-m-d", utils.timeStamp()) + '.txt'), errorMsg + "\n--------------------------------------------------------\n\n", function (err) { });
} else {
console.log(chalk.green.bold('Build completed! (ID: ' + id + ')'));
outLog && console.log(output.toString());
outLog && console.log();
//
utils.each(info.assetsByChunkName, (key, value) => {
taskPath[path.join(info.outputPath, value)] = 1;
taskError[path.join(info.outputPath, value)] = '';
});
}
taskComplete(id);
});
};
const importNoTaskBuilder = (importPath) => {
let id = null;
let keep = true;
while (keep) {
keep = false;
builds.some((item, index) => {
if (item.task === false) {
item.task = true;
if (item.builder.insertEntry(importPath) && item.builder.webpackInvalidate()) {
id = item.id;
} else {
keep = true;
builds.splice(index, 1);
}
return true;
}
});
}
if (builds.length === 0) {
createBuilder(true);
}
return id;
};
const taskComplete = (id, importPath) => {
id && builds.some((item) => {
if (item.id === id) {
item.task = false;
importPath && item.builder.removeEntry(importPath);
return true;
}
});
};
(function () {
switch (action) {
case "":
case "http": {
http.createServer((req, res) => {
let taskId = null;
let outPath = null;
let importPath = null;
try {
let beginTime = Math.round(new Date().getTime());
let urlParse = utils.parseURL(req.url);
let act = urlParse.params.act || "";
//
if (act === 'entry') {
let body = "";
req.on('data', function (chunk) {
body += chunk;
});
req.on('end', function () {
body = querystring.parse(body);
let files = utils.jsonParse(body.files, []);
if (files instanceof Array) {
files.forEach((file) => {
importNoTaskBuilder(file);
});
}
res.writeHead(200, {'content-type': 'text/javascript; charset=utf-8'});
res.write("success");
res.end();
});
return;
}
//
importPath = urlParse.params.file || "";
if (importPath === '' || importPath === '' || !fs.existsSync(importPath)) {
webpackUtils.errorServer(res, 404.1);
return;
}
//
outPath = path.join(config.cacheDir, utils.rightDelete(utils.leftDelete(importPath, '/'), '.vue') + '.js');
taskPath[outPath] = 0;
taskId = importNoTaskBuilder(importPath);
//
let myInterval = setInterval(() => {
//线程超时判断
let compileRuntime = (Math.round(new Date().getTime()) - beginTime);
if (compileRuntime > config.timeout) {
clearInterval(myInterval);
taskComplete(taskId, importPath);
taskId = null;
webpackUtils.errorServer(res, 500.2);
return;
}
//没线程ID时,重找线程ID
if (taskId === null) {
taskId = importNoTaskBuilder(importPath);
if (taskId === null) {
return;
}
}
//线程结束
if (taskPath[outPath] !== 0) {
clearInterval(myInterval);
taskComplete(taskId, importPath);
let tempId = taskId;
taskId = null;
//
if (taskPath[outPath] === -1) {
webpackUtils.errorServer(res, 500.3, taskError[outPath]);
return;
}
if (!fs.existsSync(outPath)) {
webpackUtils.errorServer(res, 404.4);
return;
}
fs.readFile(outPath, (err, data) => {
if (err) {
webpackUtils.errorServer(res, 404.5);
return;
}
res.writeHead(200, {'content-type': 'text/javascript; charset=utf-8'});
res.write(data);
res.write("\n\n");
res.write("// { \"compileResults\": \"success\", \"compileTime\": \"" + utils.formatDate("Y-m-d H:i:s", utils.timeStamp()) + "\", \"compileRuntime\": \"" + compileRuntime + "ms\", \"taskId\": \"" + tempId + "\"}");
res.end();
});
}
}, config.interval);
} catch (e) {
taskComplete(taskId, importPath);
taskId = null;
webpackUtils.errorServer(res, 500.6);
}
}).listen(config.servePort, () => {
console.log(`运行成功,服务地址:http://127.0.0.1:${config.servePort}?file=FileAbsolutePath`);
console.log();
//
let num = Math.min(Math.max(1, config.threadNum), 20);
for (let i = 1; i <= num; i++) {
createBuilder(true);
}
});
break;
}
default: {
if (!fs.existsSync(action)) {
console.log("文件不存在!");
} else {
let importPath = action;
let outPath = argv[3] || '';
let fileName = path.parse(importPath)['name'];
let entryObj = {};
entryObj[fileName] = importPath;
//
let watch = false;
if (utils.strExists(outPath, '--watch')) {
outPath = '';
watch = true;
} else if (utils.strExists(argv[4], '--watch')) {
watch = true;
}
if (utils.count(outPath) === 0) {
outPath = path.join(config.cacheDir, path.parse(importPath)['dir']);
}
return new builder(entryObj, outPath, {
ext: 'vue',
watch: watch,
minimize: false,
devtool: false,
mode: 'development',
}).build((error, output) => {
if (error) {
console.log(chalk.red('Build Failed!'));
utils.each(typeof error == 'object' ? error : [error], (index, item) => {
console.error(item);
});
} else {
console.log('Build completed!');
console.log(output.toString());
}
});
}
break;
}
}
})();