@gdjiami/cli
Version:
CLI for build front end project.
392 lines (391 loc) • 17.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
/**
* Start development server
*/
var webpack_dev_server_1 = tslib_1.__importDefault(require("webpack-dev-server"));
var webpack_1 = tslib_1.__importDefault(require("webpack"));
var express_1 = tslib_1.__importDefault(require("express"));
var webpack_dev_middleware_1 = tslib_1.__importDefault(require("webpack-dev-middleware"));
var webpack_format_messages_1 = tslib_1.__importDefault(require("webpack-format-messages"));
var readline_1 = tslib_1.__importDefault(require("readline"));
var child_process_1 = tslib_1.__importDefault(require("child_process"));
var chalk_1 = tslib_1.__importDefault(require("chalk"));
var https_1 = tslib_1.__importDefault(require("https"));
var opener_1 = tslib_1.__importDefault(require("opener"));
var tree_kill_1 = tslib_1.__importDefault(require("tree-kill"));
var inquirer_1 = tslib_1.__importDefault(require("inquirer"));
var utils_1 = require("../utils");
var proxy_1 = require("../proxy");
var info_1 = tslib_1.__importDefault(require("../services/info"));
var checkElectron_1 = tslib_1.__importDefault(require("../services/checkElectron"));
var options_1 = tslib_1.__importDefault(require("../options"));
var config_1 = tslib_1.__importDefault(require("../config"));
var cert_1 = require("../cert");
var electron_main_1 = tslib_1.__importDefault(require("../config/electron-main"));
var paths_1 = tslib_1.__importDefault(require("../paths"));
var Ora = require("ora");
var generateDll_1 = tslib_1.__importDefault(require("./dll/generateDll"));
var mode = 'development';
process.env.NODE_ENV = mode;
// initial enviroments variables
require('../env');
var electronOrBrowserProcess;
var lastElectronMainBuildTime;
/**
* get webpack-dev-server options
* @param proxy
*/
function getDevServerConfig(proxy, webpackConfig, enviroments, options) {
// https://github.com/chimurai/http-proxy-middleware
// https://webpack.docschina.org/configuration/dev-server/#devserver-proxy
// 解析proxy支持变量, 只会解析context和target
if (proxy) {
// @ts-ignore
proxy = proxy_1.interpolateProxy(proxy, enviroments);
}
return {
disableHostCheck: true,
compress: true,
clientLogLevel: 'none',
contentBase: [paths_1.default.appPublic, paths_1.default.appDist, paths_1.default.appCache],
watchContentBase: true,
hot: !options.ie8,
publicPath: webpackConfig.output.publicPath,
quiet: true,
watchOptions: {
ignored: /node_modules/,
},
https: process.env.HTTPS === 'true',
proxy: proxy,
// 使用原生的overlap
// TODO: 使用更先进的react-error-overlay
overlay: {
errors: true,
warnings: false,
},
};
}
/**
* create webpack compiler and listen build events
* @param config
*/
function createCompiler(config, electronMainConfig, onCompileSuccess) {
var compiler;
var started = false;
try {
// @ts-ignore
compiler = webpack_1.default(electronMainConfig ? [electronMainConfig, config] : config);
}
catch (err) {
// config error
utils_1.message.error(chalk_1.default.red('Failed to compile.\n'));
console.log(err.message || err);
console.log();
process.exit(1);
}
var spinner = Ora();
var firstCompile = true;
var startSpin = function () {
spinner.text = 'Compiling...';
spinner.start();
};
compiler.hooks.invalid.tap('invalid', function () {
if (!firstCompile) {
utils_1.clearConsole();
}
startSpin();
});
compiler.hooks.done.tap('done', function (stats) {
started = true;
spinner.stop();
firstCompile = false;
var messages = webpack_format_messages_1.default(stats);
if (messages.errors.length) {
utils_1.message.error('Failed to compile.\n\n');
messages.errors.forEach(function (e) { return console.log(e); });
return;
}
if (onCompileSuccess) {
onCompileSuccess(stats);
}
if (messages.warnings.length) {
utils_1.message.warn('Compiled with warnings.\n\n');
messages.warnings.forEach(function (e) { return console.log(e); });
return;
}
utils_1.message.success(chalk_1.default.green('Compiled successfully.'));
});
return [
compiler,
function () {
if (started) {
return;
}
startSpin();
},
];
}
function log(str, color, title) {
if (/[0-9A-z]+/.test(str)) {
utils_1.message.custom(title, str, color);
}
}
var restartingElectron = false;
/**
* 打开electron 实例
* @param prevProcess
*/
function openByElectron(argv, prevProcess, onRestart) {
var _this = this;
if (prevProcess && prevProcess.kill) {
try {
restartingElectron = true;
tree_kill_1.default(prevProcess.pid, 'SIGKILL');
setTimeout(function () {
restartingElectron = false;
}, 5000);
}
catch (err) {
utils_1.message.error("failed to kill electron process: " + err.message);
}
}
var DefaultPort = 5858;
var args = [
argv.electronInspectBrk != null
? "--inspect-brk=" + (argv.electronInspectBrk || DefaultPort)
: argv.electronInspect != null
? "--inspect=" + (argv.electronInspect || DefaultPort)
: '',
'.',
].filter(Boolean);
var p = child_process_1.default.spawn(utils_1.requireInCwd('electron'), args);
if (prevProcess == null) {
utils_1.message.info("calling: 'electron " + args.join(' ') + "'");
}
var stdin = readline_1.default.createInterface({ input: p.stdout });
var stderr = readline_1.default.createInterface({ input: p.stderr });
stdin.on('line', function (data) {
log(data, 'cyan', 'Electron Log');
});
stderr.on('line', function (data) {
log(data, 'red', 'Electron Log');
});
// electron 主进程退出
p.on('close', function (evt) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var res;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!!restartingElectron) return [3 /*break*/, 2];
// 可能是意外退出, 考虑重启electron进程
utils_1.message.info("\u68C0\u6D4B\u5230Electron \u4E3B\u8FDB\u7A0B\u9000\u51FA, \u9000\u51FA\u7801\u4E3A: " + evt);
return [4 /*yield*/, inquirer_1.default.prompt([
{
type: 'confirm',
name: 'restart',
message: '是否重启Electron进程?',
default: true,
},
])];
case 1:
res = _a.sent();
if (res.restart) {
if (onRestart) {
onRestart();
}
}
else {
process.exit();
}
_a.label = 2;
case 2: return [2 /*return*/];
}
});
}); });
return p;
}
function startWebpackDevServer(port, host, compiler, devServerConfig, done) {
var devServer = new webpack_dev_server_1.default(compiler, devServerConfig);
devServer.listen(port, host, function (err) {
done(err);
});
['SIGINT', 'SIGTERM'].forEach(function (sig) {
process.on(sig, function () {
if (electronOrBrowserProcess) {
restartingElectron = true;
process.kill(electronOrBrowserProcess.pid);
}
devServer.close();
process.exit();
});
});
}
function startIE8DevServer(port, host, compiler, devServerConfig, done) {
var app = express_1.default();
var listeningServer;
if (devServerConfig.compress) {
app.use(require('compression')());
}
app.use(require('cors')());
var instance = webpack_dev_middleware_1.default(compiler, { logLevel: 'silent', publicPath: devServerConfig.publicPath || '/' });
app.use(instance);
var contentBase = (devServerConfig.contentBase &&
(Array.isArray(devServerConfig.contentBase)
? devServerConfig.contentBase
: typeof devServerConfig.contentBase === 'string'
? [devServerConfig.contentBase]
: null)) || [paths_1.default.appDist, paths_1.default.appPublic];
contentBase.forEach(function (p) {
app.use(express_1.default.static(p));
});
if (devServerConfig.proxy) {
proxy_1.applyProxyToExpress(devServerConfig.proxy, app);
}
if (devServerConfig.https) {
var _a = cert_1.getCerts(), key = _a.key, cert = _a.cert;
listeningServer = https_1.default
.createServer({
key: key,
cert: cert,
}, app)
.listen(port, host, done);
}
else {
listeningServer = app.listen(port, host, done);
}
;
['SIGINT', 'SIGTERM'].forEach(function (sig) {
process.on(sig, function () {
listeningServer.close();
process.exit();
});
});
}
function default_1(argv) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var port, protocol, host, urls, environment, pkg, jmOptions, isIE8Mode, isEelectron, _a, electronMainConfig, config, devServerConfig, spinner, contentBase, folders, proxyInfo, _b, compiler, startCompileSpin, serverSetuped;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, utils_1.choosePort(parseInt(process.env.PORT, 10) || 8080)];
case 1:
port = _c.sent();
protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
host = '0.0.0.0';
urls = utils_1.prepareUrls(protocol, host, port);
process.env.PORT = port.toString();
process.env.ADDRESS = urls.lanUrlForConfig || 'localhost';
process.env.PROTOCOL = protocol;
environment = require('../env').default();
pkg = require(paths_1.default.appPackageJson);
jmOptions = options_1.default(pkg);
if (jmOptions == null) {
return [2 /*return*/];
}
isIE8Mode = jmOptions.ie8;
isEelectron = jmOptions.electron;
if (isEelectron) {
utils_1.message.info(chalk_1.default.cyan('Electron') + ' Mode');
checkElectron_1.default();
}
if (!(environment.raw.DISABLE_DLL !== 'true' && !isIE8Mode)) return [3 /*break*/, 5];
utils_1.message.info('Checking DLL...');
_c.label = 2;
case 2:
_c.trys.push([2, 4, , 5]);
return [4 /*yield*/, generateDll_1.default(environment, pkg, paths_1.default, { jmOptions: jmOptions })];
case 3:
_c.sent();
return [3 /*break*/, 5];
case 4:
_a = _c.sent();
utils_1.message.warn('Failed to compile DLL. skip');
return [3 /*break*/, 5];
case 5:
electronMainConfig = isEelectron ? electron_main_1.default(environment, pkg, paths_1.default, { jmOptions: jmOptions }) : undefined;
config = config_1.default(environment, pkg, paths_1.default, { entry: argv.entry, jmOptions: jmOptions });
devServerConfig = getDevServerConfig(jmOptions.proxy || {}, config, environment.raw, jmOptions);
if (argv.inspect) {
// TODO: 优化展示,使用fx,交互式
utils_1.inspect(jmOptions, 'CLI Options:');
utils_1.inspect(environment.raw, 'Environment:');
utils_1.inspect(devServerConfig, 'Development Server Config:');
utils_1.inspect(config, 'Webpack Configuration:');
return [2 /*return*/];
}
spinner = Ora({ text: 'Starting the development server...\n' }).start();
contentBase = devServerConfig.contentBase;
folders = typeof contentBase === 'string' ? contentBase : Array.isArray(contentBase) ? contentBase.join(', ') : '';
proxyInfo = devServerConfig.proxy && proxy_1.proxyInfomation(devServerConfig.proxy);
_b = createCompiler(config, electronMainConfig, function (stats) {
utils_1.message.info(info_1.default());
if (jmOptions.ie8) {
utils_1.message.info('IE8 Mode');
}
utils_1.message.info("Development server running at: \n Lan: " + chalk_1.default.cyan(urls.lanUrlForTerminal) + "\n Local: " + chalk_1.default.cyan(urls.localUrlForTerminal) + " ");
utils_1.message.info("Webpack output is served from " + chalk_1.default.cyan('/'));
if (folders) {
utils_1.message.info("Static resources not from webpack is served from " + chalk_1.default.cyan(folders));
}
if (proxyInfo) {
utils_1.message.info("Other HTTP requests will proxy to Proxy-Server base on:\n " + chalk_1.default.cyan(proxyInfo));
}
if (isEelectron) {
utils_1.message.info("Call " + chalk_1.default.cyan('`electron .`') + " to setup development APP");
}
try {
if (isEelectron) {
var compilerStat = stats.stats;
// @ts-ignore
var mainStat = compilerStat.find(function (i) { return i.compilation.name === 'main'; });
var buildTime = mainStat.startTime;
// 失败重启
var restart_1 = function () {
utils_1.message.info('restarting Electron');
electronOrBrowserProcess = openByElectron(argv, undefined, restart_1);
};
if (electronOrBrowserProcess == null) {
utils_1.message.info('open Electron');
electronOrBrowserProcess = openByElectron(argv, undefined, restart_1);
}
else if (argv.autoReload && lastElectronMainBuildTime !== buildTime) {
// electron 主进程更新时重启
utils_1.message.info('restart Electron');
electronOrBrowserProcess = openByElectron(argv, electronOrBrowserProcess, restart_1);
}
lastElectronMainBuildTime = buildTime;
}
else if (electronOrBrowserProcess == null) {
// 打开浏览器
var entries = Object.keys(config.entry);
var entry = entries.some(function (i) { return i === 'index'; }) ? 'index' : entries[0];
electronOrBrowserProcess = opener_1.default(urls.localUrlForBrowser + "/" + entry + ".html");
}
}
catch (err) {
utils_1.message.error(err);
}
}), compiler = _b[0], startCompileSpin = _b[1];
serverSetuped = function (err) {
spinner.stop();
if (err) {
utils_1.message.error('Fail to setup development server:');
return;
}
setTimeout(function () {
startCompileSpin();
}, 1000);
};
if (isIE8Mode) {
startIE8DevServer(port, host, compiler, devServerConfig, serverSetuped);
}
else {
startWebpackDevServer(port, host, compiler, devServerConfig, serverSetuped);
}
return [2 /*return*/];
}
});
});
}
exports.default = default_1;