vite-plugin-build-version-file 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +564 -251
- package/dist/index.cjs +65 -16
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.mjs +65 -16
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,34 +1,33 @@
|
|
|
1
1
|
# vite-plugin-build-version-file
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
一个用于 Vite 项目的构建版本信息插件。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
它负责在开发态和构建产物中暴露统一的版本信息:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
7
|
+
- 开发态通过 dev server 提供 `version.json`
|
|
8
|
+
- 构建后在输出目录生成 `version.json`
|
|
9
|
+
- 普通 Vite HTML 自动注入 `window["__VERSION__"]`
|
|
10
|
+
- VitePress 可通过顶层 `transformHtml` 注入同一份版本信息
|
|
11
|
+
- 支持自定义版本号、输出文件名、全局变量名、时区和额外字段
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
插件只负责生成和暴露版本信息,不负责运行时更新策略。
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
它不会内置这些业务行为:
|
|
14
16
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
+
- 定时轮询新版本
|
|
18
|
+
- 弹窗提示用户刷新
|
|
17
19
|
- 用户取消后的重试策略
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
适合用在这些场景:
|
|
20
|
+
- 自动刷新页面的时机
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
- 检测线上是否有新版本并提示刷新
|
|
24
|
-
- 灰度发布时对比本地版本和服务端版本
|
|
22
|
+
这些行为通常应放在业务项目中实现。
|
|
25
23
|
|
|
26
24
|
## 适用范围
|
|
27
25
|
|
|
28
|
-
-
|
|
29
|
-
-
|
|
26
|
+
- Vite 项目
|
|
27
|
+
- Vue 3 + Vite 项目
|
|
28
|
+
- VitePress 项目
|
|
30
29
|
- `peerDependencies` 要求 `vite >= 5`
|
|
31
|
-
-
|
|
30
|
+
- Node.js 要求 `>= 18`
|
|
32
31
|
|
|
33
32
|
## 安装
|
|
34
33
|
|
|
@@ -36,7 +35,7 @@
|
|
|
36
35
|
pnpm add vite-plugin-build-version-file
|
|
37
36
|
```
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
也可以使用 npm:
|
|
40
39
|
|
|
41
40
|
```bash
|
|
42
41
|
npm install vite-plugin-build-version-file
|
|
@@ -44,28 +43,56 @@ npm install vite-plugin-build-version-file
|
|
|
44
43
|
|
|
45
44
|
## 快速开始
|
|
46
45
|
|
|
46
|
+
### 普通 Vite / Vue 3 项目
|
|
47
|
+
|
|
47
48
|
```ts
|
|
48
49
|
import { defineConfig } from 'vite'
|
|
49
50
|
import vue from '@vitejs/plugin-vue'
|
|
50
51
|
import buildVersionPlugin from 'vite-plugin-build-version-file'
|
|
51
52
|
|
|
52
53
|
export default defineConfig({
|
|
53
|
-
plugins: [
|
|
54
|
+
plugins: [
|
|
55
|
+
vue(),
|
|
56
|
+
buildVersionPlugin()
|
|
57
|
+
]
|
|
54
58
|
})
|
|
55
59
|
```
|
|
56
60
|
|
|
61
|
+
### VitePress 项目
|
|
62
|
+
|
|
63
|
+
VitePress 构建 HTML 时不完全走普通 Vite `index.html` 注入链路。需要复用同一个插件实例,并把它的 `transformHtml` 接到 VitePress 顶层配置上。
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
import { defineConfig } from 'vitepress'
|
|
67
|
+
import buildVersionPlugin from 'vite-plugin-build-version-file'
|
|
68
|
+
|
|
69
|
+
const buildVersion = buildVersionPlugin()
|
|
70
|
+
|
|
71
|
+
export default defineConfig({
|
|
72
|
+
vite: {
|
|
73
|
+
plugins: [buildVersion],
|
|
74
|
+
},
|
|
75
|
+
transformHtml: buildVersion.transformHtml,
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
注意:这里必须复用同一个 `buildVersion` 实例。不要分别调用两次 `buildVersionPlugin()`,否则 `transformHtml` 拿不到 Vite 插件阶段生成的 payload。
|
|
80
|
+
|
|
57
81
|
## 默认行为
|
|
58
82
|
|
|
59
|
-
|
|
83
|
+
默认配置下,插件会做这些事:
|
|
60
84
|
|
|
61
85
|
- 开发态访问 `/version.json` 时返回版本信息
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
86
|
+
- 构建后输出 `version.json`
|
|
87
|
+
- 向 HTML 注入 `window["__VERSION__"]`
|
|
88
|
+
- 自动读取业务项目最近的 `package.json`
|
|
89
|
+
- 将 `package.json` 的 `name` 写入 `pkgName`
|
|
90
|
+
- 将 `package.json` 的 `version` 写入 `pkgVersion`
|
|
65
91
|
- 开发态默认版本号为 `0`
|
|
66
|
-
-
|
|
92
|
+
- 构建态默认版本号为当前时间,格式为 `YYYYMMDDHHmmss`
|
|
93
|
+
- 默认时区为 `Asia/Shanghai`
|
|
67
94
|
|
|
68
|
-
|
|
95
|
+
构建态默认输出示例:
|
|
69
96
|
|
|
70
97
|
```json
|
|
71
98
|
{
|
|
@@ -76,7 +103,7 @@ export default defineConfig({
|
|
|
76
103
|
}
|
|
77
104
|
```
|
|
78
105
|
|
|
79
|
-
|
|
106
|
+
开发态默认输出示例:
|
|
80
107
|
|
|
81
108
|
```json
|
|
82
109
|
{
|
|
@@ -87,29 +114,6 @@ export default defineConfig({
|
|
|
87
114
|
}
|
|
88
115
|
```
|
|
89
116
|
|
|
90
|
-
## 职责边界
|
|
91
|
-
|
|
92
|
-
这个库的职责是:
|
|
93
|
-
|
|
94
|
-
- 生成版本号
|
|
95
|
-
- 输出 `version.json`
|
|
96
|
-
- 向页面注入版本信息
|
|
97
|
-
- 让业务代码能读取当前版本
|
|
98
|
-
|
|
99
|
-
这些逻辑建议写在业务项目里,而不是放进这个库里:
|
|
100
|
-
|
|
101
|
-
- 多久检查一次新版本
|
|
102
|
-
- 请求失败后是否重试
|
|
103
|
-
- 用什么 UI 提示用户
|
|
104
|
-
- 用户点击取消后怎么处理
|
|
105
|
-
- 是否立即刷新页面
|
|
106
|
-
|
|
107
|
-
如果你的项目要做“检测到新版本后提示刷新”,推荐做法是:
|
|
108
|
-
|
|
109
|
-
- 用 `window["__VERSION__"]` 读取当前页面版本
|
|
110
|
-
- 请求 `version.json` 读取服务端版本
|
|
111
|
-
- 在业务项目里自行决定提示方式和刷新时机
|
|
112
|
-
|
|
113
117
|
## 配置项
|
|
114
118
|
|
|
115
119
|
```ts
|
|
@@ -122,8 +126,11 @@ type BuildVersionPluginOptions = {
|
|
|
122
126
|
filename?: string
|
|
123
127
|
globalName?: string
|
|
124
128
|
injectToHtml?: boolean
|
|
129
|
+
timeZone?: string
|
|
125
130
|
version?: string | number | ((ctx: BuildVersionContext) => string | number)
|
|
126
131
|
data?: Record<string, any>
|
|
132
|
+
log?: (content: any) => string
|
|
133
|
+
payload?: (json: any) => any
|
|
127
134
|
}
|
|
128
135
|
```
|
|
129
136
|
|
|
@@ -131,13 +138,29 @@ type BuildVersionPluginOptions = {
|
|
|
131
138
|
|
|
132
139
|
- 类型:`string`
|
|
133
140
|
- 默认值:`"version.json"`
|
|
134
|
-
-
|
|
141
|
+
- 作用:控制开发态访问路径和构建态输出文件路径
|
|
142
|
+
|
|
143
|
+
示例:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
buildVersionPlugin({
|
|
147
|
+
filename: 'meta/version.json'
|
|
148
|
+
})
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
构建后输出:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
dist/meta/version.json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
开发态访问:
|
|
135
158
|
|
|
136
|
-
|
|
159
|
+
```text
|
|
160
|
+
/meta/version.json
|
|
161
|
+
```
|
|
137
162
|
|
|
138
|
-
|
|
139
|
-
- 构建时会输出到 `dist/meta/version.json`
|
|
140
|
-
- 开发态访问路径也会同步变成对应地址
|
|
163
|
+
如果项目配置了 Vite `base`,访问路径会自动跟随 `base`。
|
|
141
164
|
|
|
142
165
|
### `globalName`
|
|
143
166
|
|
|
@@ -153,18 +176,23 @@ type BuildVersionPluginOptions = {
|
|
|
153
176
|
</script>
|
|
154
177
|
```
|
|
155
178
|
|
|
156
|
-
|
|
179
|
+
这里注入的是完整 payload 对象,不是单独版本字符串。
|
|
157
180
|
|
|
158
181
|
### `injectToHtml`
|
|
159
182
|
|
|
160
183
|
- 类型:`boolean`
|
|
161
184
|
- 默认值:`true`
|
|
162
|
-
-
|
|
185
|
+
- 作用:控制是否向 HTML 注入 `window["__VERSION__"]`
|
|
163
186
|
|
|
164
|
-
|
|
187
|
+
设置为 `false` 后,仍会生成和提供 `version.json`。
|
|
165
188
|
|
|
166
|
-
|
|
167
|
-
|
|
189
|
+
### `timeZone`
|
|
190
|
+
|
|
191
|
+
- 类型:`string`
|
|
192
|
+
- 默认值:`"Asia/Shanghai"`
|
|
193
|
+
- 作用:控制默认构建时间按哪个时区生成
|
|
194
|
+
|
|
195
|
+
只影响插件默认生成的 `time`。如果你传了 `version`,则以自定义逻辑为准。
|
|
168
196
|
|
|
169
197
|
### `version`
|
|
170
198
|
|
|
@@ -172,73 +200,274 @@ type BuildVersionPluginOptions = {
|
|
|
172
200
|
- 默认值:开发态为 `0`,构建态为当前时间戳
|
|
173
201
|
- 作用:自定义版本号生成逻辑
|
|
174
202
|
|
|
175
|
-
如果传入函数,函数会收到:
|
|
176
|
-
|
|
177
203
|
```ts
|
|
178
|
-
{
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
204
|
+
buildVersionPlugin({
|
|
205
|
+
version: ({ command, mode }) => {
|
|
206
|
+
if (command === 'serve') {
|
|
207
|
+
return 0
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return `${mode}-20260401153045`
|
|
211
|
+
}
|
|
212
|
+
})
|
|
182
213
|
```
|
|
183
214
|
|
|
184
215
|
### `data`
|
|
185
216
|
|
|
186
217
|
- 类型:`Record<string, any>`
|
|
187
218
|
- 默认值:`{}`
|
|
188
|
-
-
|
|
219
|
+
- 作用:向最终 payload 追加自定义字段
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
buildVersionPlugin({
|
|
223
|
+
data: {
|
|
224
|
+
appName: 'admin',
|
|
225
|
+
gitBranch: 'release/2026-04',
|
|
226
|
+
commitSha: 'abc1234'
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
生成结果示例:
|
|
189
232
|
|
|
190
|
-
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"appName": "admin",
|
|
236
|
+
"gitBranch": "release/2026-04",
|
|
237
|
+
"commitSha": "abc1234",
|
|
238
|
+
"pkgName": "your-app-name",
|
|
239
|
+
"pkgVersion": "1.0.0",
|
|
240
|
+
"time": "20260401153045",
|
|
241
|
+
"env": "production"
|
|
242
|
+
}
|
|
243
|
+
```
|
|
191
244
|
|
|
192
|
-
|
|
193
|
-
- 查找位置是从当前 Vite 项目根目录开始,向上寻找最近的 `package.json`
|
|
194
|
-
- 会同时影响开发态接口返回、构建产物中的 `version.json` 和注入到 `window` 的对象
|
|
195
|
-
- 如果 `data` 里存在 `time` 或 `env` 同名字段,最终仍以插件生成的值为准
|
|
196
|
-
- 如果 `data` 里存在 `pkgName` 或 `pkgVersion`,读取到业务项目 `package.json` 时会以自动读取的值为准;读取不到时会保留 `data` 里的值
|
|
245
|
+
字段覆盖顺序:
|
|
197
246
|
|
|
198
|
-
|
|
247
|
+
- `data` 会先写入
|
|
248
|
+
- `pkgName`、`pkgVersion` 会使用项目 `package.json` 的值覆盖同名字段
|
|
249
|
+
- `time`、`env` 会使用插件生成的值覆盖同名字段
|
|
250
|
+
- `payload` 可以在最后改写整个结果
|
|
199
251
|
|
|
200
|
-
###
|
|
252
|
+
### `payload`
|
|
253
|
+
|
|
254
|
+
- 类型:`(json: any) => any`
|
|
255
|
+
- 作用:最终改写 payload
|
|
256
|
+
|
|
257
|
+
适合做字段裁剪、字段重命名或兼容旧系统。
|
|
201
258
|
|
|
202
259
|
```ts
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
260
|
+
buildVersionPlugin({
|
|
261
|
+
payload: (json) => ({
|
|
262
|
+
version: json.time,
|
|
263
|
+
env: json.env,
|
|
264
|
+
name: json.pkgName
|
|
265
|
+
})
|
|
266
|
+
})
|
|
267
|
+
```
|
|
206
268
|
|
|
207
|
-
|
|
208
|
-
|
|
269
|
+
建议返回对象,避免业务端读取结构不稳定。
|
|
270
|
+
|
|
271
|
+
### `log`
|
|
272
|
+
|
|
273
|
+
- 类型:`(content: any) => string`
|
|
274
|
+
- 作用:自定义构建完成后的控制台输出
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
buildVersionPlugin({
|
|
278
|
+
log: (payload) => `build version: ${payload.time}`
|
|
209
279
|
})
|
|
210
280
|
```
|
|
211
281
|
|
|
212
|
-
|
|
282
|
+
## 读取版本信息
|
|
213
283
|
|
|
214
|
-
|
|
215
|
-
- `version` -> `pkgVersion`
|
|
284
|
+
### 读取全局变量
|
|
216
285
|
|
|
217
|
-
|
|
286
|
+
```ts
|
|
287
|
+
const payload = window['__VERSION__']
|
|
288
|
+
|
|
289
|
+
console.log(payload.time)
|
|
290
|
+
console.log(payload.env)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
适用于需要知道“当前页面构建版本”的场景。
|
|
294
|
+
|
|
295
|
+
### 读取 `version.json`
|
|
218
296
|
|
|
219
297
|
```ts
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
298
|
+
const response = await fetch('/version.json', {
|
|
299
|
+
cache: 'no-store'
|
|
300
|
+
})
|
|
301
|
+
const payload = await response.json()
|
|
223
302
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
303
|
+
console.log(payload.time)
|
|
304
|
+
console.log(payload.env)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
适用于和服务器上的最新版本做对比。
|
|
308
|
+
|
|
309
|
+
## 做版本检查
|
|
310
|
+
|
|
311
|
+
插件不内置版本检查 UI。推荐业务项目自行处理:
|
|
312
|
+
|
|
313
|
+
```js
|
|
314
|
+
const CHECK_INTERVAL = 60 * 1000
|
|
315
|
+
const VERSION_URL = '/version.json'
|
|
316
|
+
|
|
317
|
+
async function checkVersion() {
|
|
318
|
+
try {
|
|
319
|
+
const response = await fetch(VERSION_URL, {
|
|
320
|
+
cache: 'no-store'
|
|
229
321
|
})
|
|
230
|
-
|
|
231
|
-
|
|
322
|
+
const latestPayload = await response.json()
|
|
323
|
+
const currentPayload = window.__VERSION__
|
|
324
|
+
|
|
325
|
+
if (currentPayload && latestPayload.time !== currentPayload.time) {
|
|
326
|
+
const shouldReload = window.confirm('检测到新版本,是否刷新页面?')
|
|
327
|
+
|
|
328
|
+
if (shouldReload) {
|
|
329
|
+
window.location.reload()
|
|
330
|
+
return
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.warn('check version failed', error)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
window.setTimeout(checkVersion, CHECK_INTERVAL)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
checkVersion()
|
|
232
341
|
```
|
|
233
342
|
|
|
234
|
-
|
|
343
|
+
建议:
|
|
235
344
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
345
|
+
- 通常比较 `payload.time` 即可
|
|
346
|
+
- 请求 `version.json` 时使用 `cache: 'no-store'`
|
|
347
|
+
- 轮询间隔不要过短,通常 1 分钟或更长
|
|
348
|
+
- 弹窗、通知、静默刷新等策略放在业务项目里
|
|
349
|
+
- 请求失败后继续下一轮检查,避免一次失败中断流程
|
|
350
|
+
|
|
351
|
+
## 开发态行为
|
|
352
|
+
|
|
353
|
+
开发态下,插件不会向业务项目目录写入文件。
|
|
354
|
+
|
|
355
|
+
它会通过 Vite dev server 直接返回 JSON:
|
|
356
|
+
|
|
357
|
+
- 不污染 `public/`
|
|
358
|
+
- 不需要生成临时文件
|
|
359
|
+
- 修改插件配置后重启 dev server 即可生效
|
|
360
|
+
|
|
361
|
+
## 本地开发
|
|
362
|
+
|
|
363
|
+
仓库提供了两个调试用示例项目:
|
|
364
|
+
|
|
365
|
+
- 普通 Vite / Vue 3:`debug/fixture-app`
|
|
366
|
+
- VitePress:`debug/vitepress-app`
|
|
367
|
+
- 引用方式:直接引用根目录 `dist/index.mjs`
|
|
368
|
+
|
|
369
|
+
这意味着示例项目测试的是打包后的真实产物。
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
pnpm install
|
|
373
|
+
pnpm build
|
|
374
|
+
pnpm dev:fixture
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
调试 VitePress 示例项目:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
pnpm dev:vitepress
|
|
239
381
|
```
|
|
240
382
|
|
|
241
|
-
|
|
383
|
+
构建示例项目:
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
pnpm build:fixture
|
|
387
|
+
pnpm build:vitepress
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## 发布
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
pnpm build
|
|
394
|
+
pnpm build:fixture
|
|
395
|
+
pnpm build:vitepress
|
|
396
|
+
npm publish --access public
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
发布前建议确认:
|
|
400
|
+
|
|
401
|
+
- `dist/index.mjs` 已生成
|
|
402
|
+
- `dist/index.cjs` 已生成
|
|
403
|
+
- `dist/index.d.ts` 已生成
|
|
404
|
+
- `debug/fixture-app` 可以正常构建
|
|
405
|
+
- `debug/vitepress-app` 可以正常构建
|
|
406
|
+
- `version.json` 输出正常
|
|
407
|
+
- 普通 Vite HTML 注入正常
|
|
408
|
+
- VitePress `transformHtml` 接入后注入正常
|
|
409
|
+
|
|
410
|
+
查看最终发包内容:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
npm pack
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
正常发布包应只包含:
|
|
417
|
+
|
|
418
|
+
- `dist`
|
|
419
|
+
- `README.md`
|
|
420
|
+
- `LICENSE`
|
|
421
|
+
- `package.json`
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
# English
|
|
426
|
+
|
|
427
|
+
`vite-plugin-build-version-file` is a build metadata plugin for Vite projects.
|
|
428
|
+
|
|
429
|
+
It exposes one consistent version payload in development and production:
|
|
430
|
+
|
|
431
|
+
- serves `version.json` through the Vite dev server
|
|
432
|
+
- emits `version.json` into the build output directory
|
|
433
|
+
- injects `window["__VERSION__"]` into normal Vite HTML
|
|
434
|
+
- supports VitePress through its top-level `transformHtml` hook
|
|
435
|
+
- supports custom versions, filenames, global variable names, time zones, and extra payload fields
|
|
436
|
+
|
|
437
|
+
The plugin only generates and exposes version metadata. It does not decide how your app should check for updates or refresh the page.
|
|
438
|
+
|
|
439
|
+
It intentionally does not include:
|
|
440
|
+
|
|
441
|
+
- polling logic
|
|
442
|
+
- update prompts
|
|
443
|
+
- retry rules
|
|
444
|
+
- reload timing
|
|
445
|
+
|
|
446
|
+
Those behaviors should stay in your application code.
|
|
447
|
+
|
|
448
|
+
## Compatibility
|
|
449
|
+
|
|
450
|
+
- Vite projects
|
|
451
|
+
- Vue 3 + Vite projects
|
|
452
|
+
- VitePress projects
|
|
453
|
+
- `vite >= 5`
|
|
454
|
+
- Node.js `>= 18`
|
|
455
|
+
|
|
456
|
+
## Installation
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
pnpm add vite-plugin-build-version-file
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Or:
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
npm install vite-plugin-build-version-file
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## Quick Start
|
|
469
|
+
|
|
470
|
+
### Vite / Vue 3
|
|
242
471
|
|
|
243
472
|
```ts
|
|
244
473
|
import { defineConfig } from 'vite'
|
|
@@ -248,151 +477,275 @@ import buildVersionPlugin from 'vite-plugin-build-version-file'
|
|
|
248
477
|
export default defineConfig({
|
|
249
478
|
plugins: [
|
|
250
479
|
vue(),
|
|
251
|
-
buildVersionPlugin(
|
|
252
|
-
injectToHtml: false
|
|
253
|
-
})
|
|
480
|
+
buildVersionPlugin()
|
|
254
481
|
]
|
|
255
482
|
})
|
|
256
483
|
```
|
|
257
484
|
|
|
258
|
-
###
|
|
485
|
+
### VitePress
|
|
259
486
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
487
|
+
VitePress does not write production HTML through the same `index.html` flow as a normal Vite app. Reuse one plugin instance and pass its `transformHtml` helper to the top-level VitePress config.
|
|
488
|
+
|
|
489
|
+
```js
|
|
490
|
+
import { defineConfig } from 'vitepress'
|
|
263
491
|
import buildVersionPlugin from 'vite-plugin-build-version-file'
|
|
264
492
|
|
|
493
|
+
const buildVersion = buildVersionPlugin()
|
|
494
|
+
|
|
265
495
|
export default defineConfig({
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
})
|
|
271
|
-
]
|
|
496
|
+
vite: {
|
|
497
|
+
plugins: [buildVersion],
|
|
498
|
+
},
|
|
499
|
+
transformHtml: buildVersion.transformHtml,
|
|
272
500
|
})
|
|
273
501
|
```
|
|
274
502
|
|
|
275
|
-
|
|
503
|
+
Use the same `buildVersion` instance in both places. Calling `buildVersionPlugin()` twice creates two isolated instances, and the VitePress `transformHtml` helper will not receive the payload created during the Vite plugin lifecycle.
|
|
276
504
|
|
|
277
|
-
|
|
278
|
-
|
|
505
|
+
## Default Behavior
|
|
506
|
+
|
|
507
|
+
With default options, the plugin:
|
|
508
|
+
|
|
509
|
+
- serves `/version.json` in development
|
|
510
|
+
- emits `version.json` after build
|
|
511
|
+
- injects `window["__VERSION__"]` into HTML
|
|
512
|
+
- reads the nearest project `package.json`
|
|
513
|
+
- writes `name` as `pkgName`
|
|
514
|
+
- writes `version` as `pkgVersion`
|
|
515
|
+
- uses `0` as the development version
|
|
516
|
+
- uses `YYYYMMDDHHmmss` as the production version
|
|
517
|
+
- uses `Asia/Shanghai` as the default time zone
|
|
518
|
+
|
|
519
|
+
Production payload example:
|
|
520
|
+
|
|
521
|
+
```json
|
|
522
|
+
{
|
|
523
|
+
"pkgName": "your-app-name",
|
|
524
|
+
"pkgVersion": "1.0.0",
|
|
525
|
+
"time": "20260401153045",
|
|
526
|
+
"env": "production"
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
Development payload example:
|
|
531
|
+
|
|
532
|
+
```json
|
|
533
|
+
{
|
|
534
|
+
"pkgName": "your-app-name",
|
|
535
|
+
"pkgVersion": "1.0.0",
|
|
536
|
+
"time": 0,
|
|
537
|
+
"env": "development"
|
|
538
|
+
}
|
|
279
539
|
```
|
|
280
540
|
|
|
281
|
-
|
|
541
|
+
## Options
|
|
282
542
|
|
|
283
543
|
```ts
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
544
|
+
type BuildVersionContext = {
|
|
545
|
+
command: 'serve' | 'build'
|
|
546
|
+
mode: string
|
|
547
|
+
}
|
|
287
548
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
549
|
+
type BuildVersionPluginOptions = {
|
|
550
|
+
filename?: string
|
|
551
|
+
globalName?: string
|
|
552
|
+
injectToHtml?: boolean
|
|
553
|
+
timeZone?: string
|
|
554
|
+
version?: string | number | ((ctx: BuildVersionContext) => string | number)
|
|
555
|
+
data?: Record<string, any>
|
|
556
|
+
log?: (content: any) => string
|
|
557
|
+
payload?: (json: any) => any
|
|
558
|
+
}
|
|
559
|
+
```
|
|
296
560
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
561
|
+
### `filename`
|
|
562
|
+
|
|
563
|
+
- Type: `string`
|
|
564
|
+
- Default: `"version.json"`
|
|
565
|
+
- Controls the dev URL and build output path.
|
|
566
|
+
|
|
567
|
+
```ts
|
|
568
|
+
buildVersionPlugin({
|
|
569
|
+
filename: 'meta/version.json'
|
|
301
570
|
})
|
|
302
571
|
```
|
|
303
572
|
|
|
304
|
-
|
|
573
|
+
Build output:
|
|
574
|
+
|
|
575
|
+
```text
|
|
576
|
+
dist/meta/version.json
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
Development URL:
|
|
580
|
+
|
|
581
|
+
```text
|
|
582
|
+
/meta/version.json
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
If your project configures Vite `base`, the URL follows that base.
|
|
586
|
+
|
|
587
|
+
### `globalName`
|
|
588
|
+
|
|
589
|
+
- Type: `string`
|
|
590
|
+
- Default: `"__VERSION__"`
|
|
591
|
+
- Controls the property name injected on `window`.
|
|
592
|
+
|
|
593
|
+
Default injection:
|
|
594
|
+
|
|
595
|
+
```html
|
|
596
|
+
<script>
|
|
597
|
+
window["__VERSION__"] = { "time": "20260401153045", "env": "production" };
|
|
598
|
+
</script>
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
The injected value is the full payload object, not a single version string.
|
|
602
|
+
|
|
603
|
+
### `injectToHtml`
|
|
604
|
+
|
|
605
|
+
- Type: `boolean`
|
|
606
|
+
- Default: `true`
|
|
607
|
+
- Controls whether the plugin injects `window["__VERSION__"]`.
|
|
608
|
+
|
|
609
|
+
When set to `false`, `version.json` is still served and emitted.
|
|
610
|
+
|
|
611
|
+
### `timeZone`
|
|
612
|
+
|
|
613
|
+
- Type: `string`
|
|
614
|
+
- Default: `"Asia/Shanghai"`
|
|
615
|
+
- Controls the time zone used by the default production timestamp.
|
|
616
|
+
|
|
617
|
+
This only affects the default `time`. If you pass `version`, your custom logic wins.
|
|
618
|
+
|
|
619
|
+
### `version`
|
|
620
|
+
|
|
621
|
+
- Type: `string | number | ((ctx) => string | number)`
|
|
622
|
+
- Default: `0` in development, current timestamp in production
|
|
623
|
+
- Provides custom version generation.
|
|
305
624
|
|
|
306
625
|
```ts
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
626
|
+
buildVersionPlugin({
|
|
627
|
+
version: ({ command, mode }) => {
|
|
628
|
+
if (command === 'serve') {
|
|
629
|
+
return 0
|
|
630
|
+
}
|
|
310
631
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
vue(),
|
|
314
|
-
buildVersionPlugin({
|
|
315
|
-
data: {
|
|
316
|
-
appName: 'admin',
|
|
317
|
-
gitBranch: 'release/2026-04',
|
|
318
|
-
commitSha: 'abc1234'
|
|
319
|
-
}
|
|
320
|
-
})
|
|
321
|
-
]
|
|
632
|
+
return `${mode}-20260401153045`
|
|
633
|
+
}
|
|
322
634
|
})
|
|
323
635
|
```
|
|
324
636
|
|
|
325
|
-
|
|
637
|
+
### `data`
|
|
638
|
+
|
|
639
|
+
- Type: `Record<string, any>`
|
|
640
|
+
- Default: `{}`
|
|
641
|
+
- Adds custom fields to the final payload.
|
|
642
|
+
|
|
643
|
+
```ts
|
|
644
|
+
buildVersionPlugin({
|
|
645
|
+
data: {
|
|
646
|
+
appName: 'admin',
|
|
647
|
+
gitBranch: 'release/2026-04',
|
|
648
|
+
commitSha: 'abc1234'
|
|
649
|
+
}
|
|
650
|
+
})
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
Example output:
|
|
326
654
|
|
|
327
655
|
```json
|
|
328
656
|
{
|
|
329
657
|
"appName": "admin",
|
|
330
658
|
"gitBranch": "release/2026-04",
|
|
331
659
|
"commitSha": "abc1234",
|
|
660
|
+
"pkgName": "your-app-name",
|
|
661
|
+
"pkgVersion": "1.0.0",
|
|
332
662
|
"time": "20260401153045",
|
|
333
663
|
"env": "production"
|
|
334
664
|
}
|
|
335
665
|
```
|
|
336
666
|
|
|
337
|
-
|
|
667
|
+
Merge order:
|
|
338
668
|
|
|
339
|
-
|
|
669
|
+
- `data` is written first
|
|
670
|
+
- `pkgName` and `pkgVersion` from `package.json` override matching fields
|
|
671
|
+
- `time` and `env` from the plugin override matching fields
|
|
672
|
+
- `payload` can rewrite the final object
|
|
340
673
|
|
|
341
|
-
###
|
|
674
|
+
### `payload`
|
|
342
675
|
|
|
343
|
-
|
|
344
|
-
|
|
676
|
+
- Type: `(json: any) => any`
|
|
677
|
+
- Rewrites the final payload.
|
|
345
678
|
|
|
346
|
-
|
|
347
|
-
|
|
679
|
+
Use it to trim fields, rename fields, or keep compatibility with an older contract.
|
|
680
|
+
|
|
681
|
+
```ts
|
|
682
|
+
buildVersionPlugin({
|
|
683
|
+
payload: (json) => ({
|
|
684
|
+
version: json.time,
|
|
685
|
+
env: json.env,
|
|
686
|
+
name: json.pkgName
|
|
687
|
+
})
|
|
688
|
+
})
|
|
348
689
|
```
|
|
349
690
|
|
|
350
|
-
|
|
691
|
+
Returning an object is recommended so application reads stay stable.
|
|
351
692
|
|
|
352
|
-
|
|
353
|
-
- 这里读到的是完整对象,不是单独字符串
|
|
354
|
-
- 如果配置了 `data`,这里也可以直接读取对应字段
|
|
693
|
+
### `log`
|
|
355
694
|
|
|
356
|
-
|
|
695
|
+
- Type: `(content: any) => string`
|
|
696
|
+
- Customizes the build-complete console output.
|
|
357
697
|
|
|
358
698
|
```ts
|
|
359
|
-
|
|
360
|
-
|
|
699
|
+
buildVersionPlugin({
|
|
700
|
+
log: (payload) => `build version: ${payload.time}`
|
|
701
|
+
})
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
## Reading Version Metadata
|
|
705
|
+
|
|
706
|
+
### Read the injected global
|
|
707
|
+
|
|
708
|
+
```ts
|
|
709
|
+
const payload = window['__VERSION__']
|
|
361
710
|
|
|
362
711
|
console.log(payload.time)
|
|
363
712
|
console.log(payload.env)
|
|
364
713
|
```
|
|
365
714
|
|
|
366
|
-
|
|
715
|
+
Use this when you need the version of the currently loaded page.
|
|
367
716
|
|
|
368
|
-
|
|
717
|
+
### Read `version.json`
|
|
369
718
|
|
|
370
|
-
|
|
719
|
+
```ts
|
|
720
|
+
const response = await fetch('/version.json', {
|
|
721
|
+
cache: 'no-store'
|
|
722
|
+
})
|
|
723
|
+
const payload = await response.json()
|
|
371
724
|
|
|
372
|
-
|
|
373
|
-
|
|
725
|
+
console.log(payload.time)
|
|
726
|
+
console.log(payload.env)
|
|
727
|
+
```
|
|
374
728
|
|
|
375
|
-
|
|
729
|
+
Use this when you need to compare the current page against the latest deployed version.
|
|
376
730
|
|
|
377
|
-
|
|
731
|
+
## Checking for Updates
|
|
378
732
|
|
|
379
|
-
|
|
733
|
+
The plugin does not include update-checking UI. Keep that logic in your app.
|
|
380
734
|
|
|
381
735
|
```js
|
|
382
736
|
const CHECK_INTERVAL = 60 * 1000
|
|
383
|
-
const VERSION_URL =
|
|
737
|
+
const VERSION_URL = '/version.json'
|
|
384
738
|
|
|
385
739
|
async function checkVersion() {
|
|
386
740
|
try {
|
|
387
741
|
const response = await fetch(VERSION_URL, {
|
|
388
742
|
cache: 'no-store'
|
|
389
743
|
})
|
|
390
|
-
|
|
391
|
-
const payload = await response.json()
|
|
744
|
+
const latestPayload = await response.json()
|
|
392
745
|
const currentPayload = window.__VERSION__
|
|
393
746
|
|
|
394
|
-
if (currentPayload &&
|
|
395
|
-
const shouldReload =
|
|
747
|
+
if (currentPayload && latestPayload.time !== currentPayload.time) {
|
|
748
|
+
const shouldReload = window.confirm('A new version is available. Reload now?')
|
|
396
749
|
|
|
397
750
|
if (shouldReload) {
|
|
398
751
|
window.location.reload()
|
|
@@ -403,126 +756,86 @@ async function checkVersion() {
|
|
|
403
756
|
console.warn('check version failed', error)
|
|
404
757
|
}
|
|
405
758
|
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
function scheduleNextCheck() {
|
|
410
|
-
setTimeout(checkVersion, CHECK_INTERVAL)
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function showUpdatePrompt() {
|
|
414
|
-
// 这里替换成你自己的弹窗、消息组件或确认框
|
|
415
|
-
return Promise.resolve(window.confirm('检测到新版本,是否刷新页面?'))
|
|
759
|
+
window.setTimeout(checkVersion, CHECK_INTERVAL)
|
|
416
760
|
}
|
|
417
761
|
|
|
418
762
|
checkVersion()
|
|
419
763
|
```
|
|
420
764
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
- 版本比较只判断 `payload.time` 和当前页面里的 `window.__VERSION__.time` 是否一致
|
|
424
|
-
- 提示方式由业务项目自己决定,可以是弹窗、消息条、通知或静默刷新
|
|
425
|
-
- 轮询间隔不要过短,通常用 1 分钟或更长更合适
|
|
426
|
-
- 请求失败后继续下一轮检查,避免一次失败后整个流程中断
|
|
427
|
-
|
|
428
|
-
上面这段逻辑故意没有放进插件里,因为不同项目通常会有不同要求:
|
|
429
|
-
|
|
430
|
-
- 轮询频率不同
|
|
431
|
-
- 请求路径可能不同
|
|
432
|
-
- 弹窗组件不同
|
|
433
|
-
- 刷新策略不同
|
|
434
|
-
- 失败重试策略不同
|
|
765
|
+
Recommendations:
|
|
435
766
|
|
|
436
|
-
|
|
767
|
+
- Compare `payload.time` in most cases.
|
|
768
|
+
- Fetch `version.json` with `cache: 'no-store'`.
|
|
769
|
+
- Avoid very short polling intervals. One minute or longer is usually enough.
|
|
770
|
+
- Keep prompts, notifications, silent reloads, and retry rules in application code.
|
|
771
|
+
- Continue polling after failed requests.
|
|
437
772
|
|
|
438
|
-
|
|
773
|
+
## Development Behavior
|
|
439
774
|
|
|
440
|
-
|
|
775
|
+
In development, the plugin does not write files into your project directory.
|
|
441
776
|
|
|
442
|
-
|
|
443
|
-
- 更适合本地调试
|
|
444
|
-
- 修改配置后重新启动 dev server 即可看到结果
|
|
777
|
+
It serves JSON directly through the Vite dev server:
|
|
445
778
|
|
|
446
|
-
|
|
779
|
+
- no `public/` pollution
|
|
780
|
+
- no temporary file generation
|
|
781
|
+
- restart the dev server after changing plugin options
|
|
447
782
|
|
|
448
|
-
##
|
|
783
|
+
## Local Development
|
|
449
784
|
|
|
450
|
-
|
|
785
|
+
The repository contains two fixture apps:
|
|
451
786
|
|
|
452
|
-
-
|
|
453
|
-
-
|
|
454
|
-
|
|
455
|
-
这意味着它测试的是“打包后的真实产物”,而不是源码直连。
|
|
787
|
+
- Vite / Vue 3: `debug/fixture-app`
|
|
788
|
+
- VitePress: `debug/vitepress-app`
|
|
789
|
+
- They import the built package from `dist/index.mjs`
|
|
456
790
|
|
|
457
|
-
|
|
791
|
+
This verifies the real build output instead of importing source files directly.
|
|
458
792
|
|
|
459
793
|
```bash
|
|
460
794
|
pnpm install
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
### 构建插件
|
|
464
|
-
|
|
465
|
-
```bash
|
|
466
795
|
pnpm build
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
### 启动测试项目
|
|
470
|
-
|
|
471
|
-
```bash
|
|
472
796
|
pnpm dev:fixture
|
|
473
797
|
```
|
|
474
798
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
- `window["__VERSION__"]`
|
|
478
|
-
- `/version.json` 的返回结果
|
|
479
|
-
|
|
480
|
-
### 构建测试项目
|
|
799
|
+
Run the VitePress fixture:
|
|
481
800
|
|
|
482
801
|
```bash
|
|
483
|
-
pnpm
|
|
802
|
+
pnpm dev:vitepress
|
|
484
803
|
```
|
|
485
804
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
## 发布到 npm
|
|
489
|
-
|
|
490
|
-
### 1. 登录 npm
|
|
805
|
+
Build fixture apps:
|
|
491
806
|
|
|
492
807
|
```bash
|
|
493
|
-
|
|
808
|
+
pnpm build:fixture
|
|
809
|
+
pnpm build:vitepress
|
|
494
810
|
```
|
|
495
811
|
|
|
496
|
-
|
|
812
|
+
## Publishing
|
|
497
813
|
|
|
498
814
|
```bash
|
|
499
815
|
pnpm build
|
|
500
816
|
pnpm build:fixture
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
### 3. 发布公开包
|
|
504
|
-
|
|
505
|
-
```bash
|
|
817
|
+
pnpm build:vitepress
|
|
506
818
|
npm publish --access public
|
|
507
819
|
```
|
|
508
820
|
|
|
509
|
-
|
|
821
|
+
Before publishing, check:
|
|
510
822
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
- `dist/index.
|
|
514
|
-
-
|
|
515
|
-
-
|
|
516
|
-
-
|
|
517
|
-
-
|
|
823
|
+
- `dist/index.mjs`
|
|
824
|
+
- `dist/index.cjs`
|
|
825
|
+
- `dist/index.d.ts`
|
|
826
|
+
- fixture app build
|
|
827
|
+
- VitePress fixture build
|
|
828
|
+
- `version.json` output
|
|
829
|
+
- normal Vite HTML injection
|
|
830
|
+
- VitePress `transformHtml` injection
|
|
518
831
|
|
|
519
|
-
|
|
832
|
+
Inspect the publish package:
|
|
520
833
|
|
|
521
834
|
```bash
|
|
522
835
|
npm pack
|
|
523
836
|
```
|
|
524
837
|
|
|
525
|
-
|
|
838
|
+
The package should contain:
|
|
526
839
|
|
|
527
840
|
- `dist`
|
|
528
841
|
- `README.md`
|