Hi!这里是JustHappy,作为一个标准的“切图仔”,如何轻松的拿捏Vue或者React的框架源码呢?一行一行的看?一处一处的打断点?太磨人了,我们换种方式,直击重点!今天我们从编译原理,也就是编译器的角度聊聊吧!
编译原理真的那么高大上吗?
仔细回想,其实从大学第一节C语言课开始我们就接触了“编译原理”,众所周知,C语言是一门“高级语言”,是计算机所不能直接读懂的语言,对于一个.c的文件我们需要对其进行如下操作:预处理 → 编译 → 汇编 → 链接 ...... 好的,你成功的睡着了...
所谓“编译原理”并不是什么新兴概念,几乎从软件工程诞生的最开始时候就有了
它只是:把一种东西 变成另一种东西
其实很常见例如:
本质都是同一个事情。
哈哈还不清楚没事,至少我们已经知道这不是啥“高不可攀”的东西,而且我们这次只讲 “编译”,是不是轻松很多呢?
所以话不多说,我们开始吧!
简单的来说编译就只有几个步骤,为了缩短篇幅,我们直接就着Vue讲吧🚀🚀
从.vue到.js,需要几个步骤
众所周知,我们的浏览器是只能处理JavaScript、Css和Html的,而我们在编写Vue的时候是写在一个.vue文件中的,就像下面这样一个简单的组件:
<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
顾名思义:“一个组件 一个文件”
把原本分散的:
HTMLCSSJavaScript
全部塞进同一个文件里。对于开发者来说确实舒服了:
组件逻辑在这里模板在这里样式也在这里
维护起来非常方便。
但是浏览器读不懂啊?于是就需要 Webpack loader
其实Webpack loader就干一件事:让 webpack 可以识别任意后缀的文件
其大致原理就是将下面这个.vue 文件 拆解 为 “HTML 、CSS 、JavaScript“
(注意:是以 JS module 的形式拆解)
<template> <div>Hello {{ name }}</div></template><style scoped> .red { color: red; } </style><script setup> const name = 'JustHappy'</script>以上例子在经过 vue-loader 后大致会变成下面这样
import { render } from './App.vue?type=template'import script from './App.vue?type=script'import './App.vue?type=style'script.render = renderexport default script具体 Loader 的原理可以参照https://www.webpackjs.com/loaders/
如何编译?为什么要这么编译?
经过上面我们把 .vue 文件拆开来之后会发现,其实对于 JS、CSS 部分的处理都比较简单。
JS 本来就是 JavaScript。
CSS 本来就是 CSS。
最多做一些语法糖转换或者兼容性处理。
而对于 template 中的内容,我们就不能直接把它当成 HTML 了。
哈哈,HTML 可不能写:
<div v-if="isLogin"> 用户中心</div>// 或者<li v-for="item in list"> {{ item }}</li>这些都属于 Vue 自己扩展出来的语法。
这种为了某个特定领域而设计的语言,我们一般称为:
DSL(Domain Specific Language)领域专用语言
而 Vue Template 就是一种专门用于描述界面的 DSL。
既然是一门语言,那么编译器就必须先「看懂」它。
但是计算机其实不擅长直接处理字符串。
例如对于:
<div class="app"> <span>{{ msg }}</span></div>编译器首先会把它转换成一种更容易处理的数据结构。
这个过程叫:parse 解析。
那么完成这个过程的代码就可以叫做: parser 解析器。
解析后的结果大致会变成:
{ 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源码大概由几部分组成?每个部分的作用是什么?用的什么样的方式去实现的?虽然不能说是精通,但是也是极大的提升了我对编码的看法(😂但是还是会写出屎),总之我的体感上是学习源码能让我更好的管理我编写的代码
夜雨聆风