Vite(法语意为 "快速的",发音 /vit/
)。由两部分组成:
Vite 是 Opinionated 的,通过约定保证了易用性——前端开发者常用的功能都是开箱即用,又提供了配置以保证不会丧失灵活性。和 webpack 是 index.js 不同,vite 中入口文件是 index.html。
vite具有这些优点:
Bundle,通常使用Webpack 打包构建工具来打包构建我们的代码,因为:
Bundleless 出现的原因:
第三方依赖:这类代码大部分都是不常变化纯JavaScript,Vite2 使用 esbulid 来以 pre-bundle 的方式构建这部分代码,处理速度快。
业务代码:这部分代码通常是常被修改的非纯的 JavaScript(例如:JSX,Vue 等),而且也不需要一次性全部加载(可以根据路由,做代码分割加载)。
因此,Vite 本身只需要启动静态服务器,按需编译浏览器请求的模块代码,动态加载到当前页面中。
Vite 分为开发模式和生产模式。
开发模式:基于原生 ES 模块的开发服务器
当代码中出现 import 的时候,发送一个资源请求,Vite开发服务器拦截请求,根据不同文件类型,在服务端完成模块的改写(比如单文件的解析编译等)和请求处理,实现真正的按需编译,然后返回给浏览器。请求的资源在服务器端按需编译返回,不需要生成bundle。服务器随起随用,所以开发环境下的初次启动是非常快的。而且热更新的速度不会随着模块增多而变慢,因为代码改动后,并不会有bundle的过程。
Vite Server 所有逻辑基本都依赖中间件实现。中间件拦截请求之后进行以下处理:
处理 ESM 语法,比如将业务代码中的 import 第三方依赖路径转为浏览器可识别的依赖路径;
对 .ts、.vue 等文件进行即时编译;
对 Sass/Less 的需要预编译的模块进行编译;
和浏览器端建立 socket 连接,实现 HMR。
生产模式: 利用 Rollup 来打包构建源代码。因为嵌套 import 会导致发送大量的网络请求,即使使用HTTP2,在生产中使用未捆绑的 ESM 仍然效率低下。而且esbuild关于一些应用程序绑定所需的重要特性仍在开发中——特别是代码拆分和CSS处理。目前,Rollup 在这些方面更加成熟和灵活。
原生的 ESM 只支持通过一个相对或者绝对路径来引用资源,不支持通过一个包名来引用资源,这和 webpack 相同,也是由 vite 做了 NPM Dependency Resolving 的一层转换。
/** 通过一个包名来引用资源 */
import React from 'react'
开发阶段,只有在依赖变动时,才会去更新query id使之前的的缓存失效,预打包才需要执行,Vite2 利用 esbuild 替代 Rollup加快构建速度,而且给第三方依赖的包都设置了http 缓存,存放在node_modules/.vite下。
相比 Snowpack, Vite支持更多的特性:
1. 创建一个 vite 项目,选择 react-ts 作为预设模板
yarn create @vitejs/app
2. 依次执行安装依赖和启动开发环境命令
yarn // 安装依赖
yarn dev // 启动开发环境
3. 目录约定
├── dist/ // 默认的 build 输出目录
└── src/ // 源码目录
├── assets/ // 静态资源目录
├── config
├── config.js // 项目内部业务相关基础配置
├── components/ // 公共组件目录
├── service/ // 业务请求管理
├── store/ // 共享 store 管理目录
├── until/ // 工具函数目录
├── pages/ // 页面目录
├── router/ // 路由配置目录
├── .main.tsx // Vite 依赖主入口
├── .env // 环境变量配置
├── vite.config.ts // vite 配置选型,具体可以查看官网 api
└── package.json
4. 配置路由 router/index.ts(还包括重定向(redirect)、懒加载等)
import BlogsList from '@/pages/blogs/index'
import BlogsDetail from '@/pages/blogs/detail'
export default {
routes: [
{ exact: true, path: '/', component: BlogsList },
{ exact: true, path: '/blogs/detail/:article_id', component: BlogsDetail },
],
}
5. 改造 main.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { HashRouter, Route, Switch } from 'react-router-dom'
import routerConfig from './router/index'
import './base.less'
ReactDOM.render(
{
routerConfig.routes.map((route) => {
return (
)
})
}
,
document.getElementById('root')
)
6. service 管理
所有项目请求都放入 service,建议每个模块都有对应的文件管理:
import * as information from './information'
import * as base from './base'
export {
information,
base
}
base.ts 作为业务请求类:
import { request } from '../util/request'
const prefix = '/api'
export const getAllInfoGzip = () => {
return request({
url: `${prefix}/apis/random`,
method: 'GET'
})
}
util/request 作为统一引入的请求方法,可以自定义替换成 fetch、axios 等请求库,同时可以在此方法内封装通用拦截逻辑。
在具体业务开发使用的时候可以按照模块名引入,容易查找对应的接口模块:
import { information } from "@/service/index";
const { data } = await information.getAllInfoGzip({ id });
7. vite.config.ts 配置
import { defineConfig } from 'vite'
import reactRefresh from '@vitejs/plugin-react-refresh'
import vitePluginImp from 'vite-plugin-imp'
export default defineConfig({
plugins: [
reactRefresh(),
/** 将 antd-mobile 进行按需加载 */
vitePluginImp({
libList: [
{
libName: 'antd-mobile',
style(name) {
return `antd-mobile/lib/${name}/style/index.css`
},
},
]
})
],
resolve: {
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
/** 配置别名,如果需要 vscode 正常识别的话,也需要配置 tsconfig.json */
alias: {
'@': '/src'
}
},
server: {
/** 配置项目代理 */
proxy: {
// 选项写法
'/api': {
target: 'https://www.xxx.xxx',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
}
},
css: {
postcss: {
plugins: [
/** 配置移动端 px 转换的插件 */
require('postcss-pxtorem')({ // 把px单位换算成rem单位
rootValue: 32, // 换算基数,默认100,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
propList: ['*'], //属性的选择器,*表示通用
unitPrecision: 5, // 允许REM单位增长到的十进制数字,小数点后保留的位数。
exclude: /(node_module)/, // 默认false,可以(reg)利用正则表达式排除某些文件夹的方法
})
]
}
}
})
tsconfig.json:
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": [
"src/*"
]
},
}