transformIndexHtml 给 settings.js 自动追加时间戳,彻底避开浏览器缓存
vite 项目部署,我们为了避免多服务器频繁打包部署,抽离了共有变量到 public 中的 settings.js。
settings.js 结构如下:
const defaultSettings = {
baseApi: "/api", // 接口的base路径 开发为/api 生产可替换/ragapi
token: "Bearer XXXXXXXXXXXXXX",
appFrontBase: "http://baidu.com/", // 智能应用前端根路径
maxFileSize: 900, // 最大的上传文件
title: '项目名称',
};
代码中可直接使用。现:我们 build 项目到服务器后,更改了 settings.js 中的部分字段。由于缓存的存在,更新完成后 settings.js 请求到的数据仍然为未更新过的(当然,浏览器会一定时间后自动更新静态文件缓存,也可以清空缓存并加载)。但我们想每次部署后,再次刷新浏览器就可以看到最新的 settings.js。
我们自定义一个 vite 插件,实现每次 build 后,将:
<script src="/settings.js"></script>
加一个时间戳,更改为:
<script src="./settings.js?v=1718846778507"></script>
这样,每次 build 部署后,settings 后会有时间戳,每次都不一样,可避免浏览器缓存。
Vite 插件是一种用于扩展 Vite 功能的工具,允许开发者自定义构建配置,以满足特定的开发需求。Vite 插件可以针对开发服务器和生产构建过程进行特定的操作和优化。自定义 Vite 插件通常遵循以下格式:
通过遵循这些格式和约定,开发者可以创建出功能丰富、高度自定义的 Vite 插件,以满足项目开发中的特定需求。
export const vitePluginAddScriptVersion = {
name: "vite-plugin-add-script-version",
transformIndexHtml(html) {
const version = new Date().getTime();
// 注意这里我们移除了 \s+ 来匹配没有空格的情况,并且使用了 . 来匹配任何字符(除了换行符)
const regex = /<script\s+src="\.\/settings\.js"([^>]*)>/g;
// 使用函数作为第二个参数来确保我们只替换没有查询参数的 URL
const replacedHtml = html.replace(
regex,
(_, attrs) => `<script src="./settings.js?v=${version}"${attrs}>`
);
return replacedHtml;
},
};
| 部分 | 说明 |
|---|---|
| name | 插件名称 "vite-plugin-add-script-version" |
| transformIndexHtml(html) | 构建过程中转换 HTML 文件内容,接收原始 HTML 字符串 |
| version | new Date().getTime() 时间戳作为版本号,每次构建唯一 |
| regex | 全局匹配 src 指向 "./settings.js" 的 script 标签 |
| html.replace | 函数式替换,给 src 追加 ?v=${version} 并保留原标签其他属性 |
vite-plugin-add-script-version 文件目录和 vite.config.ts 平级。vite.config.ts 引用配置:
import { defineConfig } from 'vite'
import { vitePluginAddScriptVersion } from './vite-plugin-add-script-version'
export default defineConfig({
plugins: [vitePluginAddScriptVersion]
})
最终打包后的 index.html 结构如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./logo.ico" />
<script src="./settings.js?v=1718846778507"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="module" crossorigin src="./assets/index-DQDZevpy.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-CKmqFZ2w.css">
</head>
<body>
<div id="root" class="h-[100vh]"></div>
</body>
</html>
在 webpack 的构建过程中,特别是当与一些模板引擎(如 html-webpack-plugin)结合使用时,你会看到这样的语法。这里的 <%= ... %> 是模板引擎的插值语法,用于将某些变量或表达式的值插入到 HTML 文件中。可借助 webpack 的模板语法来实现:
<script src="<%= BASE_URL %>config/config.js?v=<%=new Date().valueOf() %>"></script>