Hi!这里是JustHappy ,作为一个标准的"切图仔",如何轻松的拿捏Vue或者React的框架源码呢?一行一行的看?一处一处的打断点?太磨人了,我们换种方式,直击重点!今天我们从编译原理 ,也就是编译器的角度聊聊吧!

编译原理真的那么高大上吗?
仔细回想,其实从大学第一节C语言课开始我们就接触了"编译原理",众所周知,C语言是一门"高级语言",是计算机所不能直接读懂的语言,对于一个.c的文件我们需要对其进行如下操作:预处理 → 编译 → 汇编 → 链接 ...... 好的,你成功的睡着了...
所谓"编译原理"并不是什么新兴概念,几乎从软件工程诞生的最开始时候就有了
它只是:把一种东西 变成另一种东西
其实很常见例如:
| C代码 ----> 机器码 |
| TypeScript ----> JavaScript |
| Vue模板 ----> Render函数 |
本质都是同一个事情。
哈哈还不清楚没事,至少我们已经知道这不是啥"高不可攀"的东西,而且我们这次只讲 "编译",是不是轻松很多呢?

所以话不多说,我们开始吧!
简单的来说编译就只有几个步骤,为了缩短篇幅,我们直接就着Vue讲吧🚀🚀
从.vue到.js,需要几个步骤
众所周知,我们的浏览器是只能处理JavaScript、Css和Html的,而我们在编写Vue的时候是写在一个.vue文件中的,就像下面这样一个简单的组件:
html
<template>
<div>Hello {{ name }}</div>
</template>
<script setup>
const name = 'JustHappy'
</script>
问题来了。浏览器认识这个东西吗?显然不认识。
浏览器只认识:
- HTML
- CSS
- JavaScript
所以在浏览器运行之前。
一定有人把它翻译成浏览器认识的代码,这个翻译的人,就是:Vue Compiler
如何读懂.vue 文件呢? Webpack loader给你解决
我们都知道.vue文件是Vue 自己设计出来的文件格式。
比较官方的概念是Single File Component
顾名思义:"一个组件 一个文件"
把原本分散的:
HTML CSS JavaScript
全部塞进同一个文件里。对于开发者来说确实舒服了:
组件逻辑在这里 模板在这里 样式也在这里
维护起来非常方便。
但是浏览器读不懂啊?于是就需要 Webpack loader
其实Webpack loader就干一件事:让 webpack 可以识别任意后缀的文件
其大致原理就是将下面这个.vue 文件 拆解 为 "HTML 、CSS 、JavaScript"
(注意:是以 JS module 的形式拆解)
html
<template>
<div>Hello {{ name }}</div>
</template>
<style scoped>
.red { color: red; }
</style>
<script setup>
const name = 'JustHappy'
</script>
以上例子在经过 vue-loader 后大致会变成下面这样
js
import { render } from './App.vue?type=template'
import script from './App.vue?type=script'
import './App.vue?type=style'
script.render = render
export default script
具体 Loader 的原理可以参照 www.webpackjs.com/loaders/
如何编译?为什么要这么编译?
经过上面我们把 .vue 文件拆开来之后会发现,其实对于 JS、CSS 部分的处理都比较简单。
JS 本来就是 JavaScript。
CSS 本来就是 CSS。
最多做一些语法糖转换或者兼容性处理。
而对于 template 中的内容,我们就不能直接把它当成 HTML 了。
哈哈,HTML 可不能写:
html
<div v-if="isLogin">
用户中心
</div>
// 或者
<li v-for="item in list">
{{ item }}
</li>
这些都属于 Vue 自己扩展出来的语法。
这种为了某个特定领域而设计的语言,我们一般称为:
DSL(Domain Specific Language) 领域专用语言
而 Vue Template 就是一种专门用于描述界面的 DSL。
既然是一门语言,那么编译器就必须先「看懂」它。
但是计算机其实不擅长直接处理字符串。
例如对于:
html
<div class="app">
<span>{{ msg }}</span>
</div>
编译器首先会把它转换成一种更容易处理的数据结构。
这个过程叫:parse 解析。
那么完成这个过程的代码就可以叫做: parser 解析器。
解析后的结果大致会变成:
json
{
type: 'Root',
children: [
{
type: 'Element',
tag: 'div',
props: [
{
name: 'class',
value: 'app'
}
],
children: [
{
type: 'Element',
tag: 'span',
children: [
{
type: 'Interpolation',
content: 'msg'
}
]
}
]
}
]
}
这个结构在软件工程中称为:
AST(Abstract Syntax Tree) 抽象语法树
名字听起来很唬人,其实本质上就是:把字符串 变成对象
这样编译器后续就不需要对着一大坨字符串做分析了,而是可以像操作普通 JavaScript 对象一样去遍历、查找和修改节点。
接下来 Vue Compiler 会在 AST 的基础上继续处理,我们下篇再聊...
我们为什么要学习源码?
难道说是为了卷吗?我想不是的,在学习Vue源码之前,我也是认为这是"卷",而且学的迷迷糊糊的。不过大体上过了一遍,也就是脑袋里有个印象,Vue源码大概由几部分组成?每个部分的作用是什么?用的什么样的方式去实现的?虽然不能说是精通,但是也是极大的提升了我对编码的看法(😂但是还是会写出屎),总之我的体感上是学习源码能让我更好的管理我编写的代码