Vite
默认配置
ts
// vite
import { defineConfig } from 'vite';
// 导入vue
import vue from '@vitejs/plugin-vue';
// vue调试工具
import vueDevTools from 'vite-plugin-vue-devtools';
// element按需引入
import AutoImport from 'unplugin-auto-import/vite';
// 自动注册全局组件
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
// 路径模块(1)
// import { resolve } from "path";
// 路径导入以及url(2)
import { fileURLToPath, URL } from 'node:url';
export default defineConfig(({ mode })=>({
base: "./",
resolve: {
alias: {
// "@": resolve(__dirname, "./src"),
// comp: resolve(__dirname, "./src/components"),
'@': fileURLToPath(new URL('./src', import.meta.url)),
'comp': fileURLToPath(new URL('./src/components', import.meta.url)),
},
},
plugins: [
vue(),
// vue调试工具 【只开发环境使用】
mode === 'development' ? vueDevTools() : undefined,
// element按需引入
AutoImport({
resolvers: [ElementPlusResolver()],
// 生成的类型文件路径(会自动创建,TS会识别)
// dts: 'src/auto-imports.d.ts',
}),
Components({
resolvers: [ElementPlusResolver()],
// 生成的组件类型文件路径
// dts: 'src/components.d.ts',
// 方法1:明确指定只扫描哪些目录
dirs: ["src/components/base"], // 只自动注册 `src/components/base`下的组件
// 方法2:使用排除规则(正则表达式)
// exclude: [
// /TopNavigation\.vue/, // 排除 TopNavigation 组件
// /loading\index\.vue/, // 排除 Loading 组件
// /Progress\.vue/, // 排除 progress 组件
// ],
}),
],
// 生产构建设置
build: {
rollupOptions: {
// 打包输出配置
output: {
/********** 使用 contenthash,确保只有内容变化的文件指纹才变 **********/
// 1. 入口文件:使用 contenthash,8位长度通常足够且兼顾文件名长度
entryFileNames: 'assets/[name]-[hash:16].js',
// 2. 动态导入的 chunk(即你的各个页面):独立计算 contenthash
chunkFileNames: 'assets/[name]-[hash:16].js',
// 3. 静态资源(CSS、图片等):同样使用 contenthash
assetFileNames: 'assets/[name]-[hash:16][extname]',
// 分包
manualChunks: (id)=> {
// 把第三方依赖进行分包处理
if (id.includes('node_modules') && (id.endsWith('.js') || id.endsWith('.ts'))) {
return 'vendor';
}
}
}
}
},
server: {
// 自动打开浏览器进行预览
open: false,
// 网络端口号
port: 9999,
host: "0.0.0.0",
// 配置反向代理
proxy: {
"/api": {
target: "http://localhost:3000",
// target就是你要访问的目标地址,可以是基础地址,这样方便在这个网站的其他api口调用数据
ws: true, //是否代理 websockets
secure: false, //是否https接口
changeOrigin: true, //是否跨域
rewrite: (path) => path.replace(/^\/api/, ""),
},
"/apiOne": {
target: "http://luke.svvs.top",
// target就是你要访问的目标地址,可以是基础地址,这样方便在这个网站的其他api口调用数据
ws: true, //是否代理 websockets
secure: false, //是否https接口
changeOrigin: true, //是否跨域
rewrite: (path) => path.replace(/^\/apiOne/, ""),
},
},
},
}));版本检测
1. 自定义vite插件
该插件的作用?
在 Vite 构建完成后,生成一个 version.json 文件,里面包含当前的时间戳作为版本号。
实现功能:线上对version.json进行轮询检测版本号,有新版上线提示用户进行页面更新。
在src同级目录下创建plugins/versionPlugin.ts文件,复制保存一下代码块即可。
ts
/****************** 把当前时间戳写入version.json中,并保存到 outDir 目录中 ******************/
/** 该插件的作用:在 Vite 构建完成后,生成一个 version.json 文件,里面包含当前的时间戳作为版本号。 */
// fs模块用于文件操作,path模块用于处理文件路径
import fs from 'node:fs';
// path模块用于处理文件路径
import path from 'node:path';
// Plugin和ResolvedConfig类型用于定义Vite插件的类型。
import type { Plugin, ResolvedConfig } from 'vite';
// versionPlugin函数返回一个符合Vite插件规范的对象
export function versionPlugin(): Plugin {
// 声明闭包变量
let config: ResolvedConfig;
// 返回插件对象
return {
/**
* 插件名称
* 当构建出错或打印警告时,Vite 会显示 [version-plugin] xxx error,让你快速定位是哪个插件的问题。
* Vite 内部通过 name 来识别插件,避免同一个插件被重复加载。
*/
name: 'version-plugin',
// 限制该插件仅在构建模式下生效
apply: 'build', // 只在 build 时生效
/* configResolved:
执行时机: 在 Vite 解析完所有配置文件和插件配置之后、构建正式开始之前触发。
参数: 接收一个 resolvedConfig 对象,这是 Vite 经过合并、校验、补全默认值后的最终只读配置。
核心作用: 当你需要在其他钩子中使用 Vite 的最终配置(如 outDir、base、环境变量等)时,就必须通过这个钩子把它存下来。 */
configResolved(resolvedConfig) {
// 保存最终配置
config = resolvedConfig;
},
// closeBundle:在整个打包流程结束后执行
closeBundle() {
const version = Date.now().toString();
// 直接写到 dist 目录(outDir),不污染源码的 public 目录
const outDir = config.build.outDir; // 使用最终配置config
const versionFile = path.resolve(outDir, 'version.json');
// 确保 dist 目录存在
if (!fs.existsSync(outDir)) {
fs.mkdirSync(outDir, { recursive: true });
}
// 将版本号的 JSON 对象同步写入到指定文件中
fs.writeFileSync(versionFile, JSON.stringify({ version }));
console.log(`\n[version-plugin] 已生成 version.json: ${version}`);
},
}
}2. 在vite中使用插件
vite.config.ts文件中配置即可。
ts
// vite
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
// 导入自动生成版本号更新插件
import { versionPlugin } from './plugins/versionPlugin';
export default defineConfig(({ mode })=>{
return {
...,
plugins: [
vue(),
// 使用自动生成版本号更新插件
versionPlugin(),
],
...,
}
});3. 轮询 version.json
关键提示
在任意的js或ts文件中,写入以下代码进行轮询查询,必须保证以下代码只执行一次即可。
ts
const CHECK_INTERVAL = 5 * 60 * 1000 // 5分钟检测一次
// 保存至本地版本号时间戳的Key
const VERSION_KEY = 'versionTimestamp';
// 保存计时器,便于清除
let versionTimer: ReturnType<typeof setInterval> | null = null;
// 开始先删除本地版本号时间戳的Key,防止刷新后还是会触发弹窗
sessionStorage.removeItem(VERSION_KEY);
// 执行请求
function startVersionCheck() {
// 首次加载立即检测
checkVersion();
// 之后定时检测
versionTimer = setInterval(()=> checkVersion(), CHECK_INTERVAL);
}
// 立即执行
startVersionCheck();
async function checkVersion() {
try {
// 发送请求获取数据
const sendVersion = await fetch('/version.json?t=' + Date.now());
// 转换json数据
const result = await sendVersion.json();
// 获取版本号时间戳
const serverVersion = result.version;
// 获取本地存储的版本时间戳
const sessionVersion = sessionStorage.getItem(VERSION_KEY);
// 判断版本是否更新
if (sessionVersion && sessionVersion !== serverVersion) {
// 清除计时器
versionTimer && clearInterval(versionTimer);
// 发现新版本,提示用户
const confirmed = confirm('页面有更新,刷新一下体验更好哦~');
// 刷新页面
confirmed && location.reload();
// 重新开启计时器
versionTimer = setInterval(()=> checkVersion(), CHECK_INTERVAL)
}
// 保存当前版本
sessionStorage.setItem(VERSION_KEY, serverVersion);
} catch (e) {
// console.warn('版本检测失败', e)
}
}