vite插件的使用
vite的编译结果
当我们执行npm run build将项目打包之后, 会生成一个dist文件, 下面我们看一下打包结果
- 首先查看页面文件
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="module" crossorigin src="/assets/index-Bz2AOqjK.js"></script><link rel="stylesheet" crossorigin href="/assets/index-CR6PgUTS.css">
</head><body><div id="div"></div></body></html>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div id="div"></div><script src="./main.js" type="module"></script>
</body></html>
- 主要的变化就是引入资源的路由由相对路径被替换为绝对路径, 只有绝对路径才能最终定位资源
- 如果我们直接使用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 buildconst 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: "首页"}}})]
})
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title><%= title %></title>
</head></html>
- 手写插件
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)}}}
}
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title><%= title %></title>
</head></html>
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的idtime: "@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方法会将处理结果交给下一个中间件m1server.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); // 这里会打印两次, 因为都会执行, 知道就行不影响什么},// 同configResolvedbuildStart(rullRollupOptions) {// 因为vite为了要和rollup保持一致, 所有会有一些重复的钩子, 对我们作用不大console.log("rullRollupOptions", rullRollupOptions);}}]
})
vite与ts的结合
搭建环境
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="./src/main.ts" type="module"></script>
</head><body></body></html>
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是只读的意思, 一般环境变量的值不希望被改*/
/// <reference types="vite/client" />
interface ImportMetaEnv {readonly VITE_TARGET: string
}
课程中是正常了, 而且我这里编译器也通过了
但是vite.config.ts文件报错了, 是因为vite不知道去哪找资源, 模块方案配置为node后, 默认去node_modules中寻找资源
// 配置一些ts的检查手段和规则
{"compilerOptions": {"moduleResolution": "node", // 模块解析方案"skipLibCheck": true, // 忽略对node_modules目录的检查"module": "ESNext" // 编译为最新的ES语法}
}