实用指南:vite插件的使用
vite的编译结果
当我们执行npm run build将项目打包之后, 会生成一个dist文件, 下面我们看一下打包结果

- 首先查看页面文件
Document
<script type="module" crossorigin src="/assets/index-Bz2AOqjK.js"></script>
Document
<script src="./main.js" type="module"></script>
- 主要的变化就是引入资源的路由由相对路径被替换为绝对路径, 只有绝对路径才能最终定位资源
- 如果我们直接使用Live Server运行这个index.html文件, 发现提示找不到资源, 因为dist不是运行根目录


- 我们确保dist是运行的根目录, 在用Live Server运行就可以了

- 在生产环境不会遇到这个问题, 因为会把dist作为项目根目录
- 查看静态资源
- 打包后的静态资源为什么要有hash?

- 浏览器是有一个缓存机制, 静态资源名字只要不改,那么他就会直接用缓存的
- 当我们刷新页面, 浏览器不是立刻去请求资源, 而是根据资源的文件名, 尝试从浏览器器缓存中获取资源, 获取不到再去请求
- hash算法: 将一串字符串经过运算得到一个新的乱码字符串, 利用好hash算法 可以让我们更好的去控制浏览器的缓存机制
- vite中的资源的哈希值是根据文件内容+文件名生产的, 只要文件内容变化或文件名变化, 就会生成新的哈希值, 就不会命中浏览器缓存, 否则生成的哈希值是不变的
- 一些打包配置
import { defineConfig } from 'vite'
export default defineConfig({
build: {
rollupOptions: { // 配置rollup的一些构建策略
output: { // 控制输出
// 控制打包后的文件名格式
assetFileNames: "[hash].[name].[ext]"
}
},
assetsInlineLimit: 4096, // 当图片小于4kb, 打包成base64图片(生成在JS中), 而不是单独的图片
outDir: "testDist", // 默认dist, 打包文件输出的文件夹名称
assetsDir: "static" // 默认assets, 静态资源的文件夹名称
}
})
vite的插件
插件是什么?
- vite会在生命周期的不同阶段中去调用不同的插件以达到不同的目的
- 生命周期: vite从开始执行到执行结束,那么整个过程就是vite的生命周期
vite-aliases
- 作用: 检测你当前目录下包括src在内的所有文件夹,并帮助我们去生成别名
{
"@": "/**/src",
"@aseets":"/**/src/assets",
"@components":"/**/src/components"
}
- 安装配置
npm install vite-aliases -D
import { defineConfig } from 'vite'
import { ViteAliases } from 'vite-aliases'
export default defineConfig({
plugins: [
ViteAliases()
]
})
- 手写插件: 我们去手写Vite-aliases其实就是抢在vite执行配置文件之前去改写配置文件
import { defineConfig } from 'vite'
import MyViteAliases from './plugins/ViteAliases'
export default defineConfig({
plugins: [
MyViteAliases()
]
})
const fs = require("fs")
const path = require("path")
function diffDirAndFile(dirFilesArr = [], basePath = "") {
const result = {
dirs: [],
files: []
}
dirFilesArr.forEach(name => {
const currentFileStat = fs.statSync(path.resolve(__dirname, basePath + "/" + name))
const isDirectory = currentFileStat.isDirectory()
if (isDirectory) {
result.dirs.push(name)
} else {
result.files.push(name)
}
})
return result
}
function getTotalSrcDir() {
const result = fs.readdirSync(path.resolve(__dirname, "../"))
const diffResult = diffDirAndFile(result, "../")
console.log("当前工程下的所有文件名夹", diffResult);
const resolveAliasesObj = {}
diffResult.dirs.forEach(dirName => {
const key = `@${dirName}`
const absPath = path.resolve(__dirname, "../" + "/" + dirName)
resolveAliasesObj[key] = absPath
})
return resolveAliasesObj
}
module.exports = () => {
return {
config(config, env) {
// config当前工程的配置对象
// env环境数据
// ---mode: 模式, 开发模式(dev)或生产模式(pro)
// ---command: 执行的命令, npm run dev或 npm run build
const resolveAliasesObj = getTotalSrcDir()
console.log("路径别名对象", resolveAliasesObj);
// config函数可以返回一个对象, 这个对象是部分的vite配置(就是要更改的那一部分)
return {
resolve: {
alias: resolveAliasesObj
}
}
}
}
}

vite常用插件之vitee-plugin-html
- 作用: 就是帮我们动态的去控制整个html文件中内容 (基于ejs语法)
- 安装使用
npm install vite-plugin-html -D
import { defineConfig } from 'vite'
import { createHtmlPlugin } from 'vite-plugin-html'
export default defineConfig({
plugins: [
createHtmlPlugin({
inject: {
data: {
title: "首页"
}
}
})
]
})
<%= title %>
- 手写插件
import { defineConfig } from 'vite'
import CreateHtmlPlugin from './plugins/CreateHtmlPlugin'
export default defineConfig({
plugins: [
CreateHtmlPlugin({
inject: {
data: {
title: "主页"
}
}
})
]
})
module.exports = (options) => {
return {
// 转换html的周期
transformIndexHtml: {
enforce: "pre", // 生命周期的执行时机
transform: (html, ctx) => {
// html: 编译前的原文
console.log(html);
// ctx: 当前执行期上下文
return html.replace(/<%= title %>/g, options.inject.data.title)
}
}
}
}
<%= title %>
vite常用插件之vite-plugin-mock
- 作用: 模拟数据
# 简单方式: 直接去写死一两个数据
# 优点: 方便调试
# 缺陷:
# --没法做海量数据测试
# --没法获得一些标准数据
# --没法去感知http的异常
# 标准方式: mock.js
- 简单示例
npm install vite-plugin-mock mock.js
import mockJS from "mockjs"
const userList = mockJS.mock({
"data|100": [{
name: "@cname", // 生成不同的中文名
"id|+1": 1, // 生成自增+1的id
time: "@time",
date: "@date"
}]
})
module.exports = [
{
method: "post",
url: "/api/user",
response: ({ body }) => {
return {
code: 200,
mas: "sucess",
data: userList
}
}
}
]
- 注意mock目录要放在根目录下才会被扫描到, 也可以配置
fetch("/api/user", {
method: "post"
}).then(data => {
console.log("data=", data);
}).catch(error => {
console.log("err=", error);
})
import { defineConfig } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig({
plugins: [
viteMockServe()
]
})

- 手写vite-plugin-mock插件
const fs = require("fs")
const path = require("path")
export default (options) => {
// 核心任务: 拦截Http请求
// 请求流程:
// 1.发送请求 ->
// 2.补全请求地址(请求发送至本地开发服务器) ->
// 3.viteserve会把请求上下文交给若干中间件处理 ->
// 4.静态资源中间件(命中返回就资源) ->
// 5.用户身份校验中间件(cookie,token)(合法继续,不合法返回) ->
// 6.Api中间件
return {
// vite提供的服务器配置的钩子
configureServer(server) {
const mockStat = fs.statSync("mock") // 默认mock文件夹位于项目根目录, 否则不处理
const isDirectory = mockStat.isDirectory() // 判断是否为文件夹
let mockResult = []
if (isDirectory) {
// process.cwd(): 获取当前的执行根目录
mockResult = require(path.resolve(process.cwd(), "mock/index.js")) // 拼接处完整的路径
console.log(mockResult, "===");
}
// 服务器的相关配置 (安装middlewares插件)(也就是配置中间件)
// req,请求对象 -->用户发过来的请求,请求头请求体 url cookie
// res:响应对象,--> res.header
// next:是否交给下一个中间件,调用next方法会将处理结果交给下一个中间件m1
server.middlewares.use((req, res, next) => {
const mathItem = mockResult.find(mockDescriptor => mockDescriptor.url === req.url)
if (mathItem) {
const responseDate = mathItem.response(req)
res.setHeader("Content-Type", "application/json")
res.end(JSON.stringify(responseDate)) // 异步代码
} else {
next() // 放行
}
})
}
}
}
import { defineConfig } from 'vite'
import VitePluginMock from './plugins/VitePluginMock'
console.log(VitePluginMock, '========');
export default defineConfig({
plugins: [
VitePluginMock()
]
})
认识其他的插件的生命周期
import { defineConfig, loadEnv } from "vite"
export default defineConfig({
build: {
rollupOptions: {
output: {
assetFileNames: "[hash].[name].[ext]"
}
}
},
plugins: [
{
// 作用: 获取用户的配置
config(options) {
// console.log("拿到vite.config中的所有配置", options);
},
// 对开发服务器进行配置
configureServer(serve) {
// console.log("对开发服务器进行控制", serve);
// server.middlewares.use((req, res, next) => { }
},
// 对Html页面进行控制
transformIndexHtml(html) {
console.log("原始Html字符串", html);
},
// 可以拿到最终的配置文件
configResolved(options) {
// console.log("解析完毕的最终配置文件", options);
},
// 配置dist预览服务器
configurePreviewServer(server) {
// 打包完成后, 可以使用vscode的live serve插件启动html, 预览打包后的文件
// vite也提供了一个服务器, 预览打包后的文件 (dist要是根目录)
// npx vite preview (打包后完直接敲就行)
// 打包后的文件预览正常, 部署到线上就基本不会有问题
// console.log("dist预览服务器的配置", server);
},
// 自定义一些热更新的行为
handleHotUpdate(serve) {
// console.log("热更新的配置", serve);
// 了解下热更新的原理:
// 1. 在服务端可以读到用户对vite的配置对象的
// 2.把用户的配置对象和vite默认配置还有命令行参数都合并到一个对象里
// 3.让配置逐个生效, 返回给浏览器, 页面就更新了
},
// 下面是一些universal hooks (就是vite和rollup都会执行的钩子)(上面的钩子只有vite执行)
options(rollupOptions) {
// 这里拿到配置就是我们在配置文件中定义的build选项中的配置
console.log("build options", rollupOptions); // 这里会打印两次, 因为都会执行, 知道就行不影响什么
},
// 同configResolved
buildStart(rullRollupOptions) {
// 因为vite为了要和rollup保持一致, 所有会有一些重复的钩子, 对我们作用不大
console.log("rullRollupOptions", rullRollupOptions);
}
}
]
})
vite与ts的结合
搭建环境

Document
<script src="./src/main.ts" type="module"></script>
console.log("hello");
npm init -y #初始化工程
npm i vite -D #安装vite
npm run dev

说明: vite天生支持ts, 我们什么都没做, 就可以运行main.ts
TS的特点就是强类型绑定, 最大的作用就是提高代码的规范性

我们将数值类型的值赋值给字符串类型的变量, 在TS中肯定是不合法的, 而且编译器也给出了提示

但是这并不影响我们运行代码, 如果我们更强制的约束, 可以引入插件帮助把语法错误直接输出到控制台
npm install vite-plugin-checker -D
import { defineConfig } from "vite"
import check from "vite-plugin-checker"
export default defineConfig({
plugins: [check({
typescript: true
})]
})
该插件依赖TS, TS也需要配置文件
npm install typescript -D
// 配置一些ts的检查手段和规则
{
"compilerOptions": {
"skipLibCheck": true // 忽略对node_modules目录的检查
}
}
重新运行项目, TS语法错误就会阻塞项目, 减少项目中的雷

由于语法错误最终打包失败, 但是在编译到错误错误之前, 还是执行了构建操作

对于大型项目, 边构建边校验这样很浪费时间, 我们希望先检验,再构建
{
"name": "04vite-ts",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build",
"test": "echo \"Error: no test specified\" && exit 1"
}
}

TS中使用环境变量会有以下坑
VITE_TARGET=http://www.baidu.com

这个报错是因为tsconfig中默认把ts编译为es3, 就不支持 import.meta属性了, 所以要配置一下
// 配置一些ts的检查手段和规则
{
"compilerOptions": {
"skipLibCheck": true, // 忽略对node_modules目录的检查
"module": "ESNext" // 编译为最新的ES语法
}
}
又发现找不到env属性

要通过声明文件解决这个问题
/**
* 下面写的是 三斜线指令
* readonly是只读的意思, 一般环境变量的值不希望被改
*/
///
interface ImportMetaEnv {
readonly VITE_TARGET: string
}
课程中是正常了, 而且我这里编译器也通过了

但是vite.config.ts文件报错了, 是因为vite不知道去哪找资源, 模块方案配置为node后, 默认去node_modules中寻找资源
// 配置一些ts的检查手段和规则
{
"compilerOptions": {
"moduleResolution": "node", // 模块解析方案
"skipLibCheck": true, // 忽略对node_modules目录的检查
"module": "ESNext" // 编译为最新的ES语法
}
}

浙公网安备 33010602011771号