@withl5e/l5e 1.0.1 → 1.1.0-alpha.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.
@@ -1,333 +1,2 @@
1
- import { t as e } from "./global-style-Cgno-yNl.js";
2
- import { existsSync as t, mkdirSync as n, readFileSync as r, readdirSync as i, rmSync as a, statSync as o, writeFileSync as s } from "fs";
3
- import { transform as c } from "esbuild";
4
- import { dirname as l, join as u, relative as d, resolve as f } from "path";
5
- //#region src/core/vite-plugin.ts
6
- var p = "virtual:l5e-views", m = "virtual:l5e-route", h = "virtual:l5e-ssr-entry", g = "virtual:l5e-global-loader", _ = "virtual:l5e-island-strategies", v = "virtual:l5e-islands", y = "virtual:l5e-actions", b = "virtual:l5e-middleware", x = /* @__PURE__ */ new Set([
7
- "MODE",
8
- "BASE_URL",
9
- "PROD",
10
- "DEV",
11
- "SSR",
12
- "LEGACY"
13
- ]);
14
- function S(e, t = []) {
15
- let n = i(e);
16
- for (let r of n) {
17
- let n = u(e, r);
18
- if (o(n).isDirectory()) {
19
- if (r === "node_modules" || r === "dist" || r === ".git") continue;
20
- S(n, t);
21
- } else (r.endsWith(".tsx") || r.endsWith(".ts")) && t.push(n);
22
- }
23
- return t;
24
- }
25
- function C(e) {
26
- let t = 0;
27
- for (let n = 0; n < e.length; n++) t = (t << 5) - t + e.charCodeAt(n), t &= t;
28
- return Math.abs(t).toString(16).slice(0, 4);
29
- }
30
- function w(e) {
31
- let t = e.split("/"), n = t[t.length - 1];
32
- return n = n.replace(/\.(tsx?|jsx?)$/, ""), n;
33
- }
34
- function T(e) {
35
- return `${w(e)}_${C(e)}`;
36
- }
37
- function E(e, n) {
38
- let r = e.replace(/^\//, ""), i = f(n, r);
39
- for (let e of [
40
- ".tsx",
41
- ".ts",
42
- ".jsx",
43
- ".js"
44
- ]) if (t(i + e)) return r + e;
45
- return t(i) ? r : null;
46
- }
47
- function D(e, t) {
48
- let n = r(e, "utf-8"), i = [], a = /<ClientIsland\s[^>]*?from\s*=\s*"([^"]+)"/g, o = /* @__PURE__ */ new Set(), s;
49
- for (; (s = a.exec(n)) !== null;) {
50
- let n = s[1], r;
51
- if (n.startsWith("~/")) r = "/src/" + n.substring(2);
52
- else if (n.startsWith("/src/")) r = n;
53
- else if (n.startsWith("./") || n.startsWith("../")) {
54
- let i = f(e, "..", n);
55
- r = "/" + d(t, i).replace(/\\/g, "/");
56
- } else r = n;
57
- let a = E(r, t);
58
- if (!a) {
59
- console.warn(`[l5e] Island component not found: ${r} (from ${n} in ${e})`);
60
- continue;
61
- }
62
- let c = T(r);
63
- o.has(c) || (o.add(c), i.push({
64
- component: w(r),
65
- resolvedPath: r,
66
- src: a,
67
- key: c
68
- }));
69
- }
70
- return i;
71
- }
72
- function O(e, t) {
73
- let n = r(e, "utf-8"), i = [], a = [], o = /useCss\s*\(\s*['"]([^'"]+)['"]\s*,?\s*\)/g, s = /useClientJs\s*\(\s*['"]([^'"]+)['"]\s*,?\s*\)/g, c;
74
- for (; (c = o.exec(n)) !== null;) {
75
- let n = c[1];
76
- if (n.startsWith("/src/")) i.push(n);
77
- else if (n.startsWith("./") || n.startsWith("../")) {
78
- let r = f(e, "..", n), a = "/" + d(t, r).replace(/\\/g, "/");
79
- i.push(a);
80
- } else i.push(n);
81
- }
82
- for (; (c = s.exec(n)) !== null;) {
83
- let n = c[1];
84
- if (n.startsWith("/src/")) a.push(n);
85
- else if (n.startsWith("./") || n.startsWith("../")) {
86
- let r = f(e, "..", n), i = "/" + d(t, r).replace(/\\/g, "/");
87
- a.push(i);
88
- } else a.push(n);
89
- }
90
- return {
91
- css: i,
92
- js: a
93
- };
94
- }
95
- function k(n) {
96
- let i = {}, a = u(n, "src"), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map();
97
- try {
98
- if (!o(a).isDirectory()) return {
99
- input: i,
100
- islandRegistry: s,
101
- pathToKey: c,
102
- keyToSrc: p,
103
- actionRegistry: m
104
- };
105
- let h = u(n, "src", "client.global.ts");
106
- t(h) && (i.global = h, console.log("[l5e] Detected src/client.global.ts and added as entry"));
107
- let g = e(n);
108
- g && (i["global-style"] = g, console.log("[l5e] Detected src/global.css and added as global stylesheet"));
109
- let _ = S(a), v = /* @__PURE__ */ new Set(), y = /* @__PURE__ */ new Set();
110
- for (let e of _) {
111
- let { css: t, js: i } = O(e, n);
112
- t.forEach((e) => v.add(e)), i.forEach((e) => y.add(e));
113
- let o = D(e, n);
114
- for (let e of o) s.set(e.key, e.resolvedPath), c.set(e.resolvedPath, e.key), p.set(e.key, e.src);
115
- let u = e.replace(/\\/g, "/");
116
- if (/\/actions\.(ts|tsx)$/.test(u)) {
117
- let t = r(e, "utf-8"), n = /export\s+const\s+(\w+)\s*=\s*defineAction\s*\(/g, i, o = d(a, l(e)).replace(/\\/g, "/") || ".";
118
- for (; (i = n.exec(t)) !== null;) {
119
- let e = i[1], t = `${e}_${C(o)}`;
120
- m.set(t, {
121
- modulePath: o,
122
- actionName: e
123
- });
124
- }
125
- }
126
- }
127
- for (let e of v) {
128
- let r = e.startsWith("/src/") || e.startsWith("/") ? e.substring(1) : e, a = f(n, r);
129
- if (g && f(a) === f(g)) continue;
130
- if (!t(a)) {
131
- console.warn(`[l5e] CSS file not found: ${a} (from ${e})`);
132
- continue;
133
- }
134
- let o = r.replace(/^src\//, "").replace(/\.css$/, "").replace(/\//g, "-").replace(/\\/g, "-");
135
- i[o] = a;
136
- }
137
- for (let e of y) {
138
- let r = e.startsWith("/src/") || e.startsWith("/") ? e.substring(1) : e, a = f(n, r);
139
- if (!t(a)) {
140
- console.warn(`[l5e] JS/TS file not found: ${a} (from ${e})`);
141
- continue;
142
- }
143
- let o = r.replace(/^src\//, "").replace(/\.(ts|tsx|js|jsx)$/, "").replace(/\//g, "-").replace(/\\/g, "-");
144
- i[o] = a;
145
- }
146
- for (let [e, t] of p) {
147
- let r = f(n, t);
148
- i[`island-${e}`] = r;
149
- }
150
- s.size > 0 && console.log(`[l5e] Detected ${s.size} island(s)`), m.size > 0 && console.log(`[l5e] Detected ${m.size} action(s)`);
151
- } catch (e) {
152
- console.warn("[l5e] Failed to discover bundler input:", e);
153
- }
154
- return {
155
- input: i,
156
- islandRegistry: s,
157
- pathToKey: c,
158
- keyToSrc: p,
159
- actionRegistry: m
160
- };
161
- }
162
- function A(e, t, n, r, i) {
163
- let a = [], o = 0, s = /ClientIsland\s*,\s*\{/g, c;
164
- for (; (c = s.exec(e)) !== null;) {
165
- let s = c.index + c[0].length, l = e.substring(s, s + 500), u = /from:\s*"([^"]+)"/.exec(l);
166
- if (!u) continue;
167
- let p = u[1], m;
168
- if (p.startsWith("~/")) m = "/src/" + p.substring(2);
169
- else if (p.startsWith("/src/")) m = p;
170
- else if (p.startsWith("./") || p.startsWith("../")) {
171
- let e = f(t, "..", p);
172
- m = "/" + d(n, e).replace(/\\/g, "/");
173
- } else m = p;
174
- let h = r.get(m);
175
- if (!h) continue;
176
- let g = i.get(h);
177
- if (!g) continue;
178
- let _ = s + u.index + u[0].length;
179
- a.push(e.substring(o, _)), a.push(`, __key: "${h}", __src: "${g}"`), o = _;
180
- }
181
- return a.push(e.substring(o)), a.join("");
182
- }
183
- function j() {
184
- let e = process.cwd(), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
185
- return {
186
- name: "l5e-jsx-classic",
187
- enforce: "pre",
188
- configResolved(t) {
189
- e = t.root || process.cwd();
190
- },
191
- handleHotUpdate({ file: t, server: n }) {
192
- let r = d(e, t);
193
- if (/actions\.(ts|tsx)$/.test(t)) {
194
- o = k(e).actionRegistry;
195
- let t = n.moduleGraph.getModuleById("\0virtual:l5e-actions");
196
- t && n.moduleGraph.invalidateModule(t), console.log(`[l5e] Action file changed: ${r} — re-scanned ${o.size} action(s)`);
197
- }
198
- if (t.endsWith(".css")) {
199
- console.log(`[l5e] CSS changed: ${r} - using Vite HMR`);
200
- return;
201
- }
202
- if (t.includes("client.ts")) {
203
- console.log(`[l5e] Client JS changed: ${r} - using Vite HMR`);
204
- return;
205
- }
206
- if (t.includes("/src/") || t.includes("\\src\\")) return console.log(`[l5e] SSR file changed: ${r} - triggering full reload`), n.ws.send({
207
- type: "full-reload",
208
- path: "*"
209
- }), [];
210
- },
211
- buildEnd() {
212
- let n = u(e, ".l5e-temp");
213
- if (t(n)) try {
214
- a(n, {
215
- recursive: !0,
216
- force: !0
217
- }), console.log("[l5e] Cleaned up temporary files");
218
- } catch (e) {
219
- console.warn("[l5e] Failed to cleanup temporary files:", e);
220
- }
221
- },
222
- writeBundle(r, i) {
223
- if (o.size > 0) {
224
- let r = u(e, "dist", "server");
225
- t(r) || n(r, { recursive: !0 });
226
- let i = Object.fromEntries(o);
227
- s(u(r, "action-registry.json"), JSON.stringify(i), "utf-8"), console.log(`[l5e] Wrote action-registry.json (${o.size} actions)`);
228
- }
229
- },
230
- config(e) {
231
- let t = k(e.root || process.cwd());
232
- t.islandRegistry, r = t.pathToKey, i = t.keyToSrc, o = t.actionRegistry;
233
- let n = e.build?.rolldownOptions?.input || {}, a = typeof n == "object" && !Array.isArray(n) ? {
234
- ...t.input,
235
- ...n
236
- } : t.input;
237
- return { build: { rolldownOptions: {
238
- ...e.build?.rolldownOptions,
239
- input: Object.keys(a).length > 0 ? a : void 0,
240
- preserveEntrySignatures: "exports-only"
241
- } } };
242
- },
243
- resolveId(e) {
244
- return e === p ? "\0virtual:l5e-views" : e === m ? "\0virtual:l5e-route" : e === h ? "\0virtual:l5e-ssr-entry" : e === g ? "\0virtual:l5e-global-loader" : e === _ ? "\0virtual:l5e-island-strategies" : e === v ? "\0virtual:l5e-islands" : e === y ? "\0virtual:l5e-actions" : e === b ? "\0virtual:l5e-middleware" : null;
245
- },
246
- async transform(t, n, a) {
247
- if (n.replace(/\\/g, "/").endsWith("src/client.global.ts") && !a?.ssr) return {
248
- code: `import '@withl5e/l5e/island/runtime';\n${t}`,
249
- map: null
250
- };
251
- if (!a?.ssr) {
252
- let e = n.replace(/\\/g, "/").match(/\/src\/(.+)\/actions\.(ts|tsx)$/);
253
- if (e) {
254
- let n = e[1], r = /export\s+const\s+(\w+)\s*=\s*defineAction\s*\(/g, i = [], a;
255
- for (; (a = r.exec(t)) !== null;) {
256
- let e = a[1], n = t.substring(a.index, a.index + 500).match(/method:\s*['"](\w+)['"]/), r = n ? n[1].toUpperCase() : "GET";
257
- i.push({
258
- name: e,
259
- method: r
260
- });
261
- }
262
- if (i.length > 0) return {
263
- code: i.map(({ name: e, method: t }) => {
264
- let r = `${e}_${C(n)}`;
265
- return t === "GET" ? `export async function ${e}(params) {
266
- const res = await fetch('/_l5e/action/${r}?' + new URLSearchParams(params));
267
- if (!res.ok) throw Object.assign(new Error('HTTP ' + res.status), { status: res.status });
268
- return res;
269
- }` : `export async function ${e}(body) {
270
- const res = await fetch('/_l5e/action/${r}', {
271
- method: '${t}',
272
- headers: { 'Content-Type': 'application/json' },
273
- body: JSON.stringify(body),
274
- });
275
- if (!res.ok) throw Object.assign(new Error('HTTP ' + res.status), { status: res.status });
276
- return res;
277
- }`;
278
- }).join("\n\n"),
279
- map: null
280
- };
281
- }
282
- }
283
- if (n.includes("node_modules") || n.includes("/react/") || n.includes("\\react\\")) return null;
284
- if (/\.(tsx|jsx)$/.test(n)) try {
285
- let a = `import { Fragment as __Fragment, jsxFactory } from "@withl5e/l5e/jsx-runtime"\n${t}`, o = await c(a, {
286
- loader: n.endsWith(".tsx") ? "tsx" : "jsx",
287
- jsx: "transform",
288
- jsxFactory: "jsxFactory",
289
- jsxFragment: "__Fragment",
290
- sourcemap: !0,
291
- sourcefile: n,
292
- target: "es2020"
293
- }), s = o.code;
294
- return s.includes("ClientIsland") && (s = A(s, n, e, r, i)), {
295
- code: s,
296
- map: o.map || null
297
- };
298
- } catch (e) {
299
- throw console.error(`[l5e] Failed to transform JSX in ${n}:`, e), e;
300
- }
301
- if (a?.ssr) {
302
- let e = t, n = !1;
303
- if (e = e.replace(/import\.meta\.env\.([a-zA-Z_][a-zA-Z0-9_]*)/g, (e, t) => x.has(t) ? e : (n = !0, `process.env.${t}`)), e = e.replace(/import\.meta\.env\[(['"`])([^'"`]+)\1\]/g, (e, t, r) => x.has(r) ? e : (n = !0, `process.env[${t}${r}${t}]`)), n) return {
304
- code: e,
305
- map: null
306
- };
307
- }
308
- return null;
309
- },
310
- load(n) {
311
- if (n === "\0virtual:l5e-views") return "\nexport const viewLoaders = import.meta.glob('/src/views/*/loader.{ts,tsx}');\nexport const viewComponents = import.meta.glob('/src/views/*/index.tsx');\n";
312
- if (n === "\0virtual:l5e-route") return "export default function routeHandler(requestInfo) {\n return import('/src/route.ts').then((mod) => mod.default(requestInfo));\n}";
313
- if (n === "\0virtual:l5e-ssr-entry") return "export { render } from '@withl5e/l5e/entry-server';\nexport { viewActions } from 'virtual:l5e-actions';";
314
- if (n === "\0virtual:l5e-global-loader") return "export const globalLoader = import.meta.glob('/src/global-loader.{ts,tsx}', { eager: false });";
315
- if (n === "\0virtual:l5e-actions") {
316
- let e = Object.fromEntries(o);
317
- return `export const viewActions = import.meta.glob('/src/**/actions.{ts,tsx}');
318
- export const actionRegistry = ${JSON.stringify(e)};`;
319
- }
320
- if (n === "\0virtual:l5e-middleware") return "\nconst middlewareModules = import.meta.glob([\n '/src/middleware.{ts,tsx,js,jsx}',\n '/src/middleware/index.{ts,tsx,js,jsx}',\n]);\n\nconst middlewarePaths = [\n '/src/middleware.ts',\n '/src/middleware.tsx',\n '/src/middleware.js',\n '/src/middleware.jsx',\n '/src/middleware/index.ts',\n '/src/middleware/index.tsx',\n '/src/middleware/index.js',\n '/src/middleware/index.jsx',\n];\n\nexport async function loadMiddleware() {\n const middlewarePath = middlewarePaths.find((path) => middlewareModules[path]);\n if (!middlewarePath) return undefined;\n\n const mod = await middlewareModules[middlewarePath]();\n return mod.onRequest;\n}\n";
321
- if (n === "\0virtual:l5e-islands") return "export const islandModules = import.meta.glob('/src/**/react/*.{tsx,jsx}');";
322
- if (n === "\0virtual:l5e-island-strategies") {
323
- let n = u(e, "src", "island-strategies.ts");
324
- return t(n) ? "import '/src/island-strategies.ts';" : "/* no custom island strategies */";
325
- }
326
- return null;
327
- }
328
- };
329
- }
330
- //#endregion
331
- export { j as coreVite, j as default };
332
-
333
- //# sourceMappingURL=vite-plugin.js.map
1
+ import { t as e } from "./vite-plugin-R3LFxv9a.js";
2
+ export { e as coreVite, e as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withl5e/l5e",
3
- "version": "1.0.1",
3
+ "version": "1.1.0-alpha.1",
4
4
  "description": "HTML-first SSR MPA framework with loaders, middleware, islands, actions, swap, SEO and cache controls.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -16,6 +16,8 @@
16
16
  "sideEffects": [
17
17
  "**/island/runtime.ts",
18
18
  "**/island/runtime.js",
19
+ "**/island/compact-runtime.ts",
20
+ "**/island/compact-runtime.js",
19
21
  "**/*.css"
20
22
  ],
21
23
  "exports": {
@@ -79,6 +81,10 @@
79
81
  "types": "./src/island/runtime.ts",
80
82
  "default": "./dist/island/runtime.js"
81
83
  },
84
+ "./island/compact-runtime": {
85
+ "types": "./src/island/compact-runtime.ts",
86
+ "default": "./dist/island/compact-runtime.js"
87
+ },
82
88
  "./router": {
83
89
  "types": "./src/router/index.ts",
84
90
  "default": "./dist/router.js"
@@ -43,6 +43,16 @@ interface BundleResult {
43
43
  content: string;
44
44
  }
45
45
 
46
+ export interface ScriptBundleOptions {
47
+ compact?: boolean;
48
+ islands?: Array<{ key: string; script: string }>;
49
+ renderer?: string;
50
+ name?: 'global' | 'bundle' | 'shared';
51
+ sharedUrl?: string;
52
+ globalUrl?: string;
53
+ exportScripts?: string[];
54
+ }
55
+
46
56
  const EMPTY_RESULT: BundleResult = { hash: '', filename: '', content: '' };
47
57
 
48
58
  // Memory map để lưu bundled files
@@ -120,22 +130,78 @@ function preserveBuildChunksPlugin(policy: ScriptBundlePolicy): Plugin {
120
130
  };
121
131
  }
122
132
 
133
+ function compactBuildPlugin(
134
+ policy: ScriptBundlePolicy,
135
+ sharedUrl?: string,
136
+ globalUrl?: string,
137
+ ): Plugin {
138
+ return {
139
+ name: 'compact-build-graph',
140
+ resolveId(source, importer) {
141
+ if (!importer || source === VIRTUAL_ENTRY_ID) return null;
142
+ const file = path.isAbsolute(source)
143
+ ? path.normalize(source)
144
+ : source.startsWith('/')
145
+ ? policy.fileForAssetUrl(source)
146
+ : source.startsWith('.')
147
+ ? path.resolve(path.dirname(importer), source)
148
+ : null;
149
+ if (!file) return null;
150
+ return policy.isShared(file) && sharedUrl
151
+ ? { id: sharedUrl, external: 'absolute' }
152
+ : policy.isGlobalOwned(file) && globalUrl
153
+ ? { id: globalUrl, external: 'absolute' }
154
+ : { id: file };
155
+ },
156
+ };
157
+ }
158
+
123
159
  async function runScriptBundle(
124
160
  uniquePaths: string[],
125
161
  policy: ScriptBundlePolicy,
162
+ options: ScriptBundleOptions = {},
126
163
  ): Promise<BundleResult> {
127
164
  const roots = uniquePaths.map((p) => policy.fileForScript(p));
165
+ const compact = options.compact && policy.compact;
128
166
  const suffix = policy.inlineableRoots(roots);
129
167
  const prefixChunks = new Map(
130
168
  roots.flatMap((file, index) =>
131
169
  !policy.isPreserved(file) && !suffix.has(file) ? [[file, `entry-${index}`] as const] : [],
132
170
  ),
133
171
  );
134
- const entryContent = roots.map((filePath) => `import ${JSON.stringify(filePath)};`).join('\n');
172
+ const islands = (options.islands || []).map(({ key, script }) => ({
173
+ key,
174
+ file: policy.fileForScript(script),
175
+ }));
176
+ const renderer = options.renderer ? policy.fileForScript(options.renderer) : undefined;
177
+ const exportFiles = (options.exportScripts || []).map((script) => policy.fileForScript(script));
178
+ const entryContent = [
179
+ ...roots.map((filePath) =>
180
+ options.name === 'shared'
181
+ ? `export * from ${JSON.stringify(filePath)};`
182
+ : `import ${JSON.stringify(filePath)};`,
183
+ ),
184
+ ...exportFiles.map((filePath) => `export * from ${JSON.stringify(filePath)};`),
185
+ ...(islands.length
186
+ ? [
187
+ 'globalThis.__L5E_ISLANDS__ ||= {};',
188
+ ...islands.map(
189
+ ({ key, file }) =>
190
+ `globalThis.__L5E_ISLANDS__[${JSON.stringify(key)}] = async () => { const [renderer, module] = await Promise.all([import(${JSON.stringify(renderer)}), import(${JSON.stringify(file)})]); return { reactDomClient: renderer.reactDomClient, createElement: renderer.createElement, module }; };`,
191
+ ),
192
+ 'globalThis.__L5E_BOOT_ISLANDS__?.();',
193
+ ]
194
+ : []),
195
+ ].join('\n');
135
196
 
136
197
  const rolldownOptions: InputOptions = {
137
198
  input: VIRTUAL_ENTRY_ID,
138
- plugins: [virtualEntryPlugin(entryContent), preserveBuildChunksPlugin(policy)],
199
+ plugins: [
200
+ virtualEntryPlugin(entryContent),
201
+ compact
202
+ ? compactBuildPlugin(policy, options.sharedUrl, options.globalUrl)
203
+ : preserveBuildChunksPlugin(policy),
204
+ ],
139
205
  platform: 'neutral',
140
206
  tsconfig: false,
141
207
  // Runtime scripts are imported for their side effects. Do not let an app's
@@ -156,9 +222,12 @@ async function runScriptBundle(
156
222
 
157
223
  const outputOptions: OutputOptions = {
158
224
  format: 'es',
159
- codeSplitting: { groups: [{ name: (id) => prefixChunks.get(id) ?? null }] },
225
+ codeSplitting: compact
226
+ ? false
227
+ : { groups: [{ name: (id) => prefixChunks.get(id) ?? null }] },
160
228
  minify: false,
161
- entryFileNames: 'bundle-[hash].js',
229
+ entryFileNames: `${options.name || 'bundle'}-[hash].js`,
230
+ strictExecutionOrder: compact,
162
231
  chunkFileNames: `bundle-${generateHash(JSON.stringify(roots))}-[hash].js`,
163
232
  };
164
233
 
@@ -206,6 +275,7 @@ export async function bundleScripts(
206
275
  scriptPaths: string[],
207
276
  distClientDir: string,
208
277
  policy?: ScriptBundlePolicy,
278
+ options: ScriptBundleOptions = {},
209
279
  ): Promise<BundleResult> {
210
280
  if (scriptPaths.length === 0) {
211
281
  return EMPTY_RESULT;
@@ -216,11 +286,11 @@ export async function bundleScripts(
216
286
  return EMPTY_RESULT;
217
287
  }
218
288
 
219
- const uniquePaths = [...new Set(scriptPaths)].sort();
220
- const cacheKey = `scripts:${policy.cacheKey}:${JSON.stringify(uniquePaths)}`;
289
+ const uniquePaths = [...new Set(scriptPaths)];
290
+ const cacheKey = `scripts:${policy.cacheKey}:${JSON.stringify([uniquePaths, options])}`;
221
291
 
222
292
  try {
223
- return await dedupe(cacheKey, () => runScriptBundle(uniquePaths, policy));
293
+ return await dedupe(cacheKey, () => runScriptBundle(uniquePaths, policy, options));
224
294
  } catch (error) {
225
295
  console.error('[bundler] Error bundling scripts:', error);
226
296
  return EMPTY_RESULT;