From c884cfef8e7aa43832136e7b11698f94c4a3525c Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Sat, 9 Nov 2024 00:19:33 +0800 Subject: [PATCH] feat: add perf init output --- lib/index.js | 67 +++++-------------------------- lib/output.js | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/process.js | 30 +++++++------- package.json | 1 + 4 files changed, 127 insertions(+), 75 deletions(-) create mode 100644 lib/output.js diff --git a/lib/index.js b/lib/index.js index 5b026d6..62349e5 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,22 +2,22 @@ const { forkTsc, forkRun } = require('./process'); const { parseArgs, debounce, - getIp, deleteFolderRecursive, readJSONCFile, copyFilesRecursive, - output, - colors, debug, getRelativeDir, triggerMessage, suffixMapping, + output, + colors, } = require('./util'); const path = require('path'); const { replaceTscAliasPaths } = require('tsc-alias'); const chokidar = require('chokidar'); const fs = require('fs'); const { startProxyServer } = require('./proxy'); +const consoleOutput = require('./output'); function run() { const { cmdPath, tscArgs, parentArgs, childArgs } = parseArgs(process.argv); @@ -231,67 +231,18 @@ function run() { async (serverReportOption, isFirstCallback, during, debugUrl) => { if (isFirstCallback) { // 第一次启动把端口等信息打印出来 - console.log(''); - output( - `${colors.green('Node.js server')} ${colors.dim( - 'started in' - )} ${during} ms ${ - hasPaths - ? colors.dim('and enable compile with ') + 'tsc-alias' - : '' - }\n` + consoleOutput.renderServerFirstReady( + serverReportOption, + during, + hasPaths, + debugUrl ); - if (serverReportOption && serverReportOption.port) { - const protocol = serverReportOption.ssl ? 'https' : 'http'; - output( - `${colors.green('➜')} Local: ${colors.cyan( - `${protocol}://127.0.0.1:${colors.bright( - serverReportOption.port - )}${colors.cyan('/')}` - )} ` - ); - const netWorkIp = getIp(); - if (netWorkIp) { - output( - `${colors.green('➜')} ${colors.dim( - `Network: ${protocol}://${netWorkIp}:${serverReportOption.port}/ ` - )}` - ); - } - if (debugUrl) { - output( - `${colors.green('➜')} ${colors.dim( - `Debugger: devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${debugUrl.replace( - 'ws://', - '' - )}` - )}` - ); - } - console.log(''); - } if (proxyServer) { proxyServer.start(); } triggerMessage('server-first-ready'); } else { - output(''); - output( - `${colors.green('Node.js server')} ${colors.dim( - 'restarted in' - )} ${during} ms` - ); - if (debugUrl) { - output( - `${colors.green('➜')} ${colors.dim( - `Debugger: devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${debugUrl.replace( - 'ws://', - '' - )}` - )}` - ); - } - output(''); + consoleOutput.renderServerReady(during, debugUrl); triggerMessage('server-ready'); } } diff --git a/lib/output.js b/lib/output.js new file mode 100644 index 0000000..b2fb3dc --- /dev/null +++ b/lib/output.js @@ -0,0 +1,104 @@ +const Table = require('cli-table3'); +const { EventEmitter } = require('events'); +const { colors, getIp, output } = require('./util'); + +class ConsoleOutput extends EventEmitter { + constructor() { + super(); + } + + renderPerfInit(items) { + const table = new Table({ + head: ['name', 'duration(ms)'], + }); + + for (const item of items) { + if (item.entryType === 'measure') { + table.push([item.name.replace('MidwayInitialize:', ''), (item.duration).toFixed(2)]); + } + } + + console.log(table.toString()); + } + + renderKeepAlive() { + output(colors.red('*'.repeat(120))); + output( + `A ${colors.red( + `${colors.bright( + 'Critical unhandledRejection or uncaughtException' + )}` + )} was detected and the process has exited automatically.` + ); + output('Please make sure to handle it.'); + output( + 'The --keepalive parameter was enabled, we will do our best to ensure the process remains normal.' + ); + output(colors.red('*'.repeat(120))); + } + + renderServerFirstReady(serverReportOption, during, hasPaths, debugUrl) { + // 第一次启动把端口等信息打印出来 + console.log(''); + output( + `${colors.green('Node.js server')} ${colors.dim( + 'started in' + )} ${during} ms ${ + hasPaths + ? colors.dim('and enable compile with ') + 'tsc-alias' + : '' + }\n` + ); + if (serverReportOption && serverReportOption.port) { + const protocol = serverReportOption.ssl ? 'https' : 'http'; + output( + `${colors.green('➜')} Local: ${colors.cyan( + `${protocol}://127.0.0.1:${colors.bright( + serverReportOption.port + )}${colors.cyan('/')}` + )} ` + ); + const netWorkIp = getIp(); + if (netWorkIp) { + output( + `${colors.green('➜')} ${colors.dim( + `Network: ${protocol}://${netWorkIp}:${serverReportOption.port}/ ` + )}` + ); + } + if (debugUrl) { + output( + `${colors.green('➜')} ${colors.dim( + `Debugger: devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${debugUrl.replace( + 'ws://', + '' + )}` + )}` + ); + } + console.log(''); + } + } + + renderServerReady(during, debugUrl) { + output(''); + output( + `${colors.green('Node.js server')} ${colors.dim( + 'restarted in' + )} ${during} ms` + ); + if (debugUrl) { + output( + `${colors.green('➜')} ${colors.dim( + `Debugger: devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${debugUrl.replace( + 'ws://', + '' + )}` + )}` + ); + } + output(''); + } +} + +module.exports = new ConsoleOutput(); diff --git a/lib/process.js b/lib/process.js index 722effc..dcdcfca 100644 --- a/lib/process.js +++ b/lib/process.js @@ -2,8 +2,6 @@ const { fork, spawn } = require('child_process'); const { filterFileChangedText, debug, - output, - colors, convertPosixToGnu, } = require('./util'); const { CHILD_PROCESS_EXCEPTION_EXIT_CODE } = require('./constants'); @@ -11,6 +9,7 @@ const path = require('path'); const fs = require('fs'); // is windows const isWin = process.platform === 'win32'; +const consoleOutput = require('./output'); /** * @@ -104,7 +103,9 @@ const forkTsc = (tscArgs = [], options = {}) => { const forkRun = (runCmdPath, runArgs = [], options = {}) => { // 判断路径是否是包名还是路径 if (!runCmdPath.startsWith('.') && !runCmdPath.startsWith('/')) { - runCmdPath = require.resolve(runCmdPath); + runCmdPath = require.resolve(runCmdPath, { + paths: [options.cwd || process.cwd()], + }); } let runChild; let onServerReadyCallback; @@ -126,6 +127,8 @@ const forkRun = (runCmdPath, runArgs = [], options = {}) => { filterExecArgv.some(filterArg => arg.startsWith(filterArg)) ); + const isPerfInit = runArgs.includes('--perf-init'); + function innerFork(isFirstFork = false) { const startTime = Date.now(); @@ -157,10 +160,14 @@ const forkRun = (runCmdPath, runArgs = [], options = {}) => { Date.now() - startTime, currentDebugUrl )); - runChild.removeListener('message', onServerReady); lastBootstrapStatus = true; } else if (data.title === 'debug-url') { currentDebugUrl = data.debugUrl; + } else if (data.title === 'perf-init') { + if (isPerfInit && isFirstFork) { + // perf init + consoleOutput.renderPerfInit(data.data); + } } } catch (err) { console.error(err); @@ -171,19 +178,7 @@ const forkRun = (runCmdPath, runArgs = [], options = {}) => { if (runArgs.includes('--keepalive')) { runChild.once('exit', code => { if (code === CHILD_PROCESS_EXCEPTION_EXIT_CODE) { - output(colors.red('*'.repeat(120))); - output( - `A ${colors.red( - `${colors.bright( - 'Critical unhandledRejection or uncaughtException' - )}` - )} was detected and the process has exited automatically.` - ); - output('Please make sure to handle it.'); - output( - 'The --keepalive parameter was enabled, we will do our best to ensure the process remains normal.' - ); - output(colors.red('*'.repeat(120))); + consoleOutput.renderKeepAlive(); if (lastBootstrapStatus === undefined || lastBootstrapStatus) { // 只有上一次启动成功了,才继续保活拉起,如果启动就失败了,就停止重启 innerFork(false); @@ -198,6 +193,7 @@ const forkRun = (runCmdPath, runArgs = [], options = {}) => { innerFork(true); const killRunningChild = async signal => { + runChild.removeAllListeners('message'); if (isWin) { await new Promise(resolve => { if (!runChild || runChild.exitCode !== null) { diff --git a/package.json b/package.json index d7a1c8a..410d873 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "dependencies": { "@midwayjs/glob": "^1.1.1", "chokidar": "^3.6.0", + "cli-table3": "^0.6.5", "compare-versions": "^6.1.0", "source-map-support": "^0.5.21", "tar": "^7.4.0",