npm install 都干了啥?

5,076 阅读3分钟

起因

本周我在将egg项目发布到生产环境之后,发现生产环境无法执行npm run start,提示如下图

image

摸索原因

script 命令是如何运行的?

作为一个前端工程师,我每天都会和各种环境打交道,经常在命令行执行cross-env NODE_ENV=dev等操作,突然有一天,我发现执行 cross-env NODE_ENV=dev 居然给我报错了?

image

检查了下原来是包没有使用全局安装,现在全局安装下npm i cross-env -g

image

嗯,果然不报错了,为啥啊?其实我们看上面的安装反馈就可以知道,全局安装会创建一个软连接

image

而使用项目依赖安装则不会有这步操作,则导致我们不能直接使用简写去执行命令。

image

那么问题来了,难道我所有需要在命令行执行的包都需要安装到全局,才能使用?

  1. 第一种方法,可以执行文件 ./node_modules/.bin/cross-env NODE=dev
  2. 作为一个懒人,当然不会用方法一啦,这个时候npm script就派上用场了

package.jsonscript中新增命令

"scripts": {
    "dev": "cross-env NODE=dev"
}

执行npm run dev,看到这里,我想大多数人肯定会说,我靠,你说的方法我几百年前就知道了啊,还需要你来BB?

但是我想还是有一部分人和我一样不懂为啥使用npm script执行上面的命令就不会报错呢,难道也会创建软连接?其实是因为我们执行npm run的时候会将node_modules/.bin下面所有文件都添加到系统的环境变量中,这样在执行期间就可以使用缩写,等执行结束会自动删除这些环境变量

理清这些之后再来看我一开始说的问题,提示找不到模块,看了下 .bin 下面的代码

image

看样子是引入上级目录的index.js,但是我们并没有在上级目录找到该文件,导致报错,难道是别人的包写错了?当然这是不可能的,经过我不断的折腾,最后才发现!!!

其实我们在npm install的时候首先会下载对应资源包的压缩包放在用户目录下的.npm文件夹下,然后解压到项目的node_modules中,并且提取依赖包中指定的bin文件,在linux下会创建一条软连接,所以在linux下我们真正执行的是.bin文件夹下文件指向的文件,看下图。

image

而我遇到的问题就是执行npm installnpm start是两台机器,生产机上的文件实际上是从发布机 copy 过来的,导致软连接没了,所以才会报错。

吸取经验

从这么一个小小的问题就可以暴露出来,虽然我们每天都会执行npm script但是却对他的执行过程很模糊,导致遇到问题却找不到原因,最终在看了一些资料之后我总结了如下几个点。

总结

  1. npm install 会先查找本地已经下载过的包,不论版本是多少,找到了就不会去下载,所以如果要升级依赖,可以使用npm update或者显示安装npm install cross-env --save
  2. npm install 会先下载项目中的依赖包,然后下载依赖的依赖,这样就会导致,生成的文件是树形结构,并且存在许多重复的包,所以这个时候npm就会将依赖扁平化,将依赖的依赖提取到第一层,遇到版本号不一致的也会保留,遇到完全一致的就会删除。
  3. 最后还会提取依赖中的bin文件,windows操作系统生成cmd文件,linux系统生成软连接

查阅的资料

每一个小问题深入下去都会头皮发麻,学不动了