vue2官网 其中"安装"介绍了关于Vue的各种版本。
- 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。
javascript
<div id="app">
<div>{{ a }}</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> <script>
const vm = new Vue({ el: '#app', data: { a: 'hello world', }, })
</script>
以上是一段简单的Vue2代码, 打开浏览器可以正确显示出 "hello world",- 可以发现 <div>{{ a }}</div>
不是浏览器支持的语法. 所以实际上能显示 hello world, 并不是由以上模板代码直接在浏览器执行的结果, 而是通过"编译器"编译, 再由浏览器执行
- 接下来用代码为大家演示Vue2是如何将上面代码编译的
- 首先必须引入"完整版",
- 打开页面, 在控制台可以发现方法: Vue.compile
- 将刚才的 template 代码放到编译方法里执行, 结果如下
- 可以看到 template 被编译成 JavaScript,_c,_v,_s,是vue实例vm上一些方法的简称
- 编译结果可以翻译成
javascript
<script>
const vm = new Vue({
el: '#app',
name: 'App',
data: () => ({
a: 'hello world!!!',
}),
render() {
const {_c, _v, _s, a} = this
//return createElement('div', [createTextNode(toString(a))])
return _c('div',[_v(_s(a))])
}
})
</script>
这样 模板template就被编译为了 render函数
- 以上便是在 .html 文件中使用template 开发, 由 Vue2完整版 进行编译的过程
.vue文件是如何进行编译的?
通常项目中是使用Webpack打包, 再由浏览器引入这些js, css等文件, 那么Webpack是如何对.vue文件进行编译的?
1. ,vue文件
.vue文件,.vue
文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每个 .vue
文件包含三种类型的顶级语言块 <template>
、<script>
和 <style>
,还允许添加可选的自定义块.
2. vue-loader
vue-loader
会解析文件,提取每个语言块,如有必要会通过其它 loader 处理,最后将他们组装成一个 ES Module,它的默认导出是一个 Vue.js 组件选项的对象。
接下来通过vue-loader的源码来了解是如何实现编译的
vue文件分为 template, script, style 三个部分, 而实际必须通过编译才能在浏览器执行的部分只有template, 所以我们在看 vue-loader 源码时可以重点关注 "template" 关键词
descriptor.template 如上图所示, 在源码搜索 template 关键字可以找到这段处理 script, template, style 的代码, 仔细观察发现这三段都在用 descriptor 对象, 接下来搜索 descriptor, 找到这个变量在哪里生成的 descriptor
再来找 parse 方法
compiler.ts compiler.ts
parse 方法从 vue/compiler-sfc 中引用
至此, 了解到 vue-loader 是通过 @vue/compiler-sfc 的 parse 方法解析 .vue 文件, 从中解析出script, template, style
用一段nodejs代码进行验证
javascript
// App.vue
<template>
<div id="app">
<div>{{ a }}</div>
<input type="text" v-model="a">
</div>
</template>
<script>
export default {
name: 'App',
data: () => ({
a: 'hello world'
}),
}
</script>
javascript
// build.js
const { parse } = require('@vue/compiler-sfc')
const fs = require('fs')
const data = fs.readFileSync('./App.vue')
const { descriptor } = parse(data.toString())
// 结果包含很多项, 本文档中只展示重点字段
console.log(Object.keys(descriptor))
运行 build.js
javascript
[
'styles',
'template',
'script',
// ...
]
通过以上代码可以解析出 .vue 文件的三部分, 接下来开始解析 template vue-template-compiler vue-template-compiler 可以将 template 编译成 Javascript
- 继续修改 build.js, 根据文档加上 compile 的部分
javascript
// build.js
const { parse } = require('@vue/compiler-sfc')
const fs = require('fs')
const compiler = require('vue-template-compiler')
const data = fs.readFileSync('./App.vue')
const { descriptor } = parse(data.toString())
// console.log(Object.keys(descriptor))
console.log(compiler.compile(descriptor.template.content).render)
- 运行结果如下
javascript
with(this){
return _c(
'div',
{attrs:{"id":"app"}},
[
_c('div',[_v(_s(a))]),
_v(" "),
_c(
'input',
{
directives:[{name:"model",rawName:"v-model",value:(a),expression:"a"}],
attrs:{"type":"text"},
domProps:{"value":(a)},
on:{
"input": function($event){
if($event.target.composing) return;
a=$event.target.value
}
}
}
)
]
)
}
再将以上代码放到 .html 的 new Vue(...) 方法中进行验证
javascript
<div id="app"/>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
const vm = new Vue({
name: 'App',
data: () => ({
a: 'hello world!!!',
}),
render() {
const {_c, _v, _s, a} = this
return _c(
'div',
{attrs: {'id': 'app'}},
[
_c('div', [_v(_s(a))]),
_v(' '),
_c(
'input',
{
directives: [{name: 'model', rawName: 'v-model', value: (a), expression: 'a'}],
attrs: {'type': 'text'},
domProps: {'value': (a)},
on: {
// 注意这里的 this, 需要改成箭头函数
'input': ($event) => {
if ($event.target.composing) return
this.a = $event.target.value
},
},
},
),
],
)
},
}).$mount('#app')
</script>
以上便是 Webpack 如何将 .vue 文件编译成浏览器可执行文件的过程