2.4 框架应该输出怎样的构建产物
框架要同时服务「HTML 直接引入」「打包工具用户」「Node.js 用户」三类场景,因此必须输出多种模块格式的产物,并分别处理
__DEV__。
一、产物格式总览
| 产物格式 | 代表文件 | 使用场景 |
|---|---|---|
| IIFE | vue.global.js / vue.global.prod.js | 直接在 HTML 中用 <script> 标签引入 |
| ESM(浏览器) | vue.esm-browser.js / vue.esm-browser.prod.js | 用 <script type="module"> 引入 |
| ESM(打包工具) | vue.esm-bundler.js | rollup / webpack 等打包工具 |
| CJS | vue.cjs.js / vue.cjs.prod.js | Node.js 环境(如服务端渲染) |
二、IIFE 格式
- 全称 Immediately Invoked Function Expression,即立即执行的函数表达式。
- 可以直接在 HTML 页面中使用
<script>标签引入框架并使用:
<script src="/path/to/vue.js"></script>
vue.global.js文件就是 IIFE 形式的资源,它会把框架挂到全局变量上:
var Vue = (function (exports) {
// ...
exports.createApp = createApp
// ...
return exports
})({})
- 在 rollup.js 中通过
format: 'iife'输出这种形式的资源:
// rollup.config.js
const config = {
input: 'input.js',
output: {
file: 'output.js',
format: 'iife' // 指定模块形式
}
}
export default config
三、ESM 格式
rollup.js 的输出格式配置为 format: 'esm'。Vue.js 3 会输出两个 ESM 文件,区别在于 __DEV__ 常量的处理方式:
| 资源 | 面向对象 | __DEV__ 的处理 |
|---|---|---|
vue.esm-browser.js | <script type="module"> | 开发版替换为 true;生产版替换为 false,从而被 Tree-Shaking 移除 |
vue.esm-bundler.js | rollup.js / webpack 等打包工具 | 替换为 (process.env.NODE_ENV !== 'production'),由用户配置的构建目标环境决定 |
浏览器直用版本:
<script type="module" src="/path/to/vue.esm-browser.js"></script>
打包工具在寻找资源时,如果 package.json 中存在 module 字段,会优先使用 module 字段指向的资源来代替 main 字段指向的资源:
{
"module": "dist/vue.esm-bundler.js",
"main": "index.js"
}
命名规律:带
-bundler字样的 ESM 资源是给 rollup.js 或 webpack 等打包工具使用的;带-browser字样的 ESM 资源是直接给<script type="module">使用的。 给打包工具的版本之所以不写死__DEV__,是因为用户可以通过 webpack 配置自行决定构建资源的目标环境,框架不能替用户下结论。
四、CJS 格式
- 在 Node.js 环境中,资源的模块格式应该是 CommonJS(简称 cjs)。
- 通过修改
rollup.config.js的配置format: 'cjs'输出:
// rollup.config.js
const config = {
input: 'input.js',
output: {
file: 'output.js',
format: 'cjs' // 指定模块形式
}
}
export default config
五、易错点
用
<script>直接引入vue.esm-bundler.js会报错——process.env在浏览器里不存在。 用打包工具引入vue.esm-browser.js则失去了按环境裁剪警告的能力(它的__DEV__已经写死)。
相关
- 2.3 框架要做到良好的 Tree-Shaking:为什么这些产物都优先提供 ESM 形式。
- 2.5 特性开关:打包工具版本额外暴露给用户的裁剪开关。