unplugin-version-injector 2.1.1-beta.1 → 2.2.0

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
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## 📌 Introduction
8
8
 
9
- `unplugin-version-injector` is a lightweight plugin that automatically injects **version** and **build timestamp** into all HTML files. It supports **Webpack 4/5**, **Vite**, and **Rollup**, and works seamlessly with both **SPA** and **MPA** projects.
9
+ `unplugin-version-injector` is a lightweight [unplugin](https://github.com/unjs/unplugin)-based plugin that automatically injects **version** and **build timestamp** into all HTML files. It supports **Vite**, **Webpack 4/5**, **Rspack**, **Rollup** and **Rolldown**, and works seamlessly with both **SPA** and **MPA** projects.
10
10
 
11
11
  ---
12
12
 
@@ -14,7 +14,7 @@
14
14
 
15
15
  ✅ Injects `<meta name="version">` and `<meta name="project">` into the `<head>`
16
16
  ✅ Injects `<script>` into the `<body>` to log version, name, and build time
17
- ✅ Supports Webpack 4 & 5, Vite, Rollup
17
+ ✅ Supports Vite, Webpack 4/5, Rspack, Rollup, Rolldown
18
18
  ✅ Fully compatible with Multi-Page Applications (MPA)
19
19
  ✅ Customizable version, project name, date format, and theme-based console styling
20
20
 
@@ -23,11 +23,14 @@
23
23
  ## 📦 Installation
24
24
 
25
25
  ```bash
26
- # Using Yarn
27
- yarn add -D unplugin-version-injector
28
-
29
26
  # Using npm
30
27
  npm install -D unplugin-version-injector
28
+
29
+ # Using yarn
30
+ yarn add -D unplugin-version-injector
31
+
32
+ # Using pnpm
33
+ pnpm add -D unplugin-version-injector
31
34
  ```
32
35
 
33
36
  ---
@@ -37,6 +40,7 @@ npm install -D unplugin-version-injector
37
40
  ### 📌 Vite
38
41
 
39
42
  ```ts
43
+ // vite.config.ts
40
44
  import versionInjector from 'unplugin-version-injector/vite';
41
45
 
42
46
  export default {
@@ -44,11 +48,10 @@ export default {
44
48
  };
45
49
  ```
46
50
 
47
- ---
48
-
49
51
  ### 📌 Webpack 4/5
50
52
 
51
53
  ```js
54
+ // webpack.config.js
52
55
  const versionInjector = require('unplugin-version-injector/webpack');
53
56
 
54
57
  module.exports = {
@@ -60,11 +63,21 @@ module.exports = {
60
63
  };
61
64
  ```
62
65
 
63
- ---
66
+ ### 📌 Rspack
67
+
68
+ ```js
69
+ // rspack.config.js
70
+ const versionInjector = require('unplugin-version-injector/rspack');
71
+
72
+ module.exports = {
73
+ plugins: [versionInjector()],
74
+ };
75
+ ```
64
76
 
65
77
  ### 📌 Rollup
66
78
 
67
79
  ```js
80
+ // rollup.config.js
68
81
  import versionInjector from 'unplugin-version-injector/rollup';
69
82
 
70
83
  export default {
@@ -72,6 +85,17 @@ export default {
72
85
  };
73
86
  ```
74
87
 
88
+ ### 📌 Rolldown
89
+
90
+ ```js
91
+ // rolldown.config.js
92
+ import versionInjector from 'unplugin-version-injector/rolldown';
93
+
94
+ export default {
95
+ plugins: [versionInjector()],
96
+ };
97
+ ```
98
+
75
99
  ---
76
100
 
77
101
  ## 🧪 Example Output
@@ -85,9 +109,9 @@ In your final HTML output:
85
109
  </head>
86
110
  <body>
87
111
  <script data-injected="unplugin-version-injector">
88
- console.log("%c Version: 1.2.3 ", "background: #222; color: #00ff00;");
89
- console.log("%c Project Name: my-project ", "background: #222; color: #0080ff;");
90
- console.log("%c Build Time: 2024-04-01T12:00:00.000Z ", "background: #222; color: #ffcc00;");
112
+ // console badges:
113
+ // my-project@1.2.3
114
+ // Build Time: 2024-04-01T12:00:00.000Z
91
115
  </script>
92
116
  </body>
93
117
  ```
@@ -96,12 +120,52 @@ In your final HTML output:
96
120
 
97
121
  ## 🔧 Configuration Options
98
122
 
99
- | Option | Type | Description | Default |
100
- |---------------|-----------|-----------------------------------------|--------------------------|
101
- | `version` | `string` | Custom version number | Read from package.json |
102
- | `name` | `string` | Custom project name | Read from package.json |
103
- | `log` | `boolean` | Whether to output console logs | `true` |
104
- | `dateFormat` | `string` | Format for build time (e.g., YYYY-MM-DD)| ISO 8601 format |
123
+ | Option | Type | Description | Default |
124
+ |------------------|-----------------------------------|--------------------------------------------------------|------------------------|
125
+ | `version` | `string` | Custom version number | Read from package.json |
126
+ | `name` | `string` | Custom project name | Read from package.json |
127
+ | `log` | `boolean` | Whether to inject the console log script | `true` |
128
+ | `formatDate` | `(date: Date) => string` | Custom build time formatter | ISO 8601 format |
129
+ | `requestHeaders` | `boolean \| RequestHeadersOptions` | Attach version/build-time headers to outgoing requests | `false` |
130
+
131
+ > `version` and `name` can be provided independently — whichever is missing falls back to the nearest `package.json`.
132
+
133
+ ---
134
+
135
+ ## 📡 Request Headers (identify clients in backend logs)
136
+
137
+ Enable `requestHeaders` to patch `window.fetch` and `XMLHttpRequest` so every API request carries the client version — making it trivial to tell which client build produced a request in backend/API logs:
138
+
139
+ ```ts
140
+ versionInjector({
141
+ requestHeaders: true, // same-origin requests only
142
+ });
143
+ ```
144
+
145
+ Every same-origin request then includes:
146
+
147
+ ```
148
+ X-Client-Version: my-app/1.2.3
149
+ X-Client-Build-Time: 2024-04-01T12:00:00.000Z
150
+ ```
151
+
152
+ Full configuration:
153
+
154
+ ```ts
155
+ versionInjector({
156
+ requestHeaders: {
157
+ versionHeaderName: 'X-Client-Version', // default
158
+ buildTimeHeaderName: 'X-Client-Build-Time', // default
159
+ // Cross-origin URLs to include (string = URL prefix, RegExp = full URL test).
160
+ // Same-origin requests are always included.
161
+ include: ['https://api.example.com/', /\.internal\.example\.com/],
162
+ },
163
+ });
164
+ ```
165
+
166
+ > ⚠️ **CORS**: custom headers on cross-origin requests trigger a preflight — the server must allow them via `Access-Control-Allow-Headers`. That's why cross-origin injection is opt-in through `include`.
167
+ >
168
+ > Note: `navigator.sendBeacon` and WebSocket connections cannot carry custom headers; the patch covers `fetch` and `XMLHttpRequest` (which includes axios and most HTTP clients).
105
169
 
106
170
  ---
107
171
 
@@ -121,4 +185,4 @@ MIT License © 2024 [Nian YI](https://github.com/nianyi778)
121
185
 
122
186
  ---
123
187
 
124
- 🔥 `unplugin-version-injector` – the simplest way to track version and build info!
188
+ 🔥 `unplugin-version-injector` – the simplest way to track version and build info!
package/README.zh-CN.md CHANGED
@@ -5,14 +5,14 @@
5
5
  ---
6
6
 
7
7
  ## **📌 插件简介**
8
- `unplugin-version-injector` 是一个轻量级插件,可在构建时自动向所有 HTML 文件注入 **版本号**、**构建时间戳** 和 **项目名**。支持 **Webpack 4/5、ViteRollup**,适用于 **SPA / MPA 项目**。
8
+ `unplugin-version-injector` 是一个基于 [unplugin](https://github.com/unjs/unplugin) 的轻量级插件,可在构建时自动向所有 HTML 文件注入 **版本号**、**构建时间戳** 和 **项目名**。支持 **Vite、Webpack 4/5、Rspack、RollupRolldown**,适用于 **SPA / MPA 项目**。
9
9
 
10
10
  ---
11
11
 
12
12
  ## **✨ 功能亮点**
13
13
  ✅ 自动注入 `<meta name="version">` 和 `<meta name="project">` 到 HTML `<head>`
14
14
  ✅ 自动注入 `<script>`,控制台输出 `项目名`、`版本号` 和 `构建时间`
15
- ✅ 支持 Webpack 4 / 5、Vite、Rollup
15
+ ✅ 支持 Vite、Webpack 4/5、Rspack、Rollup、Rolldown
16
16
  ✅ 完美兼容多页面应用(MPA)
17
17
  ✅ 支持自定义版本号、项目名、时间格式,默认读取 `package.json`
18
18
  ✅ 控制台输出支持自动适配深/浅主题配色
@@ -61,6 +61,18 @@ module.exports = {
61
61
 
62
62
  ---
63
63
 
64
+ ### **📌 Rspack**
65
+ `rspack.config.js` 中配置:
66
+ ```js
67
+ const versionInjector = require('unplugin-version-injector/rspack');
68
+
69
+ module.exports = {
70
+ plugins: [versionInjector()],
71
+ };
72
+ ```
73
+
74
+ ---
75
+
64
76
  ### **📌 Rollup**
65
77
  `rollup.config.js` 中配置:
66
78
  ```js
@@ -73,6 +85,18 @@ export default {
73
85
 
74
86
  ---
75
87
 
88
+ ### **📌 Rolldown**
89
+ `rolldown.config.js` 中配置:
90
+ ```js
91
+ import versionInjector from 'unplugin-version-injector/rolldown';
92
+
93
+ export default {
94
+ plugins: [versionInjector()],
95
+ };
96
+ ```
97
+
98
+ ---
99
+
76
100
  ## **🧪 示例输出**
77
101
 
78
102
  构建后的 HTML 文件中将自动注入:
@@ -107,7 +131,46 @@ export default {
107
131
  | `version` | `string` | 自定义版本号 | 自动读取 package.json |
108
132
  | `name` | `string` | 自定义项目名 | 自动读取 package.json |
109
133
  | `log` | `boolean` | 是否输出控制台日志 | `true` |
110
- | `formatDate` | `Date => string` | 自定义时间格式函数 | ISO 格式 |
134
+ | `formatDate` | `(date: Date) => string` | 自定义时间格式函数 | ISO 格式 |
135
+ | `requestHeaders` | `boolean \| RequestHeadersOptions` | 给发出的请求自动附加版本/构建时间请求头 | `false` |
136
+
137
+ > `version` 和 `name` 可以单独传入,缺失的一项会自动从最近的 `package.json` 读取。
138
+
139
+ ---
140
+
141
+ ## **📡 请求头注入(后端日志定位客户端版本)**
142
+
143
+ 开启 `requestHeaders` 后,插件会在页面最前面 patch `window.fetch` 和 `XMLHttpRequest`,让所有 API 请求自动带上版本信息——排查前后端请求日志时可以直接看出是哪个客户端、哪个版本发出的请求:
144
+
145
+ ```ts
146
+ versionInjector({
147
+ requestHeaders: true, // 默认仅同源请求
148
+ });
149
+ ```
150
+
151
+ 之后每个同源请求都会带上:
152
+
153
+ ```
154
+ X-Client-Version: my-app/1.2.3
155
+ X-Client-Build-Time: 2024-04-01T12:00:00.000Z
156
+ ```
157
+
158
+ 完整配置:
159
+
160
+ ```ts
161
+ versionInjector({
162
+ requestHeaders: {
163
+ versionHeaderName: 'X-Client-Version', // 默认值
164
+ buildTimeHeaderName: 'X-Client-Build-Time', // 默认值
165
+ // 跨域白名单:字符串按 URL 前缀匹配,正则按完整 URL 测试;同源请求始终注入
166
+ include: ['https://api.example.com/', /\.internal\.example\.com/],
167
+ },
168
+ });
169
+ ```
170
+
171
+ > ⚠️ **CORS 注意**:给跨域请求加自定义头会触发预检(preflight),服务端必须在 `Access-Control-Allow-Headers` 中放行这两个头,否则请求会失败——所以跨域注入设计为通过 `include` 显式开启。
172
+ >
173
+ > 说明:`navigator.sendBeacon` 和 WebSocket 无法携带自定义请求头;补丁覆盖 `fetch` 与 `XMLHttpRequest`(axios 等主流 HTTP 客户端底层都走这两条路)。
111
174
 
112
175
  ---
113
176
 
@@ -0,0 +1,8 @@
1
+ import { UnpluginInstance, UnpluginFactory } from 'unplugin';
2
+ import { V as VersionInjectorOptions } from './types-Cc-nzIS0.mjs';
3
+ export { R as RequestHeadersOptions } from './types-Cc-nzIS0.mjs';
4
+
5
+ declare const unpluginFactory: UnpluginFactory<VersionInjectorOptions | undefined>;
6
+ declare const VersionInjector: UnpluginInstance<VersionInjectorOptions | undefined>;
7
+
8
+ export { VersionInjector, VersionInjectorOptions, VersionInjector as default, unpluginFactory };
@@ -0,0 +1,8 @@
1
+ import { UnpluginInstance, UnpluginFactory } from 'unplugin';
2
+ import { V as VersionInjectorOptions } from './types-Cc-nzIS0.js';
3
+ export { R as RequestHeadersOptions } from './types-Cc-nzIS0.js';
4
+
5
+ declare const unpluginFactory: UnpluginFactory<VersionInjectorOptions | undefined>;
6
+ declare const VersionInjector: UnpluginInstance<VersionInjectorOptions | undefined>;
7
+
8
+ export { VersionInjector, VersionInjectorOptions, VersionInjector as default, unpluginFactory };
package/dist/index.js ADDED
@@ -0,0 +1,336 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var module$1 = require('module');
6
+ var unplugin = require('unplugin');
7
+ var fs = require('fs');
8
+ var path = require('path');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
13
+ var path__default = /*#__PURE__*/_interopDefault(path);
14
+
15
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
16
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
17
+ }) : x)(function(x) {
18
+ if (typeof require !== "undefined") return require.apply(this, arguments);
19
+ throw Error('Dynamic require of "' + x + '" is not supported');
20
+ });
21
+ var cachedPkg = null;
22
+ function getPackageVersion(startDir) {
23
+ if (cachedPkg) return cachedPkg;
24
+ try {
25
+ let dir = startDir || process.cwd();
26
+ while (true) {
27
+ const pkgPath = path__default.default.join(dir, "package.json");
28
+ if (fs__default.default.existsSync(pkgPath)) {
29
+ const pkg = JSON.parse(fs__default.default.readFileSync(pkgPath, "utf-8"));
30
+ cachedPkg = { version: pkg.version || "0.0.0", name: pkg.name || "unknown" };
31
+ return cachedPkg;
32
+ }
33
+ const parent = path__default.default.dirname(dir);
34
+ if (parent === dir) break;
35
+ dir = parent;
36
+ }
37
+ console.warn("[VersionInjector] package.json not found");
38
+ cachedPkg = { version: "0.0.0", name: "unknown" };
39
+ return cachedPkg;
40
+ } catch (err) {
41
+ console.warn("[VersionInjector] Failed to read package.json:", err);
42
+ cachedPkg = { version: "0.0.0", name: "unknown" };
43
+ return cachedPkg;
44
+ }
45
+ }
46
+ function defaultFormatDate(date) {
47
+ return date.toISOString();
48
+ }
49
+ var WEEKDAYS_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
50
+ var WEEKDAYS_FULL = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
51
+ var MONTHS_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
52
+ var MONTHS_FULL = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
53
+ function pad(num) {
54
+ return num < 10 ? "0" + num : String(num);
55
+ }
56
+ function formatDate(date, format) {
57
+ const year = date.getFullYear();
58
+ const month = date.getMonth();
59
+ const day = date.getDate();
60
+ const hours = date.getHours();
61
+ const minutes = date.getMinutes();
62
+ const seconds = date.getSeconds();
63
+ const ms = date.getMilliseconds();
64
+ const dayOfWeek = date.getDay();
65
+ const tokens = {
66
+ YYYY: String(year),
67
+ YY: String(year).slice(-2),
68
+ MMMM: MONTHS_FULL[month],
69
+ MMM: MONTHS_SHORT[month],
70
+ MM: pad(month + 1),
71
+ M: String(month + 1),
72
+ DD: pad(day),
73
+ D: String(day),
74
+ dddd: WEEKDAYS_FULL[dayOfWeek],
75
+ ddd: WEEKDAYS_SHORT[dayOfWeek],
76
+ dd: WEEKDAYS_SHORT[dayOfWeek].slice(0, 2),
77
+ d: String(dayOfWeek),
78
+ HH: pad(hours),
79
+ H: String(hours),
80
+ hh: pad(hours % 12 || 12),
81
+ h: String(hours % 12 || 12),
82
+ mm: pad(minutes),
83
+ m: String(minutes),
84
+ ss: pad(seconds),
85
+ s: String(seconds),
86
+ SSS: pad(ms),
87
+ SS: pad(Math.floor(ms / 10)),
88
+ S: String(Math.floor(ms / 100)),
89
+ A: hours < 12 ? "AM" : "PM",
90
+ a: hours < 12 ? "am" : "pm"
91
+ };
92
+ return format.replace(/YYYY|YY|MMMM|MMM|MM|M|DD|D|dddd|ddd|dd|d|HH|H|hh|h|mm|m|ss|s|SSS|SS|S|A|a/g, (match) => tokens[match]);
93
+ }
94
+ function escapeHtml(value) {
95
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
96
+ }
97
+ function toScriptString(value) {
98
+ return JSON.stringify(value).replace(/</g, "\\u003C");
99
+ }
100
+
101
+ // src/core.ts
102
+ var INJECTED_MARK = 'data-injected="unplugin-version-injector"';
103
+ var HEADERS_INJECTED_MARK = 'data-injected="unplugin-version-injector-headers"';
104
+ var HEADER_NAME_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
105
+ function normalizeRequestHeaders(opt) {
106
+ var _a, _b, _c;
107
+ if (!opt) return null;
108
+ const o = typeof opt === "object" ? opt : {};
109
+ const versionHeaderName = (_a = o.versionHeaderName) != null ? _a : "X-Client-Version";
110
+ const buildTimeHeaderName = (_b = o.buildTimeHeaderName) != null ? _b : "X-Client-Build-Time";
111
+ for (const h of [versionHeaderName, buildTimeHeaderName]) {
112
+ if (!HEADER_NAME_RE.test(h)) {
113
+ throw new Error(`[VersionInjector] invalid request header name: "${h}"`);
114
+ }
115
+ }
116
+ return { versionHeaderName, buildTimeHeaderName, include: (_c = o.include) != null ? _c : [] };
117
+ }
118
+ function sanitizeHeaderValue(value) {
119
+ return value.replace(/[^\t\x20-\x7E]/g, "").trim();
120
+ }
121
+ function serializeInclude(patterns) {
122
+ const items = patterns.map(
123
+ (p) => typeof p === "string" ? toScriptString(p) : `new RegExp(${toScriptString(p.source)}, ${toScriptString(p.flags)})`
124
+ );
125
+ return `[${items.join(", ")}]`;
126
+ }
127
+ function createVersionInjector(options = {}) {
128
+ const pkg = options.version && options.name ? { version: options.version, name: options.name } : getPackageVersion();
129
+ const version = options.version || pkg.version;
130
+ const name = options.name || pkg.name;
131
+ const formatDateOpt = options.formatDate;
132
+ const formatDate2 = typeof formatDateOpt === "string" ? (date) => formatDate(date, formatDateOpt) : formatDateOpt != null ? formatDateOpt : defaultFormatDate;
133
+ const headersConfig = normalizeRequestHeaders(options.requestHeaders);
134
+ const metaTag = `<meta name="version" content="${escapeHtml(version)}">
135
+ <meta name="project" content="${escapeHtml(name)}">
136
+ `;
137
+ const buildLogScript = (buildTime) => `
138
+ <script ${INJECTED_MARK}>
139
+ (function () {
140
+ var isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
141
+ var bg = isDark ? '#ffffff' : '#1e1e1e';
142
+ var base = 'background: ' + bg + '; border-radius: 4px; padding: 4px; font-size: 12px;';
143
+ console.log('%c' + ${toScriptString(` ${name}@${version} `)}, base + ' color: #00c853;');
144
+ console.log('%c' + ${toScriptString(` Build Time: ${buildTime} `)}, base + ' color: #ffab00;');
145
+ })();
146
+ </script>`;
147
+ const buildHeaderScript = (buildTime, cfg) => {
148
+ const versionValue = sanitizeHeaderValue(`${name}/${version}`);
149
+ const buildValue = sanitizeHeaderValue(buildTime);
150
+ return `
151
+ <script ${HEADERS_INJECTED_MARK}>
152
+ (function () {
153
+ if (window.__UVI_HEADERS_PATCHED__) return;
154
+ window.__UVI_HEADERS_PATCHED__ = true;
155
+ var VERSION_HEADER = ${toScriptString(cfg.versionHeaderName)};
156
+ var BUILD_HEADER = ${toScriptString(cfg.buildTimeHeaderName)};
157
+ var VERSION_VALUE = ${toScriptString(versionValue)};
158
+ var BUILD_VALUE = ${toScriptString(buildValue)};
159
+ var INCLUDE = ${serializeInclude(cfg.include)};
160
+
161
+ function resolveUrl(url) {
162
+ try {
163
+ if (typeof URL === 'function') return new URL(url, location.href);
164
+ } catch (e) {
165
+ return null;
166
+ }
167
+ try {
168
+ var a = document.createElement('a');
169
+ a.href = url;
170
+ return { protocol: a.protocol, host: a.host, href: a.href };
171
+ } catch (e2) {
172
+ return null;
173
+ }
174
+ }
175
+
176
+ function shouldInject(url) {
177
+ var u = resolveUrl(url == null ? '' : String(url));
178
+ if (!u || (u.protocol !== 'http:' && u.protocol !== 'https:')) return false;
179
+ if (u.protocol === location.protocol && u.host === location.host) return true;
180
+ for (var i = 0; i < INCLUDE.length; i++) {
181
+ var p = INCLUDE[i];
182
+ if (typeof p === 'string' ? u.href.indexOf(p) === 0 : p.test(u.href)) return true;
183
+ }
184
+ return false;
185
+ }
186
+
187
+ if (typeof window.fetch === 'function' && typeof Headers === 'function') {
188
+ var originalFetch = window.fetch;
189
+ window.fetch = function (input, init) {
190
+ try {
191
+ var isRequest = typeof Request === 'function' && input instanceof Request;
192
+ var url = isRequest ? input.url : String(input);
193
+ if (shouldInject(url)) {
194
+ var headers = new Headers(
195
+ (init && init.headers) || (isRequest ? input.headers : undefined)
196
+ );
197
+ headers.set(VERSION_HEADER, VERSION_VALUE);
198
+ headers.set(BUILD_HEADER, BUILD_VALUE);
199
+ var copy = {};
200
+ if (init) for (var k in init) copy[k] = init[k];
201
+ copy.headers = headers;
202
+ init = copy;
203
+ }
204
+ } catch (e) {}
205
+ return originalFetch.call(this, input, init);
206
+ };
207
+ }
208
+
209
+ if (window.XMLHttpRequest && XMLHttpRequest.prototype) {
210
+ var proto = XMLHttpRequest.prototype;
211
+ var originalOpen = proto.open;
212
+ var originalSend = proto.send;
213
+ if (originalOpen && originalSend) {
214
+ proto.open = function (method, url) {
215
+ try {
216
+ this.__uviInject = shouldInject(url);
217
+ } catch (e) {}
218
+ return originalOpen.apply(this, arguments);
219
+ };
220
+ proto.send = function () {
221
+ if (this.__uviInject) {
222
+ try {
223
+ this.setRequestHeader(VERSION_HEADER, VERSION_VALUE);
224
+ this.setRequestHeader(BUILD_HEADER, BUILD_VALUE);
225
+ } catch (e) {}
226
+ }
227
+ return originalSend.apply(this, arguments);
228
+ };
229
+ }
230
+ }
231
+ })();
232
+ </script>`;
233
+ };
234
+ const processHtml = function processHtml2(html) {
235
+ const buildTime = formatDate2(/* @__PURE__ */ new Date());
236
+ if (!html.includes('<meta name="version"')) {
237
+ html = html.replace(/<head[^>]*>/i, (match) => `${match}
238
+ ${metaTag}`);
239
+ }
240
+ if (headersConfig && !html.includes(HEADERS_INJECTED_MARK)) {
241
+ const headerScript = buildHeaderScript(buildTime, headersConfig);
242
+ html = html.replace(/<head[^>]*>/i, (match) => `${match}
243
+ ${headerScript}
244
+ `);
245
+ }
246
+ if (options.log !== false && !html.includes(INJECTED_MARK)) {
247
+ const logScript = buildLogScript(buildTime);
248
+ html = html.replace(/<\/body>/i, () => ` ${logScript}
249
+ </body>`);
250
+ }
251
+ return html;
252
+ };
253
+ processHtml.resetBuildTime = () => {
254
+ };
255
+ return processHtml;
256
+ }
257
+
258
+ // src/index.ts
259
+ var import_meta = {};
260
+ var PLUGIN_NAME = "unplugin-version-injector";
261
+ function injectBundleHtml(bundle, inject) {
262
+ for (const file of Object.values(bundle)) {
263
+ if (file.type === "asset" && file.fileName.endsWith(".html")) {
264
+ const source = typeof file.source === "string" ? file.source : Buffer.from(file.source).toString("utf-8");
265
+ file.source = inject(source);
266
+ }
267
+ }
268
+ }
269
+ function applyWebpackLike(compiler, inject) {
270
+ var _a;
271
+ const api = (_a = compiler.webpack) != null ? _a : compiler.rspack;
272
+ if ((api == null ? void 0 : api.Compilation) && (api == null ? void 0 : api.sources)) {
273
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
274
+ compilation.hooks.processAssets.tap(
275
+ {
276
+ name: PLUGIN_NAME,
277
+ // html-webpack-plugin 在 OPTIMIZE_INLINE 阶段产出 HTML,SUMMARIZE 保证跑在它之后
278
+ stage: api.Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
279
+ },
280
+ (assets) => {
281
+ for (const name of Object.keys(assets)) {
282
+ if (name.endsWith(".html")) {
283
+ const html = assets[name].source().toString();
284
+ compilation.updateAsset(name, new api.sources.RawSource(inject(html)));
285
+ }
286
+ }
287
+ }
288
+ );
289
+ });
290
+ } else {
291
+ const requireFn = typeof __require === "function" ? __require : module$1.createRequire(import_meta.url);
292
+ const { RawSource } = requireFn("webpack-sources");
293
+ compiler.hooks.emit.tapAsync(PLUGIN_NAME, (compilation, callback) => {
294
+ for (const name of Object.keys(compilation.assets)) {
295
+ if (name.endsWith(".html")) {
296
+ const html = compilation.assets[name].source().toString();
297
+ compilation.assets[name] = new RawSource(inject(html));
298
+ }
299
+ }
300
+ callback();
301
+ });
302
+ }
303
+ }
304
+ var unpluginFactory = (options = {}) => {
305
+ const inject = createVersionInjector(options);
306
+ return {
307
+ name: PLUGIN_NAME,
308
+ vite: {
309
+ transformIndexHtml(html) {
310
+ return inject(html);
311
+ }
312
+ },
313
+ rollup: {
314
+ generateBundle(_outputOptions, bundle) {
315
+ injectBundleHtml(bundle, inject);
316
+ }
317
+ },
318
+ rolldown: {
319
+ generateBundle(_outputOptions, bundle) {
320
+ injectBundleHtml(bundle, inject);
321
+ }
322
+ },
323
+ webpack(compiler) {
324
+ applyWebpackLike(compiler, inject);
325
+ },
326
+ rspack(compiler) {
327
+ applyWebpackLike(compiler, inject);
328
+ }
329
+ };
330
+ };
331
+ var VersionInjector = /* @__PURE__ */ unplugin.createUnplugin(unpluginFactory);
332
+ var index_default = VersionInjector;
333
+
334
+ exports.VersionInjector = VersionInjector;
335
+ exports.default = index_default;
336
+ exports.unpluginFactory = unpluginFactory;