准备工作
当设计一个框架时,我们有三种选择:纯运行时、运行时+编译时、纯编译时。为了做出合适的决策,你需要清楚地知道什么是运行时,什么是编译时,它们各自有什么特征,对框架有哪些影响。
Vue 有两个主要部分:编译器(Compiler)和运行时(Runtime),这两部分可以分别或一起使用,这就导致了 Vue 有三种主要的构建方式:纯运行时、运行时+编译器、纯编译器。
-
纯运行时:此构建方式仅包含运行时部分。由于模板需要编译器来编译成 JavaScript,这种构建方式中无法在 Vue 组件中直接编写模板。因此,需要预编译模板(例如,使用 Vue 单文件组件或 webpack 的
vue-loader
插件),或者使用 render 函数。 -
运行时+编译器:这是 Vue.js 的完整构建,包含运行时和编译器。这样可以直接在 Vue 组件中编写模板,Vue.js 会在运行时编译这些模板。尽管这使开发更方便,但会导致最终的代码体积变大,因为包含了编译器。
-
纯编译器:在这种构建方式中,Vue.js 只包含编译器部分。这种构建方式比较少见,通常在特殊的构建工具中使用。
通常情况下,在开发环境(npm run dev
)中使用运行时+编译器构建,而在生产环境(npm run build
)中使用纯运行时构建。
我们以 packages/vue
为例,因为它的 dist
目录下包含了所有的构建版本,共 12 个,结构如下:
├── packages/
│ ├── vue/
│ │ ├── dist/
│ │ ├ ├── vue.cjs.js
│ │ ├ ├── vue.cjs.prod.js
│ │ ├ ├── vue.esm-browser.js
│ │ ├ ├── vue.esm-browser.prod.js
│ │ ├ ├── vue.esm-bundler.js
│ │ ├ ├── vue.global.js
│ │ ├ ├── vue.global.prod.js
│ │ ├ ├── vue.runtime.esm-browser.js
│ │ ├ ├── vue.runtime.esm-browser.prod.js
│ │ ├ ├── vue.runtime.esm-bundler.js
│ │ ├ ├── vue.runtime.global.js
│ │ ├ ├── vue.runtime.global.prod.js
接下来,我们来探讨这 12 个构建版本之间的不同之处。
构建版本说明
构建版本 | 开发版 | 生产版 | 运行时版 |
---|---|---|---|
esm-bundler | .esm-bundler.js | .esm-bundler.prod.js | .runtime.esm-bundler.js |
esm-browser | .esm-browser.js | .esm-browser.prod.js | .runtime.esm-browser.js |
global | .global.js | .global.prod.js | .runtime.global.js 和 .runtime.global.prod.js |
cjs | .cjs.js | .cjs.prod.js | 无 |
-
开发版: 包含完整的警告和调试模式,未压缩和混淆,用于开发环境。
-
生产版: 移除了警告和调试模式,经过压缩和混淆,用于生产环境。
-
运行时版: 更轻量,不包含模板编译器,不能编译模板。
1. esm-bundler
这种构建模式适用于现代打包器,如 Rollup,支持 tree-shaking
和代码分割。主要优势是可以按需引入 Vue 的特性,减小最终的打包体积。包含开发版、生产版和运行时版:
-
开发版:.esm-bundler.js
-
生产版:.esm-bundler.prod.js
-
运行时版:.runtime.esm-bundler.js
以下是一个使用示例:
import { createApp } from 'vue'
const app = createApp({
data() {
return {
message: '瓶子'
}
}
})
app.mount('#app')
2. esm-browser
适用于 Web 开发中使用原生 ES 模块进行编写和打包。由于现代浏览器都支持 ES modules,因此可以直接在浏览器中使用 Vue,无需打包步骤。但不能进行 tree-shaking
,可能会导致最终的代码体积较大。包含开发版、生产版和运行时版。
-
开发版:.esm-browser.js
-
生产版:.esm-browser.prod.js
-
运行时版:.runtime.esm-browser.js
以下是一个使用示例:
<!DOCTYPE html>
<html>
<body>
<div id="app">
{{ message }}
</div>
<!-- 引入 Vue 的 ESM Browser 构建 -->
<script type="module">
import { createApp } from 'https://unpkg.com/vue@next/dist/vue.esm-browser.js'
const app = createApp({
data() {
return {
message: '瓶子'
}
}
})
app.mount('#app')
</script>
</body>
</html>
3. global
为浏览器直接使用的构建版本,将所有核心功能以及常用插件打包在一起,并暴露为全局变量 Vue
,可以直接在 HTML 中使用。包含开发版、开发运行时版、生产版和生产运行时版。
-
开发版:.global.js
-
开发运行时版:.runtime.global.js
-
生产版:.global.prod.js
-
生产运行时版:.runtime.global.prod.js
该版本通过 <script>
标签直接引入:
<!DOCTYPE html>
<html>
<body>
<div id="app">
{{ message }}
</div>
<!-- 引入通过 global 构建的文件 -->
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
message: "瓶子"
}
}
})
app.mount("#app")
</script>
</body>
</html>
4. cjs
使用 CommonJS
规范构建,可以和 Node.js 一起使用。包含开发版和生产版。
-
开发版:.cjs.js
-
生产版:.cjs.prod.js
以下是一个使用示例:
// 引入 Vue
const { createApp } = require('vue')
const app = createApp({
data() {
return {
message: '瓶子'
}
},
mounted() {
console.log(this.message)
}
})
app.mount('#app')