本文原创:lideguang
某乎有一个问题“2021前端会有什么新的变化?”,其中 Vue 的作者尤雨溪给出的答案:“会有很多人抛弃 Webpack 开始用 Vite”。下面来看一下为什要抛弃 Webpack、使用 Vite。
Vite
Vite 是一种新型的前端构建工具,最初是配合 Vue 3.0 使用,后面适配了常见的前端项目,提供了 Vue、react、preact 等模板。官网首页列举了 Vite 的特性:快速的启动、热重载、支持常见资源类型、支持多页/ 类库 开发、通用、类型化API。
在进入 Vite 实操前,我们来看下 被 Vite 革命 的 Webpack。
Webpack 对比 Vite
Webpack 一直以来和前端工程化紧密联系在一起,优化前端开发体验。这张图是描述 Webpack 功能最直观的一张图,从入口进入,寻找各种依赖资源,经由 Webpack 打包,生成静态资源提供网页展示。
但是使用 Webpack 有一个绕不过去的问题,就是伴随着项目体积增大、代码增长而来的性能问题:项目启动的速度、加载的性能、打包的速度、热重载的及时性等。
以 Webpack 为代表的模块打包工具,开发时启动本地服务器会从项目入口依次抓取依赖关系,对整个项目文件进行打包,这就造成了启动服务慢; 开发过程中也 HMR 热更新也存在同样问题,Webpack 的热更新服务会以当前修改文件为入口,重新 build,所有依赖也会被重新加载一次,导致热更新也就快不起来。
Vite 让浏览器接管了打包程序的部分工作,仅启动一台静态资源服务器。资源在这里被分为了两类:
- 依赖
- 依赖为外部组件库,多为纯js,开发中不需要变动;
- 这部分使用 esbuild 进行预编译,将组件库的代码从原本的 commonjs 或者 umd 转换为 esm;
- 源码
- 项目代码等;
- 加载时处理;
Vite 服务 只需要在浏览器请求源码时,进行转换并按需提供源码,只有当前页面依赖使用的资源才会处理,实现了真按需加载;同样在热更新时,也仅编译变更部分的文件,同时结合浏览器的缓存机制,使用 协商缓存,进一步提升重载的速度;
通过这种设计思路,Vite 解决了 打包工具 启动慢、更新慢的问题;
Vite Demo
下面我们通过一个例子来感受下 Vite 的速度,按照下方的命令提示,我们可以使用 Vite 搭建一个 vue 3.0 的项目
提示:这里 node 版本要求 >= 12.0.0
启动项目后,控制台可以看到两个 warn :
这里解释一下:script setup
是 vue 在 RFC 里提交的一份 REF 语法糖的提案,主要作用是:
- 自动暴露顶级变量,减少代码冗余度
- 通过 ref: 语法让 ref 更高效
这个提案也在社区引起来不小的争议,看下代码中,哪里用到了 setup,这两个组件中使用了,将这里的变量暴露出来,使得 template 可以直接使用,如果大家存在洁癖的话,可以找到代码中的 script setup
进行改写,避免warn 提示。
这样我们就创建了一个 vue 3 的项目,通过这部分模板生成的代码,我们也可以看到一些 vue 3 不同于 vue2 的部分特性:
├── index.html
├── package.json
├── public
│ └── favicon.ico
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ └── main.js
└── Vite.config.js
先从入口文件看:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
vue 3 不再使用 new vue
。在之前版本中,使用 new vue 全局会共享一个全局配置,比如做测试、或者三方监控引入时,很容易相互污染覆盖,且无法直接还原。vue 3 增加了 createAPP 这个 api,调用 createApp 会返回一个应用实例,全局范围影响 Vue 行为的 api 都会迁移到应用实例中,避免污染覆盖。当然,如果需要多实例共享的 全局配置,可以通过 工厂函数包装的形式来实现:
import { createApp } from 'vue'
import Foo from './Foo.vue'
import Bar from './Bar.vue'
const createMyApp = options => {
const app = createApp(options)
app.directive('focus' /* ... */)
return app
}
createMyApp(Foo).mount('#foo')
createMyApp(Bar).mount('#bar')
再看HelloWorld.vue
:
// src/components/HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
<p>
<a href="https://Vitejs.dev/guide/features.html" target="_blank">Vite Documentation</a> |
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
</p>
<button @click="state.count++">count is: {{ state.count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test hot module replacement.
</p>
</template>
组件模板中允许组件有多个根元素,同时 attrs,会应用到组件跟元素,现在可以允许加到任意元素位置,逻辑更加清晰。
支持 JSON、SASS、TS、组件库
Vite 支持 json,并在内部配置了CSS预处理器。对于 JSON 文件可直接引入,css 预处理器只需要安装对应的loader文件,即可。
// JSON 支持
// import the entire object
import json from './example.json'
// import a root field as named exports - helps with treeshaking!
import { field } from './example.json'
# sass 支持
# Vite 内置了对 css 预处理器的支持
npm install sass --save-dev
Vite 默认支持了 ts,而且 vue 3 不同于 vue 2 中依靠 flow 进行类型管理,使用了 ts 进行开发,对 ts 的支持更优雅;
其次看下如何支持 UI 库的使用,vue 在取消 new Vue
后,有了应用实例,UI库的挂载也是要挂载到应用实例上。由于 use 全局 API 在 Vue 3 中不再使用,此方法将停止工作并停止调用 Vue.use() 现在将触发警告。于是,开发者必须在应用程序实例上显式指定使用此插件:
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
最后
Vite 作为工具服务里的一名新同学,浏览器是否支持原生的 ESM 动态导入、崩溃、周边待完善等问题也确实存在。不过在体验下来,Vite 给人呢的感觉是速度真的很快,规避很多复杂配置,真正实现了开箱即用,同时能够和 Roolup 共享插件接口,后续的生态会变得很丰富,快收下尤大的这份礼物吧。
参考:
Vue3 官网文档:https://v3.cn.vuejs.org/guide/migration/introduction.html
Vite 2 官网:https://cn.Vitejs.dev/
Vite 2 release note :https://zhuanlan.zhihu.com/p/351147547
技术胖(Vite 1.x) :https://jspang.com/detailed?id=66#toc29
杨村长(备战2021:Vite2项目最佳实践): https://juejin.cn/post/6924912613750996999#heading-14
Vite2插件开发指南:https://zhuanlan.zhihu.com/p/351529474