unplugin-version-injector 2.2.1 → 2.3.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/dist/rspack.js CHANGED
@@ -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,6 +283,7 @@ function createVersionInjector(options = {}) {
268
283
  }
269
284
  };
270
285
  processHtml.resetBuildTime = () => {
286
+ cachedBuildTime = null;
271
287
  };
272
288
  return processHtml;
273
289
  }
@@ -322,6 +338,10 @@ var unpluginFactory = (options = {}) => {
322
338
  const inject = createVersionInjector(options);
323
339
  return {
324
340
  name: PLUGIN_NAME,
341
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
342
+ buildStart() {
343
+ inject.resetBuildTime();
344
+ },
325
345
  vite: {
326
346
  transformIndexHtml(html) {
327
347
  return inject(html);
package/dist/rspack.mjs CHANGED
@@ -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,6 +276,7 @@ function createVersionInjector(options = {}) {
261
276
  }
262
277
  };
263
278
  processHtml.resetBuildTime = () => {
279
+ cachedBuildTime = null;
264
280
  };
265
281
  return processHtml;
266
282
  }
@@ -315,6 +331,10 @@ var unpluginFactory = (options = {}) => {
315
331
  const inject = createVersionInjector(options);
316
332
  return {
317
333
  name: PLUGIN_NAME,
334
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
335
+ buildStart() {
336
+ inject.resetBuildTime();
337
+ },
318
338
  vite: {
319
339
  transformIndexHtml(html) {
320
340
  return inject(html);
@@ -21,6 +21,11 @@ interface VersionInjectorOptions {
21
21
  * 便于在后端日志中定位客户端版本。默认关闭;true 使用默认配置(仅同源)。
22
22
  */
23
23
  requestHeaders?: boolean | RequestHeadersOptions;
24
+ /**
25
+ * 给注入的内联 <script> 加上 CSP nonce(渲染为 `nonce="..."`)。
26
+ * 站点使用严格 CSP(script-src 带 nonce)时需设置,否则注入脚本会被 CSP 拦截。
27
+ */
28
+ nonce?: string;
24
29
  }
25
30
 
26
31
  export type { RequestHeadersOptions as R, VersionInjectorOptions as V };
@@ -21,6 +21,11 @@ interface VersionInjectorOptions {
21
21
  * 便于在后端日志中定位客户端版本。默认关闭;true 使用默认配置(仅同源)。
22
22
  */
23
23
  requestHeaders?: boolean | RequestHeadersOptions;
24
+ /**
25
+ * 给注入的内联 <script> 加上 CSP nonce(渲染为 `nonce="..."`)。
26
+ * 站点使用严格 CSP(script-src 带 nonce)时需设置,否则注入脚本会被 CSP 拦截。
27
+ */
28
+ nonce?: string;
24
29
  }
25
30
 
26
31
  export type { RequestHeadersOptions as R, VersionInjectorOptions as V };
package/dist/vite.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as vite from 'vite';
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) => vite.Plugin<any> | vite.Plugin<any>[];
5
5
 
package/dist/vite.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as vite from 'vite';
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) => vite.Plugin<any> | vite.Plugin<any>[];
5
5
 
package/dist/vite.js CHANGED
@@ -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,6 +283,7 @@ function createVersionInjector(options = {}) {
268
283
  }
269
284
  };
270
285
  processHtml.resetBuildTime = () => {
286
+ cachedBuildTime = null;
271
287
  };
272
288
  return processHtml;
273
289
  }
@@ -322,6 +338,10 @@ var unpluginFactory = (options = {}) => {
322
338
  const inject = createVersionInjector(options);
323
339
  return {
324
340
  name: PLUGIN_NAME,
341
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
342
+ buildStart() {
343
+ inject.resetBuildTime();
344
+ },
325
345
  vite: {
326
346
  transformIndexHtml(html) {
327
347
  return inject(html);
package/dist/vite.mjs CHANGED
@@ -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,6 +276,7 @@ function createVersionInjector(options = {}) {
261
276
  }
262
277
  };
263
278
  processHtml.resetBuildTime = () => {
279
+ cachedBuildTime = null;
264
280
  };
265
281
  return processHtml;
266
282
  }
@@ -315,6 +331,10 @@ var unpluginFactory = (options = {}) => {
315
331
  const inject = createVersionInjector(options);
316
332
  return {
317
333
  name: PLUGIN_NAME,
334
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
335
+ buildStart() {
336
+ inject.resetBuildTime();
337
+ },
318
338
  vite: {
319
339
  transformIndexHtml(html) {
320
340
  return inject(html);
@@ -1,5 +1,5 @@
1
1
  import * as webpack from 'webpack';
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) => webpack.WebpackPluginInstance;
5
5
 
package/dist/webpack.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as webpack from 'webpack';
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) => webpack.WebpackPluginInstance;
5
5
 
package/dist/webpack.js CHANGED
@@ -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,6 +283,7 @@ function createVersionInjector(options = {}) {
268
283
  }
269
284
  };
270
285
  processHtml.resetBuildTime = () => {
286
+ cachedBuildTime = null;
271
287
  };
272
288
  return processHtml;
273
289
  }
@@ -322,6 +338,10 @@ var unpluginFactory = (options = {}) => {
322
338
  const inject = createVersionInjector(options);
323
339
  return {
324
340
  name: PLUGIN_NAME,
341
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
342
+ buildStart() {
343
+ inject.resetBuildTime();
344
+ },
325
345
  vite: {
326
346
  transformIndexHtml(html) {
327
347
  return inject(html);
package/dist/webpack.mjs CHANGED
@@ -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,6 +276,7 @@ function createVersionInjector(options = {}) {
261
276
  }
262
277
  };
263
278
  processHtml.resetBuildTime = () => {
279
+ cachedBuildTime = null;
264
280
  };
265
281
  return processHtml;
266
282
  }
@@ -315,6 +331,10 @@ var unpluginFactory = (options = {}) => {
315
331
  const inject = createVersionInjector(options);
316
332
  return {
317
333
  name: PLUGIN_NAME,
334
+ // 每轮(重)构建开始时重置构建时间缓存:watch 重建刷新时间,同一次构建里 MPA 各页保持一致
335
+ buildStart() {
336
+ inject.resetBuildTime();
337
+ },
318
338
  vite: {
319
339
  transformIndexHtml(html) {
320
340
  return inject(html);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unplugin-version-injector",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "author": "Nian Yi <nianyi778@gmail.com>",
5
5
  "license": "MIT",
6
6
  "description": "A universal plugin to inject version and build time into HTML (supports Vite, Webpack, Rspack, Rollup, Rolldown)",