diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..a51197c --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,34 @@ +name: Node.js CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + timeout-minutes: 60 + strategy: + matrix: + include: + - os: ubuntu-latest + node-version: 16 + - os: ubuntu-latest + node-version: 20 + - os: windows-latest + node-version: 20 + runs-on: ${{ matrix.os }} + steps: + - name: Git checkout + uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - run: npm install && npm install codecov + - run: npm run cov + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 diff --git a/lib/index.js b/lib/index.js index e624615..bd645f5 100644 --- a/lib/index.js +++ b/lib/index.js @@ -63,6 +63,7 @@ function run() { runChild && runChild.kill(); process.exit(0); } catch (err) { + console.error(err); process.exit(1); } } diff --git a/lib/process.js b/lib/process.js index 26b51c5..2876884 100644 --- a/lib/process.js +++ b/lib/process.js @@ -57,14 +57,18 @@ const forkRun = (runCmdPath, runArgs = [], options = {}) => { function innerFork(isFirstFork = false) { const startTime = Date.now(); - runChild = fork(runCmdPath, runArgs, { + runChild = fork('wrap.js', runArgs, { stdio: 'inherit', - cwd: options.cwd, + cwd: __dirname, + env: { + CHILD_CMD_PATH: runCmdPath, + CHILD_CWD: options.cwd || process.cwd(), + ...process.env, + }, // execArgv: process.execArgv.concat(['-r', 'source-map-support/register']) }); - const onServerReady = data => { - if (data.title === 'server-ready') {89 + if (data.title === 'server-ready') { onServerReadyCallback && onServerReadyCallback(data, isFirstFork, Date.now() - startTime); runChild.removeListener('message', onServerReady); @@ -75,19 +79,32 @@ const forkRun = (runCmdPath, runArgs = [], options = {}) => { innerFork(true); - return { - kill: signal => { + const killRunningChild = signal => { + if (isWin) { + runChild.send({ + title: 'server-kill', + }); + } else { runChild.kill(signal); + } + }; + + return { + kill(signal) { + killRunningChild(signal); }, restart() { // 杀进程 - runChild.kill(); + killRunningChild(); // 重新拉起来 innerFork(); }, onServerReady(readyCallback) { onServerReadyCallback = readyCallback; }, + getRealChild() { + return runChild; + }, }; }; diff --git a/lib/wrap.js b/lib/wrap.js new file mode 100644 index 0000000..f565fc5 --- /dev/null +++ b/lib/wrap.js @@ -0,0 +1,12 @@ +// 拿到执行路径,以及执行文件 +const childPath = process.env.CHILD_CMD_PATH; +const childCwd = process.env.CHILD_CWD; + +process.on('message', data => { + if (data.title === 'server-kill') { + process.emit('SIGINT'); + } +}); + +process.chdir(childCwd); +require(childPath); diff --git a/test/fixtures/custom-event.js b/test/fixtures/custom-event.js new file mode 100644 index 0000000..3c92b08 --- /dev/null +++ b/test/fixtures/custom-event.js @@ -0,0 +1,13 @@ +process.on('SIGINT', () => { + process.send('server-kill-complete'); + // process.exit(0); +}); + +// process.on('SIGTERM', () => { +// process.send('server-kill-complete'); +// process.exit(0); +// }); + +process.send({ + title: 'server-ready', +}); diff --git a/test/index.test.js b/test/index.test.js index 9701d80..c4f35b5 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,6 +1,7 @@ const execa = require('execa'); -const { join } = require('path'); +const { join, resolve } = require('path'); const { existsSync, unlinkSync } = require('fs'); +const { forkRun } = require('../lib/process'); const mtscPath = join(__dirname, '../bin/mwtsc.js'); @@ -63,6 +64,21 @@ describe('/test/index.js', () => { setTimeout(() => { cp.kill(); }, 3000); - }) + }); + }); + + it('should send server-kill event to child process and receive response', (done) => { + const childProcess = forkRun(resolve(__dirname, './fixtures/custom-event.js')); + childProcess.getRealChild().on('message', (data) => { + if (data === 'server-kill-complete') { + childProcess.kill(); + done(); + } + }); + childProcess.onServerReady(() => { + childProcess.getRealChild().send({ + title: 'server-kill', + }); + }); }); -}); \ No newline at end of file +});