unplugin-version-injector 2.1.1 → 2.2.1

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/dist/vite.mjs CHANGED
@@ -1,73 +1,345 @@
1
+ import { createVitePlugin } from 'unplugin';
2
+ import { createRequire } from 'module';
1
3
  import fs from 'fs';
2
4
  import path from 'path';
3
5
 
4
- // src/shared/utils.ts
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined") return require.apply(this, arguments);
10
+ throw Error('Dynamic require of "' + x + '" is not supported');
11
+ });
12
+ var cachedPkg = null;
5
13
  function getPackageVersion(startDir) {
14
+ if (cachedPkg) return cachedPkg;
6
15
  try {
7
16
  let dir = startDir || process.cwd();
8
- while (dir !== path.parse(dir).root) {
17
+ while (true) {
9
18
  const pkgPath = path.join(dir, "package.json");
10
19
  if (fs.existsSync(pkgPath)) {
11
20
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
12
- return { version: pkg.version || "0.0.0", name: pkg.name || "unknown" };
21
+ cachedPkg = { version: pkg.version || "0.0.0", name: pkg.name || "unknown" };
22
+ return cachedPkg;
13
23
  }
14
- dir = path.dirname(dir);
24
+ const parent = path.dirname(dir);
25
+ if (parent === dir) break;
26
+ dir = parent;
15
27
  }
16
28
  console.warn("[VersionInjector] package.json not found");
17
- return { version: "0.0.0", name: "unknown" };
29
+ cachedPkg = { version: "0.0.0", name: "unknown" };
30
+ return cachedPkg;
18
31
  } catch (err) {
19
32
  console.warn("[VersionInjector] Failed to read package.json:", err);
20
- return { version: "0.0.0", name: "unknown" };
33
+ cachedPkg = { version: "0.0.0", name: "unknown" };
34
+ return cachedPkg;
21
35
  }
22
36
  }
23
37
  function defaultFormatDate(date) {
24
38
  return date.toISOString();
25
39
  }
40
+ var WEEKDAYS_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
41
+ var WEEKDAYS_FULL = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
42
+ var MONTHS_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
43
+ var MONTHS_FULL = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
44
+ function pad(num) {
45
+ return num < 10 ? "0" + num : String(num);
46
+ }
47
+ function formatDate(date, format) {
48
+ const year = date.getFullYear();
49
+ const month = date.getMonth();
50
+ const day = date.getDate();
51
+ const hours = date.getHours();
52
+ const minutes = date.getMinutes();
53
+ const seconds = date.getSeconds();
54
+ const ms = date.getMilliseconds();
55
+ const dayOfWeek = date.getDay();
56
+ const tokens = {
57
+ YYYY: String(year),
58
+ YY: String(year).slice(-2),
59
+ MMMM: MONTHS_FULL[month],
60
+ MMM: MONTHS_SHORT[month],
61
+ MM: pad(month + 1),
62
+ M: String(month + 1),
63
+ DD: pad(day),
64
+ D: String(day),
65
+ dddd: WEEKDAYS_FULL[dayOfWeek],
66
+ ddd: WEEKDAYS_SHORT[dayOfWeek],
67
+ dd: WEEKDAYS_SHORT[dayOfWeek].slice(0, 2),
68
+ d: String(dayOfWeek),
69
+ HH: pad(hours),
70
+ H: String(hours),
71
+ hh: pad(hours % 12 || 12),
72
+ h: String(hours % 12 || 12),
73
+ mm: pad(minutes),
74
+ m: String(minutes),
75
+ ss: pad(seconds),
76
+ s: String(seconds),
77
+ SSS: pad(ms),
78
+ SS: pad(Math.floor(ms / 10)),
79
+ S: String(Math.floor(ms / 100)),
80
+ A: hours < 12 ? "AM" : "PM",
81
+ a: hours < 12 ? "am" : "pm"
82
+ };
83
+ 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]);
84
+ }
85
+ function escapeHtml(value) {
86
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
87
+ }
88
+ function toScriptString(value) {
89
+ return JSON.stringify(value).replace(/</g, "\\u003C");
90
+ }
26
91
 
27
92
  // src/core.ts
93
+ var INJECTED_MARK = 'data-injected="unplugin-version-injector"';
94
+ var HEADERS_INJECTED_MARK = 'data-injected="unplugin-version-injector-headers"';
95
+ var HEADER_NAME_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
96
+ var DEFAULT_VERSION_HEADER = "X-Client-Version";
97
+ var DEFAULT_BUILD_TIME_HEADER = "X-Client-Build-Time";
98
+ function normalizeRequestHeaders(opt) {
99
+ if (!opt) return null;
100
+ const o = typeof opt === "object" ? opt : {};
101
+ const pickHeaderName = (value, fallback) => {
102
+ if (value == null) return fallback;
103
+ if (HEADER_NAME_RE.test(value)) return value;
104
+ console.warn(
105
+ `[VersionInjector] invalid request header name "${value}", falling back to "${fallback}"`
106
+ );
107
+ return fallback;
108
+ };
109
+ const include = (Array.isArray(o.include) ? o.include : []).filter(
110
+ (p) => typeof p === "string" || p instanceof RegExp
111
+ );
112
+ return {
113
+ versionHeaderName: pickHeaderName(o.versionHeaderName, DEFAULT_VERSION_HEADER),
114
+ buildTimeHeaderName: pickHeaderName(o.buildTimeHeaderName, DEFAULT_BUILD_TIME_HEADER),
115
+ include
116
+ };
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
+ }
28
127
  function createVersionInjector(options = {}) {
29
- var _a;
30
- const { version, name } = options.version && options.name ? options : getPackageVersion();
31
- const buildTime = ((_a = options.formatDate) != null ? _a : defaultFormatDate)(/* @__PURE__ */ new Date());
32
- const metaTag = `<meta name="version" content="${version}">
33
- <meta name="project" content="${name}">
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)}">
34
136
  `;
35
- const logScript = `
36
- <script data-injected="unplugin-version-injector">
137
+ const buildLogScript = (buildTime) => `
138
+ <script ${INJECTED_MARK}>
37
139
  (function () {
38
- var isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
39
- var bg = isDark ? '#ffffff' : '#1e1e1e' ;
40
- var border = 'border-radius: 4px; padding: 4px; font-size: 12px;';
41
- var styles = {
42
- version: \`background: \${bg}; color: #00c853; \${border}\`,
43
- time: \`background: \${bg}; color: #ffab00; \${border}\`,
44
- };
45
- console.log("%c ${name}@${version} ", styles.version);
46
- console.log("%c Build Time: ${buildTime} ", styles.time);
140
+ try {
141
+ var isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
142
+ var bg = isDark ? '#ffffff' : '#1e1e1e';
143
+ var base = 'background: ' + bg + '; border-radius: 4px; padding: 4px; font-size: 12px;';
144
+ console.log('%c' + ${toScriptString(` ${name}@${version} `)}, base + ' color: #00c853;');
145
+ console.log('%c' + ${toScriptString(` Build Time: ${buildTime} `)}, base + ' color: #ffab00;');
146
+ } catch (e) {}
47
147
  })();
48
148
  </script>`;
49
- return function processHtml(html) {
50
- if (!html.includes('<meta name="version"')) {
51
- html = html.replace(/<head>/i, `<head>
52
- ${metaTag}`);
149
+ const buildHeaderScript = (buildTime, cfg) => {
150
+ const versionValue = sanitizeHeaderValue(`${name}/${version}`);
151
+ const buildValue = sanitizeHeaderValue(buildTime);
152
+ return `
153
+ <script ${HEADERS_INJECTED_MARK}>
154
+ (function () {
155
+ try {
156
+ if (window.__UVI_HEADERS_PATCHED__) return;
157
+ window.__UVI_HEADERS_PATCHED__ = true;
158
+ var VERSION_HEADER = ${toScriptString(cfg.versionHeaderName)};
159
+ var BUILD_HEADER = ${toScriptString(cfg.buildTimeHeaderName)};
160
+ var VERSION_VALUE = ${toScriptString(versionValue)};
161
+ var BUILD_VALUE = ${toScriptString(buildValue)};
162
+ var INCLUDE = ${serializeInclude(cfg.include)};
163
+
164
+ function resolveUrl(url) {
165
+ try {
166
+ if (typeof URL === 'function') return new URL(url, location.href);
167
+ } catch (e) {
168
+ return null;
169
+ }
170
+ try {
171
+ var a = document.createElement('a');
172
+ a.href = url;
173
+ return { protocol: a.protocol, host: a.host, href: a.href };
174
+ } catch (e2) {
175
+ return null;
176
+ }
177
+ }
178
+
179
+ function shouldInject(url) {
180
+ var u = resolveUrl(url == null ? '' : String(url));
181
+ if (!u || (u.protocol !== 'http:' && u.protocol !== 'https:')) return false;
182
+ if (u.protocol === location.protocol && u.host === location.host) return true;
183
+ for (var i = 0; i < INCLUDE.length; i++) {
184
+ var p = INCLUDE[i];
185
+ if (typeof p === 'string' ? u.href.indexOf(p) === 0 : p.test(u.href)) return true;
186
+ }
187
+ return false;
188
+ }
189
+
190
+ if (typeof window.fetch === 'function' && typeof Headers === 'function') {
191
+ var originalFetch = window.fetch;
192
+ window.fetch = function (input, init) {
193
+ try {
194
+ var isRequest = typeof Request === 'function' && input instanceof Request;
195
+ var url = isRequest ? input.url : String(input);
196
+ if (shouldInject(url)) {
197
+ var headers = new Headers(
198
+ (init && init.headers) || (isRequest ? input.headers : undefined)
199
+ );
200
+ headers.set(VERSION_HEADER, VERSION_VALUE);
201
+ headers.set(BUILD_HEADER, BUILD_VALUE);
202
+ var copy = {};
203
+ if (init) for (var k in init) copy[k] = init[k];
204
+ copy.headers = headers;
205
+ init = copy;
206
+ }
207
+ } catch (e) {}
208
+ return originalFetch.call(this, input, init);
209
+ };
53
210
  }
54
- if (options.log !== false && !html.includes('data-injected="unplugin-version-injector"')) {
55
- html = html.replace(/<\/body>/i, ` ${logScript}
211
+
212
+ if (window.XMLHttpRequest && XMLHttpRequest.prototype) {
213
+ var proto = XMLHttpRequest.prototype;
214
+ var originalOpen = proto.open;
215
+ var originalSend = proto.send;
216
+ if (originalOpen && originalSend) {
217
+ proto.open = function (method, url) {
218
+ try {
219
+ this.__uviInject = shouldInject(url);
220
+ } catch (e) {}
221
+ return originalOpen.apply(this, arguments);
222
+ };
223
+ proto.send = function () {
224
+ if (this.__uviInject) {
225
+ try {
226
+ this.setRequestHeader(VERSION_HEADER, VERSION_VALUE);
227
+ this.setRequestHeader(BUILD_HEADER, BUILD_VALUE);
228
+ } catch (e) {}
229
+ }
230
+ return originalSend.apply(this, arguments);
231
+ };
232
+ }
233
+ }
234
+ } catch (e) {}
235
+ })();
236
+ </script>`;
237
+ };
238
+ const processHtml = function processHtml2(html) {
239
+ const original = html;
240
+ try {
241
+ const buildTime = formatDate2(/* @__PURE__ */ new Date());
242
+ if (!html.includes('<meta name="version"')) {
243
+ html = html.replace(/<head[^>]*>/i, (match) => `${match}
244
+ ${metaTag}`);
245
+ }
246
+ if (headersConfig && !html.includes(HEADERS_INJECTED_MARK)) {
247
+ const headerScript = buildHeaderScript(buildTime, headersConfig);
248
+ html = html.replace(/<head[^>]*>/i, (match) => `${match}
249
+ ${headerScript}
250
+ `);
251
+ }
252
+ if (options.log !== false && !html.includes(INJECTED_MARK)) {
253
+ const logScript = buildLogScript(buildTime);
254
+ html = html.replace(/<\/body>/i, () => ` ${logScript}
56
255
  </body>`);
256
+ }
257
+ return html;
258
+ } catch (err) {
259
+ console.warn("[VersionInjector] injection failed, returning original HTML unchanged:", err);
260
+ return original;
57
261
  }
58
- return html;
59
262
  };
263
+ processHtml.resetBuildTime = () => {
264
+ };
265
+ return processHtml;
60
266
  }
61
267
 
62
- // src/vite.ts
63
- function versionInjectorPlugin(options = {}) {
268
+ // src/index.ts
269
+ var import_meta = {};
270
+ var PLUGIN_NAME = "unplugin-version-injector";
271
+ function injectBundleHtml(bundle, inject) {
272
+ for (const file of Object.values(bundle)) {
273
+ if (file.type === "asset" && file.fileName.endsWith(".html")) {
274
+ const source = typeof file.source === "string" ? file.source : Buffer.from(file.source).toString("utf-8");
275
+ file.source = inject(source);
276
+ }
277
+ }
278
+ }
279
+ function applyWebpackLike(compiler, inject) {
280
+ var _a;
281
+ const api = (_a = compiler.webpack) != null ? _a : compiler.rspack;
282
+ if ((api == null ? void 0 : api.Compilation) && (api == null ? void 0 : api.sources)) {
283
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
284
+ compilation.hooks.processAssets.tap(
285
+ {
286
+ name: PLUGIN_NAME,
287
+ // html-webpack-plugin 在 OPTIMIZE_INLINE 阶段产出 HTML,SUMMARIZE 保证跑在它之后
288
+ stage: api.Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
289
+ },
290
+ (assets) => {
291
+ for (const name of Object.keys(assets)) {
292
+ if (name.endsWith(".html")) {
293
+ const html = assets[name].source().toString();
294
+ compilation.updateAsset(name, new api.sources.RawSource(inject(html)));
295
+ }
296
+ }
297
+ }
298
+ );
299
+ });
300
+ } else {
301
+ const requireFn = typeof __require === "function" ? __require : createRequire(import_meta.url);
302
+ const { RawSource } = requireFn("webpack-sources");
303
+ compiler.hooks.emit.tapAsync(PLUGIN_NAME, (compilation, callback) => {
304
+ for (const name of Object.keys(compilation.assets)) {
305
+ if (name.endsWith(".html")) {
306
+ const html = compilation.assets[name].source().toString();
307
+ compilation.assets[name] = new RawSource(inject(html));
308
+ }
309
+ }
310
+ callback();
311
+ });
312
+ }
313
+ }
314
+ var unpluginFactory = (options = {}) => {
64
315
  const inject = createVersionInjector(options);
65
316
  return {
66
- name: "vite-version-injector",
67
- transformIndexHtml(html) {
68
- return inject(html);
317
+ name: PLUGIN_NAME,
318
+ vite: {
319
+ transformIndexHtml(html) {
320
+ return inject(html);
321
+ }
322
+ },
323
+ rollup: {
324
+ generateBundle(_outputOptions, bundle) {
325
+ injectBundleHtml(bundle, inject);
326
+ }
327
+ },
328
+ rolldown: {
329
+ generateBundle(_outputOptions, bundle) {
330
+ injectBundleHtml(bundle, inject);
331
+ }
332
+ },
333
+ webpack(compiler) {
334
+ applyWebpackLike(compiler, inject);
335
+ },
336
+ rspack(compiler) {
337
+ applyWebpackLike(compiler, inject);
69
338
  }
70
339
  };
71
- }
340
+ };
341
+
342
+ // src/vite.ts
343
+ var vite_default = createVitePlugin(unpluginFactory);
72
344
 
73
- export { versionInjectorPlugin as default };
345
+ export { vite_default as default };
@@ -1,7 +1,6 @@
1
- import { Compiler } from 'webpack';
1
+ import * as webpack from 'webpack';
2
+ import { V as VersionInjectorOptions } from './types-Cc-nzIS0.mjs';
2
3
 
3
- declare function versionInjectorPlugin(options?: {}): {
4
- apply(compiler: Compiler): void;
5
- };
4
+ declare const _default: (options?: VersionInjectorOptions | undefined) => webpack.WebpackPluginInstance;
6
5
 
7
- export { versionInjectorPlugin as default };
6
+ export { _default as default };
package/dist/webpack.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import { Compiler } from 'webpack';
1
+ import * as webpack from 'webpack';
2
+ import { V as VersionInjectorOptions } from './types-Cc-nzIS0.js';
2
3
 
3
- declare function versionInjectorPlugin(options?: {}): {
4
- apply(compiler: Compiler): void;
5
- };
4
+ declare const _default: (options?: VersionInjectorOptions | undefined) => webpack.WebpackPluginInstance;
6
5
 
7
- export { versionInjectorPlugin as default };
6
+ export { _default as default };