Vite初探

150 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Vite

什么是Vite(vitejs.cn/guide/why.h…

自从进入前端框架时代,构建是现代前端绕不开的话题,所以今天和大家聊一聊新一代的构建工具vite。随着vue3一起发布的vite,最初是和vue3有一定绑定关系的,但是不久之后更新的2.x版本已经完全和vue3没有必然联系了。

vite相当于是构建工具的高阶封装,核心是封装的rollup。rollup是一个常用于第三方开源社区的构建工具

vite有哪些特点

  1. 具有开发时效率极高的特点
  2. 开箱即用,功能完备,集成了dev-server、css依赖、图片加载之类的功能
  3. 兼容rollup,支持绝大部分的rollup插件,社区丰富(rollupjs.org/guide/en/
  4. 超高速的热重载,在编辑代码之后,可以很快的看到结果
  5. 预设应用和类库打包模式
  6. 前端类库无关
  7. 依赖esbuild(esbuild.github.io/),项目极速启动,实时热更新

与传统构建工具webpack/rollup的区别

webpack/rollup更专注于构建一些细节的功能,比如文件的加载编译、模块之间的依赖关系等。

vite本身不具备编译能力,vite的编译能力来自于esbuild和rollup。

vite开发时完全基于ESM加载的方式,自动集成了dev-server,不需要额外的配置各类loader,在vite中内置了;内置了build命令,可以build类库,也可以build项目

vite是为了项目开发;webpack、rollup是为了模块的构建

传统的构建工具,从入口entry开始,就要把所有的文件打包成一个boundle,这个过程就会比较慢

vite在启动的时候,几乎没有对文件进行编译,只对一些必要的文件进行预编译,从入口文件index.html开始,按需编译用到的文件;另外一个快的原因就是使用ESbuild进行了编译。这就是vite在开发环境很快的原因

vite的使用

初始化各种前端框架项目

vite创建vue3项目

npm init @vitejs/app (yarn create @vitejs/app nvm use 12) 默认vue是3.x版本 创建的项目目录比较简单,其中public存放不需要编译的静态文件,src/assets也是存放一些图片等静态文件,可以通过import引入,这样会编译成一个路径;编译的入口文件是index.html,引入main.js;webpack/rollup是以一个js文件作为编译入口;因为vite一开始并不编译项目,而是让浏览器去渲染html,然后按需编译的;vite.config.js配置一些vite配置 因为在使用npm安装vite的依赖esbuild的时候,有可能会出现问题,可以使用yarn(npm install -g yarn)去安装vite的依赖

vite创建vue2项目

vite并没有提供生成vue2项目的官方插件 使用第三方插件underfin/vite-plugin-vue2 npm init @vitejs/app 选择vanilla,即不添加任何第三方框架支持 创建成功后,目录相对简单,手动添加vite.config.js, 手动添加vue2的vite插件到开发环境依赖 npm install vite-plugin-vue2 -D / yarn add vite-plugin-vue2 -D 然后再添加vue依赖 npm install vue -S / yarn add vue -S 创建app.vue文件

vite创建React项目

FastRefresh替代react-hot-loader实现组件局部更新 hot module replacement npm init @vitejs/app 选择react 创建成功的项目,入口文件index.html引入的是一个jsx,并不是标准的js文件,这个路径可以生效的原因是,vite启动本地server的时候,通过浏览器加载这个路径的时候,vite本地服务会经过一系列编译返回一个标准的js内容,浏览器解析的就是这个js内容

环境变量

import.meta.env

vite中默认有五个环境变量,mode/base_url/prod/dev/ssr

创建.env文件,可以自定义env,定义方式是VITE_开头

vite与热更新

webpack中的热更新

热更新、HMR(Hot Module Reload)、热重载,这类词是一个意思,可以让前端再开发过程中,不需要重新刷新页面,可以把新修改的js模块再浏览器端更新并运行,同时尽可能的保持之前的状态,可以大大的提升前端开发的效率,降低时间的浪费。

常见的HMR是webpack-dev-server,只需要把webpack --config的启动命令改成webpack-dev-server --config就可以让前端开发不需要重新刷新页面,就可以更新最新的js模块的能力。

HMR的机制其实就是重新加载一个js模块文件,比如有一个main.js脚本,只需要获取这个文件被修改的事件,然后重新加载修改之后的版本就可以了。在客户端和服务端之间创建websocket长链接,在服务端对文件的变化进行监听,事件触发后,发送到客户端,客户端接收到文件被修改事件时则动态的在DOM上挂载一个新的script标签

webpack是一个基于commonJS模块管理的构建工具,在一个具有模块管理功能的JS环境中,才有可能更新部分模块,实现HMR。

// a.js
module.exports = () => {
    console.log("hello,i am a.js")
}
​
// b.js
const a = require("./a")
a()
if(module.hot){
    module.accept("./a",(newA) => {
        newA()
    })
}
​
// webpack服务端更新webpack缓存中被修改的A模块
socket.on("update",(path) => { 
    loadScript(path).then((newModule) => {
        webpack__modules[0] = newModule
    })
})
​
// webpack编译出的可以在浏览器中执行的代码
webpack__module[0] = {moduleA}
webpack__module[1] = {moduleB}
const a = __webpack__require__(0)

__webpack__require__(0)读取的就是webpack__modules[0]

vite中的热更新

vite中的HMR则不是这样的原理,因为vite在开发时是完全基于浏览器ESM进行模块管理的,与webpack的HMR相比,更加的轻量,影响范围更小。

通过脚手架命令启动的项目,一般都是默认开启热更新的。vite中的热更新,是根据不同框架实现的,热更新是一套API,具体实现过程与使用框架是有关的。vite中的HMR是单独实现的API,与rollup无关,放在了import.meta上。

创建一个vanilla项目,不集成任何第三方框架。修改代码后,可以发现页面会有刷新,这是因为没有第三方框架的引用,没有HMR插件的支持。这种情况,就需要前端自己用Vite的HMR API来实现

export function render(){
    document.querySelector("#app").innerHTML="<p>监听到自身文件的变化,则触发HMR</p>"
}
if(import.meta.hot){ // 生产环境这里为false
    import.meta.hot.accept((newMoudle)=>{
        newMoudle.render()
    })
}

依赖预构建(预编译文件)

这也是vite启动项目快的原因之一

预编译就是对于在node_modules中安装的第三方的库,vite在第一次启动之前会先把依赖的这些包进行编译放到一个缓存.vite中,这样在用到类库的地方,都不需要重新编译,而直接从缓存中读取。

在预编译的过程中,还有一个比较重要的事情是把非ESM的文件,编译成ESM,因为在开发的时候,vite完全是依赖于原生的ESM的加载方式去加载文件的,所以必须要有这一步。

vite配置

当以命令行方式运行 vite 时,Vite 会自动解析项目根目录下名为 vite.config.js 的文件