0
点赞
收藏
分享

微信扫一扫

B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?

古得曼_63b6 2022-03-22 阅读 32


B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_加载

最近在B乎看到了这么一个问题,能不能通俗地讲 Vite 到底是用来干嘛的,一开始觉得这个问题没什么意思,因为 Vite 这个话题有太多的人讲了。

但是我看了看其他的回答,大部分都会从 Vite 的特性,ES Modules 去讲整件事情,然后还是会时不时要和 webpack 去做比较。

而且我又仔细看了看题主的疑问。

B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_javascript_02

我也陷入了深深的思考,到底是大家学习一些新知识的时候急迫了呢?还是说前端常常容易把一些简单的东西复杂化,容易形成套娃式的知识?又或者是知识太零散了,分不清到底是哪些是有关系的?

探索Vite

我打开了 Vite 的官网,他的标语是 「 下一代前端开发与构建工具」,因为一般标语需要言简意赅地表达出它的意思,所以会用最精简的去概括(也是为了宣传)。我认为确实也没有啥毛病,但是对于一些新手而且,确实这句话不知所云,官网也没有足够清楚的图,如果是一些不了解的人,确实也容易迷失。

那么这句话到底要表达出什么意思呢?我用通俗的话表述了一遍(可能不一定准确,仅代表个人的理解):

目前大部分浏览器已经支持了ESM(ES Modules)模块的方式了,因此我写了一个转化工具,可以让一些浏览器不支持的格式(.vue/.svelte/.ts)以及不支持的语法(最新的es语法/特性)让浏览器支持,它将会成为趋势。

很多人会从 ​ES Modules​ 、​Dev Server​ 、​Vue 集成度高​、​速度快啊​各种方向来讲解它,更像是在说它的优点,我觉得有点​神话它​了,所以才让它变得那么神秘(迷惑)?

而在我看来 ​Vite​ 就是一个转化器,而 Webpack 就是 模块器 + 转化器。

转化器的用途就是,​将一些浏览器无法解析的文件,转化成可以被浏览器解析的 js 文件​,Vite 做的核心就是这个。什么用 ​Vite​ 快啊,都是浏览器自己的功劳,浏览器统一了模块化方案,Vite 只是吃了一波浏览器的性能红利而已。

用一张图来描述就是(这里我盗用了 Webpack 的官方图,改了改)

B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_加载_03

Vite​ 就是把所有的资源都转化成了 js 的形式去引入,因为浏览器只支持 js 文件的 ​ES Modles​ 方式,毕竟 ​ES Modules​ 属于 ​ECMAscript​ 规范,当然只能是适用于 js 了。而整个模块化过程都是浏览器的功劳。

这里再来看看 Webpack 的整体流程图,如果你对 Webpack 了解,可能能加深印象,但是不了解 webpack 也没关系。

B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_模块化_04

由于 Webpack 要自己的模块化方式,因此需要将所有的资源都打包成一个 js,这个图很形象地解释了 Webpack 的作用。(对于不了解 Webpack 的也没有关系,知道 Vite 的图就够了。)

我举一个例子,可能能让你更加清楚地去理解 Vite 的真面目。

// index.html
<script type="module" src="main.js"></script>
// main.js
import { element, text } from './el.js';

const container = element('div');

const h1 = element('h1');

const t = text('Hello ES Modules');

h1.appendChild(t);

container.appendChild(h1);

document.body.appendChild(container);
// el.js
export function element(name) {
return document.createElement(name);
}

export function text(data) {
return document.createTextNode(data);
}

在 ​​VS Code​​​ 装一个 ​​Live Server​​ , 然后启动这个 html, 然后我们随便改点东西,可以看到,更新速度的非常快。

B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_javascript_05

也许你会说,我文件数量太少了,没事,我们这次来整活20个文件。

const fs = require('fs');

const LENGTH = 20;

new Array(LENGTH).fill(0).forEach((item, index) => {
fs.writeFileSync(`child-${index}.js`, `
export { child } from './child-${index+1}.js';
`)
})

fs.writeFileSync(`child-${LENGTH}.js`, `
import { element, text } from '../el.js';

export function child() {
const c = element('div');
const t = text('child');
c.appendChild(t);
document.body.appendChild(c);
}
`)

B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_加载_06

所以我说,​Vite 本质是拨除了 webpack 模块化功能后的一个转化器。

但是尽管浏览器解决了模块化的依赖,依旧是有两个问题:

  1. 但是没办法支持一些样式/文件(css/ttf/jpg...)资源的 import 语法
  2. 无法支持.ts/.vue/.svelte 等模板语法(或者高级特性)的直接引用

所以,才会有我们看到  Vite 仿佛又做了很多事情,因为 Vite 能够去加载 .ts/.vue/.svelte 等文件,  它整合了很多插件去做这些转化工作,将所有的资源都转化成浏览器可识别的 js 的方式去导入,将 css 文件经过包装,转化为一个 js 文件等等。

剩余的就是原文件中的内容替换,因为类似于像第三方包中的资源没办法直接引入,需要做一层替换,例如一下代码就被转化成了这样。

B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_模块化_07

B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_加载_08

在编译的时候需要去替换我们实际写代码的地址,去让浏览器加载,然后为了不让浏览器加载文件太多,还要将第三方包导成一个模块,然后还有热更新功能(这部分功能稍微复杂一些)。并且为了能够在生产环境打包(Tree shaking / 压缩啊,等等之前常规的优化),使用了 Rollup ,不仅提供了 ESM 的打包方式,以及你需要的其他模块化方式(umd/amd/cmd/iife)。

因此核心是简单的,但是相关的生态想要好用,却是要花大量的精力,Vite 团队也是花了大力气去解决了周边的生态问题,各种插件的适配啊等等。

首创的ESM

而首次提出利用浏览器原生ESM能力的工具并非是Vite,而是一个叫做Snowpack的工具(可以看我这篇文章 ​​《模块化系列》snowpack,提高10倍打包速度。​​​)。前身是​​@pika/web​​,从1.x版本开始更名为Snowpack。

Snowpack在其官网是这样进行自我介绍的:“Snowpack是一种闪电般快速的前端构建工具,专为现代Web设计。它是开发工作流程较重,较复杂的打包工具(如Webpack或Parcel)的替代方案。Snowpack利用JavaScript的模块化方式(称为ESM)来避免不必要的工作并保持流畅的开发体验”。


B乎问题:通俗的解释下Vite能用来干嘛?是怎么回事?_加载_09


为此,Pika团队开发并维护了两个技术体系:构建相关的Snowpack和造福大众的Skypack。其中 skypack 上还有很多特殊处理过的 ES Modules 形式的包(例如 React 等)直接用来调用,由于那些包原先是不支持 ES Modules 形式,他们单独维护了 ES Modules 版本。

看完了 ES Modules 的现状以及 Vite 的本质,我们就再来把模块化来回顾一下,这样整个时间线就完整了以及我们的开发方式变化到现在,Web 真的做出了巨大的努力。

模块化简史

把时间回退到2006年,这个时候 ​「jQuery」​ 刚呱呱落地,那个时候虽然没有模块化,使用 jQuery 相比传统那样写已经提高极大的速度,当然虽然已经很方便了,单还是阻挡不了爱研究的程序员们。

在2009年的时候 ​「CommonJS」​ 诞生了,但是 ​「CommonJS」​ 由于有两个重要问题没能得到解决,所以迟迟不能推广到浏览器上。(1.由于外层没有 ​function​ 包裹,被导出的变量会暴露在全局中。2.在服务端 ​require​ 一个模块,只会有磁盘 I/O,所以同步加载机制没什么问题;但如果是浏览器加载,一是会产生开销更大的网络 I/O,二是天然异步,就会产生时序上的错误。)中间百家争鸣(​「AMD、CMD、UMD」​)一直到2016年5月,经过了两年的讨论,ECMAScript 6.0 终于正式通过决议,成为了国际标准。在这一标准中,首次引入了 ​import​ 和 ​export​ 两个 JavaScript 关键字,并提供了被称为 ​「ES Module」​ 的模块化方案。在 JavaScript 出生的第 21 个年头里,JavaScript 终于迎来了属于自己的模块化方案。而在这期间想要使用模块化,只能通过打包工具来解决。

有了标准之后,也不是能立马让所有设备都支持 ​「ES Module」​ 因为浏览器的推进是一个漫长的过程,不像服务端,如果做一个升级,只需要对服务端升级,而浏览器的升级伴随着电脑/手机等一系列的因素,因素非常不可控,因为用户总是可以有多种多样的选择,​「ES Modules(ESM)」​ 是 JavaScript 官方的标准化模块系统,而它这一走,却在标准化的道路上已经花费了近 10 年的时间。在2018 年 5 月 Firefox 60 发布之后,所有的主流浏览器就都支持 ​「ESM」​ 了。直到现在,​「ES Module」​ 还并不能真正地用在生产环境使用,还是需要转化成以旧的方式(非ESM方式)。

写在最后

当回答完这个问题的时候,不禁会想,前端的发展过程中却是会有一些新瓶装旧酒的东西,然后神话它,然后让小白觉得它很高大上,让人惧怕,然后大佬就会觉得这个东西很简单,也不愿意去拆解它,是否我们需要转化一些思考,当我们讲一个东西的时候,剥离那些高大上的词汇,做一些更加亲民的解释?当然我不否则这些新的工具带来的便利以及背后的付出,但是亲民是否也是一种方式,或许会变得更加美好?答案我也不得而知,本文只是作出了自己的一个思考,如有错误请大家批评指出。

参考

https://segmentfault.com/a/1190000039370642


关注公众号秋风的笔记​​,一个专注于前端面试、工程化、开源的前端公众号

  • 关注后回复​​简历​​获取100+套的精美简历模板
  • 欢迎关注​​秋风的笔记​


 

举报

相关推荐

0 条评论