库模式下,dependencies、devDependencie
首先是结论。devDependencies
会使包被编译。比如你import something from 'something'
,如果something
在devDependencies
中,最终build
出的产物是不会出现import something from 'something'
的,something
中用到的内容会被编译。而external
和dependencies
都会使包被保留,意思是如果你import something from 'something'
,那么最终build
出的产物中import something from 'something'
会被原样保留。external
和dependencies
的不同之处是,dependencies
中的依赖会在你的包被安装的时候自动安装,而external
中的包不会被自动安装,需要用户手动安装。
external
只作用于打包阶段,使你在external
中的包在最终生成的产物中不被编译;由于你发布npm包的时候package.json
会被一起打包进去,所以dependencies
会作用于以你的包为依赖的包。如果你使用的依赖既在external
中,又没在dependencies
中,最终用你包的人需要自己安装补全依赖。
至于什么时候会用到external
,我想应该可以external
、devDependencies
和peerDependencies
一起使用。
以下是我的实验过程:
在这个示例中我创建了三个项目,一个是upstream-dependency
(以下简称upstream
),作为最顶层的依赖包;一个以upstream-dependency
作为依赖的testing-dependency
(以下简称testing
);还有一个是依赖testing-dependency
的client-dependency
(以下简称client
),用来模拟最终使用的用户环境。都使用unbuild
进行构建。
upstream
中有一个dependencies
依赖:
package.json
{
...
"dependencies": {
"vue": "^3.2.47"
},
...
}
upstream
有一个简单的导出:
import { createSSRApp, h } from "vue";
import { renderToString } from "vue/server-renderer";
export default renderToString(createSSRApp(h("div", "Hello World")));
最终build后的产物,以mjs
为例,是这样的:
import { createSSRApp, h } from 'vue';
import { renderToString } from 'vue/server-renderer';
const index = renderToString(createSSRApp(h("div", "Hello World")));
export { index as default };
testing
中只有简单的两行导出:
import appString from "upstream";
export default `${appString}test`;
首先我将upstream
作为devDependencies
安装,然后build,此时就有warning了。因为我的upstream
实际上是在production
环境中用到了,但是我放到了devDependencies
中。而devDependencies
中的依赖会被全部编译。可以通过设置{rollup:{inlineDependencies: true}}
解决这个warning。此时再打包,可以发现打包的产物有8000多行,因为vue
中与createSSRApp
,h
,renderToString
相关的代码也被全部编译了。
如果在上一步,不设置{rollup:{inlineDependencies: true}}
,而是设置{external: ["upstream"]}
,再进行打包,最终产物是这样:
import appString from 'upstream';
const index = `${appString}test`;
export { index as default };
我们发布这个testing
包,再在client
中引入。然后去执行的时候发现报错了。因为upstream
这个包没有在testing
的dependencies
中出现,并且我们还将其作为external
没打包进最终产物里,所以我们在client
中引入的时候,是找不到upstream
的,此时我们需要手动安装upstream
包。我们在client
中手动安装upstream
,此时再去执行,可以发现执行成功了。
如果在上述步骤中,我们不添加external
,再把upstream
挪到dependencies
中,再build,产物是这样:
import appString from 'upstream';
const index = `${appString}test`;
export { index as default };
可以发现,{external: ["upstream"]}
和{"dependencies": {"upstream": "^0.0.0"}}
对最终打包产物的效果是一样的,都是使upstream
作为外部依赖引入。此时我们再发布这个包,再在client
中引入。这时我们可以成功运行,因为upstream
被testing
作为dependencies
引入了: