*实际*使用的是哪个版本的 npm 库?

djh*_*987 4 javascript node.js npm

我知道 npm 库在安装后可以在分层树中安装同一库的多个版本,如下所示:

a@0.1.0
  -> b@1.0
  -> c@2.0
       -> b@2.0
Run Code Online (Sandbox Code Playgroud)

在上面,a版本中的包0.1.0被拉入,其依赖项b@1.0和c@2.0. 同样,c@2.0的依赖被拉入,即b@2.0.

我从某人那里听说,即使软件包b安装在两个不同的版本上,但实际上只有其中一个被加载到内存中并使用。我还听说 javascript 与浏览器部署的节点部署可能是也可能不是这种情况。

所以我的问题是:真的只有一个包b被加载到内存中吗?如果是,节点和浏览器都是如此,还是存在差异?

Mat*_*att 5

节点

可以加载 Node 模块/库的多个版本,具体取决于它们的加载位置。该模块加载器是覆盖在Node.js的深入文档。

该require()调用根据解析的文件路径缓存模块。

require('b')from 模块a将解析为.../a/node_modules/b

require('b')from 模块c将解析为.../a/node_modules/c/node_modules/b

因此,将为同一个调用加载单独的模块。这可以通过一个小例子来证明。

模块 B - node_modules/b/index.js

module.exports = {
  VERSION = 'b-0.5.0'
}
Run Code Online (Sandbox Code Playgroud)

模块 C - node_modules/c/index.js

module.exports = {
  VERSION: 'c-1.0.0',
  BVERSION: require('b').VERSION,
}
Run Code Online (Sandbox Code Playgroud)

模块 C 的 B 副本 - node_modules/c/node_modules/b/index.js

module.exports = {
  VERSION: 'b-9.8.7',
}
Run Code Online (Sandbox Code Playgroud)

创建一个程序来输出版本。

console.log('b', require('b').VERSION)
console.log('c', require('c').VERSION)
console.log('cb', require('c').BVERSION)
Run Code Online (Sandbox Code Playgroud)

然后输出版本

?node index.js 
b b-0.5.0
c c-1.0.0
cb b-9.8.7
Run Code Online (Sandbox Code Playgroud)

所以使用不同路径的两个模块require('b').VERSION得到不同的值。

遍历

值得注意的是,如果 Node.jsrequire('b')无法找到本地安装的,./node_modules/b那么它将遍历目录树以b在父node_modules目录中查找。

再次使用上面的示例案例,但删除a/node_modules/c/node_modules/b.

模块c执行了require('b')但无法找到...a/node_modules/c/node_modules/b然后它将进入父级node_modules/并查找b,在这种情况下它将加载缓存的副本...a/node_modules/b

?node index.js 
b b-0.5.0
c c-1.0.0
cb b-0.5.0
Run Code Online (Sandbox Code Playgroud)

浏览器

浏览器没有 npm 模块的概念。你需要一个支持 CommonJS 模块的加载器,比如 Browserify 或 Webpack。如果加载器不遵守 CommonJS/Node.js 规则,那么它不太可能与 npm 包一起工作。

你应该能够用你的加载器打包上面的例子,看看它的行为。