Vite (法语意为 “快速的”,发音 /vit/
) 是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:
Vite 意在提供开箱即用的配置,同时它的 插件 API 和 JavaScript API 带来了高度的可扩展性,并有完整的类型支持。
npm init @vitejs/app my-react-demo --template react-ts
构建项目只用了2秒,启动项目只用了466毫秒,是不是特别快,那么它是怎么做到这么快的呢?
语法类似于node,因为node使用commonjs规范,commonjs导入模块是同步导入,不能用于浏览器环境
// 文件名: foo.js
// 依赖
var $ = require('jquery');
// 方法
function myFunc(){};
// 暴露公共方法(一个)
module.exports = myFunc;
由许多不喜欢commonjs的人员创造,最大特点是支持异步,但是语法不直观,不好书写
// 文件名: foo.js
define(['jquery'], function ($) {
// 方法
function myFunc(){};
// 暴露公共方法
return myFunc;
});
其是amd和commonjs的统一规范,支持两种规范,即写一套代码,可用于多种场景。通常用作Rollup/ Webpack之类的bundler时通常用作备用模块
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之类的
module.exports = factory(require('jquery'));
} else {
// 浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// 方法
function myFunc(){};
// 暴露公共方法
return myFunc;
}));
ESM 是ES6提出的标准模块系统,就是我们经常使用的方式,浏览器支持,支持同步异步加载
import React from 'react';
各种模块详细特点可以查看下面链接
commonjs
es6
amd
vite 在构建过程中使用esbuild进行构建,esbuild 是一个新的代码构建工具,近来构建速度及其迅猛,圈粉速度也很疯狂,它可以将 CommonJS / UMD 转换为 ESM 格式,转换ts, tsx文件等,它使用go编写,并编译成了机器码,利用paralleljs 的高并行优势,具有大量的并行算法。
esbuild这么厉害?为什么vite不适用esbuild 打包而使用rollup 呢?
esbuild的作为一个势头很强劲的开发工具,但是在代码分割和css处理方面还存在问题,相比来说rollup 更加成熟和灵活,但可能在不久的以后,当esbuild 稳定之后,esbuild很有可能会成为vite生产环境的构建工具。
但是esbuild 的最低只兼容到es6,这也意味着一些 to C的项目会存在兼容行问题,那么vite怎么来解决的呢?
vite 通过它的插件系统来解决兼容性问题。(vite插件)
@vitejs/plugin-legacy 在 esbuild 构建之后再经过一层 @babel/preset-env,用来兼容不支持 ESM 或 ie11 的旧版浏览器。
vite 的预编译是通过原生ES模块实现的,对于模块中使用的是commonjs或者AMD 的模块,则需要进行模块间的转换,同时减少模块间依赖降低请求次数
比如我们在使用lodash-es时,
import { debounce } from "lodash-es"
lodash-es会有上百个请求, 我们需要使用预编译去处理这种情况
这里节省的时间,我们指的就是预编译
在调用预编译后,vite会将运行的函数放到,构建的前置步骤上
const listen = httpServer.listen.bind(httpServer)
httpServer.listen = (async (port: number, ...args: any[]) => {
try {
await container.buildStart({})
// 这里会进行依赖的预构建
await runOptimize()
} catch (e) {
httpServer.emit('error', e)
return
}
return listen(port, ...args)
}) as any
const runOptimize = async () => {
if (config.optimizeCacheDir) {
..
try {
server._optimizeDepsMetadata = await optimizeDeps(config)
}
..
server._registerMissingImport = createMissingImpoterRegisterFn(server)
}
}
通过runOptimize中的optimizeDeps方法会根据package.json 的 dependencies
的参数进行编译,然后将编译出来的依赖通过esbuild打包成单文件,当浏览器器请求时就可以保证只请求一次接口了。
使用esbuild 将 .tsx .jsx .vue 等文件转化成浏览器可以识别的js文件
具体原理过程如下:
文件main.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(
,
document.getElementById('root')
)
按理说index.html 中是不能引入react 代码的,也不会去认识.tsx文件的,这是怎么做到的呢?
当浏览器识别type="module"
引入js文件的时候,内部的import 就会发起一个网络请求,尝试去获取这个文件
vite 的作用就是体现在了这里,vite的任务就是用koa起一个http请求,然后利用拦截器去拦截修改这些请求内容,然后返回适合的内容
浏览器识别js代码实现大致原理:
const fs = require('fs')
const path = require('path')
const Koa = require('koa')
const app = new Koa()
app.use(async ctx=>{
const {request:{url} } = ctx
if(url=='/'){n
ctx.type="text/html"
ctx.body = fs.readFileSync('./index.html','utf-8')
}else if(url.endsWith('.tsx')){
const p = path.resolve(__dirname,url.slice(1))
ctx.type = 'application/javascript'
const content = fs.readFileSync(p,'utf-8')
ctx.body = content
}
})
app.listen(3001, ()=>{
console.log('项目启动于3001端口')
})
对于热重载,我们先看下热重载的效果
热重载原理(以下均为模拟代码)
1、监听文件变动
使用node的 fs.watch监听文件变动
(fs.FSWatcher) fs.watch(filename[, options][, listener])
2、读取文件内容
使用node的fs.readFileSync 读取文件内容
${fs.readFileSync(runtimeFilePath, 'utf-8')}
3、通知浏览器更新
使用websocket 通知浏览器更新
见操作
见操作
webpack 打包图解
vite 打包图解
从上图可以看出:
webpack会先进行打包操作然后将,打包后的数据存储到内存中,然后启动服务器,与浏览器进行交互
而vite是直接启动开发服务器,请求哪个模块再对该模块进行实时编译,没有本地打包的过程
由于现代浏览器本身就支持ES Module,会自动向依赖的Module发出请求。vite充分利用这一点,将开发环境下的模块文件,就作为浏览器要执行的文件,而不是像webpack那样进行打包合并。
由于vite在启动的时候不需要打包,也就意味着不需要分析模块的依赖、不需要编译,因此启动速度非常快。当浏览器请求某个模块时,再根据需要对模块内容进行编译。这种按需动态编译的方式,极大的缩减了编译时间,项目越复杂、模块越多,vite的优势越明显。
在HMR(热更新)方面,当改动了一个模块后,仅需让浏览器重新请求该模块即可,不像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。
当需要打包到生产环境时,vite使用传统的rollup(也可以自己手动安装webpack来)进行打包,因此,vite的主要优势在开发阶段。
现在的vite就像当初的M1,刚出现时大家都担心兼容性不好,但是一旦上手就发现真香,虽然目前还存在一些问题,但是vite使用平台原生的开发方式确实让人眼前一亮,并且非常容易上手,用户体验度也很高,并且原生的平台提供的标准特性,大部分也会发展为主流特性,所以vite极有可能代表了未来前端工程化的方向,同时在vue3 大生态的趋势下,vite已经成为前端开发者必须了解的一个框架。
那么vite到底会不会取代webpack 呢?我认为不会,对于vite的崛起,webpack不会坐视不管,如果未来webpack也将构建性能进行了优化,那么webpack将利于不败之地,就算webpack不进行优化,它现在稳定的生态环境和庞大用户量注定了webpack在未来很长的一段时间内构建工具老大的地位不会被动摇,而且在许多场景下性能并不是最重要的问题,所以我认为未来最有可能的一种情况是,webpack ,vite,rollup 三者形成三足鼎立的局面,三者相互借鉴共同发展。