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
仔细看异常信息,几个关键点:
npm ERR! code ELIFECYCLE
,npm ERR! errno 1
,npm ERR! Exit status 1
都说明,是 npm 运行的命令意外退出了npm run generator:watch exited with code 1
,npm run dev exited with code 0
说明 concurrently 执行的两个命令,报错的是npm run generator:watch
- 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) })
问题解决!
最后总结一下:
- 报错信息还是要仔细看的,之前走了弯路,怀疑了 concurrently 和 webpack-dev-server,甚至翻了 concurrently 的源码,在它的
--kill-others
和--kill-others-on-fail
上浪费了很多时间,其实出问题的命令已经打出来了,虽然不明显。 - 定位这种没太多有用信息的异常,“二分调试法” 还是很有用的,也就是删代码大法,逐步缩小包围圈,直到发现问题。