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 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
- "version": "20260401153045",
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
- "version": 0,
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__"] = { "version": "20260401153045", "env": "production" };
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 version = payload.version
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.version)
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.version)
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
- const response = await fetch(import.meta.env.VITE_BASE_PATH + '/version.json')
346
- const payload = await response.json()
414
+ try {
415
+ const response = await fetch(VERSION_URL, {
416
+ cache: 'no-store'
417
+ })
347
418
 
348
- if (payload.version !== import.meta.env.__VERSION__) {
349
- const shouldReload = window.confirm('检测到新版本,是否刷新页面?')
419
+ const payload = await response.json()
350
420
 
351
- if (shouldReload) {
352
- window.location.reload()
353
- return
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
- setTimeout(checkVersion, 1000)
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
- version,
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
- version: string | number;
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
- version: string | number;
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
- version,
139
+ ...data,
140
+ ...packageInfo,
141
+ time: version,
92
142
  env: config.mode
93
143
  };
94
144
  if (options.payload) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-build-version-file",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "A Vite plugin that emits version.json and injects version metadata into HTML.",
5
5
  "license": "MIT",
6
6
  "type": "module",