@zntc/web 0.1.1 → 0.1.3

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/index.js CHANGED
@@ -3,44 +3,52 @@ import { createHash } from "node:crypto";
3
3
  var createHash$1 = createHash;
4
4
  import { watch as fsWatch, readdirSync, existsSync, mkdirSync, readFileSync, writeFileSync, cpSync, mkdtempSync, rmSync, symlinkSync } from "node:fs";
5
5
  var readFileSync$1 = readFileSync;
6
+ var readdirSync$1 = readdirSync;
6
7
  var writeFileSync$1 = writeFileSync;
7
8
  var readFileSync$2 = readFileSync;
8
- var writeFileSync$2 = writeFileSync;
9
9
  var readFileSync$3 = readFileSync;
10
- var writeFileSync$3 = writeFileSync;
10
+ var writeFileSync$2 = writeFileSync;
11
11
  var readFileSync$4 = readFileSync;
12
+ var writeFileSync$3 = writeFileSync;
13
+ var readFileSync$5 = readFileSync;
12
14
  var writeFileSync$4 = writeFileSync;
13
15
  var existsSync$1 = existsSync;
14
16
  var mkdirSync$1 = mkdirSync;
15
17
  var writeFileSync$5 = writeFileSync;
18
+ var readFileSync$6 = readFileSync;
16
19
  import { resolve as resolvePath, join, basename, dirname, relative, sep, extname } from "node:path";
17
20
  var resolve = resolvePath;
18
21
  var join$1 = join;
19
22
  var resolve$1 = resolvePath;
20
23
  var basename$1 = basename;
21
24
  var join$2 = join;
25
+ var dirname$1 = dirname;
26
+ var resolve$2 = resolvePath;
27
+ var sep$1 = sep;
22
28
  var join$3 = join;
23
29
  var basename$2 = basename;
24
- var dirname$1 = dirname;
30
+ var dirname$2 = dirname;
25
31
  var basename$3 = basename;
26
32
  var relative$1 = relative;
27
- var sep$1 = sep;
28
- var dirname$2 = dirname;
33
+ var sep$2 = sep;
34
+ var dirname$3 = dirname;
29
35
  var join$4 = join;
30
36
  var relative$2 = relative;
31
- var resolve$2 = resolvePath;
32
- var sep$2 = sep;
37
+ var resolve$3 = resolvePath;
38
+ var sep$3 = sep;
33
39
  import { createRequire } from "node:module";
40
+ var createRequire$1 = createRequire;
34
41
  import { tmpdir } from "node:os";
42
+ import { fileURLToPath } from "node:url";
35
43
  import { loadEnv, prepareAppDevSync } from "@zntc/core";
36
44
  //#region protocol.ts
37
- const HMR_MSG = Object.freeze({ Connected: "connected", CssUpdate: "css-update", ClearError: "clear-error", Error: "error", FullReload: "full-reload" }),APP_DEV_HMR_CLIENT_PATH = "/__zntc_app_dev_hmr__",APP_DEV_HMR_WS_PATH = "/__hmr",HMR_WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
45
+ const HMR_MSG = Object.freeze({ Connected: "connected", CssUpdate: "css-update", ClearError: "clear-error", Error: "error", FullReload: "full-reload", UpdateStart: "update-start", Update: "update", UpdateDone: "update-done" }),APP_DEV_HMR_CLIENT_PATH = "/__zntc_app_dev_hmr__",APP_DEV_HMR_WS_PATH = "/__hmr",APP_DEV_REACT_REFRESH_PATH = "/__zntc_react_refresh__",HMR_WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
38
46
  function normalizeHmrErrors(errors) {
39
47
  if (!Array.isArray(errors) || errors.length === 0) {
40
48
  return [{ file: "", message: "Unknown build error" }];
41
49
  }
42
50
  return errors.map((error) => {
43
- const e = (error ?? {}),file = typeof e.location?.file == "string" ? e.location.file : "",message = String(e.text ?? e.message ?? error);
51
+ const e = error ?? {},file = typeof e.location?.file == "string" ? e.location.file : "",message = String(e.text ?? e.message ?? error);
44
52
  return { file, message };
45
53
  });
46
54
  }
@@ -165,8 +173,8 @@ function createWatcher(options) {
165
173
  //#endregion
166
174
  //#region hmr-channel.ts
167
175
  function extractErrorText(error) {
168
- const e = (error ?? {});
169
- return ((typeof e.stack == "string" && e.stack) || (typeof e.message == "string" && e.message) || String(error));
176
+ const e = error ?? {};
177
+ return typeof e.stack == "string" && e.stack || typeof e.message == "string" && e.message || String(error);
170
178
  }
171
179
  function createHmrChannel() {
172
180
  const nodeSockets = new Set(),bunClients = new Set(),incomingHandlers = [],connectedText = JSON.stringify({ type: HMR_MSG.Connected });
@@ -194,14 +202,15 @@ function createHmrChannel() {
194
202
  let recvBuffer = Buffer.alloc(0);
195
203
  socket.on("data", (chunk) => {
196
204
  if (incomingHandlers.length === 0)return;
197
- recvBuffer = (recvBuffer.length === 0 ? chunk : Buffer.concat([recvBuffer, chunk]));
205
+ recvBuffer = recvBuffer.length === 0 ? chunk : Buffer.concat([recvBuffer, chunk]);
206
+ const reply = (text) => writeTextFrame(socket, text);
198
207
  while (recvBuffer.length > 0) {
199
208
  const parsed = parseTextFrame(recvBuffer);
200
209
  if (!parsed)break;
201
210
  recvBuffer = recvBuffer.subarray(parsed.consumed);
202
211
  for (const handler of incomingHandlers) {
203
212
  try {
204
- handler(parsed.text, socket);
213
+ handler(parsed.text, reply);
205
214
  } catch {
206
215
  }
207
216
  }
@@ -215,6 +224,15 @@ function createHmrChannel() {
215
224
  greetBun(ws);
216
225
  }, removeBunClient(ws) {
217
226
  bunClients.delete(ws);
227
+ }, dispatchBunIncoming(ws,text) {
228
+ if (incomingHandlers.length === 0)return;
229
+ const reply = (out) => ws.send(out);
230
+ for (const handler of incomingHandlers) {
231
+ try {
232
+ handler(text, reply);
233
+ } catch {
234
+ }
235
+ }
218
236
  }, onIncoming(handler) {
219
237
  incomingHandlers.push(handler);
220
238
  }, broadcast(message) {
@@ -233,6 +251,35 @@ function createHmrChannel() {
233
251
  } };
234
252
  }
235
253
  //#endregion
254
+ //#region hmr-rebuild-broadcast.ts
255
+ function broadcastRebuildEvent(hmr,event) {
256
+ if (!event.success) {
257
+ if (event.errors && event.errors.length > 0) {
258
+ hmr.reportError(event.errors.map((e) => ({ text: e.message, location: { file: e.file } })));
259
+ } else {
260
+ hmr.reportError([{ text: event.error ?? "Unknown build error" }]);
261
+ }
262
+ return "error";
263
+ }
264
+ if (event.errors && event.errors.length > 0) {
265
+ hmr.reportError(event.errors.map((e) => ({ text: e.message, location: { file: e.file } })));
266
+ }
267
+ if (event.graphChanged) {
268
+ if (!event.errors || event.errors.length === 0)hmr.clearError();
269
+ hmr.broadcast({ type: HMR_MSG.FullReload, timestamp: Date.now() });
270
+ return "full-reload";
271
+ }
272
+ if (event.updates && event.updates.length > 0) {
273
+ if (!event.errors || event.errors.length === 0)hmr.clearError();
274
+ hmr.broadcast({ type: HMR_MSG.UpdateStart });
275
+ hmr.broadcast({ type: HMR_MSG.Update, modules: event.updates.map((u) => ({ id: u.id, code: u.code })) });
276
+ hmr.broadcast({ type: HMR_MSG.UpdateDone });
277
+ return "update";
278
+ }
279
+ if (!event.errors || event.errors.length === 0)hmr.clearError();
280
+ return "noop";
281
+ }
282
+ //#endregion
236
283
  //#region url.ts
237
284
  function joinUrl(base,rel) {
238
285
  if (!base)return rel;
@@ -299,7 +346,7 @@ function collectPostcssMessages(messages,deps,dirDeps) {
299
346
  deps.add(resolve$1(message.file));
300
347
  }
301
348
  if (message.type === "dir-dependency") {
302
- const dir = (typeof message.dir == "string" && message.dir) || (typeof message.directory == "string" && message.directory);
349
+ const dir = typeof message.dir == "string" && message.dir || typeof message.directory == "string" && message.directory;
303
350
  if (dir)dirDeps.add(resolve$1(dir));
304
351
  }
305
352
  if (message.type === "context-dependency" && typeof message.file == "string") {
@@ -311,8 +358,8 @@ function logPostcssProcessed(logLevel,count,configFile) {
311
358
  if (logLevel === "silent")return;
312
359
  console.error(`[postcss] processed ${count} CSS file(s) using ${basename(configFile ?? "postcss config")}`);
313
360
  }
314
- async function loadPostcssConfig(root,configEnv,fallbackRequire) {
315
- const postcssrc = requireFromAppRoot(root, fallbackRequire, "postcss-load-config"),postcssModule = requireFromAppRoot(root, fallbackRequire, "postcss"),postcss = (postcssModule.default ?? postcssModule),config = await postcssrc({ cwd: root, env: configEnv.mode }, root).catch((err) => {
361
+ async function loadPostcssConfig(root,configEnv,fallbackRequire,requireBase) {
362
+ const reqBase = requireBase ?? root,postcssrc = requireFromAppRoot(reqBase, fallbackRequire, "postcss-load-config"),postcssModule = requireFromAppRoot(reqBase, fallbackRequire, "postcss"),postcss = postcssModule.default ?? postcssModule,config = await postcssrc({ cwd: root, env: configEnv.mode }, root).catch((err) => {
316
363
  if (err?.message?.includes("No PostCSS Config found"))return null;
317
364
  throw err;
318
365
  });
@@ -321,29 +368,109 @@ async function loadPostcssConfig(root,configEnv,fallbackRequire) {
321
368
  if (plugins.length === 0)return null;
322
369
  return { postcss, plugins, options: config.options ?? {}, configFile: config.file ?? null };
323
370
  }
324
- async function runPostcssIfConfigured(root,cssDir,skipDir,configEnv,logLevel,fallbackRequire) {
325
- const loaded = await loadPostcssConfig(root, configEnv, fallbackRequire);
326
- if (!loaded)return;
371
+ async function runPostcssIfConfigured(root,cssDir,skipDir,configEnv,logLevel,fallbackRequire,override,cssAutoDiscoverRoot) {
372
+ const deps = new Set(),dirDeps = new Set();
373
+ let loaded;
374
+ if (override) {
375
+ if (override.plugins.length === 0)return { deps, dirDeps };
376
+ const requireBase = override.root ?? root;
377
+ let postcssModule;
378
+ try {
379
+ postcssModule = requireFromAppRoot(requireBase, fallbackRequire, "postcss");
380
+ } catch {
381
+ if (logLevel !== "silent") {
382
+ console.error("[postcss] override path: postcss require 실패 — skip");
383
+ }
384
+ return { deps, dirDeps };
385
+ }
386
+ const postcss = postcssModule.default ?? postcssModule;
387
+ loaded = { postcss, plugins: override.plugins, options: override.options ?? {}, configFile: null };
388
+ } else {
389
+ loaded = await loadPostcssConfig(cssAutoDiscoverRoot ?? root, configEnv, fallbackRequire, root);
390
+ }
391
+ if (!loaded)return { deps, dirDeps };
327
392
  const cssFiles = collectAppFiles(cssDir, { skipDir, predicate: isCssFile });
328
393
  await Promise.all(cssFiles.map(async (file) => {
329
394
  const input = readFileSync(file, "utf8"),result = await loaded.postcss(loaded.plugins).process(input, { ...loaded.options, from: file, to: file });
330
395
  writeFileSync(file, result.css);
331
396
  if (result.map)writeFileSync(`${file}.map`, result.map.toString());
397
+ collectPostcssMessages(result.messages, deps, dirDeps);
332
398
  }));
333
399
  logPostcssProcessed(logLevel, cssFiles.length, loaded.configFile);
400
+ return { deps, dirDeps };
334
401
  }
335
402
  async function runPostcssForAppDev(options) {
336
- const { root:root, outdir:outdir, configEnv:configEnv, logLevel:logLevel, base:base, changedPath:changedPath=null, fallbackRequire:fallbackRequire } = options,deps = new Set(),dirDeps = new Set();
403
+ const { root:root, outdir:outdir, configEnv:configEnv, logLevel:logLevel, base:base, changedPath:changedPath=null, fallbackRequire:fallbackRequire, postcssOverride:postcssOverride=null, skipPostcssRun:skipPostcssRun=false, sourceRoot:sourceRoot, cssAutoDiscoverRoot:cssAutoDiscoverRoot=null } = options;
404
+ if (skipPostcssRun && sourceRoot === undefined) {
405
+ throw new Error("runPostcssForAppDev: skipPostcssRun=true 시 sourceRoot 명시 필수 (issue #3853). prepare 의 tempRoot path 전달하지 않으면 raw root 의 PostCSS 미적용 .css 가 mirror 됨.");
406
+ }
407
+ const mirrorRoot = sourceRoot ?? root,deps = new Set(),dirDeps = new Set();
337
408
  let primaryHref = null;
338
- const configPath = findPostcssConfig(root);
339
- if (!configPath) {
340
- const first = collectAppFiles(root, { skipDir: outdir, predicate: isCssFile })[0];
341
- if (first)primaryHref = joinUrl(base, relative(root, first));
409
+ if (skipPostcssRun) {
410
+ const mirrorCssFiles = collectAppFiles(mirrorRoot, { skipDir: outdir, predicate: isCssFile });
411
+ mkdirSync(outdir, { recursive: true });
412
+ for (const f of mirrorCssFiles) {
413
+ const outputRel = relative(mirrorRoot, f),outputPath = join$1(outdir, outputRel);
414
+ mkdirSync(dirname(outputPath), { recursive: true });
415
+ const input = readFileSync(f, "utf8");
416
+ writeFileSync(outputPath, input);
417
+ }
418
+ const watchCssFiles = collectAppFiles(root, { skipDir: outdir, predicate: isCssFile });
419
+ for (const f of watchCssFiles)deps.add(resolve$1(f));
420
+ if (watchCssFiles[0])primaryHref = joinUrl(base, relative(root, watchCssFiles[0]));
421
+ return { deps, dirDeps, primaryHref, processed: 0 };
422
+ }
423
+ const configPath = postcssOverride ? null : findPostcssConfig(cssAutoDiscoverRoot ?? root);
424
+ if (!configPath && !postcssOverride) {
425
+ const mirrorBase = sourceRoot ?? root,allCssFiles = collectAppFiles(mirrorBase, { skipDir: outdir, predicate: isCssFile }),targets = changedPath && changedPath.endsWith(".css") ? allCssFiles.filter((p) => p === changedPath || relative(root, p) === relative(root, changedPath)) : allCssFiles;
426
+ mkdirSync(outdir, { recursive: true });
427
+ for (const file of targets) {
428
+ const outputRel = relative(mirrorBase, file),outputPath = join$1(outdir, outputRel);
429
+ mkdirSync(dirname(outputPath), { recursive: true });
430
+ writeFileSync(outputPath, readFileSync(file, "utf8"));
431
+ }
432
+ const watchCssFiles = collectAppFiles(root, { skipDir: outdir, predicate: isCssFile });
433
+ for (const f of watchCssFiles)deps.add(resolve$1(f));
434
+ if (watchCssFiles[0])primaryHref = joinUrl(base, relative(root, watchCssFiles[0]));
435
+ return { deps, dirDeps, primaryHref, processed: 0 };
436
+ }
437
+ let loaded;
438
+ if (postcssOverride) {
439
+ if (postcssOverride.plugins.length === 0) {
440
+ const allCssFiles = collectAppFiles(root, { skipDir: outdir, predicate: isCssFile });
441
+ for (const f of allCssFiles)deps.add(resolve$1(f));
442
+ if (allCssFiles[0])primaryHref = joinUrl(base, relative(root, allCssFiles[0]));
443
+ return { deps, dirDeps, primaryHref, processed: 0 };
444
+ }
445
+ const requireBase = postcssOverride.root ?? root;
446
+ let postcssModule;
447
+ try {
448
+ postcssModule = requireFromAppRoot(requireBase, fallbackRequire, "postcss");
449
+ } catch {
450
+ if (logLevel !== "silent") {
451
+ console.error("[postcss] override path (dev): postcss require 실패 — skip");
452
+ }
453
+ return { deps, dirDeps, primaryHref, processed: 0 };
454
+ }
455
+ const postcss = postcssModule.default ?? postcssModule;
456
+ loaded = { postcss, plugins: postcssOverride.plugins, options: postcssOverride.options ?? {}, configFile: null };
457
+ } else {
458
+ loaded = await loadPostcssConfig(cssAutoDiscoverRoot ?? root, configEnv, fallbackRequire, root);
459
+ }
460
+ if (!loaded) {
461
+ const mirrorBase = sourceRoot ?? root,allCssFiles = collectAppFiles(mirrorBase, { skipDir: outdir, predicate: isCssFile }),changedRel = changedPath && changedPath.endsWith(".css") ? relative(root, changedPath) : null,targets = changedRel ? allCssFiles.filter((p) => relative(mirrorBase, p) === changedRel) : allCssFiles;
462
+ mkdirSync(outdir, { recursive: true });
463
+ for (const file of targets) {
464
+ const outputRel = relative(mirrorBase, file),outputPath = join$1(outdir, outputRel);
465
+ mkdirSync(dirname(outputPath), { recursive: true });
466
+ writeFileSync(outputPath, readFileSync(file, "utf8"));
467
+ }
468
+ const watchCssFiles = collectAppFiles(root, { skipDir: outdir, predicate: isCssFile });
469
+ for (const f of watchCssFiles)deps.add(resolve$1(f));
470
+ if (watchCssFiles[0])primaryHref = joinUrl(base, relative(root, watchCssFiles[0]));
342
471
  return { deps, dirDeps, primaryHref, processed: 0 };
343
472
  }
344
- const loaded = await loadPostcssConfig(root, configEnv, fallbackRequire);
345
- if (!loaded)return { deps, dirDeps, primaryHref, processed: 0 };
346
- deps.add(resolve$1(loaded.configFile ?? configPath));
473
+ if (loaded.configFile)deps.add(resolve$1(loaded.configFile)); else if (configPath)deps.add(resolve$1(configPath));
347
474
  mkdirSync(outdir, { recursive: true });
348
475
  const allCssFiles = collectAppFiles(root, { skipDir: outdir, predicate: isCssFile }),targets = changedPath && changedPath.endsWith(".css") && allCssFiles.includes(changedPath) ? [changedPath] : allCssFiles;
349
476
  await Promise.all(targets.map(async (file) => {
@@ -381,6 +508,30 @@ function injectAppDevHmrClient(outdir) {
381
508
  return `<script type="module" src="${APP_DEV_HMR_CLIENT_PATH}"></script>`;
382
509
  });
383
510
  }
511
+ function injectAppDevReactRefreshPreamble(outdir) {
512
+ const htmlPath = join$2(outdir, "index.html");
513
+ let html;
514
+ try {
515
+ html = readFileSync$1(htmlPath, "utf8");
516
+ } catch (err) {
517
+ if (err?.code === "ENOENT")return;
518
+ throw err;
519
+ }
520
+ if (html.includes(APP_DEV_REACT_REFRESH_PATH))return;
521
+ const tag = `<script src="${APP_DEV_REACT_REFRESH_PATH}"></script>`,headOpen = html.match(/<head\b[^>]*>/i);
522
+ let next;
523
+ if (headOpen && headOpen.index !== undefined) {
524
+ const at = headOpen.index + headOpen[0].length;
525
+ next = `${html.slice(0, at)}\n${tag}${html.slice(at)}`;
526
+ } else if (html.includes("</head>")) {
527
+ next = html.replace("</head>", `${tag}\n</head>`);
528
+ } else if (html.includes("<script")) {
529
+ next = html.replace("<script", `${tag}\n<script`);
530
+ } else {
531
+ next = `${tag}\n${html}`;
532
+ }
533
+ writeFileSync$1(htmlPath, next);
534
+ }
384
535
  function injectAppDevBundleCssLinks(outdir,base,bundleResult) {
385
536
  injectIntoDevHtml(outdir, (html) => {
386
537
  const cssHrefs = [];
@@ -393,6 +544,24 @@ function injectAppDevBundleCssLinks(outdir,base,bundleResult) {
393
544
  return cssHrefs.map((href) => `<link rel="stylesheet" href="${href}">`).join("\n");
394
545
  });
395
546
  }
547
+ function injectAppDevBundleCssLinksFromOutdir(outdir,base) {
548
+ injectIntoDevHtml(outdir, (html) => {
549
+ let entries;
550
+ try {
551
+ entries = readdirSync$1(outdir);
552
+ } catch {
553
+ return null;
554
+ }
555
+ const cssHrefs = [];
556
+ for (const name of entries) {
557
+ if (!isCssFile(name))continue;
558
+ const href = joinUrl(base, name);
559
+ if (!html.includes(`href="${href}"`) && !html.includes(`href='${href}'`))cssHrefs.push(href);
560
+ }
561
+ if (cssHrefs.length === 0)return null;
562
+ return cssHrefs.map((href) => `<link rel="stylesheet" href="${href}">`).join("\n");
563
+ });
564
+ }
396
565
  function injectAppDevPipelineCssLinks(outdir,base,cssRelPaths) {
397
566
  if (cssRelPaths.length === 0)return;
398
567
  injectIntoDevHtml(outdir, (html) => {
@@ -406,6 +575,33 @@ function injectAppDevPipelineCssLinks(outdir,base,cssRelPaths) {
406
575
  });
407
576
  }
408
577
  //#endregion
578
+ //#region react-refresh-preamble.ts
579
+ const NOOP_PREAMBLE = "console.warn(\"[zntc] react-refresh not found — React Fast Refresh disabled. `npm install react-refresh` for HMR with state preservation.\");\n(function(){var g=typeof globalThis!==\"undefined\"?globalThis:window;g.$RefreshReg$=g.$RefreshReg$||function(){};g.$RefreshSig$=g.$RefreshSig$||function(){return function(t){return t}};})();";
580
+ function buildReactRefreshPreamble(rootDir) {
581
+ const req = createRequire$1(resolve$2(rootDir, "__zntc_resolve__.js"));
582
+ let runtimeSource;
583
+ try {
584
+ const runtimeJsPath = req.resolve("react-refresh/runtime"),pkgDir = dirname$1(runtimeJsPath),dispatcher = readFileSync$2(runtimeJsPath, "utf8"),m = dispatcher.match(/require\((['"])(\.[^'"]*development[^'"]*)\1\)/);
585
+ if (m) {
586
+ const cjsPath = resolve$2(pkgDir, m[2]);
587
+ if (cjsPath !== pkgDir && !cjsPath.startsWith(pkgDir + sep$1))return NOOP_PREAMBLE;
588
+ runtimeSource = readFileSync$2(cjsPath, "utf8");
589
+ } else if (!/\brequire\s*\(/.test(dispatcher)) {
590
+ runtimeSource = dispatcher;
591
+ } else {
592
+ return NOOP_PREAMBLE;
593
+ }
594
+ } catch {
595
+ try {
596
+ req.resolve("react");
597
+ } catch {
598
+ return null;
599
+ }
600
+ return NOOP_PREAMBLE;
601
+ }
602
+ return "(function(){\nvar process={env:{NODE_ENV:\"development\"}};\nvar exports={};var module={exports:exports};\n" + runtimeSource + "\nvar rt=module.exports;\n" + "var g=typeof globalThis!==\"undefined\"?globalThis:window;\n" + "g.__ReactRefresh=rt;g.__REACT_REFRESH_RUNTIME__=rt;\n" + "if(rt&&typeof rt.injectIntoGlobalHook===\"function\")rt.injectIntoGlobalHook(g);\n" + "g.$RefreshReg$=function(){};\n" + "g.$RefreshSig$=function(){return function(t){return t}};\n" + "g.__zntc_react_refresh_preamble__=true;\n" + "})();";
603
+ }
604
+ //#endregion
409
605
  //#region html-env.ts
410
606
  const DEFAULT_HTML_ENV_PREFIX = "ZNTC_";
411
607
  const TOKEN_RE = /<%=\s*([A-Za-z_][A-Za-z0-9_]*)\s*%>/g,HTML_ESCAPE = { "&": "&amp;", "<": "&lt;", ">": "&gt;", "\"": "&quot;" };
@@ -431,7 +627,7 @@ function applyHtmlEnvTokens(outdir,env,prefix=DEFAULT_HTML_ENV_PREFIX) {
431
627
  const htmlPath = join$3(outdir, "index.html");
432
628
  let html;
433
629
  try {
434
- html = readFileSync$2(htmlPath, "utf8");
630
+ html = readFileSync$3(htmlPath, "utf8");
435
631
  } catch (err) {
436
632
  if (err?.code === "ENOENT")return { warnings: [] };
437
633
  throw err;
@@ -470,10 +666,10 @@ function startsWithCssIdent(css,offset,value) {
470
666
  return css.slice(offset, offset + value.length).toLowerCase() === value;
471
667
  }
472
668
  function isCssIdentStart(ch) {
473
- return ch === "_" || (ch >= "A" && ch <= "Z") || (ch >= "a" && ch <= "z");
669
+ return ch === "_" || ch >= "A" && ch <= "Z" || ch >= "a" && ch <= "z";
474
670
  }
475
671
  function isCssIdent(ch) {
476
- return isCssIdentStart(ch) || ch === "-" || (ch >= "0" && ch <= "9");
672
+ return isCssIdentStart(ch) || ch === "-" || ch >= "0" && ch <= "9";
477
673
  }
478
674
  //#endregion
479
675
  //#region sass.ts
@@ -495,7 +691,7 @@ function loadSassCompiler(root,fallbackRequire) {
495
691
  return requireFromAppRoot(root, fallbackRequire, "sass");
496
692
  }
497
693
  function compileSassFile(sass,file,loadRoot) {
498
- return sass.compile(file, { style: "expanded", loadPaths: [dirname$1(file), loadRoot], sourceMap: false });
694
+ return sass.compile(file, { style: "expanded", loadPaths: [dirname$2(file), loadRoot], sourceMap: false });
499
695
  }
500
696
  const STYLE_REFERENCE_RE = /\.(?:html|mjs|cjs|js|jsx|ts|tsx)$/;
501
697
  function isStyleReferenceSource(path) {
@@ -504,7 +700,7 @@ function isStyleReferenceSource(path) {
504
700
  function rewriteSassReferences(sourceFiles) {
505
701
  ;
506
702
  for (const source of sourceFiles) {
507
- const input = readFileSync$3(source, "utf8");
703
+ const input = readFileSync$4(source, "utf8");
508
704
  if (!input.includes(".scss") && !input.includes(".sass"))continue;
509
705
  const toExt = /\.html?$/i.test(source) ? ".css" : ".css.js",output = input.replace(/(["'])([^"']+\.(?:scss|sass))([?#][^"']*)?\1/g, (_match, quote, spec, suffix = "") => `${quote}${spec.replace(/\.(?:scss|sass)$/, toExt)}${suffix}${quote}`);
510
706
  if (output !== input)writeFileSync$3(source, output);
@@ -516,7 +712,7 @@ function buildCssPreprocessorProxy(cssPath) {
516
712
  }
517
713
  function transformCssPreprocessors(root,files,sourceFiles,logLevel,fallbackRequire,options={}) {
518
714
  if (files.length === 0)return [];
519
- const { dirtyOnly:dirtyOnly=null, dirtySources:dirtySources=null } = options,targets = dirtyOnly ? files.filter((f) => dirtyOnly.has(f)) : files;
715
+ const { dirtyOnly:dirtyOnly=null, dirtySources:dirtySources=null, onDeps:onDeps=null } = options,targets = dirtyOnly ? files.filter((f) => dirtyOnly.has(f)) : files;
520
716
  if (targets.length === 0)return files.map(cssPreprocessorOutputPath);
521
717
  let sass;
522
718
  try {
@@ -529,6 +725,7 @@ function transformCssPreprocessors(root,files,sourceFiles,logLevel,fallbackRequi
529
725
  const result = compileSassFile(sass, file, root),cssPath = cssPreprocessorOutputPath(file);
530
726
  writeFileSync$3(cssPath, result.css);
531
727
  writeFileSync$3(cssPreprocessorProxyPath(file), buildCssPreprocessorProxy(cssPath));
728
+ if (onDeps && result.loadedUrls)onDeps(file, result.loadedUrls);
532
729
  }
533
730
  rewriteSassReferences(dirtySources ?? sourceFiles);
534
731
  if (logLevel !== "silent") {
@@ -549,7 +746,7 @@ function cssModuleProxyPath(file) {
549
746
  }
550
747
  const SAFE_LOCAL_RE = /[^a-zA-Z0-9_]/g;
551
748
  function cssModuleLocalName(root,file,local) {
552
- const rel = relative$1(root, file).replaceAll(sep$1, "/"),fileName = basename$3(file, ".module.css").replace(SAFE_LOCAL_RE, "_");
749
+ const rel = relative$1(root, file).replaceAll(sep$2, "/"),fileName = basename$3(file, ".module.css").replace(SAFE_LOCAL_RE, "_");
553
750
  return cssModuleLocalNameWithCachedFile(rel, fileName, local);
554
751
  }
555
752
  function cssModuleLocalNameWithCachedFile(rel,fileName,local) {
@@ -603,7 +800,7 @@ function rewriteCssModuleReferences(sourceFiles) {
603
800
  ;
604
801
  for (const source of sourceFiles) {
605
802
  if (/\.html?$/i.test(source))continue;
606
- const input = readFileSync$4(source, "utf8");
803
+ const input = readFileSync$5(source, "utf8");
607
804
  if (!input.includes(".module.css"))continue;
608
805
  const output = input.replace(/(["'])([^"']+\.module\.css)([?#][^"']*)?\1/g, (_match, quote, spec, suffix = "") => `${quote}${spec}.js${suffix}${quote}`);
609
806
  if (output !== input)writeFileSync$4(source, output);
@@ -614,7 +811,7 @@ function transformCssModules(root,moduleFiles,styleSources,logLevel,options={})
614
811
  const { dirtyOnly:dirtyOnly=null, dirtySources:dirtySources=null } = options,targets = dirtyOnly ? moduleFiles.filter((f) => dirtyOnly.has(f)) : moduleFiles;
615
812
  if (targets.length === 0)return moduleFiles.map(cssModuleGeneratedCssPath);
616
813
  for (const file of targets) {
617
- const css = readFileSync$4(file, "utf8"),tokens = scanCssModuleClassTokens(css),rel = relative$1(root, file).replaceAll(sep$1, "/"),fileName = basename$3(file, ".module.css").replace(SAFE_LOCAL_RE, "_"),mapping = {};
814
+ const css = readFileSync$5(file, "utf8"),tokens = scanCssModuleClassTokens(css),rel = relative$1(root, file).replaceAll(sep$2, "/"),fileName = basename$3(file, ".module.css").replace(SAFE_LOCAL_RE, "_"),mapping = Object.create(null);
618
815
  for (const token of tokens) {
619
816
  if (!mapping[token.local]) {
620
817
  mapping[token.local] = cssModuleLocalNameWithCachedFile(rel, fileName, token.local);
@@ -633,6 +830,7 @@ function transformCssModules(root,moduleFiles,styleSources,logLevel,options={})
633
830
  function rewriteCssModuleClassesWithTokens(css,tokens,mapping) {
634
831
  let out = "",offset = 0;
635
832
  for (const token of tokens) {
833
+ if (!Object.hasOwn(mapping, token.local))continue;
636
834
  const scoped = mapping[token.local];
637
835
  if (!scoped)continue;
638
836
  out += css.slice(offset, token.start);
@@ -653,7 +851,7 @@ function normalizeBase(base) {
653
851
  return normalized;
654
852
  }
655
853
  function mirrorFile(srcAbs,dstAbs) {
656
- mkdirSync$1(dirname$2(dstAbs), { recursive: true });
854
+ mkdirSync$1(dirname$3(dstAbs), { recursive: true });
657
855
  cpSync(srcAbs, dstAbs);
658
856
  }
659
857
  function mirrorPipelineCssToOutdir(pipelineRoot,outdir,absPaths) {
@@ -714,12 +912,12 @@ function cleanupPostcssTempRoot(tempRoot) {
714
912
  function copyAppRootForPostcss(root,outdir,phase,cliNodeModules) {
715
913
  const tempRoot = mkdtempSync(join$4(tmpdir(), `zntc-postcss-${phase}-`));
716
914
  registerPostcssTempRoot(tempRoot);
717
- const skip = new Set([resolve$2(outdir), resolve$2(tempRoot), resolve$2(join$4(root, "node_modules")), resolve$2(join$4(root, ".git")), resolve$2(join$4(root, "dist")), resolve$2(join$4(root, ".zntc-dev"))]);
915
+ const skip = new Set([resolve$3(outdir), resolve$3(tempRoot), resolve$3(join$4(root, "node_modules")), resolve$3(join$4(root, ".git")), resolve$3(join$4(root, "dist")), resolve$3(join$4(root, ".zntc-dev"))]);
718
916
  cpSync(root, tempRoot, { recursive: true, dereference: false, filter(source) {
719
- const abs = resolve$2(source);
720
- if (abs === resolve$2(root))return true;
917
+ const abs = resolve$3(source);
918
+ if (abs === resolve$3(root))return true;
721
919
  for (const ignored of skip) {
722
- if (abs === ignored || abs.startsWith(`${ignored}${sep$2}`))return false;
920
+ if (abs === ignored || abs.startsWith(`${ignored}${sep$3}`))return false;
723
921
  }
724
922
  return true;
725
923
  } });
@@ -729,18 +927,54 @@ function copyAppRootForPostcss(root,outdir,phase,cliNodeModules) {
729
927
  }
730
928
  return tempRoot;
731
929
  }
930
+ function recordSassReverseDep(reverseDep,file,loadedUrls) {
931
+ for (const url of loadedUrls) {
932
+ let dep;
933
+ try {
934
+ dep = fileURLToPath(url);
935
+ } catch {
936
+ continue;
937
+ }
938
+ if (dep === file)continue;
939
+ let set = reverseDep.get(dep);
940
+ if (!set) {
941
+ set = new Set();
942
+ reverseDep.set(dep, set);
943
+ }
944
+ set.add(file);
945
+ }
946
+ }
732
947
  async function prepareAppCssPipelineRoot(root,outdir,configEnv,logLevel,phase,deps,options={}) {
733
- const { existingTempRoot:existingTempRoot=null, dirtyPaths:dirtyPaths=null, cache:cache=null } = options,{ fallbackRequire:fallbackRequire, cliNodeModules:cliNodeModules } = deps,configPath = findPostcssConfig(root),stylePipelineFiles = cache?.stylePipelineFiles ?? collectAppFiles(root, { skipDir: outdir, predicate: (path) => isCssPreprocessorFile(path) || isCssModuleFile(path) }),preprocessorFiles = stylePipelineFiles.filter(isCssPreprocessorFile),moduleFiles = stylePipelineFiles.filter(isCssModuleFile),needsSource = preprocessorFiles.length > 0 || moduleFiles.length > 0;
734
- if (!configPath && !needsSource)return null;
948
+ const { existingTempRoot:existingTempRoot=null, dirtyPaths:dirtyPaths=null, cache:cache=null, sassReverseDep:sassReverseDep=null, postcssOverride:postcssOverride=null, cssAutoDiscoverRoot:cssAutoDiscoverRoot=null } = options,{ fallbackRequire:fallbackRequire, cliNodeModules:cliNodeModules } = deps,configPath = postcssOverride ? null : findPostcssConfig(cssAutoDiscoverRoot ?? root);
949
+ if (cssAutoDiscoverRoot && !configPath && !postcssOverride && logLevel !== "silent") {
950
+ console.error(`[postcss] css({root}) 명시 — ${cssAutoDiscoverRoot} 에서 postcss.config.* 발견 못함 — auto-discover skip`);
951
+ }
952
+ const stylePipelineFiles = cache?.stylePipelineFiles ?? collectAppFiles(root, { skipDir: outdir, predicate: (path) => isCssPreprocessorFile(path) || isCssModuleFile(path) }),preprocessorFiles = stylePipelineFiles.filter(isCssPreprocessorFile),moduleFiles = stylePipelineFiles.filter(isCssModuleFile),needsSource = preprocessorFiles.length > 0 || moduleFiles.length > 0;
953
+ if (!configPath && !needsSource && !postcssOverride)return null;
735
954
  const tempRoot = existingTempRoot ?? copyAppRootForPostcss(root, outdir, phase, cliNodeModules),isIncremental = existingTempRoot && dirtyPaths;
736
955
  if (isIncremental && dirtyPaths) {
737
956
  syncDirtyFilesIntoTempRoot(root, tempRoot, dirtyPaths);
738
957
  }
739
- const toTemp = (path) => join$4(tempRoot, relative$2(root, path)),styleSourceFiles = !needsSource ? [] : (cache?.styleSourceFiles ?? collectAppFiles(tempRoot, { predicate: isStyleReferenceSource }));
958
+ const toTemp = (path) => join$4(tempRoot, relative$2(root, path)),recordSassDeps = (file, loadedUrls) => {
959
+ if (sassReverseDep)recordSassReverseDep(sassReverseDep, file, loadedUrls);
960
+ },styleSourceFiles = !needsSource ? [] : cache?.styleSourceFiles ?? collectAppFiles(tempRoot, { predicate: isStyleReferenceSource });
740
961
  let dirtySassSet = null,dirtyModuleSet = null,dirtySourceList = null;
741
962
  if (isIncremental && dirtyPaths) {
742
963
  const dirtyTempPaths = dirtyPaths.map(toTemp);
743
964
  dirtySassSet = new Set(dirtyTempPaths.filter((p) => isCssPreprocessorFile(p)));
965
+ if (sassReverseDep) {
966
+ const queue = [...dirtySassSet];
967
+ while (queue.length > 0) {
968
+ const dep = queue.pop(),dependents = sassReverseDep.get(dep);
969
+ if (!dependents)continue;
970
+ for (const dependent of dependents) {
971
+ if (!dirtySassSet.has(dependent)) {
972
+ dirtySassSet.add(dependent);
973
+ queue.push(dependent);
974
+ }
975
+ }
976
+ }
977
+ }
744
978
  dirtyModuleSet = new Set(dirtyTempPaths.filter((p) => isCssModuleFile(p)));
745
979
  for (const sassDirty of dirtySassSet) {
746
980
  const cssOut = cssPreprocessorOutputPath(sassDirty);
@@ -748,16 +982,21 @@ async function prepareAppCssPipelineRoot(root,outdir,configEnv,logLevel,phase,de
748
982
  }
749
983
  dirtySourceList = dirtyTempPaths.filter((p) => isStyleReferenceSource(p) && existsSync$1(p));
750
984
  }
751
- const sassOutputs = transformCssPreprocessors(tempRoot, preprocessorFiles.map(toTemp), styleSourceFiles, logLevel, fallbackRequire, isIncremental ? { dirtyOnly: dirtySassSet, dirtySources: dirtySourceList } : undefined),postcssRelevant = !isIncremental || (dirtyPaths !== null && dirtyPaths.some((p) => isCssFile(p) || isCssPreprocessorFile(p) || isPostcssConfigFile(p)));
985
+ const sassOutputs = transformCssPreprocessors(tempRoot, preprocessorFiles.map(toTemp), styleSourceFiles, logLevel, fallbackRequire, isIncremental ? { dirtyOnly: dirtySassSet, dirtySources: dirtySourceList, onDeps: recordSassDeps } : { onDeps: recordSassDeps }),postcssRelevant = !isIncremental || dirtyPaths !== null && dirtyPaths.some((p) => isCssFile(p) || isCssPreprocessorFile(p) || isPostcssConfigFile(p));
986
+ let postcssDeps,postcssDirDeps;
752
987
  if (postcssRelevant) {
753
- await runPostcssIfConfigured(tempRoot, tempRoot, null, configEnv, logLevel, fallbackRequire);
988
+ const postcssResult = await runPostcssIfConfigured(tempRoot, tempRoot, null, configEnv, logLevel, fallbackRequire, postcssOverride, cssAutoDiscoverRoot);
989
+ postcssDeps = postcssResult.deps;
990
+ postcssDirDeps = postcssResult.dirDeps;
754
991
  }
755
992
  const generatedModuleFiles = preprocessorFiles.map(cssPreprocessorOutputPath).filter(isCssModuleFile),moduleOutputs = transformCssModules(tempRoot, [...moduleFiles, ...generatedModuleFiles].map(toTemp), styleSourceFiles, logLevel, isIncremental ? { dirtyOnly: dirtyModuleSet, dirtySources: dirtySourceList } : undefined),moduleInputCssPaths = new Set(generatedModuleFiles.map((p) => join$4(tempRoot, relative$2(root, p)))),generatedCssAbsPaths = [...sassOutputs.filter((p) => !moduleInputCssPaths.has(p)), ...moduleOutputs];
756
- return { tempRoot, generatedCssAbsPaths, cache: { stylePipelineFiles, styleSourceFiles } };
993
+ return { tempRoot, generatedCssAbsPaths, cache: { stylePipelineFiles, styleSourceFiles }, postcssDeps, postcssDirDeps };
757
994
  }
758
995
  function createAppDevController(opts,root,configEnv,deps) {
759
- const { fallbackRequire:fallbackRequire } = deps,outdir = resolve$2(opts.outdir || join$4(root, ".zntc-dev")),base = normalizeBase(opts.base ?? opts.publicPath ?? "/");
760
- let cssDeps = new Set(),cssDirDeps = new Set(),primaryHref = null,pipelineRoot = null,pipelineCache = null,hasPipelineCss = false,htmlEnvCache = null;
996
+ const { fallbackRequire:fallbackRequire } = deps,outdir = resolve$3(opts.outdir || join$4(root, ".zntc-dev")),base = normalizeBase(opts.base ?? opts.publicPath ?? "/"),reactRefreshInject = opts.reactRefresh === true && buildReactRefreshPreamble(opts.appRoot ?? root) != null;
997
+ let cssDeps = new Set(),cssDirDeps = new Set(),preparePostcssApplied = false,preparePostcssDeps = new Set(),preparePostcssDirDeps = new Set();
998
+ const sassReverseDep = new Map();
999
+ let primaryHref = null,pipelineRoot = null,pipelineCache = null,hasPipelineCss = false,htmlEnvCache = null;
761
1000
  const warnedHtmlEnv = new Set();
762
1001
  return { root, outdir, base, async prepare(dirtyPaths=null) {
763
1002
  const reuseRoot = pipelineRoot && dirtyPaths != null;
@@ -765,15 +1004,23 @@ function createAppDevController(opts,root,configEnv,deps) {
765
1004
  cleanupPostcssTempRoot(pipelineRoot);
766
1005
  pipelineRoot = null;
767
1006
  pipelineCache = null;
1007
+ sassReverseDep.clear();
768
1008
  }
769
1009
  if (reuseRoot && dirtyPaths && dirtyPaths.some((p) => isCssPreprocessorFile(p) || isCssModuleFile(p))) {
770
1010
  pipelineCache = null;
771
1011
  }
772
- const pipeline = await prepareAppCssPipelineRoot(root, outdir, configEnv, opts.logLevel, "dev", deps, reuseRoot ? { existingTempRoot: pipelineRoot, dirtyPaths, cache: pipelineCache } : undefined);
1012
+ const postcssOverride = opts.postcssOverride ?? null,cssAutoDiscoverRoot = opts.cssAutoDiscoverRoot ?? null,pipeline = await prepareAppCssPipelineRoot(root, outdir, configEnv, opts.logLevel, "dev", deps, reuseRoot ? { existingTempRoot: pipelineRoot, dirtyPaths, cache: pipelineCache, sassReverseDep, postcssOverride, cssAutoDiscoverRoot } : { sassReverseDep, postcssOverride, cssAutoDiscoverRoot });
773
1013
  pipelineRoot = pipeline?.tempRoot ?? null;
774
1014
  pipelineCache = pipeline?.cache ?? null;
775
1015
  hasPipelineCss = (pipeline?.generatedCssAbsPaths.length ?? 0) > 0;
776
- const prepareRoot = pipelineRoot ?? root,envDir = opts.envDir ? resolve$2(opts.envDir) : prepareRoot,prepared = prepareAppDevSync({ root: prepareRoot, outdir, entryHtml: opts.entryHtml ?? "index.html", publicDir: opts.publicDir === undefined ? "public" : opts.publicDir, base, mode: configEnv.mode, envDir, envPrefixes: opts.envPrefixes ? Array.from(opts.envPrefixes) : undefined }),htmlEnv = htmlEnvCache && htmlEnvCache.mode === configEnv.mode && htmlEnvCache.dir === envDir ? htmlEnvCache.env : (htmlEnvCache = { mode: configEnv.mode, dir: envDir, env: loadEnv(configEnv.mode, envDir, ["ZNTC_"]) }).env,{ warnings:htmlWarnings } = applyHtmlEnvTokens(outdir, htmlEnv);
1016
+ preparePostcssApplied = !!pipeline;
1017
+ if (pipeline?.postcssDeps !== undefined) {
1018
+ preparePostcssDeps = pipeline.postcssDeps;
1019
+ }
1020
+ if (pipeline?.postcssDirDeps !== undefined) {
1021
+ preparePostcssDirDeps = pipeline.postcssDirDeps;
1022
+ }
1023
+ const prepareRoot = pipelineRoot ?? root,envDir = opts.envDir ? resolve$3(opts.envDir) : prepareRoot,prepared = prepareAppDevSync({ root: prepareRoot, outdir, entryHtml: opts.entryHtml ?? "index.html", publicDir: opts.publicDir === undefined ? "public" : opts.publicDir, base, mode: configEnv.mode, envDir, envPrefixes: opts.envPrefixes ? Array.from(opts.envPrefixes) : undefined }),htmlEnv = htmlEnvCache && htmlEnvCache.mode === configEnv.mode && htmlEnvCache.dir === envDir ? htmlEnvCache.env : (htmlEnvCache = { mode: configEnv.mode, dir: envDir, env: loadEnv(configEnv.mode, envDir, ["ZNTC_"]) }).env,{ warnings:htmlWarnings } = applyHtmlEnvTokens(outdir, htmlEnv);
777
1024
  if (opts.logLevel !== "silent") {
778
1025
  for (const w of htmlWarnings) {
779
1026
  if (warnedHtmlEnv.has(w))continue;
@@ -782,42 +1029,65 @@ function createAppDevController(opts,root,configEnv,deps) {
782
1029
  }
783
1030
  }
784
1031
  injectAppDevHmrClient(outdir);
1032
+ if (reactRefreshInject)injectAppDevReactRefreshPreamble(outdir);
785
1033
  if (pipeline && pipeline.generatedCssAbsPaths.length > 0 && pipelineRoot) {
786
- const sassOrModuleDirty = !reuseRoot || (dirtyPaths !== null && dirtyPaths.some((p) => isCssPreprocessorFile(p) || isCssModuleFile(p))),rels = sassOrModuleDirty ? mirrorPipelineCssToOutdir(pipelineRoot, outdir, pipeline.generatedCssAbsPaths) : pipeline.generatedCssAbsPaths.map((p) => relative$2(pipelineRoot ?? root, p));
1034
+ const sassOrModuleDirty = !reuseRoot || dirtyPaths !== null && dirtyPaths.some((p) => isCssPreprocessorFile(p) || isCssModuleFile(p)),rels = sassOrModuleDirty ? mirrorPipelineCssToOutdir(pipelineRoot, outdir, pipeline.generatedCssAbsPaths) : pipeline.generatedCssAbsPaths.map((p) => relative$2(pipelineRoot ?? root, p));
787
1035
  injectAppDevPipelineCssLinks(outdir, base, rels);
788
1036
  }
789
1037
  return prepared;
1038
+ }, syncDirty(dirtyPaths) {
1039
+ if (!pipelineRoot)return;
1040
+ syncDirtyFilesIntoTempRoot(root, pipelineRoot, dirtyPaths);
790
1041
  }, async afterBundle({ changedPath:changedPath=null }={}) {
791
- const result = await runPostcssForAppDev({ root, outdir, configEnv, logLevel: opts.logLevel, base, changedPath, fallbackRequire });
1042
+ const skipPostcssRun = preparePostcssApplied && !changedPath,result = await runPostcssForAppDev({ root, outdir, configEnv, logLevel: opts.logLevel, base, changedPath, fallbackRequire, postcssOverride: opts.postcssOverride ?? null, skipPostcssRun, sourceRoot: pipelineRoot ?? root, cssAutoDiscoverRoot: opts.cssAutoDiscoverRoot ?? null });
792
1043
  cssDeps = result.deps;
793
1044
  cssDirDeps = result.dirDeps;
1045
+ if (preparePostcssApplied) {
1046
+ for (const d of preparePostcssDeps)cssDeps.add(d);
1047
+ for (const d of preparePostcssDirDeps)cssDirDeps.add(d);
1048
+ }
794
1049
  primaryHref = result.primaryHref;
795
- return result;
1050
+ return { ...result, deps: cssDeps, dirDeps: cssDirDeps };
796
1051
  }, injectBundleCssLinks(bundleResult) {
797
1052
  if (hasPipelineCss)return;
798
1053
  injectAppDevBundleCssLinks(outdir, base, bundleResult);
1054
+ }, injectBundleCssLinksFromOutdir() {
1055
+ if (hasPipelineCss)return;
1056
+ injectAppDevBundleCssLinksFromOutdir(outdir, base);
799
1057
  }, isPostcssConfig(absPath) {
800
1058
  return isPostcssConfigFile(absPath);
1059
+ }, isCssLikeChange(absPath) {
1060
+ if (isPostcssConfigFile(absPath))return true;
1061
+ if (isCssFile(absPath) || isCssPreprocessorFile(absPath))return true;
1062
+ if (isCssModuleFile(absPath) || isCssModulePreprocessorFile(absPath))return true;
1063
+ return false;
801
1064
  }, isCssOnlyChange(absPath) {
802
1065
  if (isCssModuleFile(absPath) || isCssModulePreprocessorFile(absPath))return false;
803
1066
  if (isCssFile(absPath) || isCssPreprocessorFile(absPath))return true;
804
1067
  if (cssDeps.has(absPath))return true;
805
1068
  for (const dir of cssDirDeps) {
806
- if (absPath === dir || absPath.startsWith(`${dir}${sep$2}`))return true;
1069
+ if (absPath === dir || absPath.startsWith(`${dir}${sep$3}`))return true;
807
1070
  }
808
1071
  return false;
809
1072
  }, isSassOnlyChange(absPath) {
810
- return isCssPreprocessorFile(absPath) && !isCssModulePreprocessorFile(absPath);
1073
+ if (!isCssPreprocessorFile(absPath) || isCssModulePreprocessorFile(absPath))return false;
1074
+ if (pipelineRoot) {
1075
+ const temp = join$4(pipelineRoot, relative$2(root, absPath));
1076
+ if (sassReverseDep.has(temp))return false;
1077
+ }
1078
+ return true;
811
1079
  }, async rebuildScssIncremental(absPath) {
812
1080
  if (!pipelineRoot)return null;
813
1081
  if (findPostcssConfig(root))return null;
814
1082
  const srcTemp = join$4(pipelineRoot, relative$2(root, absPath));
815
1083
  mirrorFile(absPath, srcTemp);
816
- const sass = loadSassCompiler(root, fallbackRequire),result = compileSassFile(sass, srcTemp, pipelineRoot),cssTempPath = cssPreprocessorOutputPath(srcTemp);
1084
+ const sass = loadSassCompiler(root, fallbackRequire),result = compileSassFile(sass, srcTemp, pipelineRoot);
1085
+ if (result.loadedUrls)recordSassReverseDep(sassReverseDep, srcTemp, result.loadedUrls);
1086
+ const cssTempPath = cssPreprocessorOutputPath(srcTemp);
817
1087
  writeFileSync$5(cssTempPath, result.css);
818
1088
  const cssRel = relative$2(pipelineRoot, cssTempPath);
819
1089
  mirrorFile(cssTempPath, join$4(outdir, cssRel));
820
- return joinUrl(base, cssRel.replaceAll(sep$2, "/"));
1090
+ return joinUrl(base, cssRel.replaceAll(sep$3, "/"));
821
1091
  }, hrefFor(absPath) {
822
1092
  if (absPath.endsWith(".css"))return joinUrl(base, relative$2(root, absPath));
823
1093
  return primaryHref ?? joinUrl(base, "style.css");
@@ -825,300 +1095,16 @@ function createAppDevController(opts,root,configEnv,deps) {
825
1095
  }
826
1096
  //#endregion
827
1097
  //#region dev-overlay-client.mjs
828
- const APP_DEV_HMR_CLIENT = `
829
- const socketProtocol = location.protocol === "https:" ? "wss:" : "ws:";
830
- let overlay = null;
831
- let closeOverlayOnEsc = null;
832
- function hideOverlay() {
833
- if (closeOverlayOnEsc) document.removeEventListener("keydown", closeOverlayOnEsc);
834
- closeOverlayOnEsc = null;
835
- if (overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay);
836
- overlay = null;
837
- }
838
- function normalizeErrors(errors) {
839
- if (!Array.isArray(errors) || errors.length === 0) {
840
- return [{ file: "", message: "Unknown build error" }];
841
- }
842
- return errors.map((error) => {
843
- if (typeof error === "string") return { file: "", message: error };
844
- return {
845
- file: error && typeof error.file === "string" ? error.file : "",
846
- message: error && typeof error.message === "string" ? error.message : String(error),
847
- };
848
- });
849
- }
850
- function normalizeRuntimeError(error, file) {
851
- if (error && typeof error.stack === "string" && error.stack) {
852
- return { file: file || "", message: error.stack };
853
- }
854
- if (error && typeof error.message === "string" && error.message) {
855
- const name = typeof error.name === "string" && error.name ? error.name : "Error";
856
- return { file: file || "", message: name + ": " + error.message };
857
- }
858
- return { file: file || "", message: String(error || "Unknown runtime error") };
859
- }
860
- const sourceMapCache = new Map();
861
- const sourceMapVlqChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
862
- function displaySourceName(source) {
863
- if (!source) return "";
864
- const clean = String(source).split("?")[0].split("#")[0];
865
- const slash = Math.max(clean.lastIndexOf("/"), clean.lastIndexOf("\\\\"));
866
- return slash >= 0 ? clean.slice(slash + 1) : clean;
867
- }
868
- function decodeSourceMapVlq(segment) {
869
- const values = [];
870
- let result = 0;
871
- let shift = 0;
872
- for (const ch of segment) {
873
- let digit = sourceMapVlqChars.indexOf(ch);
874
- if (digit < 0) return values;
875
- const continuation = digit & 32;
876
- digit &= 31;
877
- result += digit << shift;
878
- if (continuation) {
879
- shift += 5;
880
- continue;
881
- }
882
- const negative = result & 1;
883
- const value = result >> 1;
884
- values.push(negative ? -value : value);
885
- result = 0;
886
- shift = 0;
887
- }
888
- return values;
889
- }
890
- function parseSourceMapMappings(map) {
891
- if (map.__zntcParsedMappings) return map.__zntcParsedMappings;
892
- let source = 0;
893
- let originalLine = 0;
894
- let originalColumn = 0;
895
- let name = 0;
896
- const parsed = [];
897
- for (const line of String(map.mappings || "").split(";")) {
898
- let generatedColumn = 0;
899
- const segments = [];
900
- for (const segment of line.split(",")) {
901
- if (!segment) continue;
902
- const values = decodeSourceMapVlq(segment);
903
- if (values.length === 0) continue;
904
- generatedColumn += values[0];
905
- if (values.length >= 4) {
906
- source += values[1];
907
- originalLine += values[2];
908
- originalColumn += values[3];
909
- if (values.length >= 5) name += values[4];
910
- segments.push({ generatedColumn, source, originalLine, originalColumn });
911
- }
912
- }
913
- parsed.push(segments);
914
- }
915
- Object.defineProperty(map, "__zntcParsedMappings", { value: parsed });
916
- return parsed;
917
- }
918
- function findOriginalPosition(map, line, column) {
919
- const segments = parseSourceMapMappings(map)[line - 1];
920
- if (!segments || segments.length === 0) return null;
921
- let lo = 0;
922
- let hi = segments.length - 1;
923
- let best = null;
924
- while (lo <= hi) {
925
- const mid = (lo + hi) >> 1;
926
- const segment = segments[mid];
927
- if (segment.generatedColumn <= column) {
928
- best = segment;
929
- lo = mid + 1;
930
- } else {
931
- hi = mid - 1;
932
- }
933
- }
934
- best = best || segments[0];
935
- const source = map.sources && map.sources[best.source];
936
- if (!source) return null;
937
- const columnOffset = Math.max(0, column - best.generatedColumn);
938
- return {
939
- source: displaySourceName(source),
940
- line: best.originalLine + 1,
941
- column: best.originalColumn + columnOffset,
942
- };
943
- }
944
- async function loadSourceMapForGeneratedUrl(url) {
945
- const generatedUrl = new URL(url, location.href).href;
946
- if (sourceMapCache.has(generatedUrl)) return sourceMapCache.get(generatedUrl);
947
- const safeJson = async (response) => {
948
- try { return await response.json(); } catch (_) { return null; }
949
- };
950
- const promise = (async () => {
951
- const direct = await fetch(generatedUrl + ".map", { cache: "no-store" }).catch(() => null);
952
- if (direct && direct.ok) return safeJson(direct);
953
- const jsResponse = await fetch(generatedUrl, { cache: "no-store" }).catch(() => null);
954
- if (!jsResponse || !jsResponse.ok) return null;
955
- const code = await jsResponse.text();
956
- const match =
957
- code.match(/\\/\\/[#@]\\s*sourceMappingURL=([^\\n\\r]+)/) ||
958
- code.match(/\\/\\*[#@]\\s*sourceMappingURL=([^*]+)\\*\\//);
959
- if (!match) return null;
960
- const ref = match[1].trim();
961
- if (ref.startsWith("data:")) {
962
- const comma = ref.indexOf(",");
963
- if (comma < 0) return null;
964
- const meta = ref.slice(0, comma);
965
- const data = ref.slice(comma + 1);
966
- try {
967
- const json = meta.includes(";base64") ? atob(data) : decodeURIComponent(data);
968
- return JSON.parse(json);
969
- } catch (_) {
970
- return null;
971
- }
972
- }
973
- const mapResponse = await fetch(new URL(ref, generatedUrl).href, { cache: "no-store" }).catch(() => null);
974
- return mapResponse && mapResponse.ok ? safeJson(mapResponse) : null;
975
- })();
976
- sourceMapCache.set(generatedUrl, promise);
977
- return promise;
978
- }
979
- async function mapGeneratedLocation(url, line, column) {
980
- const map = await loadSourceMapForGeneratedUrl(url);
981
- return map ? findOriginalPosition(map, line, column) : null;
982
- }
983
- async function mapLocationText(text) {
984
- if (!text) return text;
985
- const match = String(text).match(/(https?:\\/\\/[^\\s)]+):(\\d+):(\\d+)/);
986
- if (!match) return text;
987
- const mapped = await mapGeneratedLocation(match[1], Number(match[2]), Number(match[3]));
988
- if (!mapped) return text;
989
- return String(text).replace(match[0], mapped.source + ":" + mapped.line + ":" + mapped.column);
990
- }
991
- async function mapStackTrace(stack) {
992
- if (typeof stack !== "string") return stack;
993
- const lines = await Promise.all(stack.split("\\n").map(mapLocationText));
994
- return lines.join("\\n");
995
- }
996
- async function normalizeRuntimeErrorWithSourceMap(error, file) {
997
- const item = normalizeRuntimeError(error, file);
998
- item.file = await mapLocationText(item.file);
999
- item.message = await mapStackTrace(item.message);
1000
- return item;
1001
- }
1002
- async function showRuntimeOverlay(error, file) {
1003
- let item;
1004
- try {
1005
- item = await normalizeRuntimeErrorWithSourceMap(error, file);
1006
- } catch (_) {
1007
- item = normalizeRuntimeError(error, file);
1008
- }
1009
- showOverlay([item], "Runtime Error");
1010
- }
1011
- function showOverlay(errors, titleText = "Build Error") {
1012
- hideOverlay();
1013
- const items = normalizeErrors(errors);
1014
- overlay = document.createElement("div");
1015
- overlay.id = "zntc-error-overlay";
1016
- const root = overlay.attachShadow({ mode: "open" });
1017
- const style = document.createElement("style");
1018
- style.textContent = ":host{position:fixed;inset:0;z-index:2147483647;display:block;--font:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;--red:#fb7185;--text:#f8fafc;--blue:#93c5fd;--window:#181818;}" +
1019
- ".backdrop{position:fixed;inset:0;overflow:auto;padding:32px;box-sizing:border-box;background:rgba(0,0,0,.66);font:14px/1.5 var(--font);color:var(--text);}" +
1020
- ".window{max-width:980px;margin:0 auto;background:var(--window);border-top:8px solid var(--red);border-radius:6px 6px 8px 8px;box-shadow:0 19px 38px rgba(0,0,0,.30),0 15px 12px rgba(0,0,0,.22);overflow:hidden;}" +
1021
- ".header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:18px 20px;border-bottom:1px solid rgba(255,255,255,.12);}" +
1022
- ".title{font-size:18px;font-weight:700;color:#fecdd3;}" +
1023
- ".close{width:30px;height:30px;border:1px solid rgba(255,255,255,.25);border-radius:4px;background:#111827;color:var(--text);cursor:pointer;font:18px/1 var(--font);}" +
1024
- ".card{padding:18px 20px;border-top:1px solid rgba(255,255,255,.08);}" +
1025
- ".file{margin-bottom:10px;color:var(--blue);word-break:break-all;}" +
1026
- ".message{margin:0;white-space:pre-wrap;color:#fff;word-break:break-word;font:14px/1.5 var(--font);}";
1027
- const backdrop = document.createElement("div");
1028
- backdrop.className = "backdrop";
1029
- const panel = document.createElement("div");
1030
- panel.className = "window";
1031
- panel.onclick = (event) => event.stopPropagation();
1032
- const header = document.createElement("div");
1033
- header.className = "header";
1034
- const title = document.createElement("div");
1035
- title.className = "title";
1036
- title.textContent = titleText;
1037
- const close = document.createElement("button");
1038
- close.type = "button";
1039
- close.textContent = "x";
1040
- close.className = "close";
1041
- close.setAttribute("aria-label", "Close error overlay");
1042
- close.onclick = hideOverlay;
1043
- header.appendChild(title);
1044
- header.appendChild(close);
1045
- panel.appendChild(header);
1046
- for (const item of items) {
1047
- const card = document.createElement("div");
1048
- card.className = "card";
1049
- if (item.file) {
1050
- const file = document.createElement("div");
1051
- file.className = "file";
1052
- file.textContent = item.file;
1053
- card.appendChild(file);
1054
- }
1055
- const message = document.createElement("pre");
1056
- message.className = "message";
1057
- message.textContent = item.message;
1058
- card.appendChild(message);
1059
- panel.appendChild(card);
1060
- }
1061
- backdrop.appendChild(panel);
1062
- root.appendChild(style);
1063
- root.appendChild(backdrop);
1064
- closeOverlayOnEsc = (event) => {
1065
- if (event.key === "Escape" || event.code === "Escape") hideOverlay();
1066
- };
1067
- document.addEventListener("keydown", closeOverlayOnEsc);
1068
- (document.body || document.documentElement).appendChild(overlay);
1069
- }
1070
- globalThis.__zntc_show_error_overlay = showOverlay;
1071
- globalThis.__zntc_clear_error_overlay = hideOverlay;
1072
- if (!globalThis.__zntc_runtime_listeners_attached) {
1073
- globalThis.__zntc_runtime_listeners_attached = true;
1074
- window.addEventListener("error", (event) => {
1075
- const file = event.filename ? event.filename + ":" + event.lineno + ":" + event.colno : "";
1076
- showRuntimeOverlay(event.error || event.message, file);
1077
- });
1078
- window.addEventListener("unhandledrejection", (event) => {
1079
- showRuntimeOverlay(event.reason, "");
1080
- });
1081
- }
1082
- const socket = new WebSocket(socketProtocol + "//" + location.host + "${APP_DEV_HMR_WS_PATH}");
1083
- socket.addEventListener("message", (event) => {
1084
- const msg = JSON.parse(event.data);
1085
- if (msg.type === "${HMR_MSG.Error}") {
1086
- showOverlay(msg.errors);
1087
- return;
1088
- }
1089
- if (msg.type === "${HMR_MSG.ClearError}") {
1090
- hideOverlay();
1091
- return;
1092
- }
1093
- if (msg.type === "${HMR_MSG.FullReload}") {
1094
- hideOverlay();
1095
- location.reload();
1096
- return;
1097
- }
1098
- if (msg.type !== "${HMR_MSG.CssUpdate}") return;
1099
- hideOverlay();
1100
- const stamp = msg.timestamp || Date.now();
1101
- const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]'));
1102
- let updated = false;
1103
- for (const link of links) {
1104
- const href = link.getAttribute("href");
1105
- if (!href) continue;
1106
- const current = new URL(href, location.href);
1107
- const target = new URL(msg.href || current.pathname, location.href);
1108
- if (msg.href && current.pathname !== target.pathname) continue;
1109
- const next = new URL(current.href);
1110
- next.searchParams.set("t", String(stamp));
1111
- const replacement = link.cloneNode();
1112
- replacement.href = next.href;
1113
- replacement.onload = () => link.remove();
1114
- replacement.onerror = () => location.reload();
1115
- link.after(replacement);
1116
- updated = true;
1117
- }
1118
- if (!updated) location.reload();
1119
- });
1120
- `;
1098
+ const RAW_TEMPLATE_PATH = new URL("./dev-overlay-client.raw.js", import.meta.url),PLACEHOLDERS = [["__ZNTC_HMR_WS_PATH__", APP_DEV_HMR_WS_PATH], ["__ZNTC_HMR_MSG_ERROR__", HMR_MSG.Error], ["__ZNTC_HMR_MSG_CLEAR_ERROR__", HMR_MSG.ClearError], ["__ZNTC_HMR_MSG_UPDATE_START__", HMR_MSG.UpdateStart], ["__ZNTC_HMR_MSG_UPDATE_DONE__", HMR_MSG.UpdateDone], ["__ZNTC_HMR_MSG_UPDATE__", HMR_MSG.Update], ["__ZNTC_HMR_MSG_FULL_RELOAD__", HMR_MSG.FullReload], ["__ZNTC_HMR_MSG_CSS_UPDATE__", HMR_MSG.CssUpdate]];
1099
+ function substitute(raw) {
1100
+ let out = raw;
1101
+ for (const [token, value] of PLACEHOLDERS) {
1102
+ out = out.replaceAll(token, value);
1103
+ }
1104
+ return out;
1105
+ }
1106
+ const APP_DEV_HMR_CLIENT = substitute(readFileSync$6(RAW_TEMPLATE_PATH, "utf8"));
1121
1107
  //#endregion
1122
1108
  //#region index.ts
1123
- export { APP_DEV_HMR_CLIENT_PATH, APP_DEV_HMR_WS_PATH, createHmrChannel, createWatcher, HMR_MSG, injectAppDevBundleCssLinks, injectAppDevHmrClient, injectAppDevPipelineCssLinks, injectIntoDevHtml, DEFAULT_HTML_ENV_PREFIX, applyHtmlEnvTokens, transformHtmlEnvTokens, joinUrl, isCssIdent, isCssIdentStart, skipCssString, skipCssUrl, startsWithCssIdent, collectAppFiles, requireFromAppOrFallback, collectPostcssMessages, findPostcssConfig, isCssFile, isPostcssConfigFile, loadPostcssConfig, logPostcssProcessed, POSTCSS_CONFIG_NAMES, runPostcssForAppDev, runPostcssIfConfigured, buildCssPreprocessorProxy, CSS_PREPROCESSOR_EXTENSIONS, compileSassFile, cssPreprocessorOutputPath, cssPreprocessorProxyPath, isCssModulePreprocessorFile, isCssPreprocessorFile, isStyleReferenceSource, loadSassCompiler, rewriteSassReferences, transformCssPreprocessors, buildCssModuleProxy, collectCssModuleClasses, cssModuleGeneratedCssPath, cssModuleLocalName, cssModuleProxyPath, isCssModuleFile, isValidExportName, rewriteCssModuleClasses, rewriteCssModuleReferences, scanCssModuleClassTokens, transformCssModules, cleanupPostcssTempRoot, createAppDevController, prepareAppCssPipelineRoot, APP_DEV_HMR_CLIENT };
1109
+ export { APP_DEV_HMR_CLIENT_PATH, APP_DEV_HMR_WS_PATH, APP_DEV_REACT_REFRESH_PATH, broadcastRebuildEvent, createHmrChannel, createWatcher, HMR_MSG, injectAppDevBundleCssLinks, injectAppDevBundleCssLinksFromOutdir, injectAppDevHmrClient, injectAppDevPipelineCssLinks, injectAppDevReactRefreshPreamble, injectIntoDevHtml, buildReactRefreshPreamble, DEFAULT_HTML_ENV_PREFIX, applyHtmlEnvTokens, transformHtmlEnvTokens, joinUrl, isCssIdent, isCssIdentStart, skipCssString, skipCssUrl, startsWithCssIdent, collectAppFiles, requireFromAppOrFallback, collectPostcssMessages, findPostcssConfig, isCssFile, isPostcssConfigFile, loadPostcssConfig, logPostcssProcessed, POSTCSS_CONFIG_NAMES, runPostcssForAppDev, runPostcssIfConfigured, buildCssPreprocessorProxy, CSS_PREPROCESSOR_EXTENSIONS, compileSassFile, cssPreprocessorOutputPath, cssPreprocessorProxyPath, isCssModulePreprocessorFile, isCssPreprocessorFile, isStyleReferenceSource, loadSassCompiler, rewriteSassReferences, transformCssPreprocessors, buildCssModuleProxy, collectCssModuleClasses, cssModuleGeneratedCssPath, cssModuleLocalName, cssModuleProxyPath, isCssModuleFile, isValidExportName, rewriteCssModuleClasses, rewriteCssModuleReferences, scanCssModuleClassTokens, transformCssModules, cleanupPostcssTempRoot, createAppDevController, prepareAppCssPipelineRoot, APP_DEV_HMR_CLIENT };
1124
1110
  //#endregion