unplugin-version-injector 2.2.1 → 2.3.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/README.md CHANGED
@@ -129,6 +129,7 @@ In your final HTML output:
129
129
  | `log` | `boolean` | Whether to inject the console log script | `true` |
130
130
  | `formatDate` | `string \| ((date: Date) => string)` | Custom build time format: a dayjs-style pattern (e.g. `'YYYY-MM-DD HH:mm:ss'`) or a function | ISO 8601 format |
131
131
  | `requestHeaders` | `boolean \| RequestHeadersOptions` | Attach version/build-time headers to outgoing requests | `false` |
132
+ | `nonce` | `string` | CSP nonce added to the injected inline `<script>` tags | — |
132
133
 
133
134
  > `version` and `name` can be provided independently — whichever is missing falls back to the nearest `package.json`.
134
135
 
package/README.zh-CN.md CHANGED
@@ -135,6 +135,7 @@ export default {
135
135
  | `log` | `boolean` | 是否输出控制台日志 | `true` |
136
136
  | `formatDate` | `string \| ((date: Date) => string)` | 自定义构建时间格式:支持 dayjs 风格字符串(如 `'YYYY-MM-DD HH:mm:ss'`)或函数 | ISO 格式 |
137
137
  | `requestHeaders` | `boolean \| RequestHeadersOptions` | 给发出的请求自动附加版本/构建时间请求头 | `false` |
138
+ | `nonce` | `string` | 给注入的内联 `<script>` 加 CSP nonce(严格 CSP 站点需设置) | — |
138
139
 
139
140
  > `version` 和 `name` 可以单独传入,缺失的一项会自动从最近的 `package.json` 读取。
140
141
 
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
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';
2
+ import { V as VersionInjectorOptions } from './types-CLRw9rBI.mjs';
3
+ export { R as RequestHeadersOptions } from './types-CLRw9rBI.mjs';
4
4
 
5
5
  declare const unpluginFactory: UnpluginFactory<VersionInjectorOptions | undefined>;
6
6
  declare const VersionInjector: UnpluginInstance<VersionInjectorOptions | undefined>;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
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';
2
+ import { V as VersionInjectorOptions } from './types-CLRw9rBI.js';
3
+ export { R as RequestHeadersOptions } from './types-CLRw9rBI.js';
4
4
 
5
5
  declare const unpluginFactory: UnpluginFactory<VersionInjectorOptions | undefined>;
6
6
  declare const VersionInjector: UnpluginInstance<VersionInjectorOptions | undefined>;
package/dist/index.js CHANGED
@@ -3,14 +3,14 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var module$1 = require('module');
6
+ var path = require('path');
6
7
  var unplugin = require('unplugin');
7
8
  var fs = require('fs');
8
- var path = require('path');
9
9
 
10
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
11
 
12
- var fs__default = /*#__PURE__*/_interopDefault(fs);
13
12
  var path__default = /*#__PURE__*/_interopDefault(path);
13
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
14
14
 
15
15
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
16
16
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -133,6 +133,7 @@ function serializeInclude(patterns) {
133
133
  );
134
134
  return `[${items.join(", ")}]`;
135
135
  }
136
+ var HEAD_OPEN_RE = /<head(\s[^>]*)?>/i;
136
137
  function createVersionInjector(options = {}) {
137
138
  const pkg = options.version && options.name ? { version: options.version, name: options.name } : getPackageVersion();
138
139
  const version = options.version || pkg.version;
@@ -140,11 +141,17 @@ function createVersionInjector(options = {}) {
140
141
  const formatDateOpt = options.formatDate;
141
142
  const formatDate2 = typeof formatDateOpt === "string" ? (date) => formatDate(date, formatDateOpt) : formatDateOpt != null ? formatDateOpt : defaultFormatDate;
142
143
  const headersConfig = normalizeRequestHeaders(options.requestHeaders);
144
+ let cachedBuildTime = null;
145
+ const getBuildTime = () => {
146
+ if (cachedBuildTime === null) cachedBuildTime = formatDate2(/* @__PURE__ */ new Date());
147
+ return cachedBuildTime;
148
+ };
149
+ const nonceAttr = options.nonce ? ` nonce="${escapeHtml(options.nonce)}"` : "";
143
150
  const metaTag = `<meta name="version" content="${escapeHtml(version)}">
144
151
  <meta name="project" content="${escapeHtml(name)}">
145
152
  `;
146
153
  const buildLogScript = (buildTime) => `
147
- <script ${INJECTED_MARK}>
154
+ <script${nonceAttr} ${INJECTED_MARK}>
148
155
  (function () {
149
156
  try {
150
157
  var isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
@@ -159,7 +166,7 @@ function createVersionInjector(options = {}) {
159
166
  const versionValue = sanitizeHeaderValue(`${name}/${version}`);
160
167
  const buildValue = sanitizeHeaderValue(buildTime);
161
168
  return `
162
- <script ${HEADERS_INJECTED_MARK}>
169
+ <script${nonceAttr} ${HEADERS_INJECTED_MARK}>
163
170
  (function () {
164
171
  try {
165
172
  if (window.__UVI_HEADERS_PATCHED__) return;
@@ -185,13 +192,21 @@ function createVersionInjector(options = {}) {
185
192
  }
186
193
  }
187
194
 
195
+ function matchesPrefix(href, p) {
196
+ if (href.indexOf(p) !== 0) return false;
197
+ // \u524D\u7F00\u672C\u8EAB\u4EE5 / \u7ED3\u5C3E\uFF0C\u6216\u524D\u7F00\u540E\u7D27\u8DDF\u8FB9\u754C\u5B57\u7B26\uFF0C\u907F\u514D 'https://api.x.com' \u547D\u4E2D 'https://api.x.com.evil.com'
198
+ if (p.charAt(p.length - 1) === '/') return true;
199
+ var next = href.charAt(p.length);
200
+ return next === '' || next === '/' || next === '?' || next === '#';
201
+ }
202
+
188
203
  function shouldInject(url) {
189
204
  var u = resolveUrl(url == null ? '' : String(url));
190
205
  if (!u || (u.protocol !== 'http:' && u.protocol !== 'https:')) return false;
191
206
  if (u.protocol === location.protocol && u.host === location.host) return true;
192
207
  for (var i = 0; i < INCLUDE.length; i++) {
193
208
  var p = INCLUDE[i];
194
- if (typeof p === 'string' ? u.href.indexOf(p) === 0 : p.test(u.href)) return true;
209
+ if (typeof p === 'string' ? matchesPrefix(u.href, p) : p.test(u.href)) return true;
195
210
  }
196
211
  return false;
197
212
  }
@@ -247,14 +262,14 @@ function createVersionInjector(options = {}) {
247
262
  const processHtml = function processHtml2(html) {
248
263
  const original = html;
249
264
  try {
250
- const buildTime = formatDate2(/* @__PURE__ */ new Date());
265
+ const buildTime = getBuildTime();
251
266
  if (!html.includes('<meta name="version"')) {
252
- html = html.replace(/<head[^>]*>/i, (match) => `${match}
267
+ html = html.replace(HEAD_OPEN_RE, (match) => `${match}
253
268
  ${metaTag}`);
254
269
  }
255
270
  if (headersConfig && !html.includes(HEADERS_INJECTED_MARK)) {
256
271
  const headerScript = buildHeaderScript(buildTime, headersConfig);
257
- html = html.replace(/<head[^>]*>/i, (match) => `${match}
272
+ html = html.replace(HEAD_OPEN_RE, (match) => `${match}
258
273
  ${headerScript}
259
274
  `);
260
275
  }
@@ -270,12 +285,12 @@ function createVersionInjector(options = {}) {
270
285
  }
271
286
  };
272
287
  processHtml.resetBuildTime = () => {
288
+ cachedBuildTime = null;
273
289
  };
274
290
  return processHtml;
275
291
  }
276
292
 
277
293
  // src/index.ts
278
- var import_meta = {};
279
294
  var PLUGIN_NAME = "unplugin-version-injector";
280
295
  function injectBundleHtml(bundle, inject) {
281
296
  for (const file of Object.values(bundle)) {
@@ -307,7 +322,7 @@ function applyWebpackLike(compiler, inject) {
307
322
  );
308
323
  });
309
324
  } else {
310
- const requireFn = typeof __require === "function" ? __require : module$1.createRequire(import_meta.url);
325
+ const requireFn = typeof __require === "function" ? __require : module$1.createRequire(path.join(compiler.context || process.cwd(), "noop.js"));
311
326
  const { RawSource } = requireFn("webpack-sources");
312
327
  compiler.hooks.emit.tapAsync(PLUGIN_NAME, (compilation, callback) => {
313
328
  for (const name of Object.keys(compilation.assets)) {
@@ -324,6 +339,10 @@ var unpluginFactory = (options = {}) => {
324
339
  const inject = createVersionInjector(options);
325
340
  return {
326
341
  name: PLUGIN_NAME,
342
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
343
+ buildStart() {
344
+ inject.resetBuildTime();
345
+ },
327
346
  vite: {
328
347
  transformIndexHtml(html) {
329
348
  return inject(html);
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'module';
2
+ import path, { join } from 'path';
2
3
  import { createUnplugin } from 'unplugin';
3
4
  import fs from 'fs';
4
- import path from 'path';
5
5
 
6
6
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
7
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -124,6 +124,7 @@ function serializeInclude(patterns) {
124
124
  );
125
125
  return `[${items.join(", ")}]`;
126
126
  }
127
+ var HEAD_OPEN_RE = /<head(\s[^>]*)?>/i;
127
128
  function createVersionInjector(options = {}) {
128
129
  const pkg = options.version && options.name ? { version: options.version, name: options.name } : getPackageVersion();
129
130
  const version = options.version || pkg.version;
@@ -131,11 +132,17 @@ function createVersionInjector(options = {}) {
131
132
  const formatDateOpt = options.formatDate;
132
133
  const formatDate2 = typeof formatDateOpt === "string" ? (date) => formatDate(date, formatDateOpt) : formatDateOpt != null ? formatDateOpt : defaultFormatDate;
133
134
  const headersConfig = normalizeRequestHeaders(options.requestHeaders);
135
+ let cachedBuildTime = null;
136
+ const getBuildTime = () => {
137
+ if (cachedBuildTime === null) cachedBuildTime = formatDate2(/* @__PURE__ */ new Date());
138
+ return cachedBuildTime;
139
+ };
140
+ const nonceAttr = options.nonce ? ` nonce="${escapeHtml(options.nonce)}"` : "";
134
141
  const metaTag = `<meta name="version" content="${escapeHtml(version)}">
135
142
  <meta name="project" content="${escapeHtml(name)}">
136
143
  `;
137
144
  const buildLogScript = (buildTime) => `
138
- <script ${INJECTED_MARK}>
145
+ <script${nonceAttr} ${INJECTED_MARK}>
139
146
  (function () {
140
147
  try {
141
148
  var isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
@@ -150,7 +157,7 @@ function createVersionInjector(options = {}) {
150
157
  const versionValue = sanitizeHeaderValue(`${name}/${version}`);
151
158
  const buildValue = sanitizeHeaderValue(buildTime);
152
159
  return `
153
- <script ${HEADERS_INJECTED_MARK}>
160
+ <script${nonceAttr} ${HEADERS_INJECTED_MARK}>
154
161
  (function () {
155
162
  try {
156
163
  if (window.__UVI_HEADERS_PATCHED__) return;
@@ -176,13 +183,21 @@ function createVersionInjector(options = {}) {
176
183
  }
177
184
  }
178
185
 
186
+ function matchesPrefix(href, p) {
187
+ if (href.indexOf(p) !== 0) return false;
188
+ // \u524D\u7F00\u672C\u8EAB\u4EE5 / \u7ED3\u5C3E\uFF0C\u6216\u524D\u7F00\u540E\u7D27\u8DDF\u8FB9\u754C\u5B57\u7B26\uFF0C\u907F\u514D 'https://api.x.com' \u547D\u4E2D 'https://api.x.com.evil.com'
189
+ if (p.charAt(p.length - 1) === '/') return true;
190
+ var next = href.charAt(p.length);
191
+ return next === '' || next === '/' || next === '?' || next === '#';
192
+ }
193
+
179
194
  function shouldInject(url) {
180
195
  var u = resolveUrl(url == null ? '' : String(url));
181
196
  if (!u || (u.protocol !== 'http:' && u.protocol !== 'https:')) return false;
182
197
  if (u.protocol === location.protocol && u.host === location.host) return true;
183
198
  for (var i = 0; i < INCLUDE.length; i++) {
184
199
  var p = INCLUDE[i];
185
- if (typeof p === 'string' ? u.href.indexOf(p) === 0 : p.test(u.href)) return true;
200
+ if (typeof p === 'string' ? matchesPrefix(u.href, p) : p.test(u.href)) return true;
186
201
  }
187
202
  return false;
188
203
  }
@@ -238,14 +253,14 @@ function createVersionInjector(options = {}) {
238
253
  const processHtml = function processHtml2(html) {
239
254
  const original = html;
240
255
  try {
241
- const buildTime = formatDate2(/* @__PURE__ */ new Date());
256
+ const buildTime = getBuildTime();
242
257
  if (!html.includes('<meta name="version"')) {
243
- html = html.replace(/<head[^>]*>/i, (match) => `${match}
258
+ html = html.replace(HEAD_OPEN_RE, (match) => `${match}
244
259
  ${metaTag}`);
245
260
  }
246
261
  if (headersConfig && !html.includes(HEADERS_INJECTED_MARK)) {
247
262
  const headerScript = buildHeaderScript(buildTime, headersConfig);
248
- html = html.replace(/<head[^>]*>/i, (match) => `${match}
263
+ html = html.replace(HEAD_OPEN_RE, (match) => `${match}
249
264
  ${headerScript}
250
265
  `);
251
266
  }
@@ -261,12 +276,12 @@ function createVersionInjector(options = {}) {
261
276
  }
262
277
  };
263
278
  processHtml.resetBuildTime = () => {
279
+ cachedBuildTime = null;
264
280
  };
265
281
  return processHtml;
266
282
  }
267
283
 
268
284
  // src/index.ts
269
- var import_meta = {};
270
285
  var PLUGIN_NAME = "unplugin-version-injector";
271
286
  function injectBundleHtml(bundle, inject) {
272
287
  for (const file of Object.values(bundle)) {
@@ -298,7 +313,7 @@ function applyWebpackLike(compiler, inject) {
298
313
  );
299
314
  });
300
315
  } else {
301
- const requireFn = typeof __require === "function" ? __require : createRequire(import_meta.url);
316
+ const requireFn = typeof __require === "function" ? __require : createRequire(join(compiler.context || process.cwd(), "noop.js"));
302
317
  const { RawSource } = requireFn("webpack-sources");
303
318
  compiler.hooks.emit.tapAsync(PLUGIN_NAME, (compilation, callback) => {
304
319
  for (const name of Object.keys(compilation.assets)) {
@@ -315,6 +330,10 @@ var unpluginFactory = (options = {}) => {
315
330
  const inject = createVersionInjector(options);
316
331
  return {
317
332
  name: PLUGIN_NAME,
333
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
334
+ buildStart() {
335
+ inject.resetBuildTime();
336
+ },
318
337
  vite: {
319
338
  transformIndexHtml(html) {
320
339
  return inject(html);
@@ -1,5 +1,5 @@
1
1
  import * as unplugin from 'unplugin';
2
- import { V as VersionInjectorOptions } from './types-Cc-nzIS0.mjs';
2
+ import { V as VersionInjectorOptions } from './types-CLRw9rBI.mjs';
3
3
 
4
4
  declare const _default: (options?: VersionInjectorOptions | undefined) => unplugin.RolldownPlugin<any> | unplugin.RolldownPlugin<any>[];
5
5
 
@@ -1,5 +1,5 @@
1
1
  import * as unplugin from 'unplugin';
2
- import { V as VersionInjectorOptions } from './types-Cc-nzIS0.js';
2
+ import { V as VersionInjectorOptions } from './types-CLRw9rBI.js';
3
3
 
4
4
  declare const _default: (options?: VersionInjectorOptions | undefined) => unplugin.RolldownPlugin<any> | unplugin.RolldownPlugin<any>[];
5
5
 
package/dist/rolldown.js CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  var unplugin = require('unplugin');
4
4
  var module$1 = require('module');
5
- var fs = require('fs');
6
5
  var path = require('path');
6
+ var fs = require('fs');
7
7
 
8
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
9
 
10
- var fs__default = /*#__PURE__*/_interopDefault(fs);
11
10
  var path__default = /*#__PURE__*/_interopDefault(path);
11
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
12
12
 
13
13
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
14
14
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -131,6 +131,7 @@ function serializeInclude(patterns) {
131
131
  );
132
132
  return `[${items.join(", ")}]`;
133
133
  }
134
+ var HEAD_OPEN_RE = /<head(\s[^>]*)?>/i;
134
135
  function createVersionInjector(options = {}) {
135
136
  const pkg = options.version && options.name ? { version: options.version, name: options.name } : getPackageVersion();
136
137
  const version = options.version || pkg.version;
@@ -138,11 +139,17 @@ function createVersionInjector(options = {}) {
138
139
  const formatDateOpt = options.formatDate;
139
140
  const formatDate2 = typeof formatDateOpt === "string" ? (date) => formatDate(date, formatDateOpt) : formatDateOpt != null ? formatDateOpt : defaultFormatDate;
140
141
  const headersConfig = normalizeRequestHeaders(options.requestHeaders);
142
+ let cachedBuildTime = null;
143
+ const getBuildTime = () => {
144
+ if (cachedBuildTime === null) cachedBuildTime = formatDate2(/* @__PURE__ */ new Date());
145
+ return cachedBuildTime;
146
+ };
147
+ const nonceAttr = options.nonce ? ` nonce="${escapeHtml(options.nonce)}"` : "";
141
148
  const metaTag = `<meta name="version" content="${escapeHtml(version)}">
142
149
  <meta name="project" content="${escapeHtml(name)}">
143
150
  `;
144
151
  const buildLogScript = (buildTime) => `
145
- <script ${INJECTED_MARK}>
152
+ <script${nonceAttr} ${INJECTED_MARK}>
146
153
  (function () {
147
154
  try {
148
155
  var isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
@@ -157,7 +164,7 @@ function createVersionInjector(options = {}) {
157
164
  const versionValue = sanitizeHeaderValue(`${name}/${version}`);
158
165
  const buildValue = sanitizeHeaderValue(buildTime);
159
166
  return `
160
- <script ${HEADERS_INJECTED_MARK}>
167
+ <script${nonceAttr} ${HEADERS_INJECTED_MARK}>
161
168
  (function () {
162
169
  try {
163
170
  if (window.__UVI_HEADERS_PATCHED__) return;
@@ -183,13 +190,21 @@ function createVersionInjector(options = {}) {
183
190
  }
184
191
  }
185
192
 
193
+ function matchesPrefix(href, p) {
194
+ if (href.indexOf(p) !== 0) return false;
195
+ // \u524D\u7F00\u672C\u8EAB\u4EE5 / \u7ED3\u5C3E\uFF0C\u6216\u524D\u7F00\u540E\u7D27\u8DDF\u8FB9\u754C\u5B57\u7B26\uFF0C\u907F\u514D 'https://api.x.com' \u547D\u4E2D 'https://api.x.com.evil.com'
196
+ if (p.charAt(p.length - 1) === '/') return true;
197
+ var next = href.charAt(p.length);
198
+ return next === '' || next === '/' || next === '?' || next === '#';
199
+ }
200
+
186
201
  function shouldInject(url) {
187
202
  var u = resolveUrl(url == null ? '' : String(url));
188
203
  if (!u || (u.protocol !== 'http:' && u.protocol !== 'https:')) return false;
189
204
  if (u.protocol === location.protocol && u.host === location.host) return true;
190
205
  for (var i = 0; i < INCLUDE.length; i++) {
191
206
  var p = INCLUDE[i];
192
- if (typeof p === 'string' ? u.href.indexOf(p) === 0 : p.test(u.href)) return true;
207
+ if (typeof p === 'string' ? matchesPrefix(u.href, p) : p.test(u.href)) return true;
193
208
  }
194
209
  return false;
195
210
  }
@@ -245,14 +260,14 @@ function createVersionInjector(options = {}) {
245
260
  const processHtml = function processHtml2(html) {
246
261
  const original = html;
247
262
  try {
248
- const buildTime = formatDate2(/* @__PURE__ */ new Date());
263
+ const buildTime = getBuildTime();
249
264
  if (!html.includes('<meta name="version"')) {
250
- html = html.replace(/<head[^>]*>/i, (match) => `${match}
265
+ html = html.replace(HEAD_OPEN_RE, (match) => `${match}
251
266
  ${metaTag}`);
252
267
  }
253
268
  if (headersConfig && !html.includes(HEADERS_INJECTED_MARK)) {
254
269
  const headerScript = buildHeaderScript(buildTime, headersConfig);
255
- html = html.replace(/<head[^>]*>/i, (match) => `${match}
270
+ html = html.replace(HEAD_OPEN_RE, (match) => `${match}
256
271
  ${headerScript}
257
272
  `);
258
273
  }
@@ -268,12 +283,12 @@ function createVersionInjector(options = {}) {
268
283
  }
269
284
  };
270
285
  processHtml.resetBuildTime = () => {
286
+ cachedBuildTime = null;
271
287
  };
272
288
  return processHtml;
273
289
  }
274
290
 
275
291
  // src/index.ts
276
- var import_meta = {};
277
292
  var PLUGIN_NAME = "unplugin-version-injector";
278
293
  function injectBundleHtml(bundle, inject) {
279
294
  for (const file of Object.values(bundle)) {
@@ -305,7 +320,7 @@ function applyWebpackLike(compiler, inject) {
305
320
  );
306
321
  });
307
322
  } else {
308
- const requireFn = typeof __require === "function" ? __require : module$1.createRequire(import_meta.url);
323
+ const requireFn = typeof __require === "function" ? __require : module$1.createRequire(path.join(compiler.context || process.cwd(), "noop.js"));
309
324
  const { RawSource } = requireFn("webpack-sources");
310
325
  compiler.hooks.emit.tapAsync(PLUGIN_NAME, (compilation, callback) => {
311
326
  for (const name of Object.keys(compilation.assets)) {
@@ -322,6 +337,10 @@ var unpluginFactory = (options = {}) => {
322
337
  const inject = createVersionInjector(options);
323
338
  return {
324
339
  name: PLUGIN_NAME,
340
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
341
+ buildStart() {
342
+ inject.resetBuildTime();
343
+ },
325
344
  vite: {
326
345
  transformIndexHtml(html) {
327
346
  return inject(html);
package/dist/rolldown.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRolldownPlugin } from 'unplugin';
2
2
  import { createRequire } from 'module';
3
+ import path, { join } from 'path';
3
4
  import fs from 'fs';
4
- import path from 'path';
5
5
 
6
6
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
7
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -124,6 +124,7 @@ function serializeInclude(patterns) {
124
124
  );
125
125
  return `[${items.join(", ")}]`;
126
126
  }
127
+ var HEAD_OPEN_RE = /<head(\s[^>]*)?>/i;
127
128
  function createVersionInjector(options = {}) {
128
129
  const pkg = options.version && options.name ? { version: options.version, name: options.name } : getPackageVersion();
129
130
  const version = options.version || pkg.version;
@@ -131,11 +132,17 @@ function createVersionInjector(options = {}) {
131
132
  const formatDateOpt = options.formatDate;
132
133
  const formatDate2 = typeof formatDateOpt === "string" ? (date) => formatDate(date, formatDateOpt) : formatDateOpt != null ? formatDateOpt : defaultFormatDate;
133
134
  const headersConfig = normalizeRequestHeaders(options.requestHeaders);
135
+ let cachedBuildTime = null;
136
+ const getBuildTime = () => {
137
+ if (cachedBuildTime === null) cachedBuildTime = formatDate2(/* @__PURE__ */ new Date());
138
+ return cachedBuildTime;
139
+ };
140
+ const nonceAttr = options.nonce ? ` nonce="${escapeHtml(options.nonce)}"` : "";
134
141
  const metaTag = `<meta name="version" content="${escapeHtml(version)}">
135
142
  <meta name="project" content="${escapeHtml(name)}">
136
143
  `;
137
144
  const buildLogScript = (buildTime) => `
138
- <script ${INJECTED_MARK}>
145
+ <script${nonceAttr} ${INJECTED_MARK}>
139
146
  (function () {
140
147
  try {
141
148
  var isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
@@ -150,7 +157,7 @@ function createVersionInjector(options = {}) {
150
157
  const versionValue = sanitizeHeaderValue(`${name}/${version}`);
151
158
  const buildValue = sanitizeHeaderValue(buildTime);
152
159
  return `
153
- <script ${HEADERS_INJECTED_MARK}>
160
+ <script${nonceAttr} ${HEADERS_INJECTED_MARK}>
154
161
  (function () {
155
162
  try {
156
163
  if (window.__UVI_HEADERS_PATCHED__) return;
@@ -176,13 +183,21 @@ function createVersionInjector(options = {}) {
176
183
  }
177
184
  }
178
185
 
186
+ function matchesPrefix(href, p) {
187
+ if (href.indexOf(p) !== 0) return false;
188
+ // \u524D\u7F00\u672C\u8EAB\u4EE5 / \u7ED3\u5C3E\uFF0C\u6216\u524D\u7F00\u540E\u7D27\u8DDF\u8FB9\u754C\u5B57\u7B26\uFF0C\u907F\u514D 'https://api.x.com' \u547D\u4E2D 'https://api.x.com.evil.com'
189
+ if (p.charAt(p.length - 1) === '/') return true;
190
+ var next = href.charAt(p.length);
191
+ return next === '' || next === '/' || next === '?' || next === '#';
192
+ }
193
+
179
194
  function shouldInject(url) {
180
195
  var u = resolveUrl(url == null ? '' : String(url));
181
196
  if (!u || (u.protocol !== 'http:' && u.protocol !== 'https:')) return false;
182
197
  if (u.protocol === location.protocol && u.host === location.host) return true;
183
198
  for (var i = 0; i < INCLUDE.length; i++) {
184
199
  var p = INCLUDE[i];
185
- if (typeof p === 'string' ? u.href.indexOf(p) === 0 : p.test(u.href)) return true;
200
+ if (typeof p === 'string' ? matchesPrefix(u.href, p) : p.test(u.href)) return true;
186
201
  }
187
202
  return false;
188
203
  }
@@ -238,14 +253,14 @@ function createVersionInjector(options = {}) {
238
253
  const processHtml = function processHtml2(html) {
239
254
  const original = html;
240
255
  try {
241
- const buildTime = formatDate2(/* @__PURE__ */ new Date());
256
+ const buildTime = getBuildTime();
242
257
  if (!html.includes('<meta name="version"')) {
243
- html = html.replace(/<head[^>]*>/i, (match) => `${match}
258
+ html = html.replace(HEAD_OPEN_RE, (match) => `${match}
244
259
  ${metaTag}`);
245
260
  }
246
261
  if (headersConfig && !html.includes(HEADERS_INJECTED_MARK)) {
247
262
  const headerScript = buildHeaderScript(buildTime, headersConfig);
248
- html = html.replace(/<head[^>]*>/i, (match) => `${match}
263
+ html = html.replace(HEAD_OPEN_RE, (match) => `${match}
249
264
  ${headerScript}
250
265
  `);
251
266
  }
@@ -261,12 +276,12 @@ function createVersionInjector(options = {}) {
261
276
  }
262
277
  };
263
278
  processHtml.resetBuildTime = () => {
279
+ cachedBuildTime = null;
264
280
  };
265
281
  return processHtml;
266
282
  }
267
283
 
268
284
  // src/index.ts
269
- var import_meta = {};
270
285
  var PLUGIN_NAME = "unplugin-version-injector";
271
286
  function injectBundleHtml(bundle, inject) {
272
287
  for (const file of Object.values(bundle)) {
@@ -298,7 +313,7 @@ function applyWebpackLike(compiler, inject) {
298
313
  );
299
314
  });
300
315
  } else {
301
- const requireFn = typeof __require === "function" ? __require : createRequire(import_meta.url);
316
+ const requireFn = typeof __require === "function" ? __require : createRequire(join(compiler.context || process.cwd(), "noop.js"));
302
317
  const { RawSource } = requireFn("webpack-sources");
303
318
  compiler.hooks.emit.tapAsync(PLUGIN_NAME, (compilation, callback) => {
304
319
  for (const name of Object.keys(compilation.assets)) {
@@ -315,6 +330,10 @@ var unpluginFactory = (options = {}) => {
315
330
  const inject = createVersionInjector(options);
316
331
  return {
317
332
  name: PLUGIN_NAME,
333
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
334
+ buildStart() {
335
+ inject.resetBuildTime();
336
+ },
318
337
  vite: {
319
338
  transformIndexHtml(html) {
320
339
  return inject(html);
package/dist/rollup.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as rollup from 'rollup';
2
- import { V as VersionInjectorOptions } from './types-Cc-nzIS0.mjs';
2
+ import { V as VersionInjectorOptions } from './types-CLRw9rBI.mjs';
3
3
 
4
4
  declare const _default: (options?: VersionInjectorOptions | undefined) => rollup.Plugin<any> | rollup.Plugin<any>[];
5
5
 
package/dist/rollup.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as rollup from 'rollup';
2
- import { V as VersionInjectorOptions } from './types-Cc-nzIS0.js';
2
+ import { V as VersionInjectorOptions } from './types-CLRw9rBI.js';
3
3
 
4
4
  declare const _default: (options?: VersionInjectorOptions | undefined) => rollup.Plugin<any> | rollup.Plugin<any>[];
5
5