vite-plugin-build-version-file 0.1.4 → 0.1.6
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 +109 -17
- package/dist/index.cjs +51 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +51 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- 构建产物中生成 `version.json`
|
|
8
8
|
- 可选地向 HTML 注入 `window["__VERSION__"]`
|
|
9
9
|
- 通过 `import.meta.env.__VERSION__` 在代码中直接读取版本号
|
|
10
|
-
-
|
|
10
|
+
- 支持自定义版本号、文件名、全局变量名和额外数据
|
|
11
11
|
|
|
12
12
|
这个插件只负责产出和暴露版本信息。
|
|
13
13
|
|
|
@@ -62,6 +62,7 @@ export default defineConfig({
|
|
|
62
62
|
- 开发态访问 `/version.json` 时返回版本信息
|
|
63
63
|
- 构建后在输出目录生成 `version.json`
|
|
64
64
|
- 构建后的 HTML 中注入 `window["__VERSION__"]`
|
|
65
|
+
- 自动尝试读取业务项目 `package.json` 中的 `name` 和 `version`
|
|
65
66
|
- 开发态默认版本号为 `0`
|
|
66
67
|
- 构建态默认版本号为当前时间戳,格式为 `YYYYMMDDHHmmss`
|
|
67
68
|
|
|
@@ -69,7 +70,9 @@ export default defineConfig({
|
|
|
69
70
|
|
|
70
71
|
```json
|
|
71
72
|
{
|
|
72
|
-
"
|
|
73
|
+
"pkgName": "your-app-name",
|
|
74
|
+
"pkgVersion": "1.0.0",
|
|
75
|
+
"time": "20260401153045",
|
|
73
76
|
"env": "production"
|
|
74
77
|
}
|
|
75
78
|
```
|
|
@@ -78,7 +81,9 @@ export default defineConfig({
|
|
|
78
81
|
|
|
79
82
|
```json
|
|
80
83
|
{
|
|
81
|
-
"
|
|
84
|
+
"pkgName": "your-app-name",
|
|
85
|
+
"pkgVersion": "1.0.0",
|
|
86
|
+
"time": 0,
|
|
82
87
|
"env": "development"
|
|
83
88
|
}
|
|
84
89
|
```
|
|
@@ -119,6 +124,7 @@ type BuildVersionPluginOptions = {
|
|
|
119
124
|
globalName?: string
|
|
120
125
|
injectToHtml?: boolean
|
|
121
126
|
version?: string | number | ((ctx: BuildVersionContext) => string | number)
|
|
127
|
+
data?: Record<string, any>
|
|
122
128
|
}
|
|
123
129
|
```
|
|
124
130
|
|
|
@@ -144,7 +150,7 @@ type BuildVersionPluginOptions = {
|
|
|
144
150
|
|
|
145
151
|
```html
|
|
146
152
|
<script>
|
|
147
|
-
window["__VERSION__"] = { "
|
|
153
|
+
window["__VERSION__"] = { "time": "20260401153045", "env": "production" };
|
|
148
154
|
</script>
|
|
149
155
|
```
|
|
150
156
|
|
|
@@ -176,6 +182,20 @@ type BuildVersionPluginOptions = {
|
|
|
176
182
|
}
|
|
177
183
|
```
|
|
178
184
|
|
|
185
|
+
### `data`
|
|
186
|
+
|
|
187
|
+
- 类型:`Record<string, any>`
|
|
188
|
+
- 默认值:`{}`
|
|
189
|
+
- 作用:向最终生成的版本信息对象中追加自定义字段
|
|
190
|
+
|
|
191
|
+
说明:
|
|
192
|
+
|
|
193
|
+
- 插件会自动从业务项目的 `package.json` 中读取 `name` 和 `version`,分别写入 `pkgName` 和 `pkgVersion`
|
|
194
|
+
- 查找位置是从当前 Vite 项目根目录开始,向上寻找最近的 `package.json`
|
|
195
|
+
- 会同时影响开发态接口返回、构建产物中的 `version.json` 和注入到 `window` 的对象
|
|
196
|
+
- 如果 `data` 里存在 `time` 或 `env` 同名字段,最终仍以插件生成的值为准
|
|
197
|
+
- 如果 `data` 里存在 `pkgName` 或 `pkgVersion`,读取到业务项目 `package.json` 时会以自动读取的值为准;读取不到时会保留 `data` 里的值
|
|
198
|
+
|
|
179
199
|
## 使用示例
|
|
180
200
|
|
|
181
201
|
### 1. 使用默认配置
|
|
@@ -190,6 +210,11 @@ export default defineConfig({
|
|
|
190
210
|
})
|
|
191
211
|
```
|
|
192
212
|
|
|
213
|
+
默认情况下,插件会尝试从业务项目的 `package.json` 中读取:
|
|
214
|
+
|
|
215
|
+
- `name` -> `pkgName`
|
|
216
|
+
- `version` -> `pkgVersion`
|
|
217
|
+
|
|
193
218
|
### 2. 自定义全局变量名
|
|
194
219
|
|
|
195
220
|
```ts
|
|
@@ -211,7 +236,7 @@ export default defineConfig({
|
|
|
211
236
|
|
|
212
237
|
```ts
|
|
213
238
|
const payload = window['__APP_VERSION__']
|
|
214
|
-
const
|
|
239
|
+
const time = payload.time
|
|
215
240
|
```
|
|
216
241
|
|
|
217
242
|
### 3. 只保留 `version.json`,不注入 `window`
|
|
@@ -277,6 +302,39 @@ export default defineConfig({
|
|
|
277
302
|
})
|
|
278
303
|
```
|
|
279
304
|
|
|
305
|
+
### 6. 追加自定义数据
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
import { defineConfig } from 'vite'
|
|
309
|
+
import vue from '@vitejs/plugin-vue'
|
|
310
|
+
import buildVersionPlugin from 'vite-plugin-build-version-file'
|
|
311
|
+
|
|
312
|
+
export default defineConfig({
|
|
313
|
+
plugins: [
|
|
314
|
+
vue(),
|
|
315
|
+
buildVersionPlugin({
|
|
316
|
+
data: {
|
|
317
|
+
appName: 'admin',
|
|
318
|
+
gitBranch: 'release/2026-04',
|
|
319
|
+
commitSha: 'abc1234'
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
]
|
|
323
|
+
})
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
生成结果示例:
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{
|
|
330
|
+
"appName": "admin",
|
|
331
|
+
"gitBranch": "release/2026-04",
|
|
332
|
+
"commitSha": "abc1234",
|
|
333
|
+
"time": "20260401153045",
|
|
334
|
+
"env": "production"
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
280
338
|
## 在项目中读取版本
|
|
281
339
|
|
|
282
340
|
插件提供三种方式读取版本号,可根据场景选择:
|
|
@@ -313,7 +371,7 @@ interface ImportMeta {
|
|
|
313
371
|
```ts
|
|
314
372
|
const payload = window['__VERSION__']
|
|
315
373
|
|
|
316
|
-
console.log(payload.
|
|
374
|
+
console.log(payload.time)
|
|
317
375
|
console.log(payload.env)
|
|
318
376
|
```
|
|
319
377
|
|
|
@@ -321,6 +379,7 @@ console.log(payload.env)
|
|
|
321
379
|
|
|
322
380
|
- 需要确保 `injectToHtml` 为 `true`(默认值)
|
|
323
381
|
- 这里读到的是完整对象,不是单独字符串
|
|
382
|
+
- 如果配置了 `data`,这里也可以直接读取对应字段
|
|
324
383
|
|
|
325
384
|
### 方式三:读取 `version.json`
|
|
326
385
|
|
|
@@ -328,38 +387,71 @@ console.log(payload.env)
|
|
|
328
387
|
const response = await fetch('/version.json')
|
|
329
388
|
const payload = await response.json()
|
|
330
389
|
|
|
331
|
-
console.log(payload.
|
|
390
|
+
console.log(payload.time)
|
|
332
391
|
console.log(payload.env)
|
|
333
392
|
```
|
|
334
393
|
|
|
335
394
|
如果你配置了自定义 `filename`,这里的请求路径也需要改成对应地址。
|
|
336
395
|
|
|
396
|
+
如果你配置了 `data`,返回结果中也会包含这些额外字段。
|
|
397
|
+
|
|
398
|
+
默认情况下,如果业务项目存在 `package.json`,返回结果中也会包含:
|
|
399
|
+
|
|
400
|
+
- `pkgName`
|
|
401
|
+
- `pkgVersion`
|
|
402
|
+
|
|
337
403
|
## 在项目中做版本检查
|
|
338
404
|
|
|
339
405
|
推荐把“检查新版本并提示刷新”的逻辑写在业务项目里。
|
|
340
406
|
|
|
341
|
-
|
|
407
|
+
通用伪代码:
|
|
408
|
+
|
|
409
|
+
```js
|
|
410
|
+
const CHECK_INTERVAL = 60 * 1000
|
|
411
|
+
const VERSION_URL = `${import.meta.env.VITE_BASE_PATH}/version.json`
|
|
342
412
|
|
|
343
|
-
```ts
|
|
344
413
|
async function checkVersion() {
|
|
345
|
-
|
|
346
|
-
|
|
414
|
+
try {
|
|
415
|
+
const response = await fetch(VERSION_URL, {
|
|
416
|
+
cache: 'no-store'
|
|
417
|
+
})
|
|
347
418
|
|
|
348
|
-
|
|
349
|
-
const shouldReload = window.confirm('检测到新版本,是否刷新页面?')
|
|
419
|
+
const payload = await response.json()
|
|
350
420
|
|
|
351
|
-
if (
|
|
352
|
-
|
|
353
|
-
|
|
421
|
+
if (payload.time !== import.meta.env.__VERSION__) {
|
|
422
|
+
const shouldReload = await showUpdatePrompt()
|
|
423
|
+
|
|
424
|
+
if (shouldReload) {
|
|
425
|
+
window.location.reload()
|
|
426
|
+
return
|
|
427
|
+
}
|
|
354
428
|
}
|
|
429
|
+
} catch (error) {
|
|
430
|
+
console.warn('check version failed', error)
|
|
355
431
|
}
|
|
356
432
|
|
|
357
|
-
|
|
433
|
+
scheduleNextCheck()
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function scheduleNextCheck() {
|
|
437
|
+
setTimeout(checkVersion, CHECK_INTERVAL)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function showUpdatePrompt() {
|
|
441
|
+
// 这里替换成你自己的弹窗、消息组件或确认框
|
|
442
|
+
return Promise.resolve(window.confirm('检测到新版本,是否刷新页面?'))
|
|
358
443
|
}
|
|
359
444
|
|
|
360
445
|
checkVersion()
|
|
361
446
|
```
|
|
362
447
|
|
|
448
|
+
建议:
|
|
449
|
+
|
|
450
|
+
- 版本比较只判断 `payload.time` 和 `import.meta.env.__VERSION__` 是否一致
|
|
451
|
+
- 提示方式由业务项目自己决定,可以是弹窗、消息条、通知或静默刷新
|
|
452
|
+
- 轮询间隔不要过短,通常用 1 分钟或更长更合适
|
|
453
|
+
- 请求失败后继续下一轮检查,避免一次失败后整个流程中断
|
|
454
|
+
|
|
363
455
|
上面这段逻辑故意没有放进插件里,因为不同项目通常会有不同要求:
|
|
364
456
|
|
|
365
457
|
- 轮询频率不同
|
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,8 @@ __export(index_exports, {
|
|
|
24
24
|
default: () => index_default
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
var import_node_fs = require("fs");
|
|
28
|
+
var import_node_path = require("path");
|
|
27
29
|
var PLUGIN_NAME = "vite-plugin-build-version-file";
|
|
28
30
|
var DEFAULT_FILENAME = "version.json";
|
|
29
31
|
var DEFAULT_GLOBAL_NAME = "__VERSION__";
|
|
@@ -55,6 +57,49 @@ function normalizeGlobalName(globalName) {
|
|
|
55
57
|
}
|
|
56
58
|
return globalName;
|
|
57
59
|
}
|
|
60
|
+
function normalizeData(data) {
|
|
61
|
+
if (data === void 0) {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
if (!data || Array.isArray(data) || typeof data !== "object") {
|
|
65
|
+
throw new Error(`[${PLUGIN_NAME}] "data" must be a plain object.`);
|
|
66
|
+
}
|
|
67
|
+
return data;
|
|
68
|
+
}
|
|
69
|
+
function findNearestPackageJson(root) {
|
|
70
|
+
let currentDir = root;
|
|
71
|
+
while (true) {
|
|
72
|
+
const packageJsonPath = (0, import_node_path.join)(currentDir, "package.json");
|
|
73
|
+
if ((0, import_node_fs.existsSync)(packageJsonPath)) {
|
|
74
|
+
return packageJsonPath;
|
|
75
|
+
}
|
|
76
|
+
const parentDir = (0, import_node_path.dirname)(currentDir);
|
|
77
|
+
if (parentDir === currentDir) {
|
|
78
|
+
return void 0;
|
|
79
|
+
}
|
|
80
|
+
currentDir = parentDir;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function readPackageInfo(root) {
|
|
84
|
+
const packageJsonPath = findNearestPackageJson(root);
|
|
85
|
+
if (!packageJsonPath) {
|
|
86
|
+
return {};
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const content = (0, import_node_fs.readFileSync)(packageJsonPath, "utf-8");
|
|
90
|
+
const packageJson = JSON.parse(content);
|
|
91
|
+
const packageInfo = {};
|
|
92
|
+
if (packageJson.name !== void 0) {
|
|
93
|
+
packageInfo.pkgName = packageJson.name;
|
|
94
|
+
}
|
|
95
|
+
if (packageJson.version !== void 0) {
|
|
96
|
+
packageInfo.pkgVersion = packageJson.version;
|
|
97
|
+
}
|
|
98
|
+
return packageInfo;
|
|
99
|
+
} catch {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
58
103
|
function serializePayload(payload) {
|
|
59
104
|
return `${JSON.stringify(payload, null, 2)}
|
|
60
105
|
`;
|
|
@@ -77,6 +122,8 @@ function buildVersionPlugin(options = {}) {
|
|
|
77
122
|
options.globalName ?? DEFAULT_GLOBAL_NAME
|
|
78
123
|
);
|
|
79
124
|
const injectToHtml = options.injectToHtml ?? true;
|
|
125
|
+
const data = normalizeData(options.data);
|
|
126
|
+
let packageInfo = {};
|
|
80
127
|
let payload;
|
|
81
128
|
return {
|
|
82
129
|
name: PLUGIN_NAME,
|
|
@@ -100,6 +147,7 @@ function buildVersionPlugin(options = {}) {
|
|
|
100
147
|
};
|
|
101
148
|
},
|
|
102
149
|
configResolved(config) {
|
|
150
|
+
packageInfo = readPackageInfo(config.root);
|
|
103
151
|
const context = {
|
|
104
152
|
command: config.command,
|
|
105
153
|
mode: config.mode
|
|
@@ -113,7 +161,9 @@ function buildVersionPlugin(options = {}) {
|
|
|
113
161
|
version = createDefaultVersion(context.command);
|
|
114
162
|
}
|
|
115
163
|
payload = {
|
|
116
|
-
|
|
164
|
+
...data,
|
|
165
|
+
...packageInfo,
|
|
166
|
+
time: version,
|
|
117
167
|
env: config.mode
|
|
118
168
|
};
|
|
119
169
|
if (options.payload) {
|
package/dist/index.d.cts
CHANGED
|
@@ -5,14 +5,16 @@ interface BuildVersionContext {
|
|
|
5
5
|
mode: string;
|
|
6
6
|
}
|
|
7
7
|
interface BuildVersionPayload {
|
|
8
|
-
|
|
8
|
+
time: string | number;
|
|
9
9
|
env: string;
|
|
10
|
+
[key: string]: any;
|
|
10
11
|
}
|
|
11
12
|
interface BuildVersionPluginOptions {
|
|
12
13
|
filename?: string;
|
|
13
14
|
globalName?: string;
|
|
14
15
|
injectToHtml?: boolean;
|
|
15
16
|
version?: string | number | ((ctx: BuildVersionContext) => string | number);
|
|
17
|
+
data?: Record<string, any>;
|
|
16
18
|
log?: (content: any) => string;
|
|
17
19
|
payload?: (json: any) => any;
|
|
18
20
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,14 +5,16 @@ interface BuildVersionContext {
|
|
|
5
5
|
mode: string;
|
|
6
6
|
}
|
|
7
7
|
interface BuildVersionPayload {
|
|
8
|
-
|
|
8
|
+
time: string | number;
|
|
9
9
|
env: string;
|
|
10
|
+
[key: string]: any;
|
|
10
11
|
}
|
|
11
12
|
interface BuildVersionPluginOptions {
|
|
12
13
|
filename?: string;
|
|
13
14
|
globalName?: string;
|
|
14
15
|
injectToHtml?: boolean;
|
|
15
16
|
version?: string | number | ((ctx: BuildVersionContext) => string | number);
|
|
17
|
+
data?: Record<string, any>;
|
|
16
18
|
log?: (content: any) => string;
|
|
17
19
|
payload?: (json: any) => any;
|
|
18
20
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
2
4
|
var PLUGIN_NAME = "vite-plugin-build-version-file";
|
|
3
5
|
var DEFAULT_FILENAME = "version.json";
|
|
4
6
|
var DEFAULT_GLOBAL_NAME = "__VERSION__";
|
|
@@ -30,6 +32,49 @@ function normalizeGlobalName(globalName) {
|
|
|
30
32
|
}
|
|
31
33
|
return globalName;
|
|
32
34
|
}
|
|
35
|
+
function normalizeData(data) {
|
|
36
|
+
if (data === void 0) {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
if (!data || Array.isArray(data) || typeof data !== "object") {
|
|
40
|
+
throw new Error(`[${PLUGIN_NAME}] "data" must be a plain object.`);
|
|
41
|
+
}
|
|
42
|
+
return data;
|
|
43
|
+
}
|
|
44
|
+
function findNearestPackageJson(root) {
|
|
45
|
+
let currentDir = root;
|
|
46
|
+
while (true) {
|
|
47
|
+
const packageJsonPath = join(currentDir, "package.json");
|
|
48
|
+
if (existsSync(packageJsonPath)) {
|
|
49
|
+
return packageJsonPath;
|
|
50
|
+
}
|
|
51
|
+
const parentDir = dirname(currentDir);
|
|
52
|
+
if (parentDir === currentDir) {
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
currentDir = parentDir;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function readPackageInfo(root) {
|
|
59
|
+
const packageJsonPath = findNearestPackageJson(root);
|
|
60
|
+
if (!packageJsonPath) {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
65
|
+
const packageJson = JSON.parse(content);
|
|
66
|
+
const packageInfo = {};
|
|
67
|
+
if (packageJson.name !== void 0) {
|
|
68
|
+
packageInfo.pkgName = packageJson.name;
|
|
69
|
+
}
|
|
70
|
+
if (packageJson.version !== void 0) {
|
|
71
|
+
packageInfo.pkgVersion = packageJson.version;
|
|
72
|
+
}
|
|
73
|
+
return packageInfo;
|
|
74
|
+
} catch {
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
33
78
|
function serializePayload(payload) {
|
|
34
79
|
return `${JSON.stringify(payload, null, 2)}
|
|
35
80
|
`;
|
|
@@ -52,6 +97,8 @@ function buildVersionPlugin(options = {}) {
|
|
|
52
97
|
options.globalName ?? DEFAULT_GLOBAL_NAME
|
|
53
98
|
);
|
|
54
99
|
const injectToHtml = options.injectToHtml ?? true;
|
|
100
|
+
const data = normalizeData(options.data);
|
|
101
|
+
let packageInfo = {};
|
|
55
102
|
let payload;
|
|
56
103
|
return {
|
|
57
104
|
name: PLUGIN_NAME,
|
|
@@ -75,6 +122,7 @@ function buildVersionPlugin(options = {}) {
|
|
|
75
122
|
};
|
|
76
123
|
},
|
|
77
124
|
configResolved(config) {
|
|
125
|
+
packageInfo = readPackageInfo(config.root);
|
|
78
126
|
const context = {
|
|
79
127
|
command: config.command,
|
|
80
128
|
mode: config.mode
|
|
@@ -88,7 +136,9 @@ function buildVersionPlugin(options = {}) {
|
|
|
88
136
|
version = createDefaultVersion(context.command);
|
|
89
137
|
}
|
|
90
138
|
payload = {
|
|
91
|
-
|
|
139
|
+
...data,
|
|
140
|
+
...packageInfo,
|
|
141
|
+
time: version,
|
|
92
142
|
env: config.mode
|
|
93
143
|
};
|
|
94
144
|
if (options.payload) {
|