【白话前端】在爱情故事中明悟dependencies和devDependencies的区别

1,985 阅读6分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

声明

本文中提到的爱情故事的情节纯属虚构,请各位不要被破防,流泪,砸手机。

一个问题 && 错误的答案

【故事时间】

小瑞是一个人类高质量男性,中分飘飘,油光锃亮。于是,他的生活中出现了两个追求他的女生。

其中小依是一个乖乖女,她的英文名叫dependencies,大家都觉得她是过日子的类型,一定是将来的新娘

小开则是一个开放又浑身魅力的女生,英文名叫devDependencies,大家给她的评价是,适合在谈恋爱时交往,但最后和小瑞结婚的肯定不是她

那么问题来了:

对于小瑞而言,小依小开的区别到底有多大?本质上的区别又在哪里呢?


【技术时间】

现代前端项目离不开npm,哪怕有了yarn/pnpm/ni等一系列的替代工具,但我们依然离不开npm所带来的标准。

package.json文件,无疑是其中的关键。

但是,你能快速回答出下面这个问题吗?

dependenciesdevDependencies对于你的项目而言,本质区别到底是什么?

星爷01.gif

很多同学对于这个知识点,只有一个模糊的认知,甚至于是来自于语义上的认知:

dependencies里的依赖最后会构建到制品包里去;

devDependencies里的依赖只在开发期有效;

回答的很好,可惜:

       🔺🔺❌❌完全错误❌❌🔺🔺

语义化并不能完全指引你走向正确的道路,反而可能会走向歧路。

那么正确答案是什么呢?

看看小瑞怎么说?


寻根问底 && 真正的差异

【故事时间】

小瑞虽然是个渣男,但他还是想弄清楚:“对于他而言,小依小开真正的区别是什么?”

于是他找到了小依小开的全部资料,扒掉伪装,深入本质,把握重点...

终于,小瑞得到了一个让他有点犯懵的结论:

虽然有一些差距,但如果只是把范围局限到对他而言上的话,

小依小开的区别竟然微乎其微!

       💗💗💗💗怎么可能?💗💗💗💗

【技术时间】

对于技术人员而言,真正可靠的差异,还得是 百度和问群友 看文档

npm官方文档地址: docs.npmjs.com/specifying-…

官方文档里怎么说?

"dependencies":您的应用程序在生产中所需的包。
"devDependencies": 只需要本地开发和测试的包。

看到这儿某些同学放声大笑:“这不就是我刚才的答案吗?”

xingye2.gif

很抱歉,这也只是它们的定义语义化约定,做不得数的!!

真正的区别,其实在这里:

docs.npmjs.com/cli/v8/comm…

差异一:

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

屏幕截图 2021-11-16 215015.png

当我们执行npm install时,对于当前根项目(图中的A项目)而言,dependenciesdevDependencies对它而言,表现上是一模一样的,都将资源安装到了node_modules中。
一旦资源被安装到了node_modules中,对于后续的开发和构建而言,程序就更加无法感知到它们的区别。

     👧👧👧小瑞心想:呵,陷入爱情的女人,一般无二👧👧👧

但是!!
再往下看,到了D/E/F/G这一层依赖时,dependenciesdevDependencies的区别就凸现出来了。

在第三层里,所有被上一层dependencies的库,都得以安装,所有devDependencies里的,都未能被安装

如果你仍有疑虑,可以尝试做个验证:

mkdir test-dep
cd test-dep
yarn init
yarn add -D fast-glob

然后打开项目,去node_modules中验证一番,是否符合我们刚才得出的结论:
正常情况下,dependencies和devDependencies的影响不是直接的,而是跨代的!

【吐槽时间】

好家伙,这波是对舔狗的杀人诛心了,可谓是。

小瑞在无形中,对小依小开的追求者,造成了深远的影响。

不过,我们严谨一点,也有例外:

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了,原来这不是约定,而是规范。


意料之外,情理之中。绝绝子的结局(有翻转)

最后这段才是真正的杀人诛心,因为它是根据**真实事件**改编!
看下去吧!

【故事时间】

小瑞发现了上面的知识点后,开始对语义化不屑一顾。

于是他决定抛开人们的成见(也就是语义化),要娶小开为妻。

(某个著名开源团队将本应该放在devDependencies的内容放到了dependencies中。)

小瑞心想:我太懂女人了。

(该开源团队:我太懂依赖了;只要我项目里不依赖,它们就不会影响我包的体积,完美!)

      👫👫👫这会是完美的结局吗?👫👫👫

非常可惜,不是。


【社区时间】

真人真事:

前端项目的denpendencies里应不应该放开发时的依赖?

create-react-app项目组在4年前的答案是“适合”,因为dep和devDep的区别主要是语义上的,并不会影响项目的构建,为了解决某些问题,忽略语义是值得的。

但万万没想到的是,第2年,npm 6就推出了audit指令,dependencies拥有了更多的意义。

非常多用户因扫描出高危漏洞而困扰。

4年前那个“讨巧”的解决方案再次被提出讨论,而且大概率会被重新扔回devDependencues里去。

这真是个悲伤的故事。

【故事时间】结局

小瑞万万没想到,他们美满的婚姻只持续了一年。

第二年,他们的婚姻就因为“社区身体普查”小开被意外查出了_ _ _ ,而走向了破灭...

    🎗️🎗️🎗️可惜不是你,陪我到最后🎗️🎗️🎗️

总结

关于技术细节,不再多说,上面都有来源,大家也可以自行验证,如果有错误,欢迎指出。

我只是想发出一点感叹:

面向“可以、有用、没关系”的解决之道可能并不长久,语义化也并不是虚妄的内容,它可能是真正面向未来的编程思维。

关于故事真实性

请参考github相关讨论:
a. github.com/facebook/cr…
b. github.com/facebook/cr…