UNPKG

utquidem

Version:

The meta-framework suite designed from scratch for frontend-focused modern web development.

261 lines (231 loc) 6.11 kB
const path = require('path'); const spawn = require('cross-spawn'); const treeKill = require('tree-kill'); const portfinder = require('portfinder'); const kModernBin = path.join( __dirname, '../node_modules/@modern-js/core/bin/modern-js', ); function runModernCommand(argv, options = {}) { const { cwd } = options; const cmd = argv[0]; const env = { ...process.env, ...options.env, }; return new Promise((resolve, reject) => { // console.log(`Running command "modern ${argv.join(' ')}"`); const instance = spawn(process.execPath, [kModernBin, ...argv], { ...options.spawnOptions, cwd, env, stdio: ['ignore', 'pipe', 'pipe'], }); if (typeof options.instance === 'function') { options.instance(instance); } let stderrOutput = ''; if (options.stderr) { instance.stderr.on('data', chunk => { stderrOutput += chunk; }); } let stdoutOutput = ''; // if (options.stdout) { instance.stdout.on('data', async chunk => { let marker = options.marker || /compiled successfully/i; if (cmd === 'deploy') { marker = /end deploy!/i; } stdoutOutput += chunk; const message = chunk.toString(); if (marker.test(message)) { resolve({ stdout: stdoutOutput, }); await killApp(instance); } }); // } instance.on('close', code => { resolve({ code, stdout: stdoutOutput, stderr: stderrOutput, }); }); instance.on('error', err => { err.stdout = stdoutOutput; err.stderr = stderrOutput; reject(err); }); }); } function runModernCommandDev(argv, stdOut, options = {}) { const { cwd } = options; const env = { ...process.env, ...options.env, }; return new Promise((resolve, reject) => { const instance = spawn(process.execPath, [kModernBin, ...argv], { cwd, env, }); let didResolve = false; function handleStdout(data) { const message = data.toString(); const bootupMarkers = { dev: /App running at/i, start: /App running at/i, }; if (bootupMarkers[options.modernStart ? 'start' : 'dev'].test(message)) { if (!didResolve) { didResolve = true; resolve(stdOut ? message : instance); } } if (typeof options.onStdout === 'function') { options.onStdout(message); } if (options.stdout !== false) { process.stdout.write(message); } } instance.stdout.on('data', handleStdout); instance.on('error', error => { reject(error); }); instance.on('close', () => { instance.stdout.removeListener('data', handleStdout); if (!didResolve) { didResolve = true; resolve(); } }); }); } function modernBuild(dir, args = [], opts = {}) { return runModernCommand(['build', ...args], { ...opts, cwd: dir, stdout: true, stderr: true, env: { NODE_ENV: 'production', }, }); } function modernDeploy(dir, mode = '', opts = {}) { return runModernCommand(['deploy', `--dir=${dir}`, `--mode=${mode}`], { ...opts, stdout: true, cwd: dir, env: { NODE_ENV: 'production', BUILD_PATH: '', }, cmd: 'deploy', }); } function launchApp(dir, port, opts = {}, env = {}) { return runModernCommandDev(['dev'], undefined, { ...opts, cwd: dir, env: { PORT: port, NODE_ENV: 'development', ...env, }, }); } function modernStart(dir, port, opts = {}) { return runModernCommandDev(['start'], undefined, { ...opts, cwd: dir, env: { PORT: port, NODE_ENV: 'production', }, modernStart: true, }); } async function killApp(instance) { await new Promise((resolve, reject) => { if (!instance) { resolve(); } treeKill(instance.pid, err => { if (err) { if ( process.platform === 'win32' && typeof err.message === 'string' && (err.message.includes(`no running instance of the task`) || err.message.includes(`not found`)) ) { // Windows throws an error if the process is already dead // // Command failed: taskkill /pid 6924 /T /F // ERROR: The process with PID 6924 (child process of PID 6736) could not be terminated. // Reason: There is no running instance of the task. return resolve(); } return reject(err); } return resolve(); }); }); } function markGuardian() { // IGNORE } // eslint-disable-next-line no-unused-vars function installDeps(dir) { // console.log(`Installing dependencies in ${dir}`); // FIXME: 跳过本地依赖的安装,因为在根目录执行 pnpm install --ignore-scripts 的时候已经安装好了 // spawn.sync('pnpm', ['install', '--filter', './', '--ignore-scripts'], { // stdio: 'inherit', // cwd: dir, // }); } // eslint-disable-next-line no-unused-vars function clearBuildDist(dir) { // console.log(`Clearing build dist in ${dir}`); // not support nested projects // const _clearBuildDist = _dir => { // const isProjectRoot = fs.existsSync(path.join(_dir, 'package.json')); // if (isProjectRoot) { // rimraf.sync(path.join(_dir, 'dist')); // } else { // const files = fs.readdirSync(_dir); // files.forEach(f => { // const curPath = path.join(_dir, f); // const isDir = fs.statSync(curPath).isDirectory(); // if (f !== 'node_modules' && isDir) { // _clearBuildDist(curPath); // } // }); // } // }; // _clearBuildDist(dir); } async function getPort() { return await portfinder.getPortPromise({ port: 8080 }); } function sleep(t) { return new Promise(resolve => setTimeout(resolve, t)); } module.exports = { runModernCommand, runModernCommandDev, modernBuild, modernDeploy, modernStart, launchApp, killApp, markGuardian, getPort, installDeps, clearBuildDist, sleep, };