四月份的时候,尤大在 vue 3.0 beta 直播中提到了vite工具,还在微博上表示再也回不去 webpack 了, 引来了 webpack 核心开发人员肖恩的搞笑回复, 上一张尤大微博截图
1、什么是 Vite
Vite 是一个由原生 ES-Module 驱动的 Web 开发构建工具,vue3配套的脚手架工具。在开发环境下基于浏览器es6的import开发,生产环境下使用Rollup 打包。
它主要具有以下特点:
- 快速的冷启动
- 即时的模块热更新
- 真正的按需编译
2、代码地址
3、怎么使用vite
npm init vite-app <project-name>
cd <project-name>
npm install
npm run dev
保持了跟vue-cli相同的结构,是不是还是熟悉的味道
├── index.html
├── package.json
├── public
│ └── favicon.ico
└── src
├── App.vue
├── assets
│ └── logo.png
├── components
│ └── HelloWorld.vue
├── index.css
└── main.js
main.js
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
createApp(App).mount('#app')
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
<script>标签中使用type="module",浏览器就会知道这是一个ES6模块, 目前主流的浏览器都已经支持。
在浏览器端使用import、export导入导出模块,浏览器识别模块内部的import,发起http网络请求,获取文件内容。
我们可以试着理解 vite 的几个特性了。
- webpack 之类的打包工具为了在浏览器里加载各模块,会借助胶水代码用来组装各模块,比如 webpack 使用 map 存放模块 id 和路径,使用 webpack_require 方法获取模块导出,vite 利用浏览器原生支持模块化导入这一特性,省略了对模块的组装,也就不需要生成 bundle,所以 冷启动是非常快的。
- 打包工具会将各模块提前打包进 bundle 里,但打包的过程是静态的——不管某个模块的代码是否执行到,这个模块都要打包到 bundle 里,这样的坏处就是随着项目越来越大打包后的 bundle 也越来越大。而 ESM 天生就是按需加载的,只有 import 的时候才会去按需加载。
既然浏览器能直接识别ES-Module,为什么还要用vite呢?我们直接用浏览器打开index.html看一下,会发现报错了
其实vite是起了一个koa的http server,拦截import请求,根据请求内容的不同返回响应的结果。
比如,main.js的返回结果会变成这样
可见,vite对import的内容做了一些修改,下面我们实现一个迷你的vite。
4、实现一个迷你vite
代码地址: tiny-vite 引入koa-route来匹配路由,利用中间件来代替冗长的if-else。
支持第三方库
- import文件的路径以
"/", "./", or "../"开头才会合法的,所以第三方库,比如vue会被修改为/@modules/vue.js的形式; - 然后遇到
/@modules/开头的请求,就去node_modules中找到package.json模块,加载module字段对应的文件。
支持.vue文件
- 利用
@vue-compiler-sfc解析vue单文件组件,变成import加type=template的形式 - 文件内容拼成_script对象, 添加render方法,并将_script导出
- 然后遇到
?type=template结尾的请求,利用@vue-compiler-dom将template解析成render函数,也就是第二步中的render
最后的结果
const __script = {
name: 'App',
setup() {
//...
}
}
import {render as __render} from "/src/App.vue?type=template"
__script.render = __render
export default __script
支持.css文件
结果
import { updateStyle } from "/vite/client"
const css = "#app {\n text-align: center;\n color: #2c3e50;\n margin-top: 60px;\n}\n"
updateStyle("\"2418ba23\"", css)
export default css
我们直接用一种简单的方式,添加style标签,innerHTML为css文件的内容来实现
其他
还可以支持ts、less、sass等等,感兴趣的话可以自己实现~