@webjsdev/server 0.8.82 → 0.8.84

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.
@@ -508,7 +508,7 @@ async function walk(dir, appDir, graph, seen, dynamic, bare, bareDynamic) {
508
508
  * rebuilds incremental for large apps without restructuring the caller.
509
509
  * Keyed by mtime AND size: a same-tick edit that also changes the file length
510
510
  * is caught even on coarse-resolution filesystems where mtime alone could miss.
511
- * @type {Map<string, { mtimeMs: number, size: number, deps: Set<string> }>}
511
+ * @type {Map<string, { mtimeMs: number, size: number, specs: string[], dynSpecs: string[], bareDeps: Set<string>, bareDynDeps: Set<string> }>}
512
512
  */
513
513
  const PARSE_CACHE = new Map();
514
514
 
@@ -530,10 +530,7 @@ async function parseFile(file, appDir, graph, seen, dynamic, bare, bareDynamic)
530
530
  seen?.add(file); // mark live (both cache-hit and miss paths) for cache eviction
531
531
  const cached = PARSE_CACHE.get(file);
532
532
  if (cached && cached.mtimeMs === mtimeMs && cached.size === size) {
533
- if (cached.deps.size) graph.set(file, cached.deps);
534
- if (cached.dynDeps && cached.dynDeps.size && dynamic) dynamic.set(file, cached.dynDeps);
535
- if (cached.bareDeps && cached.bareDeps.size && bare) bare.set(file, cached.bareDeps);
536
- if (cached.bareDynDeps && cached.bareDynDeps.size && bareDynamic) bareDynamic.set(file, cached.bareDynDeps);
533
+ addResolved(file, appDir, cached, graph, dynamic, bare, bareDynamic);
537
534
  return;
538
535
  }
539
536
 
@@ -574,7 +571,8 @@ async function parseFile(file, appDir, graph, seen, dynamic, bare, bareDynamic)
574
571
  // string (blanked here), so it is read back from raw `src` via the match's
575
572
  // group indices (the `d` flag).
576
573
  const masked = redactStringsAndTemplates(src, true);
577
- const deps = new Set();
574
+ /** @type {string[]} local (relative / aliased) static specifiers */
575
+ const specs = [];
578
576
  /** @type {Set<string>} bare npm vendor specifiers imported by this file (#754) */
579
577
  const bareDeps = new Set();
580
578
  for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {
@@ -612,8 +610,7 @@ async function parseFile(file, appDir, graph, seen, dynamic, bare, bareDynamic)
612
610
  if (isVendorSpecifier(spec)) bareDeps.add(spec);
613
611
  continue;
614
612
  }
615
- const resolved = resolveImport(spec, file, appDir);
616
- if (resolved) deps.add(resolved);
613
+ specs.push(spec);
617
614
  }
618
615
  }
619
616
  // Dynamic `import('…')` with a string-literal specifier (#751): a separate
@@ -636,7 +633,8 @@ async function parseFile(file, appDir, graph, seen, dynamic, bare, bareDynamic)
636
633
  // computed `import(expr)` still falls out (its char after the quote is not
637
634
  // `,`/`)`), preserving the documented limitation.
638
635
  const { redacted: holeAware, literals } = redactToPlaceholders(src);
639
- const dynDeps = new Set();
636
+ /** @type {string[]} local dynamic-import specifiers */
637
+ const dynSpecs = [];
640
638
  const bareDynDeps = new Set();
641
639
  for (const m of holeAware.matchAll(DYNAMIC_IMPORT_RE)) {
642
640
  const token = m[1];
@@ -651,14 +649,43 @@ async function parseFile(file, appDir, graph, seen, dynamic, bare, bareDynamic)
651
649
  if (isVendorSpecifier(spec)) bareDynDeps.add(spec);
652
650
  continue;
653
651
  }
652
+ dynSpecs.push(spec);
653
+ }
654
+ const parsed = { mtimeMs, size, specs, dynSpecs, bareDeps, bareDynDeps };
655
+ PARSE_CACHE.set(file, parsed);
656
+ addResolved(file, appDir, parsed, graph, dynamic, bare, bareDynamic);
657
+ }
658
+
659
+ /**
660
+ * Resolve a parsed file's specifiers and add its edges to the graph maps.
661
+ *
662
+ * The cache holds SPECIFIERS, not resolved paths (#1575): resolution depends on
663
+ * which files exist, not on the importer's own bytes, so a cached resolution
664
+ * outlives the file system it was made against. An importer written before the
665
+ * module it imports (the order an agent often writes them in) resolved to
666
+ * nothing, was cached that way, and kept no edge after the target appeared,
667
+ * because the importer's mtime never changed again; the gate then 404'd the new
668
+ * module. Resolving on every build costs a few `existsSync` calls per edge.
669
+ *
670
+ * @param {string} file
671
+ * @param {string} appDir
672
+ * @param {{ specs: string[], dynSpecs: string[], bareDeps: Set<string>, bareDynDeps: Set<string> }} parsed
673
+ */
674
+ function addResolved(file, appDir, parsed, graph, dynamic, bare, bareDynamic) {
675
+ const deps = new Set();
676
+ for (const spec of parsed.specs) {
677
+ const resolved = resolveImport(spec, file, appDir);
678
+ if (resolved) deps.add(resolved);
679
+ }
680
+ const dynDeps = new Set();
681
+ for (const spec of parsed.dynSpecs) {
654
682
  const resolved = resolveImport(spec, file, appDir);
655
683
  if (resolved && !deps.has(resolved)) dynDeps.add(resolved);
656
684
  }
657
- PARSE_CACHE.set(file, { mtimeMs, size, deps, dynDeps, bareDeps, bareDynDeps });
658
685
  if (deps.size) graph.set(file, deps);
659
686
  if (dynDeps.size && dynamic) dynamic.set(file, dynDeps);
660
- if (bareDeps.size && bare) bare.set(file, bareDeps);
661
- if (bareDynDeps.size && bareDynamic) bareDynamic.set(file, bareDynDeps);
687
+ if (parsed.bareDeps.size && bare) bare.set(file, parsed.bareDeps);
688
+ if (parsed.bareDynDeps.size && bareDynamic) bareDynamic.set(file, parsed.bareDynDeps);
662
689
  }
663
690
 
664
691
  /**
package/src/ssr/render.js CHANGED
@@ -17,7 +17,7 @@ import { escapeHtml } from './escape.js';
17
17
  import {
18
18
  cachedHtmlResponse, getNonce, htmlResponse, streamingHtmlResponse,
19
19
  } from './responses.js';
20
- import { devImportSpecifier } from '../dev-import.js';
20
+ import { devImport } from '../dev-import.js';
21
21
  import { applySeoDefaults } from './seo.js';
22
22
 
23
23
 
@@ -108,7 +108,7 @@ export function privateFragment(res) {
108
108
  * @param {boolean} dev
109
109
  */
110
110
  async function loadModule(file, dev) {
111
- return import(devImportSpecifier(file, dev));
111
+ return devImport(file, dev);
112
112
  }
113
113
 
114
114
  /**