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