npm ELIFECYCLE 异常排查

2022-09-01 · 844 chars · 5 min read

我的一个项目,一直存在一个“小问题”,每次启动,执行 npm start 是正常的,运行的非常好,但是退出的时候,按下 ctrl-c 便会报错。因为是退出报错,没有任何实质影响,就一直没有仔细去排查。这两天又看到这个错,花了点时间查了下,应该对类似的问题有点借鉴意义,于是记录一下。

先看报错的完整信息:


> [email protected] start /Users/keenwon/Code/blog
> npm run generator:once && concurrently "npm run generator:watch" "npm run dev" -n Generator,DevServer -c yellow,cyan


> [email protected] generator:once /Users/keenwon/Code/blog
> npm run generator:watch -- --once


> [email protected] generator:watch /Users/keenwon/Code/blog
> TS_NODE_PROJECT="./tsconfig.scripts.json" ts-node ./scripts/generator "--once"

[Generator]
[Generator] > [email protected] generator:watch /Users/keenwon/Code/blog
[Generator] > TS_NODE_PROJECT="./tsconfig.scripts.json" ts-node ./scripts/generator
[Generator]
[DevServer]
[DevServer] > [email protected] dev /Users/keenwon/Code/blog
[DevServer] > ACTION=start NODE_ENV=development webpack serve
[DevServer]
[DevServer] ℹ Compiling Webpack
[DevServer] <i> [webpack-dev-server] Project is running at:
[DevServer] <i> [webpack-dev-server] Loopback: http://localhost:8080/
[DevServer] <i> [webpack-dev-server] On Your Network (IPv4): http://10.221.71.58:8080/
[DevServer] <i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::1]:8080/
[DevServer] <i> [webpack-dev-server] Content not from webpack is served from '/Users/keenwon/Code/blog/public' directory
[DevServer] <i> [webpack-dev-server] 404s will fallback to '/index.html'
^C[Generator] npm ERR! code ELIFECYCLE
[Generator] npm ERR! errno 1
[Generator] npm ERR! [email protected] generator:watch: `TS_NODE_PROJECT="./tsconfig.scripts.json" ts-node ./scripts/generator`
[Generator] npm ERR! Exit status 1
[Generator] npm ERR!
[Generator] npm ERR! Failed at the [email protected] generator:watch script.
[Generator] npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
[Generator]
npm ERR! A complete log of this run can be found in:
[Generator] npm ERR!     /Users/keenwon/.npm/_logs/2022-09-01T02_20_38_999Z-debug.log
[Generator] npm run generator:watch exited with code 1
[DevServer] <i> [webpack-dev-server] Gracefully shutting down. To force exit, press ^C again. Please wait...
[DevServer] npm run dev exited with code 0

排除掉和问题无关的信息,npm start 其实就是使用 concurrently 同时执行两个命令,分别是:

  • npm run generator:watch:执行 ts-node ./scripts/generator,通过 chokidar 监听并转换本地文件
  • npm run dev:执行 webpack serve 启动 webpack-dev-server

仔细看异常信息,几个关键点:

  1. npm ERR! code ELIFECYCLEnpm ERR! errno 1npm ERR! Exit status 1 都说明,是 npm 运行的命令意外退出了
  2. npm run generator:watch exited with code 1npm run dev exited with code 0 说明 concurrently 执行的两个命令,报错的是 npm run generator:watch
  3. npm 的 log 文件依然没什么用,除了 “免责声明” 外再次印证了报错的是 npm run generator:watch

至此,基本定位到 ctrl-c 时报错的命令了,就是 ts-node ./scripts/generator,内部使用 chokidar 监听本地文件,核心代码:

import { watch } from 'chokidar'

const watcher = watch('/path/dir')

watcher
  .on('add', () => {
    /* ... */
  })
  .on('change', () => {
    /* ... */
  })
  .on('unlink', () => {
    /* ... */
  })

也就是说,点击 ctrl-c 后,concurrently 发送了 SIGINT,但是 chokidar 并未正常退出。我翻了它的文档,没看到什么有用的信息,只有这么一个 issue

Never thought about it, but I think that's intentional.

The reason is: chokidar is usually as a library for doing something else — for example, for building javascript apps. So the app builder would handle sigint on its own and execute the proper watcher.close() logic in there.

只能自己处理退出逻辑了,添加如下代码:

import process from 'node:process'

process.on('SIGINT', async () => {
  await watcher.close()
  process.exit(0)
})

问题解决!

最后总结一下:

  1. 报错信息还是要仔细看的,之前走了弯路,怀疑了 concurrently 和 webpack-dev-server,甚至翻了 concurrently 的源码,在它的 --kill-others--kill-others-on-fail 上浪费了很多时间,其实出问题的命令已经打出来了,虽然不明显。
  2. 定位这种没太多有用信息的异常,“二分调试法” 还是很有用的,也就是删代码大法,逐步缩小包围圈,直到发现问题。
赞赏

微信