3 个回答

其实可以看到下方有很多相似问题,里面也有很详尽的答案,可以多看看。
最近在准备相关的分享,故直接贴过来,希望对新人有一些帮助,有误请指出🤓。

为了少打几个字
devDep = devdependencies
dep = dependecies

一、npm i xxx 不加后缀跟加后缀有什么区别吗?

在早前的版本,npm i 不加后缀,他仅仅只会将依赖下载到node_modules,而不会对应将添加到package.json 中的devDep 或者是 dep中。后面npm版本升级后优化了,不加后缀,默认为在dep。

二、devDep 跟 dep 有什么区别吗?

1、首先是语义不同。

  • dep我们认为,我们最终项目实际的运行代码依赖它们
  • devDep 我们认为,我们最终项目实际的运行代码不依赖它们,但是我们在打包,开发的过程需要它们

举一个形象的示例?

比如我们希望造一个🔨。🔨 = 🪵 + 金属
dep 则是 🪵 、 金属
devDep 可能是把 🪵 变成细锤子棒的 🪓 或者 锯子,还有把金属打造成锤子型的各种机器。

举一个具体示例?

假如我们的主入口是

import vue from "vue"
const log=()=>console.log("adasd")

很明显vue 是dep,但是注意到了我们有一个es6 箭头函数log,和const 声明,我们希望把它转为es5

// ...省略 vue 
function log(){console.log("adasd")}

这个转化的过程我们假如用到babel,那babel就是devDep。类似的,开发过程中经常存在的devDep还有eslint prettier webpack rollup等等

2、安装依赖附带

一个npm 包必须有一个package.json 我们将之称为描述文件,它描述了所有关于此包的信息。所以你的项目本身其实也是一个合法的npm包

当我们npm i xxx一个模块时,我们会同时安装此模块package.json 中的所有dep,因为基于如上的解释,我们容易理解,那些dep都是必需品,运行需要没了就gg了。

3、依赖版本冲突时,有依赖层级提升优先级的区别

一个项目通常有很多依赖,不同的依赖之间可能有相同的依赖,但是版本不一致。npm优化了早期黑洞式的嵌套,尽量把它们扁平化,所以必定有一个被提升到项目的node_modules下。而另一个在自己下的node_modules。
假如我们安装 vue-cli-service 这个包,它依赖了webpack@4
假如我们同时安装 my-cli-service 这个包,它依赖了webpack@5

相当于

my-project
 -node_modules
  -vue-cli-service
   -node_modules
    -webpack
  -my-cli-service
  -webpack

但是问题来了,哪个版本的webpack在外面那层?
默认来说版本大的在外面那层。
但是如果
vue-cli-service 是dep而 my-cli-service 是devDep,那就是vue-cli-service的webpack在 外面,这就是dep所带来的优先级😁

三、npm i xxx 跟打包有什么关系?

打包往往需要npm i xxx 但是 npm i xxx不一定都跟打包有关系。简单想也能知道,打包本身是一个非常细粒度的依赖查找过程,本身是非常聪明的,把npm i的东西都一味打进去这么愚蠢的行为是不可能的。
还是拿上面那个例子,假如这个是入口

// entry.js
import vue from "vue"
import { getA } from "./aaa.js"
const log=()=>console.log("adasd")

那过程是(简化过程,实际当然会复杂一些)

打包工具通过获取entry文件内容,然后ast(正则可以吗?可以,但是在一些复杂的情况就会有问题,不可靠)解析出对应的依赖 
  -> 打包工具:我找到了 "vue" "./aaa.js" 可能是一个依赖 
    ->打包工具:"./aaa.js" 看起来是一个相对路径,我尝试根据当前文件找找在不在,"vue" 看起来是一个npm 模块,我去node_modules 找找

所以你的问题到这里终于有了答案
Q: 使用npm i moduleName 安装到node_modules中的依赖,打包时,会被打包到生产环境吗?
A: 重要的不是你装没装,而是你实际代码用没用。 可以装而不用,这是的权利,也是被同事乱叼一顿的伏笔🤣

顺便补充一下,tree-shaking
它不是npm包的,而是基于esm规范的,模块导出导入之间的,是更细粒度一级的用不用。
像我们的entry.js例子, getA 只有引入,没有实际使用,所以aaa.js 即使有导入,但是最终也不会出现在最终产物中。因为没用,出现在我的世界中,但是一点用没有,俗称废物。

刚好饭点了,我该吃饭了🤓

新手上路,请多包涵

这个只决定了是放在package.json的dependecies还是devdependencies中
一个文件你没在代码中引入自然是不会打包的

不会,你可以看下打包后的体积就知道,即便是有压缩机制,也不可能把依赖包压缩到这么小。不管你是用webpack打包还是使用vite打包。 他们都会有自己的一个 tree shaking的优化过程。简单讲你可以理解为他会分析你的代码,然后只提取出被你代码中用到的方法,没用到的都会统统丢掉。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题