module-develop-kit 1.2.4 → 1.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/dist/commonjs-virtual-dir/_commonjsHelpers.js +3 -28
- package/dist/commonjs-virtual-dir/index2.js +5 -3
- package/dist/commonjs-virtual-dir/index3.js +3 -5
- package/dist/src/outside-call/utils.js +1 -1
- package/dist/src/shield/crypto/sm4.js +1 -1
- package/dist/src/vite-plugins/generateSriHash.js +26 -0
- package/dist/src/vite-plugins/vite-plugin-sri/config.js +8 -0
- package/dist/src/vite-plugins/vite-plugin-sri/index.js +128 -0
- package/dist/src/vite-plugins/vite-plugin-sri/internal.js +1172 -0
- package/dist/vendor/file-type/source/detectors/ebml.js +1 -1
- package/dist/vendor/file-type/source/detectors/zip.js +1 -1
- package/dist/vendor/file-type/source/index.js +1 -1
- package/dist/vendor/file-type/source/tokens.js +1 -1
- package/dist/vendor/gm-crypt/src/crypt.js +1 -1
- package/dist/vendor/jssip/lib-es5/Message.js +11 -11
- package/dist/vendor/jssip/lib-es5/Options.js +13 -13
- package/dist/vendor/jssip/lib-es5/RTCSession/DTMF.js +4 -4
- package/dist/vendor/jssip/lib-es5/RTCSession/Info.js +12 -12
- package/dist/vendor/jssip/lib-es5/RTCSession/ReferSubscriber.js +7 -7
- package/dist/vendor/jssip/lib-es5/RTCSession.js +2 -2
- package/dist/vendor/jssip/lib-es5/Transactions.js +15 -15
- package/dist/vendor/jssip/lib-es5/UA.js +5 -5
- package/dist/vendor/parse5/dist/common/doctype.js +98 -0
- package/dist/vendor/parse5/dist/common/error-codes.js +7 -0
- package/dist/vendor/parse5/dist/common/foreign-content.js +210 -0
- package/dist/vendor/parse5/dist/common/html.js +261 -0
- package/dist/vendor/parse5/dist/common/token.js +14 -0
- package/dist/vendor/parse5/dist/common/unicode.js +73 -0
- package/dist/vendor/parse5/dist/index.js +18 -0
- package/dist/vendor/parse5/dist/parser/formatting-element-list.js +84 -0
- package/dist/vendor/parse5/dist/parser/index.js +2271 -0
- package/dist/vendor/parse5/dist/parser/open-element-stack.js +240 -0
- package/dist/vendor/parse5/dist/serializer/index.js +85 -0
- package/dist/vendor/parse5/dist/tokenizer/index.js +1940 -0
- package/dist/vendor/parse5/dist/tokenizer/preprocessor.js +88 -0
- package/dist/vendor/parse5/dist/tree-adapters/default.js +162 -0
- package/dist/vendor/parse5/node_modules/entities/dist/decode-codepoint.js +37 -0
- package/dist/vendor/parse5/node_modules/entities/dist/decode.js +270 -0
- package/dist/vendor/parse5/node_modules/entities/dist/escape.js +22 -0
- package/dist/vendor/parse5/node_modules/entities/dist/generated/decode-data-html.js +5 -0
- package/dist/vendor/parse5/node_modules/entities/dist/internal/bin-trie-flags.js +7 -0
- package/dist/vendor/parse5/node_modules/entities/dist/internal/decode-shared.js +11 -0
- package/dist/vite-plugins/index.d.ts +161 -0
- package/dist/vite-plugins/index.js +14 -6
- package/package.json +2 -1
- package/dist/commonjs-virtual-dir/___vite-browser-external.js +0 -6
- package/dist/commonjs-virtual-dir/__vite-browser-external.js +0 -4
- package/dist/commonjs-virtual-dir/events.js +0 -4
- package/dist/vendor/events/events.js +0 -216
|
@@ -0,0 +1,1172 @@
|
|
|
1
|
+
import { createHash as X } from "node:crypto";
|
|
2
|
+
import { createRequire as Q } from "node:module";
|
|
3
|
+
import $ from "node:path";
|
|
4
|
+
import { pathToFileURL as _ } from "node:url";
|
|
5
|
+
import { parse as T } from "../../../vendor/parse5/dist/index.js";
|
|
6
|
+
import { getVitePluginSriBase as Y } from "./config.js";
|
|
7
|
+
import { serialize as H } from "../../../vendor/parse5/dist/serializer/index.js";
|
|
8
|
+
function C(e) {
|
|
9
|
+
return typeof e == "string" && /^(https?:)?\/\//i.test(e);
|
|
10
|
+
}
|
|
11
|
+
function B(e) {
|
|
12
|
+
return e.replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
13
|
+
}
|
|
14
|
+
function F(e) {
|
|
15
|
+
return typeof e != "string" ? e : e.startsWith("//") ? e.slice(2) : e.startsWith("/") ? e.slice(1) : e.startsWith("./") ? e.slice(2) : e;
|
|
16
|
+
}
|
|
17
|
+
function V(e, t) {
|
|
18
|
+
if (C(e)) {
|
|
19
|
+
const n = e.endsWith("/") ? e : `${e}/`, r = t.startsWith("/") ? t.slice(1) : t;
|
|
20
|
+
return n + r;
|
|
21
|
+
}
|
|
22
|
+
return $.posix.join(e, t);
|
|
23
|
+
}
|
|
24
|
+
function Z(e, t, n) {
|
|
25
|
+
if (C(e) || e.startsWith("/"))
|
|
26
|
+
return V(e, t);
|
|
27
|
+
const r = $.posix.dirname(n), i = $.posix.relative(r === "" ? "." : r, t);
|
|
28
|
+
return i.startsWith("..") ? i : `./${i}`;
|
|
29
|
+
}
|
|
30
|
+
function tt(e) {
|
|
31
|
+
return e.startsWith("/") || C(e);
|
|
32
|
+
}
|
|
33
|
+
function U(e, t, n = [], r = /* @__PURE__ */ new Set()) {
|
|
34
|
+
if (!tt(t)) return null;
|
|
35
|
+
const i = {};
|
|
36
|
+
for (const { pathname: s, fileName: f } of P(e, n, r))
|
|
37
|
+
i[V(t, f)] = e[s];
|
|
38
|
+
return i;
|
|
39
|
+
}
|
|
40
|
+
function P(e, t = [], n = /* @__PURE__ */ new Set()) {
|
|
41
|
+
const r = [];
|
|
42
|
+
for (const i of Object.keys(e)) {
|
|
43
|
+
if (!/\.m?js(\?|$)/i.test(i)) continue;
|
|
44
|
+
const s = i.startsWith("/") ? i.slice(1) : i;
|
|
45
|
+
R(s, t) || n.has(s) || r.push({ pathname: i, fileName: s });
|
|
46
|
+
}
|
|
47
|
+
return r;
|
|
48
|
+
}
|
|
49
|
+
function R(e, t) {
|
|
50
|
+
if (!t || t.length === 0) return !1;
|
|
51
|
+
for (const n of t)
|
|
52
|
+
if (A(n, e) || A(n, `/${e}`)) return !0;
|
|
53
|
+
return !1;
|
|
54
|
+
}
|
|
55
|
+
function et(e) {
|
|
56
|
+
if (C(e))
|
|
57
|
+
try {
|
|
58
|
+
const n = e.startsWith("//") ? `https:${e}` : e;
|
|
59
|
+
return new URL(n).pathname;
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
const t = F(e);
|
|
63
|
+
return t.startsWith("/") ? t : `/${t}`;
|
|
64
|
+
}
|
|
65
|
+
function nt(e, t) {
|
|
66
|
+
if (!e) return null;
|
|
67
|
+
const n = Object.keys(e);
|
|
68
|
+
if (e[t]) return e[t];
|
|
69
|
+
let r = n.find((s) => s === t || s.endsWith(`/${t}`));
|
|
70
|
+
if (r) return e[r];
|
|
71
|
+
const i = t.split("/").pop();
|
|
72
|
+
return i ? (r = n.find((s) => s === i || s.endsWith(`/${i}`)), r ? e[r] : null) : null;
|
|
73
|
+
}
|
|
74
|
+
async function rt(e, t, n) {
|
|
75
|
+
if (!e) return null;
|
|
76
|
+
const r = n?.enableCache !== !1, i = n?.cache, s = n?.fetchTimeoutMs ?? 0, f = n?.pending;
|
|
77
|
+
if (C(e)) {
|
|
78
|
+
const u = e.startsWith("//") ? `https:${e}` : e;
|
|
79
|
+
if (r && i && i.has(u))
|
|
80
|
+
return i.get(u) ?? null;
|
|
81
|
+
let l, d, g;
|
|
82
|
+
s && s > 0 && typeof AbortController < "u" && (l = new AbortController(), d = l.signal, g = setTimeout(() => l.abort(), s));
|
|
83
|
+
const p = async () => {
|
|
84
|
+
let h;
|
|
85
|
+
try {
|
|
86
|
+
h = await fetch(u, d ? { signal: d } : void 0);
|
|
87
|
+
} finally {
|
|
88
|
+
g && clearTimeout(g);
|
|
89
|
+
}
|
|
90
|
+
if (!h.ok)
|
|
91
|
+
throw new Error(`Failed to fetch ${u}: ${h.status} ${h.statusText}`);
|
|
92
|
+
return new Uint8Array(await h.arrayBuffer());
|
|
93
|
+
};
|
|
94
|
+
if (r && f) {
|
|
95
|
+
let h = f.get(u);
|
|
96
|
+
h || (h = p(), f.set(u, h));
|
|
97
|
+
const m = await h;
|
|
98
|
+
return r && i && i.set(u, m), m;
|
|
99
|
+
}
|
|
100
|
+
const o = await p();
|
|
101
|
+
return r && i && i.set(u, o), o;
|
|
102
|
+
}
|
|
103
|
+
if (!t) return null;
|
|
104
|
+
const a = F(e);
|
|
105
|
+
if (typeof a != "string" || !a) return null;
|
|
106
|
+
const c = nt(t, a);
|
|
107
|
+
return c ? c.code ?? c.source ?? null : null;
|
|
108
|
+
}
|
|
109
|
+
function q(e, t) {
|
|
110
|
+
const n = Buffer.from(e), r = X(t).update(n).digest("base64");
|
|
111
|
+
return `${t}-${r}`;
|
|
112
|
+
}
|
|
113
|
+
function A(e, t) {
|
|
114
|
+
if (!e || !t) return !1;
|
|
115
|
+
if (e === t) return !0;
|
|
116
|
+
const n = e.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
117
|
+
return new RegExp(`^${n}$`).test(t);
|
|
118
|
+
}
|
|
119
|
+
function it(e, t) {
|
|
120
|
+
if (!t || t.length === 0) return !1;
|
|
121
|
+
const n = w(e, "id"), r = w(e, "src"), i = w(e, "href");
|
|
122
|
+
for (const s of t)
|
|
123
|
+
if (n && A(s, n) || r && A(s, r) || i && A(s, i))
|
|
124
|
+
return !0;
|
|
125
|
+
return !1;
|
|
126
|
+
}
|
|
127
|
+
function st(e) {
|
|
128
|
+
return !e || !e.nodeName ? null : e.nodeName.toLowerCase() === "script" ? "src" : "href";
|
|
129
|
+
}
|
|
130
|
+
function N(e, t) {
|
|
131
|
+
const n = [];
|
|
132
|
+
function r(i) {
|
|
133
|
+
if ("nodeName" in i && "attrs" in i && t(i) && n.push(i), "childNodes" in i && i.childNodes)
|
|
134
|
+
for (const s of i.childNodes)
|
|
135
|
+
r(s);
|
|
136
|
+
}
|
|
137
|
+
return r(e), n;
|
|
138
|
+
}
|
|
139
|
+
function w(e, t) {
|
|
140
|
+
return e.attrs.find((r) => r.name === t)?.value;
|
|
141
|
+
}
|
|
142
|
+
function ot(e) {
|
|
143
|
+
if (!e.childNodes) return 0;
|
|
144
|
+
for (let t = 0; t < e.childNodes.length; t++) {
|
|
145
|
+
const n = e.childNodes[t];
|
|
146
|
+
if (!("tagName" in n)) continue;
|
|
147
|
+
const r = n, i = r.tagName?.toLowerCase();
|
|
148
|
+
if (i === "meta") {
|
|
149
|
+
const s = w(r, "http-equiv")?.toLowerCase();
|
|
150
|
+
if (w(r, "charset") !== void 0 || s === "content-type")
|
|
151
|
+
return t + 1;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (i === "script" || i === "link") return 0;
|
|
155
|
+
}
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
function z(e, t, n) {
|
|
159
|
+
const r = e.attrs.find((i) => i.name === t);
|
|
160
|
+
r ? r.value = n : e.attrs.push({ name: t, value: n });
|
|
161
|
+
}
|
|
162
|
+
async function at(e, t, n, r, i, s) {
|
|
163
|
+
if (!e || !e.attrs || w(e, "integrity")) return;
|
|
164
|
+
const f = st(e);
|
|
165
|
+
if (!f) return;
|
|
166
|
+
let a = w(e, f);
|
|
167
|
+
if (!a) return;
|
|
168
|
+
const c = Y();
|
|
169
|
+
c && a.startsWith(c) && (a = a.slice(c.length));
|
|
170
|
+
let u;
|
|
171
|
+
if (s && a) {
|
|
172
|
+
const l = et(a);
|
|
173
|
+
if (u = s[l], !u) {
|
|
174
|
+
const d = F(l);
|
|
175
|
+
u = s[d] || s[`/${d}`];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (!u) {
|
|
179
|
+
const l = await rt(a, t, i);
|
|
180
|
+
if (!l) return;
|
|
181
|
+
u = q(l, n);
|
|
182
|
+
}
|
|
183
|
+
z(e, "integrity", u), r && z(e, "crossorigin", r);
|
|
184
|
+
}
|
|
185
|
+
function ct(e, t) {
|
|
186
|
+
if (!e.nodeName || !e.attrs || t && it(e, t))
|
|
187
|
+
return !1;
|
|
188
|
+
const n = e.nodeName.toLowerCase(), r = w(e, "rel")?.toLowerCase(), i = w(e, "as")?.toLowerCase();
|
|
189
|
+
return !!(n === "script" && w(e, "src") || n === "link" && w(e, "href") && (r === "stylesheet" || r === "modulepreload" || r === "preload" && (i === "script" || i === "style")));
|
|
190
|
+
}
|
|
191
|
+
async function ft(e, t, n, {
|
|
192
|
+
algorithm: r = "sha384",
|
|
193
|
+
crossorigin: i,
|
|
194
|
+
resourceOpts: s,
|
|
195
|
+
skipResources: f = [],
|
|
196
|
+
preComputedHashes: a
|
|
197
|
+
} = {}) {
|
|
198
|
+
try {
|
|
199
|
+
const c = T(e, {
|
|
200
|
+
sourceCodeLocationInfo: !1
|
|
201
|
+
}), u = N(c, (l) => ct(l, f));
|
|
202
|
+
return await Promise.all(
|
|
203
|
+
u.map(
|
|
204
|
+
(l) => at(l, t, r, i, s, a).catch((d) => {
|
|
205
|
+
const g = w(l, "src") || w(l, "href") || "unknown";
|
|
206
|
+
n.error(`Failed to compute integrity for ${g}:`, d?.message || d);
|
|
207
|
+
})
|
|
208
|
+
)
|
|
209
|
+
), H(c);
|
|
210
|
+
} catch (c) {
|
|
211
|
+
return n.error("Failed to parse HTML with parse5", c instanceof Error ? c : void 0), e;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function yt(e, t = !1) {
|
|
215
|
+
if (e && typeof e.warn == "function")
|
|
216
|
+
return {
|
|
217
|
+
warn: e.warn.bind(e),
|
|
218
|
+
info: t ? e.info.bind(e) : () => {
|
|
219
|
+
},
|
|
220
|
+
error: e.error.bind(e),
|
|
221
|
+
summary: e.info.bind(e)
|
|
222
|
+
};
|
|
223
|
+
{
|
|
224
|
+
const n = (r) => console.info(`[vite-plugin-sri-gen] ${r}`);
|
|
225
|
+
return {
|
|
226
|
+
warn: (r) => console.warn(`[vite-plugin-sri-gen] ${r}`),
|
|
227
|
+
info: t ? n : () => {
|
|
228
|
+
},
|
|
229
|
+
error: (r, i) => {
|
|
230
|
+
console.error(`[vite-plugin-sri-gen] ${r}`, i);
|
|
231
|
+
},
|
|
232
|
+
summary: n
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function wt(e, t) {
|
|
237
|
+
if (!e || typeof e != "object")
|
|
238
|
+
return {
|
|
239
|
+
isValid: !1,
|
|
240
|
+
shouldWarn: !0,
|
|
241
|
+
message: "Invalid bundle provided to generateBundle. Bundle must be a valid object."
|
|
242
|
+
};
|
|
243
|
+
const n = Object.entries(e);
|
|
244
|
+
return n.length === 0 ? {
|
|
245
|
+
isValid: !1,
|
|
246
|
+
shouldWarn: !0,
|
|
247
|
+
message: "Empty bundle detected. No assets to process for SRI generation."
|
|
248
|
+
} : n.some(
|
|
249
|
+
([i, s]) => i.toLowerCase().endsWith(".html") && s && s.type === "asset"
|
|
250
|
+
) ? { isValid: !0, shouldWarn: !1, message: null } : t ? {
|
|
251
|
+
isValid: !1,
|
|
252
|
+
shouldWarn: !0,
|
|
253
|
+
message: "No emitted HTML detected during SSR build. SRI can only be added to HTML files; pure SSR server output will be skipped."
|
|
254
|
+
} : {
|
|
255
|
+
isValid: !1,
|
|
256
|
+
shouldWarn: !1,
|
|
257
|
+
message: null
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function kt(e, t) {
|
|
261
|
+
const n = e instanceof Error ? e.message : String(e);
|
|
262
|
+
t.error(`Critical error during SRI generation: ${n}`, e instanceof Error ? e : void 0), n.includes("cheerio") ? t.warn("HTML parsing failed. Ensure cheerio dependency is properly installed and HTML is valid.") : n.includes("fetch") ? t.warn("Remote resource fetching failed. Check network connectivity and resource availability.") : n.includes("integrity") && t.warn("Integrity computation failed. Verify file contents and hashing algorithm support.");
|
|
263
|
+
}
|
|
264
|
+
class St {
|
|
265
|
+
algorithm;
|
|
266
|
+
logger;
|
|
267
|
+
/**
|
|
268
|
+
* File extension patterns for assets that should have integrity computed.
|
|
269
|
+
* Includes common JavaScript and CSS variations with query parameter support.
|
|
270
|
+
*
|
|
271
|
+
* Supported Extensions:
|
|
272
|
+
* - .css - Stylesheets
|
|
273
|
+
* - .js - JavaScript modules
|
|
274
|
+
* - .mjs - ECMAScript modules
|
|
275
|
+
* - Query parameters are preserved (e.g., .js?version=123)
|
|
276
|
+
*/
|
|
277
|
+
PROCESSABLE_EXTENSIONS = /\.(css|js|mjs)($|\?)/i;
|
|
278
|
+
/**
|
|
279
|
+
* Constructs a new IntegrityProcessor with specified algorithm and logger.
|
|
280
|
+
*
|
|
281
|
+
* @param algorithm - Hash algorithm for integrity computation
|
|
282
|
+
* @param logger - Logger instance for consistent reporting
|
|
283
|
+
*/
|
|
284
|
+
constructor(t, n) {
|
|
285
|
+
this.algorithm = t, this.logger = n;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Builds comprehensive integrity mappings for all processable assets in the bundle.
|
|
289
|
+
* Processes both chunks (with code) and assets (with source) while maintaining
|
|
290
|
+
* proper error boundaries for individual asset failures.
|
|
291
|
+
*
|
|
292
|
+
* Processing Flow:
|
|
293
|
+
* 1. Extract all bundle entries for processing
|
|
294
|
+
* 2. Process entries in parallel with individual error handling
|
|
295
|
+
* 3. Collect results and statistics
|
|
296
|
+
* 4. Log processing summary
|
|
297
|
+
*
|
|
298
|
+
* @param bundle - Output bundle containing assets and chunks
|
|
299
|
+
* @param options - Optional filtering options for chunk processing
|
|
300
|
+
* @param options.excludeEntryChunks - If true, skip entry chunks (for first-pass hashing)
|
|
301
|
+
* @param options.onlyEntryChunks - If true, only process entry chunks (for post-injection hashing)
|
|
302
|
+
* @returns Promise<Record<string, string>> - Mapping of pathname to integrity hash
|
|
303
|
+
*/
|
|
304
|
+
async buildIntegrityMappings(t, n) {
|
|
305
|
+
const r = {}, i = Object.entries(t);
|
|
306
|
+
let s = 0, f = 0;
|
|
307
|
+
const a = n?.excludeEntryChunks ?? !1, c = n?.onlyEntryChunks ?? !1;
|
|
308
|
+
if (a && c)
|
|
309
|
+
throw new Error(
|
|
310
|
+
"Invalid integrity mapping options: 'excludeEntryChunks' and 'onlyEntryChunks' cannot both be true."
|
|
311
|
+
);
|
|
312
|
+
const u = a ? "non-entry chunks and assets" : c ? "entry chunks only" : "all bundle assets";
|
|
313
|
+
this.logger.info(
|
|
314
|
+
`Processing ${i.length} bundle entries for integrity computation (${u})`
|
|
315
|
+
);
|
|
316
|
+
const l = i.map(async ([d, g]) => {
|
|
317
|
+
try {
|
|
318
|
+
if (g.type === "chunk") {
|
|
319
|
+
const o = g.isEntry;
|
|
320
|
+
if (a && o) {
|
|
321
|
+
f++;
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (c && !o) {
|
|
325
|
+
f++;
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
} else if (c) {
|
|
329
|
+
f++;
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const p = await this.processBundleItem(d, g);
|
|
333
|
+
p ? (r[p.pathname] = p.integrity, s++) : f++;
|
|
334
|
+
} catch (p) {
|
|
335
|
+
this.logger.error(
|
|
336
|
+
`Failed to process bundle item ${d}: ${p instanceof Error ? p.message : String(p)}`,
|
|
337
|
+
p instanceof Error ? p : void 0
|
|
338
|
+
), f++;
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
return await Promise.allSettled(l), this.logger.info(`Integrity mapping completed: ${s} processed, ${f} skipped`), r;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Processes an individual bundle item (asset or chunk) for integrity computation.
|
|
345
|
+
* Handles type discrimination and source extraction with proper validation.
|
|
346
|
+
*
|
|
347
|
+
* Processing Steps:
|
|
348
|
+
* 1. Check file extension against processable patterns
|
|
349
|
+
* 2. Extract source content based on item type (asset vs chunk)
|
|
350
|
+
* 3. Compute integrity hash
|
|
351
|
+
* 4. Generate pathname for mapping
|
|
352
|
+
*
|
|
353
|
+
* @param fileName - Name of the file in the bundle
|
|
354
|
+
* @param bundleItem - The bundle item (asset or chunk)
|
|
355
|
+
* @returns Promise<{pathname: string, integrity: string} | null> - Result or null if skipped
|
|
356
|
+
*/
|
|
357
|
+
async processBundleItem(t, n) {
|
|
358
|
+
if (!this.PROCESSABLE_EXTENSIONS.test(t))
|
|
359
|
+
return null;
|
|
360
|
+
let r;
|
|
361
|
+
if (n.type === "asset") {
|
|
362
|
+
const i = n;
|
|
363
|
+
if (!i.source)
|
|
364
|
+
return this.logger.warn(`Asset ${t} has no source content, skipping`), null;
|
|
365
|
+
r = typeof i.source == "string" ? i.source : new Uint8Array(i.source);
|
|
366
|
+
} else if (n.type === "chunk") {
|
|
367
|
+
const i = n;
|
|
368
|
+
if (!i.code)
|
|
369
|
+
return this.logger.warn(`Chunk ${t} has no code content, skipping`), null;
|
|
370
|
+
r = i.code;
|
|
371
|
+
} else
|
|
372
|
+
return this.logger.warn(`Unknown bundle item type for ${t}, skipping`), null;
|
|
373
|
+
try {
|
|
374
|
+
const i = q(r, this.algorithm);
|
|
375
|
+
return { pathname: $.posix.join("/", t), integrity: i };
|
|
376
|
+
} catch (i) {
|
|
377
|
+
return this.logger.error(
|
|
378
|
+
`Failed to compute integrity for ${t}: ${i instanceof Error ? i.message : String(i)}`,
|
|
379
|
+
i instanceof Error ? i : void 0
|
|
380
|
+
), null;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
class bt {
|
|
385
|
+
logger;
|
|
386
|
+
/**
|
|
387
|
+
* Per-bundle memos: analyzeDynamicImports and redundantImportMapChunks
|
|
388
|
+
* both derive the same chunk list and module-id map from the same bundle
|
|
389
|
+
* in one generateBundle pass. WeakMap keys mean a new bundle object gets
|
|
390
|
+
* fresh results and old bundles are garbage-collected with their caches.
|
|
391
|
+
*
|
|
392
|
+
* CAUTION: the cache is keyed by bundle object identity, not contents.
|
|
393
|
+
* Adding or removing bundle chunks between calls on the same analyzer
|
|
394
|
+
* instance returns stale results — do all bundle-shape mutation (e.g.
|
|
395
|
+
* runtime injection) BEFORE constructing the analyzer, or construct a
|
|
396
|
+
* fresh analyzer after mutating.
|
|
397
|
+
*/
|
|
398
|
+
chunksCache = /* @__PURE__ */ new WeakMap();
|
|
399
|
+
idMapCache = /* @__PURE__ */ new WeakMap();
|
|
400
|
+
/**
|
|
401
|
+
* Constructs a new DynamicImportAnalyzer with the provided logger.
|
|
402
|
+
*
|
|
403
|
+
* @param logger - Logger instance for consistent reporting
|
|
404
|
+
*/
|
|
405
|
+
constructor(t) {
|
|
406
|
+
this.logger = t;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Analyzes bundle to discover dynamic import relationships and return chunk file names.
|
|
410
|
+
* Creates multiple mapping strategies to ensure dynamic imports are properly resolved.
|
|
411
|
+
*
|
|
412
|
+
* Analysis Flow:
|
|
413
|
+
* 1. Build comprehensive module ID to file name mappings
|
|
414
|
+
* 2. Extract all chunks from bundle
|
|
415
|
+
* 3. Process dynamic imports from each chunk
|
|
416
|
+
* 4. Resolve import identifiers to actual file names
|
|
417
|
+
* 5. Collect and deduplicate results
|
|
418
|
+
*
|
|
419
|
+
* @param bundle - Output bundle to analyze
|
|
420
|
+
* @returns Set<string> - Set of dynamic chunk file names
|
|
421
|
+
*/
|
|
422
|
+
analyzeDynamicImports(t) {
|
|
423
|
+
const n = /* @__PURE__ */ new Set(), r = this.buildModuleIdMappings(t), i = this.extractChunksFromBundle(t);
|
|
424
|
+
let s = 0;
|
|
425
|
+
for (const f of i) {
|
|
426
|
+
const a = f.dynamicImports || [];
|
|
427
|
+
s += a.length;
|
|
428
|
+
for (const c of a) {
|
|
429
|
+
const u = this.resolveDynamicImport(c, r, t);
|
|
430
|
+
u ? n.add(u) : this.logger.warn(`Could not resolve dynamic import "${c}" to a chunk file`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return this.logger.info(
|
|
434
|
+
`Dynamic import analysis completed: ${s} imports analyzed, ${n.size} unique chunks discovered`
|
|
435
|
+
), n;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Filenames of chunks that are REDUNDANT in the import map: chunks that
|
|
439
|
+
* (a) no other chunk imports (statically or dynamically) AND (b) are
|
|
440
|
+
* referenced by an emitted HTML file. Such a chunk is loaded only via a
|
|
441
|
+
* rendered <script>/<link> tag, whose `integrity` attribute already
|
|
442
|
+
* protects it — so an import-map entry for it adds nothing (issue #41).
|
|
443
|
+
* A chunk reached through another chunk's static `import` or dynamic
|
|
444
|
+
* `import()` — even if it is also a declared entry — is NOT redundant:
|
|
445
|
+
* its module-graph fetch carries no integrity attribute and needs the
|
|
446
|
+
* map. Likewise a chunk with no import edges that is NOT referenced by
|
|
447
|
+
* any emitted HTML (e.g. an extra input consumed by server-rendered
|
|
448
|
+
* templates, or loaded via a runtime-constructed import(url)) stays in
|
|
449
|
+
* the map — nothing else protects it.
|
|
450
|
+
*
|
|
451
|
+
* Import identifiers are resolved with the same multi-strategy resolver as
|
|
452
|
+
* analyzeDynamicImports, so identifiers arriving as module IDs, bundle
|
|
453
|
+
* keys, or chunk names (Rollup/Rolldown/Vite differ here) all resolve.
|
|
454
|
+
*/
|
|
455
|
+
redundantImportMapChunks(t) {
|
|
456
|
+
const n = this.buildModuleIdMappings(t), r = this.extractChunksFromBundle(t), i = /* @__PURE__ */ new Set();
|
|
457
|
+
for (const c of r) {
|
|
458
|
+
const u = [...c.imports || [], ...c.dynamicImports || []];
|
|
459
|
+
for (const l of u) {
|
|
460
|
+
const d = this.resolveDynamicImport(l, n, t);
|
|
461
|
+
d ? i.add(d) : this.logger.warn(`Could not resolve import "${l}" to a chunk file`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
const s = [];
|
|
465
|
+
for (const [c, u] of Object.entries(t)) {
|
|
466
|
+
if (u.type !== "asset" || !c.toLowerCase().endsWith(".html"))
|
|
467
|
+
continue;
|
|
468
|
+
const l = u.source;
|
|
469
|
+
let d;
|
|
470
|
+
if (typeof l == "string")
|
|
471
|
+
d = l;
|
|
472
|
+
else if (l instanceof Uint8Array)
|
|
473
|
+
d = Buffer.from(l).toString("utf8");
|
|
474
|
+
else
|
|
475
|
+
continue;
|
|
476
|
+
const g = T(d, { sourceCodeLocationInfo: !1 });
|
|
477
|
+
for (const p of N(g, (o) => {
|
|
478
|
+
const h = o.nodeName?.toLowerCase();
|
|
479
|
+
return h === "script" || h === "link";
|
|
480
|
+
})) {
|
|
481
|
+
const o = w(p, p.nodeName.toLowerCase() === "script" ? "src" : "href");
|
|
482
|
+
o && s.push(o.split(/[?#]/)[0]);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
const f = (c) => s.some((u) => u === c || u.endsWith(`/${c}`)), a = /* @__PURE__ */ new Set();
|
|
486
|
+
for (const c of r)
|
|
487
|
+
i.has(c.fileName) || f(c.fileName) && a.add(c.fileName);
|
|
488
|
+
return a;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Builds comprehensive mappings from module IDs to file names.
|
|
492
|
+
* Creates multiple mapping strategies for robust dynamic import resolution.
|
|
493
|
+
*
|
|
494
|
+
* Mapping Strategies:
|
|
495
|
+
* 1. Facade Module ID mapping (primary entry point)
|
|
496
|
+
* 2. Chunk name mapping (fallback identifier)
|
|
497
|
+
* 3. All module IDs within chunk (comprehensive coverage)
|
|
498
|
+
*
|
|
499
|
+
* @param bundle - Output bundle to analyze
|
|
500
|
+
* @returns Map<string, string> - Module ID to file name mappings
|
|
501
|
+
*/
|
|
502
|
+
buildModuleIdMappings(t) {
|
|
503
|
+
const n = this.idMapCache.get(t);
|
|
504
|
+
if (n) return n;
|
|
505
|
+
const r = /* @__PURE__ */ new Map(), i = this.extractChunksFromBundle(t);
|
|
506
|
+
for (const s of i)
|
|
507
|
+
if (s.facadeModuleId && r.set(s.facadeModuleId, s.fileName), s.name && r.set(s.name, s.fileName), s.modules)
|
|
508
|
+
for (const f of Object.keys(s.modules))
|
|
509
|
+
r.set(f, s.fileName);
|
|
510
|
+
return this.logger.info(`Built module ID mappings for ${r.size} entries`), this.idMapCache.set(t, r), r;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Extracts and validates chunks from bundle, filtering out non-chunk entries.
|
|
514
|
+
* Ensures type safety by filtering only chunk-type bundle items.
|
|
515
|
+
*
|
|
516
|
+
* @param bundle - Output bundle to process
|
|
517
|
+
* @returns OutputChunk[] - Array of valid chunks
|
|
518
|
+
*/
|
|
519
|
+
extractChunksFromBundle(t) {
|
|
520
|
+
const n = this.chunksCache.get(t);
|
|
521
|
+
if (n) return n;
|
|
522
|
+
const r = Object.values(t).filter((i) => i.type === "chunk");
|
|
523
|
+
return this.chunksCache.set(t, r), r;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Resolves a dynamic import identifier to a concrete chunk file name.
|
|
527
|
+
* Uses multiple resolution strategies with fallback mechanisms.
|
|
528
|
+
*
|
|
529
|
+
* Resolution Strategies (in order):
|
|
530
|
+
* 1. Direct module ID/facade module ID lookup
|
|
531
|
+
* 2. Direct bundle key lookup (when dynamic import is a bundle key)
|
|
532
|
+
* 3. Chunk name matching (fallback when facade module ID is missing)
|
|
533
|
+
*
|
|
534
|
+
* @param dynamicImport - Dynamic import identifier
|
|
535
|
+
* @param idToFileMap - Module ID to file name mappings
|
|
536
|
+
* @param bundle - Output bundle for direct lookups
|
|
537
|
+
* @returns string | null - Resolved file name or null if not found
|
|
538
|
+
*/
|
|
539
|
+
resolveDynamicImport(t, n, r) {
|
|
540
|
+
const i = n.get(t);
|
|
541
|
+
if (i)
|
|
542
|
+
return i;
|
|
543
|
+
const s = r[t];
|
|
544
|
+
if (s && s.type === "chunk")
|
|
545
|
+
return s.fileName;
|
|
546
|
+
const a = this.extractChunksFromBundle(r).find((c) => c.name === t);
|
|
547
|
+
return a ? a.fileName : null;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
class vt {
|
|
551
|
+
config;
|
|
552
|
+
/**
|
|
553
|
+
* Constructs a new HtmlProcessor with the provided configuration.
|
|
554
|
+
*
|
|
555
|
+
* @param config - Comprehensive configuration for HTML processing behavior
|
|
556
|
+
*/
|
|
557
|
+
constructor(t) {
|
|
558
|
+
this.config = t;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Processes all HTML files in the bundle to inject SRI attributes and preload links.
|
|
562
|
+
* Handles individual file failures gracefully while maintaining overall processing flow.
|
|
563
|
+
*
|
|
564
|
+
* Processing Flow:
|
|
565
|
+
* 1. Extract and validate HTML files from bundle
|
|
566
|
+
* 2. Process each HTML file with individual error boundaries
|
|
567
|
+
* 3. Apply SRI attributes to existing elements
|
|
568
|
+
* 4. Add preload links for dynamic chunks (if enabled)
|
|
569
|
+
* 5. Update bundle with processed HTML content
|
|
570
|
+
*
|
|
571
|
+
* @param bundle - Output bundle containing HTML assets
|
|
572
|
+
* @param sriByPathname - Mapping of pathnames to integrity hashes
|
|
573
|
+
* @param dynamicChunkFiles - Set of dynamic chunk file names for preloading
|
|
574
|
+
* @returns Promise<void> - Completes when all HTML files are processed
|
|
575
|
+
*/
|
|
576
|
+
async processHtmlFiles(t, n, r, i = /* @__PURE__ */ new Set()) {
|
|
577
|
+
const s = this.extractHtmlFiles(t);
|
|
578
|
+
if (s.length === 0) {
|
|
579
|
+
this.config.logger.warn("No HTML files found in bundle for processing");
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
this.config.logger.info(`Processing ${s.length} HTML files`);
|
|
583
|
+
const f = s.map(async ([l, d]) => {
|
|
584
|
+
try {
|
|
585
|
+
await this.processSingleHtmlFile(
|
|
586
|
+
l,
|
|
587
|
+
d,
|
|
588
|
+
t,
|
|
589
|
+
n,
|
|
590
|
+
r,
|
|
591
|
+
i
|
|
592
|
+
), this.config.logger.info(`Successfully processed HTML file: ${l}`);
|
|
593
|
+
} catch (g) {
|
|
594
|
+
this.config.logger.error(
|
|
595
|
+
`Failed to process HTML file ${l}: ${g instanceof Error ? g.message : String(g)}`,
|
|
596
|
+
g instanceof Error ? g : void 0
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
}), a = await Promise.allSettled(f), c = a.filter((l) => l.status === "fulfilled").length, u = a.filter((l) => l.status === "rejected").length;
|
|
600
|
+
this.config.logger.info(`HTML processing completed: ${c} successful, ${u} failed`);
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Extracts HTML assets from bundle with proper type validation.
|
|
604
|
+
* Filters bundle entries to find only HTML assets with proper type checking.
|
|
605
|
+
*
|
|
606
|
+
* @param bundle - Output bundle to search
|
|
607
|
+
* @returns Array<[string, OutputAsset]> - Array of HTML file name and asset pairs
|
|
608
|
+
*/
|
|
609
|
+
extractHtmlFiles(t) {
|
|
610
|
+
const n = [];
|
|
611
|
+
for (const [r, i] of Object.entries(t))
|
|
612
|
+
typeof r == "string" && r.toLowerCase().endsWith(".html") && i && i.type === "asset" && n.push([r, i]);
|
|
613
|
+
return n;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Processes a single HTML file with comprehensive SRI injection and preload generation.
|
|
617
|
+
*
|
|
618
|
+
* Processing Steps:
|
|
619
|
+
* 1. Extract and validate HTML content from asset
|
|
620
|
+
* 2. Add SRI attributes to existing elements
|
|
621
|
+
* 3. Add preload links for dynamic chunks (if enabled)
|
|
622
|
+
* 4. Update asset source with processed HTML
|
|
623
|
+
*
|
|
624
|
+
* @param fileName - Name of the HTML file
|
|
625
|
+
* @param asset - HTML asset from bundle
|
|
626
|
+
* @param bundle - Complete bundle for resource resolution
|
|
627
|
+
* @param sriByPathname - Integrity mappings
|
|
628
|
+
* @param dynamicChunkFiles - Dynamic chunks for preloading
|
|
629
|
+
* @returns Promise<void> - Completes when file is processed
|
|
630
|
+
*/
|
|
631
|
+
async processSingleHtmlFile(t, n, r, i, s, f) {
|
|
632
|
+
const a = this.extractHtmlContent(n, t);
|
|
633
|
+
if (!a)
|
|
634
|
+
return;
|
|
635
|
+
let c = await this.addSriToHtmlContent(a, r, i);
|
|
636
|
+
const u = this.config.importMapIntegrity === !1 ? /* @__PURE__ */ new Set([
|
|
637
|
+
...s,
|
|
638
|
+
...P(i, this.config.skipResources, f).map(
|
|
639
|
+
(l) => l.fileName
|
|
640
|
+
)
|
|
641
|
+
]) : s;
|
|
642
|
+
this.config.preloadDynamicChunks && u.size > 0 && (c = await this.addDynamicChunkPreloads(c, u, i, t)), this.config.importMapIntegrity !== !1 && (c = this.injectImportMap(c, i, t, f)), n.source = c;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Extracts HTML content from asset with proper validation and type handling.
|
|
646
|
+
* Handles both string and buffer sources with appropriate error reporting.
|
|
647
|
+
*
|
|
648
|
+
* @param asset - HTML asset to extract content from
|
|
649
|
+
* @param fileName - File name for error reporting
|
|
650
|
+
* @returns string | null - HTML content or null if invalid
|
|
651
|
+
*/
|
|
652
|
+
extractHtmlContent(t, n) {
|
|
653
|
+
if (!t.source)
|
|
654
|
+
return this.config.logger.warn(`HTML file ${n} has no source content`), null;
|
|
655
|
+
const r = typeof t.source == "string" ? t.source : String(t.source);
|
|
656
|
+
return r.trim() ? r : (this.config.logger.warn(`HTML file ${n} appears to be empty`), null);
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Adds SRI attributes to existing HTML elements using the internal SRI processor.
|
|
660
|
+
* Delegates to the established addSriToHtml function with proper configuration.
|
|
661
|
+
*
|
|
662
|
+
* @param htmlContent - Original HTML content
|
|
663
|
+
* @param bundle - Bundle for resource resolution
|
|
664
|
+
* @param sriByPathname - Pre-computed integrity hashes by pathname
|
|
665
|
+
* @returns Promise<string> - HTML with SRI attributes added
|
|
666
|
+
*/
|
|
667
|
+
async addSriToHtmlContent(t, n, r) {
|
|
668
|
+
return ft(t, n, this.config.logger, {
|
|
669
|
+
algorithm: this.config.algorithm,
|
|
670
|
+
crossorigin: this.config.crossorigin,
|
|
671
|
+
resourceOpts: {
|
|
672
|
+
cache: this.config.remoteCache,
|
|
673
|
+
pending: this.config.pending,
|
|
674
|
+
enableCache: this.config.enableCache,
|
|
675
|
+
fetchTimeoutMs: this.config.fetchTimeoutMs
|
|
676
|
+
},
|
|
677
|
+
skipResources: this.config.skipResources,
|
|
678
|
+
preComputedHashes: r
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Adds modulepreload links for dynamic chunks with integrity attributes.
|
|
683
|
+
* Uses parse5 for safe DOM manipulation and duplicate prevention.
|
|
684
|
+
*
|
|
685
|
+
* Features:
|
|
686
|
+
* - Safe DOM manipulation with parse5
|
|
687
|
+
* - Duplicate link prevention
|
|
688
|
+
* - Proper integrity and crossorigin attributes
|
|
689
|
+
* - Error handling with fallback to original HTML
|
|
690
|
+
*
|
|
691
|
+
* @param htmlContent - HTML content to modify
|
|
692
|
+
* @param dynamicChunkFiles - Set of dynamic chunk file names
|
|
693
|
+
* @param sriByPathname - Integrity mappings
|
|
694
|
+
* @returns Promise<string> - HTML with preload links added
|
|
695
|
+
*/
|
|
696
|
+
async addDynamicChunkPreloads(t, n, r, i) {
|
|
697
|
+
try {
|
|
698
|
+
const s = T(t, {
|
|
699
|
+
sourceCodeLocationInfo: !1
|
|
700
|
+
});
|
|
701
|
+
let f = 0;
|
|
702
|
+
const c = N(s, (u) => !!u.nodeName && u.nodeName.toLowerCase() === "head")[0];
|
|
703
|
+
if (!c)
|
|
704
|
+
return this.config.logger.warn("No head element found, skipping dynamic chunk preloads"), t;
|
|
705
|
+
for (const u of n)
|
|
706
|
+
this.addPreloadLinkForChunk(c, u, r, i) && f++;
|
|
707
|
+
return this.config.logger.info(`Added ${f} modulepreload links for dynamic chunks`), H(s);
|
|
708
|
+
} catch (s) {
|
|
709
|
+
return this.config.logger.error(
|
|
710
|
+
`Failed to add dynamic chunk preloads: ${s instanceof Error ? s.message : String(s)}`,
|
|
711
|
+
s instanceof Error ? s : void 0
|
|
712
|
+
), t;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Adds a single preload link for a dynamic chunk with proper duplicate checking.
|
|
717
|
+
* Implements comprehensive validation and attribute generation.
|
|
718
|
+
*
|
|
719
|
+
* Validation Steps:
|
|
720
|
+
* 1. Build absolute href using base path
|
|
721
|
+
* 2. Check for existing preload links (duplicate prevention)
|
|
722
|
+
* 3. Verify integrity availability
|
|
723
|
+
* 4. Generate and inject preload link with proper attributes
|
|
724
|
+
*
|
|
725
|
+
* @param head - Head element from parse5 document
|
|
726
|
+
* @param chunkFile - Chunk file name
|
|
727
|
+
* @param sriByPathname - Integrity mappings
|
|
728
|
+
* @returns boolean - Whether a link was added
|
|
729
|
+
*/
|
|
730
|
+
addPreloadLinkForChunk(t, n, r, i) {
|
|
731
|
+
const s = Z(this.config.base, n, i);
|
|
732
|
+
if (N(t, (u) => {
|
|
733
|
+
if (u.nodeName?.toLowerCase() !== "link") return !1;
|
|
734
|
+
const l = w(u, "rel"), d = w(u, "href");
|
|
735
|
+
return l === "modulepreload" && d === s;
|
|
736
|
+
}).length > 0 || R(n, this.config.skipResources))
|
|
737
|
+
return !1;
|
|
738
|
+
const a = r[$.posix.join("/", n)];
|
|
739
|
+
if (!a)
|
|
740
|
+
return this.config.logger.warn(`No integrity found for dynamic chunk: ${n}`), !1;
|
|
741
|
+
const c = {
|
|
742
|
+
nodeName: "link",
|
|
743
|
+
tagName: "link",
|
|
744
|
+
attrs: [
|
|
745
|
+
{ name: "rel", value: "modulepreload" },
|
|
746
|
+
{ name: "href", value: s },
|
|
747
|
+
{ name: "integrity", value: a }
|
|
748
|
+
],
|
|
749
|
+
namespaceURI: "http://www.w3.org/1999/xhtml",
|
|
750
|
+
childNodes: [],
|
|
751
|
+
parentNode: t,
|
|
752
|
+
sourceCodeLocation: void 0
|
|
753
|
+
};
|
|
754
|
+
return this.config.crossorigin && c.attrs.push({
|
|
755
|
+
name: "crossorigin",
|
|
756
|
+
value: this.config.crossorigin
|
|
757
|
+
}), t.childNodes || (t.childNodes = []), t.childNodes.push(c), !0;
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Injects (or merges into) a `<script type="importmap">` carrying an
|
|
761
|
+
* `integrity` object for every emitted JS module chunk. Browsers
|
|
762
|
+
* supporting import map integrity (Chrome 127+, Firefox 138+,
|
|
763
|
+
* Safari 18+) then enforce SRI natively on static AND dynamic module
|
|
764
|
+
* imports — single fetch, no TOCTOU. Older browsers ignore the
|
|
765
|
+
* `integrity` key (progressive enhancement, same model as SRI attributes
|
|
766
|
+
* generally).
|
|
767
|
+
*
|
|
768
|
+
* Must run AFTER addDynamicChunkPreloads: preload links are appended to
|
|
769
|
+
* <head>, while a newly-created import map is inserted near its start. This
|
|
770
|
+
* preserves the spec requirement that the map precede modulepreload links.
|
|
771
|
+
*
|
|
772
|
+
* No-ops (returning the input unchanged) when: base is relative (the
|
|
773
|
+
* resulting keys — bare or document-relative — cannot be used portably
|
|
774
|
+
* across pages in subdirectories), no JS chunks exist, <head> is missing,
|
|
775
|
+
* or an existing import map contains unparseable JSON (warned).
|
|
776
|
+
*/
|
|
777
|
+
injectImportMap(t, n, r, i) {
|
|
778
|
+
const s = U(
|
|
779
|
+
n,
|
|
780
|
+
this.config.base,
|
|
781
|
+
this.config.skipResources,
|
|
782
|
+
i
|
|
783
|
+
);
|
|
784
|
+
if (s === null || Object.keys(s).length === 0)
|
|
785
|
+
return t;
|
|
786
|
+
try {
|
|
787
|
+
const f = T(t, {
|
|
788
|
+
sourceCodeLocationInfo: !1
|
|
789
|
+
}), a = N(f, (l) => l.nodeName?.toLowerCase() === "head")[0];
|
|
790
|
+
if (!a)
|
|
791
|
+
return this.config.logger.warn(`No <head> element found in ${r}, skipping import map injection`), t;
|
|
792
|
+
const c = N(
|
|
793
|
+
a,
|
|
794
|
+
(l) => l.nodeName?.toLowerCase() === "base" && C(w(l, "href"))
|
|
795
|
+
);
|
|
796
|
+
c.length > 0 && this.config.logger.warn(
|
|
797
|
+
`${r} contains <base href="${w(c[0], "href")}">; import map integrity keys resolve against the document base URL and may not match the served module URLs`
|
|
798
|
+
);
|
|
799
|
+
const u = N(a, (l) => l.nodeName?.toLowerCase() !== "script" ? !1 : w(l, "type")?.toLowerCase() === "importmap");
|
|
800
|
+
if (u.length > 0) {
|
|
801
|
+
const l = u[0], d = l.childNodes.find((m) => m.nodeName === "#text");
|
|
802
|
+
let g;
|
|
803
|
+
try {
|
|
804
|
+
g = JSON.parse(d?.value ?? "{}");
|
|
805
|
+
} catch {
|
|
806
|
+
return this.config.logger.warn(
|
|
807
|
+
`Existing <script type="importmap"> in ${r} contains invalid JSON; integrity entries not merged`
|
|
808
|
+
), t;
|
|
809
|
+
}
|
|
810
|
+
const p = g.integrity ?? {}, o = U(n, this.config.base, this.config.skipResources) ?? {};
|
|
811
|
+
for (const [m, y] of Object.entries(p))
|
|
812
|
+
m in o && o[m] !== y && this.config.logger.warn(
|
|
813
|
+
`Existing import map in ${r} pins integrity for ${m} (${String(y)}) that differs from the build-computed hash (${o[m]}); keeping the existing entry`
|
|
814
|
+
);
|
|
815
|
+
g.integrity = {
|
|
816
|
+
...s,
|
|
817
|
+
...p
|
|
818
|
+
};
|
|
819
|
+
const h = B(JSON.stringify(g));
|
|
820
|
+
d ? d.value = h : l.childNodes.push({
|
|
821
|
+
nodeName: "#text",
|
|
822
|
+
value: h,
|
|
823
|
+
parentNode: l
|
|
824
|
+
});
|
|
825
|
+
} else {
|
|
826
|
+
const d = {
|
|
827
|
+
nodeName: "#text",
|
|
828
|
+
value: B(JSON.stringify({ integrity: s })),
|
|
829
|
+
parentNode: null
|
|
830
|
+
}, g = {
|
|
831
|
+
nodeName: "script",
|
|
832
|
+
tagName: "script",
|
|
833
|
+
attrs: [{ name: "type", value: "importmap" }],
|
|
834
|
+
namespaceURI: "http://www.w3.org/1999/xhtml",
|
|
835
|
+
childNodes: [d],
|
|
836
|
+
parentNode: a,
|
|
837
|
+
sourceCodeLocation: void 0
|
|
838
|
+
};
|
|
839
|
+
d.parentNode = g, a.childNodes || (a.childNodes = []), a.childNodes.splice(ot(a), 0, g);
|
|
840
|
+
}
|
|
841
|
+
return H(f);
|
|
842
|
+
} catch (f) {
|
|
843
|
+
return this.config.logger.error(
|
|
844
|
+
`Failed to inject import map into ${r}: ${f instanceof Error ? f.message : String(f)}`,
|
|
845
|
+
f instanceof Error ? f : void 0
|
|
846
|
+
), t;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
class L {
|
|
851
|
+
constructor(t) {
|
|
852
|
+
this.logger = t;
|
|
853
|
+
}
|
|
854
|
+
static KNOWN_MANIFEST_NAMES = /* @__PURE__ */ new Set([".vite/manifest.json", "manifest.json"]);
|
|
855
|
+
static SSR_MANIFEST_NAME = ".vite/ssr-manifest.json";
|
|
856
|
+
/**
|
|
857
|
+
* Finds every Vite-style manifest asset in the bundle and augments each
|
|
858
|
+
* entry with an integrity value (for the primary `file`) and a parallel
|
|
859
|
+
* `cssIntegrity` array (for the `css` array, when present).
|
|
860
|
+
*
|
|
861
|
+
* @param bundle Rollup OutputBundle
|
|
862
|
+
* @param sriByPathname Map of pathnames (with leading `/`) to SRI hashes
|
|
863
|
+
* @param skipResources skipResources patterns — matching files get no integrity
|
|
864
|
+
* @returns counts of manifest files processed and entries augmented
|
|
865
|
+
*/
|
|
866
|
+
injectIntegrity(t, n, r) {
|
|
867
|
+
let i = 0, s = 0;
|
|
868
|
+
for (const [f, a] of Object.entries(t)) {
|
|
869
|
+
if (a.type !== "asset" || !this.isManifestCandidate(f)) continue;
|
|
870
|
+
const c = a, u = this.assetSourceToString(c.source);
|
|
871
|
+
if (u === null) continue;
|
|
872
|
+
const l = this.isKnownManifestName(f);
|
|
873
|
+
let d;
|
|
874
|
+
try {
|
|
875
|
+
d = JSON.parse(u);
|
|
876
|
+
} catch (p) {
|
|
877
|
+
l && this.logger.warn(
|
|
878
|
+
`Failed to parse Vite manifest at ${f}; leaving untouched. ${p instanceof Error ? p.message : String(p)}`
|
|
879
|
+
);
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
if (!this.isManifestShape(d, f, l) || !l && !this.looksLikeViteManifest(d)) continue;
|
|
883
|
+
const g = this.augmentManifest(d, n, r, f);
|
|
884
|
+
g > 0 && (c.source = JSON.stringify(d, null, 2), s += g, i++);
|
|
885
|
+
}
|
|
886
|
+
return { processedFiles: i, augmentedEntries: s };
|
|
887
|
+
}
|
|
888
|
+
isManifestCandidate(t) {
|
|
889
|
+
return t === L.SSR_MANIFEST_NAME ? !1 : L.KNOWN_MANIFEST_NAMES.has(t) ? !0 : t.endsWith("manifest.json");
|
|
890
|
+
}
|
|
891
|
+
isKnownManifestName(t) {
|
|
892
|
+
return L.KNOWN_MANIFEST_NAMES.has(t);
|
|
893
|
+
}
|
|
894
|
+
assetSourceToString(t) {
|
|
895
|
+
if (typeof t == "string") return t;
|
|
896
|
+
if (t instanceof Uint8Array)
|
|
897
|
+
try {
|
|
898
|
+
return new TextDecoder().decode(t);
|
|
899
|
+
} catch {
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
isManifestShape(t, n, r) {
|
|
905
|
+
return !t || typeof t != "object" || Array.isArray(t) ? (r && this.logger.warn(`Vite manifest at ${n} is not a plain object; skipping integrity injection.`), !1) : !0;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Duck-type check: true if the object looks like a Vite build manifest
|
|
909
|
+
* (at least one own-property value is an object with a string `file`).
|
|
910
|
+
* Used to filter out unrelated *manifest.json assets emitted by other plugins.
|
|
911
|
+
*/
|
|
912
|
+
looksLikeViteManifest(t) {
|
|
913
|
+
for (const n of Object.values(t))
|
|
914
|
+
if (n && typeof n == "object" && !Array.isArray(n) && typeof n.file == "string")
|
|
915
|
+
return !0;
|
|
916
|
+
return !1;
|
|
917
|
+
}
|
|
918
|
+
augmentManifest(t, n, r, i) {
|
|
919
|
+
let s = 0;
|
|
920
|
+
for (const [f, a] of Object.entries(t)) {
|
|
921
|
+
if (!a || typeof a != "object" || Array.isArray(a)) {
|
|
922
|
+
this.logger.warn(`Skipping manifest entry "${f}" in ${i}: not an object.`);
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
if (typeof a.file != "string") {
|
|
926
|
+
this.logger.warn(`Skipping manifest entry "${f}" in ${i}: missing string "file".`);
|
|
927
|
+
continue;
|
|
928
|
+
}
|
|
929
|
+
let c = !1;
|
|
930
|
+
if (typeof a.integrity != "string") {
|
|
931
|
+
const u = this.lookupHash(a.file, n, r);
|
|
932
|
+
u && (a.integrity = u, c = !0);
|
|
933
|
+
}
|
|
934
|
+
if (Array.isArray(a.css) && a.css.length > 0 && !Array.isArray(a.cssIntegrity)) {
|
|
935
|
+
const u = [];
|
|
936
|
+
let l = !1;
|
|
937
|
+
for (const d of a.css) {
|
|
938
|
+
if (typeof d != "string") {
|
|
939
|
+
u.push(null);
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
const g = this.lookupHash(d, n, r);
|
|
943
|
+
u.push(g ?? null), g && (l = !0);
|
|
944
|
+
}
|
|
945
|
+
l && (a.cssIntegrity = u, c = !0);
|
|
946
|
+
}
|
|
947
|
+
c && s++;
|
|
948
|
+
}
|
|
949
|
+
return s;
|
|
950
|
+
}
|
|
951
|
+
lookupHash(t, n, r) {
|
|
952
|
+
if (this.isSkipped(t, r)) return;
|
|
953
|
+
const i = t.startsWith("/") ? t : `/${t}`;
|
|
954
|
+
return n[i];
|
|
955
|
+
}
|
|
956
|
+
isSkipped(t, n) {
|
|
957
|
+
return R(t, n);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
const D = "sri-runtime.js";
|
|
961
|
+
async function Et(e, t = () => import("vite")) {
|
|
962
|
+
try {
|
|
963
|
+
return await t();
|
|
964
|
+
} catch {
|
|
965
|
+
const n = Q(_($.join(e, "package.json")).href), r = $.dirname(n.resolve("vite/package.json"));
|
|
966
|
+
return await import(_($.join(r, "dist", "node", "index.js")).href);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
async function $t(e, t, n = () => import("vite")) {
|
|
970
|
+
try {
|
|
971
|
+
const r = await n();
|
|
972
|
+
let i;
|
|
973
|
+
if (typeof r.minifySync == "function") {
|
|
974
|
+
const f = r.minifySync(D, e);
|
|
975
|
+
if (f?.errors?.length)
|
|
976
|
+
return t?.info(`SRI runtime minification skipped: ${String(f.errors[0])}`), e;
|
|
977
|
+
i = f?.code;
|
|
978
|
+
} else if (typeof r.transformWithEsbuild == "function")
|
|
979
|
+
i = (await r.transformWithEsbuild(e, D, {
|
|
980
|
+
minify: !0,
|
|
981
|
+
target: "esnext",
|
|
982
|
+
keepNames: !1
|
|
983
|
+
}))?.code;
|
|
984
|
+
else
|
|
985
|
+
return t?.info("SRI runtime minification skipped: this Vite version exposes no minifier"), e;
|
|
986
|
+
const s = typeof i == "string" ? i.trim() : "";
|
|
987
|
+
return s.startsWith("function") ? s : (t?.info("SRI runtime minification skipped: minifier output was not a bare function declaration"), e);
|
|
988
|
+
} catch (r) {
|
|
989
|
+
return t?.info(`SRI runtime minification skipped: ${r instanceof Error ? r.message : String(r)}`), e;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
function Nt(e, t) {
|
|
993
|
+
let n;
|
|
994
|
+
try {
|
|
995
|
+
const r = new Map(Object.entries(e || {})), i = t && Object.hasOwn(t, "crossorigin") ? t.crossorigin : "anonymous", s = t && t.skipResources || [];
|
|
996
|
+
let f = "/";
|
|
997
|
+
try {
|
|
998
|
+
const o = t && t.base;
|
|
999
|
+
o && typeof o == "string" && (f = new URL(o, "http://x/").pathname, f.endsWith("/") || (f += "/"));
|
|
1000
|
+
} catch {
|
|
1001
|
+
}
|
|
1002
|
+
const a = (o) => {
|
|
1003
|
+
let h = r.get(o);
|
|
1004
|
+
return h === void 0 && f !== "/" && o.indexOf(f) === 0 && (h = r.get(`/${o.slice(f.length)}`)), h;
|
|
1005
|
+
}, c = (o, h) => {
|
|
1006
|
+
if (!o || !h) return !1;
|
|
1007
|
+
if (o === h) return !0;
|
|
1008
|
+
const m = o.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
1009
|
+
return new RegExp(`^${m}$`).test(h);
|
|
1010
|
+
}, u = (o) => {
|
|
1011
|
+
if (!s || s.length === 0) return !1;
|
|
1012
|
+
const h = o.getAttribute && o.getAttribute("id"), m = o.getAttribute && o.getAttribute("src"), y = o.getAttribute && o.getAttribute("href");
|
|
1013
|
+
for (const S of s)
|
|
1014
|
+
if (h && c(S, h) || m && c(S, m) || y && c(S, y))
|
|
1015
|
+
return !0;
|
|
1016
|
+
return !1;
|
|
1017
|
+
}, l = (o) => {
|
|
1018
|
+
if (!o) return;
|
|
1019
|
+
let h;
|
|
1020
|
+
try {
|
|
1021
|
+
const m = new URL(o, globalThis.location?.href || "");
|
|
1022
|
+
h = a(m.pathname);
|
|
1023
|
+
} catch {
|
|
1024
|
+
}
|
|
1025
|
+
return h;
|
|
1026
|
+
}, d = (o) => {
|
|
1027
|
+
if (!o || u(o)) return;
|
|
1028
|
+
const h = typeof HTMLLinkElement < "u" && o instanceof HTMLLinkElement, m = typeof HTMLScriptElement < "u" && o instanceof HTMLScriptElement;
|
|
1029
|
+
if (!h && !m) return;
|
|
1030
|
+
let y = null;
|
|
1031
|
+
if (h) {
|
|
1032
|
+
const I = (o.rel || "").toLowerCase(), M = (o.getAttribute && o.getAttribute("as") || "").toLowerCase();
|
|
1033
|
+
if (!(I === "stylesheet" || I === "modulepreload" || I === "preload" && (M === "script" || M === "style" || M === "font"))) return;
|
|
1034
|
+
y = o.getAttribute && o.getAttribute("href");
|
|
1035
|
+
} else m && (y = o.getAttribute && o.getAttribute("src"));
|
|
1036
|
+
if (!y) return;
|
|
1037
|
+
const S = l(y);
|
|
1038
|
+
S && (!o.hasAttribute || !o.setAttribute || (o.hasAttribute("integrity") || o.setAttribute("integrity", S), i && !o.hasAttribute("crossorigin") && o.setAttribute("crossorigin", i)));
|
|
1039
|
+
};
|
|
1040
|
+
if (t && t.enforceDynamicImports)
|
|
1041
|
+
try {
|
|
1042
|
+
const o = globalThis, h = (k) => {
|
|
1043
|
+
const E = k.indexOf("-");
|
|
1044
|
+
if (E <= 0) return null;
|
|
1045
|
+
const b = k.slice(0, E);
|
|
1046
|
+
return b === "sha256" ? "SHA-256" : b === "sha384" ? "SHA-384" : b === "sha512" ? "SHA-512" : null;
|
|
1047
|
+
}, m = (k) => {
|
|
1048
|
+
let E = "";
|
|
1049
|
+
for (let v = 0; v < k.length; v += 32768)
|
|
1050
|
+
E += String.fromCharCode.apply(null, k.subarray(v, v + 32768));
|
|
1051
|
+
return btoa(E);
|
|
1052
|
+
}, y = async function(k, E) {
|
|
1053
|
+
if (typeof crypto > "u" || !crypto.subtle || typeof btoa > "u")
|
|
1054
|
+
throw new Error(
|
|
1055
|
+
`[vite-plugin-sri-gen] Cannot verify dynamic import for ${E}: crypto.subtle is unavailable (requires a secure context, e.g. HTTPS or localhost)`
|
|
1056
|
+
);
|
|
1057
|
+
let b;
|
|
1058
|
+
try {
|
|
1059
|
+
b = new URL(E, k || globalThis.location?.href || void 0);
|
|
1060
|
+
} catch (G) {
|
|
1061
|
+
throw new Error(
|
|
1062
|
+
`[vite-plugin-sri-gen] Cannot resolve dynamic import specifier ${E}${k ? ` against ${k}` : ""}`,
|
|
1063
|
+
{ cause: G }
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
const v = a(b.pathname);
|
|
1067
|
+
if (!v)
|
|
1068
|
+
throw new Error(
|
|
1069
|
+
`[vite-plugin-sri-gen] Refusing dynamic import: no integrity registered for ${E} (resolved to ${b.href})`
|
|
1070
|
+
);
|
|
1071
|
+
const O = h(v);
|
|
1072
|
+
if (!O)
|
|
1073
|
+
throw new Error(`[vite-plugin-sri-gen] Unsupported integrity algorithm: ${v}`);
|
|
1074
|
+
const j = {};
|
|
1075
|
+
i === "use-credentials" ? j.credentials = "include" : j.credentials = "same-origin";
|
|
1076
|
+
const x = await fetch(b.href, j);
|
|
1077
|
+
if (!x.ok)
|
|
1078
|
+
throw new Error(
|
|
1079
|
+
`[vite-plugin-sri-gen] Failed to fetch ${b.href} for integrity verification (HTTP ${x.status})`
|
|
1080
|
+
);
|
|
1081
|
+
const J = await x.arrayBuffer(), K = await crypto.subtle.digest(O, J), W = v.slice(0, v.indexOf("-") + 1) + m(new Uint8Array(K));
|
|
1082
|
+
if (W !== v)
|
|
1083
|
+
throw new Error(
|
|
1084
|
+
`[vite-plugin-sri-gen] Integrity verification failed for ${b.href} (expected ${v}, got ${W})`
|
|
1085
|
+
);
|
|
1086
|
+
return o.__sriNativeImport(b.href);
|
|
1087
|
+
}, S = "__vitePluginSriGen", I = (k) => !!k && k[S] === !0;
|
|
1088
|
+
if (o.__sriImport && !I(o.__sriImport))
|
|
1089
|
+
throw new Error(
|
|
1090
|
+
"[vite-plugin-sri-gen] Refusing to install: globalThis.__sriImport is already defined by another script. This indicates a pre-installation tampering attempt; dynamic import enforcement cannot proceed."
|
|
1091
|
+
);
|
|
1092
|
+
if (o.__sriNativeImport && !I(o.__sriNativeImport))
|
|
1093
|
+
throw new Error(
|
|
1094
|
+
"[vite-plugin-sri-gen] Refusing to install: globalThis.__sriNativeImport is already defined by another script."
|
|
1095
|
+
);
|
|
1096
|
+
const M = (k) => import(
|
|
1097
|
+
/* @vite-ignore */
|
|
1098
|
+
k
|
|
1099
|
+
);
|
|
1100
|
+
M[S] = !0, y[S] = !0, o.__sriNativeImport = M, o.__sriImport = y;
|
|
1101
|
+
} catch (o) {
|
|
1102
|
+
n = o;
|
|
1103
|
+
}
|
|
1104
|
+
const g = Element?.prototype?.setAttribute;
|
|
1105
|
+
g && (Element.prototype.setAttribute = function(o, h) {
|
|
1106
|
+
const m = g.apply(this, arguments);
|
|
1107
|
+
try {
|
|
1108
|
+
const y = String(o || "").toLowerCase();
|
|
1109
|
+
(this instanceof globalThis.HTMLLinkElement && (y === "href" || y === "rel" || y === "as") || this instanceof globalThis.HTMLScriptElement && y === "src") && d(this);
|
|
1110
|
+
} catch {
|
|
1111
|
+
}
|
|
1112
|
+
return m;
|
|
1113
|
+
});
|
|
1114
|
+
const p = (o, h) => {
|
|
1115
|
+
const m = o && o[h];
|
|
1116
|
+
if (!m || typeof m != "function") return;
|
|
1117
|
+
const y = function() {
|
|
1118
|
+
try {
|
|
1119
|
+
const S = arguments[0];
|
|
1120
|
+
S && d(S);
|
|
1121
|
+
} catch {
|
|
1122
|
+
}
|
|
1123
|
+
return m.apply(this, arguments);
|
|
1124
|
+
};
|
|
1125
|
+
try {
|
|
1126
|
+
Object.defineProperty(o, h, {
|
|
1127
|
+
value: y,
|
|
1128
|
+
configurable: !0,
|
|
1129
|
+
writable: !0
|
|
1130
|
+
});
|
|
1131
|
+
} catch {
|
|
1132
|
+
try {
|
|
1133
|
+
o[h] = y;
|
|
1134
|
+
} catch {
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
p(Node.prototype, "appendChild"), p(Node.prototype, "insertBefore"), p(Element.prototype, "append"), p(Element.prototype, "prepend");
|
|
1139
|
+
} catch {
|
|
1140
|
+
}
|
|
1141
|
+
if (n) throw n;
|
|
1142
|
+
}
|
|
1143
|
+
export {
|
|
1144
|
+
bt as DynamicImportAnalyzer,
|
|
1145
|
+
vt as HtmlProcessor,
|
|
1146
|
+
St as IntegrityProcessor,
|
|
1147
|
+
L as ManifestProcessor,
|
|
1148
|
+
ft as addSriToHtml,
|
|
1149
|
+
U as buildImportIntegrityObject,
|
|
1150
|
+
P as collectModuleChunkFiles,
|
|
1151
|
+
q as computeIntegrity,
|
|
1152
|
+
yt as createLogger,
|
|
1153
|
+
B as escapeForScript,
|
|
1154
|
+
et as extractPathnameFromResourceUrl,
|
|
1155
|
+
st as getUrlAttrName,
|
|
1156
|
+
kt as handleGenerateBundleError,
|
|
1157
|
+
Nt as installSriRuntime,
|
|
1158
|
+
ct as isEligibleForSri,
|
|
1159
|
+
C as isHttpUrl,
|
|
1160
|
+
tt as isImportMapCapableBase,
|
|
1161
|
+
R as isSkippedResource,
|
|
1162
|
+
V as joinBaseHref,
|
|
1163
|
+
rt as loadResource,
|
|
1164
|
+
Et as loadVite,
|
|
1165
|
+
A as matchesPattern,
|
|
1166
|
+
$t as minifyRuntimeSource,
|
|
1167
|
+
F as normalizeBundlePath,
|
|
1168
|
+
Z as preloadHref,
|
|
1169
|
+
at as processElement,
|
|
1170
|
+
it as shouldSkipElement,
|
|
1171
|
+
wt as validateGenerateBundleInputs
|
|
1172
|
+
};
|