浅析npm install常用的-S、-D、-g的区别、dependencies与devDependencies的区别及常见误区解析
一、结论
npm install,本身就有一个别名 npm i
npm i module_name -S,即 npm install module_name --save ,写入dependencies,发布到生产环境
npm i module_name -D,即 npm install module_name --save-dev ,写入devDependencies,发布到开发环境
npm i module_name -g 即 global全局安装(命令行使用)
npm i module_name 即 本地安装(将安装包放在 ./node_modules 下)
二、npm install -S -D 的区别
1、npm i --save 写入 dependencies
会把msbuild
包安装到node_modules
目录中
会在package.json
的dependencies
属性下添加msbuild
之后运行npm install
命令时,会自动安装msbuild
到node_modules
目录中
之后运行npm install --production
或者注明NODE_ENV
变量值为production
时,会自动安装msbuild
到node_modules
目录中
2、npm i --save-dev 写入 devDependencies
会把msbuild
包安装到node_modules
目录中
会在package.json
的devDependencies
属性下添加msbuild
之后运行npm install
命令时,会自动安装msbuild
到node_modules
目录中
之后运行npm install --production
或者注明NODE_ENV
变量值为production
时,不会自动安装msbuild
到node_modules
目录中
3、还有一个 npm i module_name -g ,-g 指的是全局安装。不带 -g 的为本地安装
将安装包放在 /usr/local
下或者你 node
的安装目录。
可以直接在命令行里使用。
4、npm install 本地安装
将安装包放在 ./node_modules
下(运行 npm 命令时所在的目录),如果没有 node_modules
目录,会在当前执行 npm
命令的目录下生成 node_modules
目录。
可以通过 require()
来引入本地安装的包。
三、dependencies 与 devDependencies 的区别
dependencies与devDependencies 都是在package.json中的配置信息:
1、devDependencies 的理解:
我们在开发一个前端项目的时候,需要使用到webpack或者gulp来构建我们的开发和本地运行环境,这时我们就要安装到 devDependencies 里。webpack或者gulp是用来打包压缩代码的工具,在项目实际运行的时候用不到,所以把webpack或者gulp放到 devDependencies 中就行了。
2、dependencies 的理解:
我们在项目中用到了element-ui,在生产环境中运行项目,当然也需要element-ui,所以我们把element-ui安装到dependencies中。
3、dependencies
和devDependencies
对于你的项目而言,本质区别
到底是什么?
官方文档里怎么说?
"dependencies":您的应用程序在生产中所需的包。
"devDependencies": 只需要本地开发和测试的包。
很抱歉,这也只是它们的定义
和语义化
约定,做不得数的!!真正的区别,其实在这里:
(1)第一点:
By default, npm install will install all modules listed as dependencies in package.json.
翻译一下:默认情况下,npm install 将安装 package.json 里所有列为 dependencies 的模块
什么意思呢?
1. 这种依赖是向下遍历的,比如A库依赖B库,B库依赖C库,在A库中npm install时,会同时安装B和C!
2. 但是devDependencies却不是,npm install 时只会在node_modules里安装当前项目的devDep;比如A的开发依赖是B,B的开发依赖是C,在A库里npm install,只会安装B!
如下图:实线
表示dependencies
, 虚线
表示devDependencies
当我们执行npm install时,对于当前根项目(图中的A项目)而言,dependencies
和devDependencies
对它而言,表现上是一模一样的,都将资源安装到了node_modules
中。
一旦资源被安装到了node_modules
中,对于后续的开发和构建而言,程序就更加无法感知到它们的区别。
但是!!再往下看,到了D/E/F/G这一层依赖时,dependencies
和devDependencies
的区别就凸现出来了。在第三层里,所有被上一层dependencies的库,都得以安装,所有devDependencies里的,都未能被安装。
(2)不过,我们严谨一点,也有例外:
With the --production flag (or when the NODE_ENV environment variable is set to production), npm will not install modules listed in devDependencies.
翻译下:npm install 时使用 --production 标志(或当NODE_ENV环境变量设置为production),npm 将不会安装devDependencies
对,这里确实是符合语义化,
“生产模式”不装“开发环境的依赖”。看到这里,我突然意识到,为什么很多项目在build
脚本中要使用--production
了,原来这不是约定,而是规范。
4、真人真事
前端项目的denpendencies里应不应该放开发时的依赖?
create-react-app项目组在4年前的答案是“适合”,因为dep和devDep的区别主要是语义上的,并不会影响项目的构建,为了解决某些问题,忽略语义是值得的。
但万万没想到的是,第2年,npm 6就推出了audit指令,dependencies拥有了更多的意义。非常多用户因扫描出高危漏洞而困扰。
4年前那个“讨巧”的解决方案再次被提出讨论,而且大概率会被重新扔回devDependencues里去。这真是个悲伤的故事。
四、关于dependencies 与devDependencies的误区
我的理解,打不打包和dependencies、devDependencies没有任何关系,需要打包的肯定是你自己写的代码引用了,打包工具都有自己的判断,没听说过哪款打包工具不通过引入判断直接全量打包的,这样还需要commjs,esm干嘛。
1、本质区别
dependencies和devDependencies主要本质区别:
(1)一是在你安装一个外部模块时,不会自动安装这个模块下 package.json 里边 devDependencies 的依赖(因为你只是要使用这个模块,而不是要开发这个模块,这个模块的正常功能不需要 devDependencies 的依赖)
(2)二是在运行 npm install 时加入 --production 有区别,加入这个参数不会下载 devDependencies 的依赖(前提是保证这里边的依赖不影响项目打包部署,也只有eslint、prettier这种才是完全不影响的了)
如果只是用npm install
,放哪个目录其实都无所谓,该打包就得打包,这是打包工具的事。想想也是,npm只是一个依赖管理工具,它怎么能决定项目打包需不需要呢。
2、误区反驳
所以如果有文章上来就提什么vue放dependencies
,webpack放devDependencies
,然后生产环境就不打包webpack了,都是扯淡,二者没有任何关系。
想想也是,npm自己出的东西肯定是为了方便处理依赖关系,打包都是下游干的事。
用是否打包来区分依赖类型还可以理解,但是这种以依赖类型来判定是否打包就不合适了。
3、总结:
对于自己要发布上线的项目,eslint、prettier以及ts的type等这些发布完全用不到的可以放到devDependencies
下,然后上线打包部署的时候可以用npm install --production
可以减少一些依赖安装时间,前提一定是不参与打包的;不过大部分人不用这个命令,那这时候就随便了,反正两种依赖都要安装。
然后对于要发布到npm仓库的第三方模块,不影响本模块功能的都可以放到devDependencies
下,这样别人在引用的模块时也不会安装这些模块,减少冲突。例如这时候被引入模块的webpack、babel依赖这时候对于引入方可能就不是必须的。
五、问题深入
1、当我们敲 npm install 的时候会安装哪些依赖,dependencies 和 devDependencies 都会安装吗?还是只安装 dependencies?
2、项目依赖包是放在 dependencies 和 devDependencies?
1、【npm install 默认会安装 dependencies 字段和 devDependencies 字段中的所有模块】。 如果软件包具有 package-lock 或 shrinkwrap 文件,则依赖项的安装将由此驱动,如果两个文件都存在,则 npm-shrinkwrap.json 优先。 请参阅 package-lock.json 和 npm-shrinkwrap。
那么也就是说,当我们在拿到一个项目的时候,使用 npm install 是会安装 dependencies 和 devDependencies 里所有的依赖包的。
那么是否意味着,我们在安装依赖包的时候,不需要过多的去纠结是使用 -S 还是 -D 呢 ?随便安装到 dependencies 或者 devDependencies 里都行,反正 npm install 的时候,都会安装 dependencies 和 devDependencies 里面的依赖。
其实不然!如果使用 --production 参数,可以只安装 dependencies 字段的模块。
$ npm install --production
// 或者
$ NODE_ENV=production npm install
【所以我们做好 dependencies 和 devDependencies 的区分的话,在使用 npm install --production 的时候,还是有区别的。】
不过,感觉这个 npm install --production 的使用场景不是很多。我好像没怎么用,可能以后会用到吧。
2、内心os:既然 npm install --production 我用不到,那我在安装依赖包的时候,还是随意吧,放到 dependencies 或者 devDependencies 都无所谓,反正 npm install 的时候会把 dependencies 和 devDependencies 里面的依赖包都安装下来。哈哈~~,随意使用 -S 或者 -D 咯~
错!这样想就错了。dependencies 和 devDependencies 还是有明显区别的。我们接着来看。
我们在安装依赖包的时候,要如何区分是安装到 dependencies 还是 devDependencies 中呢?
(1)dependencies 依赖
这个可以说是 npm 核心一项内容,依赖管理,这个对象里面的内容就是我们这个项目所依赖的 js 模块包。下面这段代码表示我们依赖了 markdown-it 这个包,版本是 ^8.1.0 ,代表最小依赖版本是 8.1.0 ,如果这个包有更新,那么当我们使用 npm install 命令的时候,npm 会帮我们下载最新的包。当别人引用我们这个包的时候,包内的依赖包也会被下载下来。
"dependencies": {
"markdown-it": "^8.1.0"
}
重点是:如果我们把devDependencies开发依赖需要的包放到dependencies上去,那么别人使用的时候,都会需要下载这个包以及它所依赖的包,那是不是就挺坑的
(2)devDependencies 开发依赖
在我们开发的时候会用到的一些包,只是在开发环境中需要用到,但是在别人引用我们包的时候,不会用到这些内容,放在 devDependencies 的包,在别人引用的时候不会被 npm 下载。如:
"devDependencies": {
"autoprefixer": "^6.4.0",0",
"babel-preset-es2015": "^6.0.0",
"babel-preset-stage-2": "^6.0.0",
"babel-register": "^6.0.0",
"webpack": "^1.13.2",
}
当你有了一个完整的 package.json 文件的时候,就可以让人一眼看出来,这个模块的基本信息,和这个模块所需要依赖的包。我们可以通过 npm install 就可以很方便的下载好这个模块所需要的包。
3、结论:当你在开发一个 npm 包的时候,还是要好好管理你的 dependencies 依赖 和 devDependencies 依赖。
之前有个同事写了一个 loading 组件,发到 npm 上面去了,他跟我说简单好用,我就用了。但是我发现他这么小的一个组件,为什么包这么大。一看,原来他写这个 npm 包的时候,所有的依赖都放到 dependencies 里面了(包括 gulp,browser-asyc,压缩代码的,express…等等一些他开发时用的工具)。你们说,他是不是挺狠的!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2017-06-06 JSON.parse(JSON.stringify(obj))实现深拷贝应该注意的坑