初识vite

329 阅读6分钟

分享目标

vite是什么,带给我们什么好处,vite的一些基本配置

vite 是什么

vite是一个高阶的前端构建工具

vite 初衷

出生背景

构建越来越大型的应用时,需要处理的 JavaScript 代码量也呈指数级增长

性能瓶颈:

  • JavaScript 开发的工具通常需要很长时间(甚至是几分钟!)才能启动开发服务器
  • 即使使用 HMR,文件修改后的效果也需要几秒钟才能在浏览器中反映出来

极大的影响开发者开发效率

目的

  • 使用简单

与传统构建工具区别

  • 自己没有编译构建能力 预编译采用esbuild 打包使用rollup

  • 开发时基于原生ESM加载的方式(下边会有介绍)

  • vite 减少很多配置量

    vite 配置 不繁琐,为前端项目而生,dev-server,css依赖,图片加载功能都是开箱即用的,不需要你去配置插件,loader,所以你的vite配置可能不超过20行代码,webpack 项目基本不太可能

  • vite 为项目而生 不是为构建而生

原生ESM

我们一直提到一个概念就是 vite以原生ES Moudle 的加载方式,那么我们详细来了解下

我们之前的js是没有模块管理能力的,所以出现了一些模块管理规范和库

我们已经知道一些前端的模块管理方案: commonJs AMD (RequireJs) UMD

而这些本质都是通过JS脚本的执行来进行管理的,不是原生的Native模块管理能力

那么 ES Moudle是随着ES6推出的正式的JavaScript模块语法

更多详情参考 ES Moudle

我本地也部署了一个示例帮大家理解(代码basic-modules

开始创建一个vite应用

npm init vite@latest

这样你就可以快速创建一个vite项目 vite项目默认目录

├── src
│   ├── App.css
│   ├── App.jsx
│   ├── favicon.svg
│   ├── index.css
│   ├── logo.svg
│   └── main.jsx
├── index.html
├── package.json
└── vite.config.js

index.html是项目的入口文件

推荐用yarn安装依赖 github.com/evanw/esbuild/issues/462

vite-show

优势

上手简单,开发效率高

webpack 配置复杂,这点我们应该深有体会

比如数据平台的配置就很多数据平台webpack配置

而vite配置(帮我们省去了很多配置)

image.png

即使我们有方便的脚手架构建工具例如 vue-cli create-react-app

你还是要学习webpack 才能修改,就官网来说看起来就内容很多,学习成本不低

vite你不需要管那么多配置问题,只需要了解基本的配置就可以了

随着项目增多 ,webpack项目启动速度明显变慢,但vite不会

速度对比

  • vite 编译和webpack区别

image.png

不难看出,webpack 需要把所有模块生成一个bundle ,随着项目变大,构建时间必定会显著增长

image.png

vite你可以理解为她是一个服务器,index.html是一个入口

让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。

(直接浏览器加载html 通过script 加载main.js 这个js请求到达vite的server,vite再去找对应的文件,再根据用到的文件去加载)

当项目提交增大的时候,vite 编译时间不会有太大变化

另一个快原因:

vite 采用esbuild预编译

Vite 将会使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。

性能对比图可以看 esbuild官网

vite配置

typescript

天然支持ts(通过esbuild 将ts文件编译成 js),但不会校验,需要自己配置

配置过程

npm install typescript

配置tsconfig.json

{
    "compilerOptions": {
      "target": "ESNext",
      "useDefineForClassFields": true,
      "lib": ["DOM", "DOM.Iterable", "ESNext"],
      "allowJs": false,
      "skipLibCheck": false,
      "esModuleInterop": false,
      "allowSyntheticDefaultImports": true,
      "strict": true,
      "forceConsistentCasingInFileNames": true,
      "module": "ESNext",
      "moduleResolution": "Node",
      "resolveJsonModule": true,
      "isolatedModules": true,
      "noEmit": true,
      "jsx": "react-jsx"
    },
    "include": ["./src"]
  }

因为vite不会校验ts,所以我们可以在构建脚本中运行 tsc --noEmit,这样在构建的时候可以进行校验

 "scripts": {
    "dev": "tsc --noEmit && vite",
    "build": "tsc --noEmit && vite build",
    "preview": "vite preview"
  },

只针对 单文件 有些ts功能没法实现 不支持模块间关联的类型校验 所以我们在tsconfig.json 中

静态资源处理

静态资源处理

集成eslint

npm install eslint-config-standard eslint-plugin-import eslint-plugin-promise -D npm install eslint

自己配置eslint

module.exports = {
  extends: 'standard',
}

因为vite 构建时不会自行校验,需要做如下配置

  "scripts": {
    "dev": "npm run lint && tsc --noEmit && vite",
    "build": "npm run lint && tsc --noEmit && vite build",
    "preview": "vite preview",
    "lint":"eslint --ext jsx src/"
  },

环境变量

通过不通的文件获取不同的环境变量

.env.production

.env.development

.env.local

变量名要加 VITE前缀

关于 import.meta 是 ECMAScript 实现的

通过 import.meta.env 获取环境变量

配置文件要重启才能生效

vite 功能

热更新

Vite 提供了一套原生 ESM 的 HMR API

vite 命令行创建的项目,都是默认开启热更新的

接下来我们实现以下vite怎么使用热更新

npm init @vitejs/app 创建没有任何框架继承的项目

可以发现是没有支持热更新的,改变内容页面会刷新,而有热更新的项目,改变内容页面不会刷新

修改前

import './style.css'

document.querySelector('#app').innerHTML = `
  <h1>Hello Vite!</h1>
  <a href="https://vitejs.dev/guide/features.html" target="_blank">Documentation</a>
`

修改后

import './style.css'

export function render(){
  document.querySelector('#app').innerHTML = `
  <h1>Hello Vite!123</h1>
  <a href="https://vitejs.dev/guide/features.html" target="_blank">Documentation</a>
`

}

render()

// vite build 后 import.meta.hot可能是undefined

if(import.meta.hot){
  import.meta.hot.accept((newModule)=>{
    newModule.render()
  })
}

页面热更新实现

image.png

image.png

glob

vite提供的功能: 通过正则方式多文件引入

const globModule = import.meta.glob('./glob/*')
const globModule = import.meta.glob('./glob/*.js')
const globModule = import.meta.glob('./glob/*.json')

image.png

image.png

可以在浏览器看到编译后的代码

image.png

如果我们不希望异步引入文件,可以使用 globEager


const globModuleEager = import.meta.globEager('./glob/*')


实现库 fast-glob

预编译

vite快的一个原因是: 第一次启动时会把第三方包编译放到cache里,之后会从cache里面去取(预编译有点像webpack 的dll 打包)

cache 目录 node_modules/.vite

预编译过程中,会把非ESM文件 编译成 ESM

例如 commonJs => ESM

可以看 node_modules/react/cjs/react.development.js

react 通过commonJs管理模块,vite需要进行转换

node_modules/.vite/react.js

配置预编译 optimizeDeps

{
  plugins: [react()],
  optimizeDeps: { // 是否需要预编译
    include: [], // 需要预编译的文件
    exclude: ['react'] // 不需要预编译的文件
  }
}

Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能。

比如lodash-es 他包含600个内置模块 vite 会打成一个包

如果不进行编译的话,我们再浏览器可以看到600个请求,影响页面性能

不要随便把包exclud

image.png

rollup

vite 插件