@stacksjs/stx 0.2.140 → 0.2.142

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.
@@ -0,0 +1 @@
1
+ export declare function importOnce<T>(key: string, importer: () => Promise<T>): Promise<T>;
@@ -0,0 +1,18 @@
1
+ const LAZY_MODULE_PROMISES = Symbol.for("stx.lazy-module-promises");
2
+ function modulePromises() {
3
+ const shared = globalThis;
4
+ shared[LAZY_MODULE_PROMISES] ??= new Map;
5
+ return shared[LAZY_MODULE_PROMISES];
6
+ }
7
+ export function importOnce(key, importer) {
8
+ const promises = modulePromises(), scopedKey = `${import.meta.url}\x00${key}`, pending = promises.get(scopedKey);
9
+ if (pending)
10
+ return pending;
11
+ const imported = importer();
12
+ promises.set(scopedKey, imported);
13
+ imported.catch(() => {
14
+ if (promises.get(scopedKey) === imported)
15
+ promises.delete(scopedKey);
16
+ });
17
+ return imported;
18
+ }
package/dist/process.js CHANGED
@@ -47,6 +47,7 @@ import { isProduction, isTest } from "./env.js";
47
47
  import { warnUnbalancedTags } from "./template-tag-balance.js";
48
48
  import { deriveLayoutGroup } from "stx-router/layout-metadata";
49
49
  import { initializeComponentClientFactories, injectComponentClientFactories } from "./component-client-factories.js";
50
+ import { importOnce } from "./lazy-module.js";
50
51
  export { injectRouterScript } from "./runtime-injection.js";
51
52
  export { processJsonDirective, processOnceDirective } from "./misc-directives.js";
52
53
  export { validateClientScript } from "./script-validation.js";
@@ -300,7 +301,7 @@ export async function processDirectives(template, context, filePath, options, de
300
301
  }
301
302
  if (isTopLevel)
302
303
  try {
303
- const { getStoreScript } = await import("./store-loader.js"), resolvedStoresDir = options.storesDir, storeCode = await getStoreScript(resolvedStoresDir);
304
+ const { getStoreScript } = await importOnce("stx/store-loader", () => import("./store-loader.js")), resolvedStoresDir = options.storesDir, storeCode = await getStoreScript(resolvedStoresDir);
304
305
  if (storeCode) {
305
306
  const storeTag = `<script data-stx-stores>${storeCode}</script>`, runtime = findScriptBlockByAttribute(result, "data-stx-runtime");
306
307
  if (runtime)
@@ -310,7 +311,7 @@ export async function processDirectives(template, context, filePath, options, de
310
311
  } catch {}
311
312
  if (isTopLevel)
312
313
  try {
313
- const { getComposableScript } = await import("./composable-loader.js"), resolvedComposablesDir = options.composablesDir, composableCode = await getComposableScript(resolvedComposablesDir);
314
+ const { getComposableScript } = await importOnce("stx/composable-loader", () => import("./composable-loader.js")), resolvedComposablesDir = options.composablesDir, composableCode = await getComposableScript(resolvedComposablesDir);
314
315
  if (composableCode) {
315
316
  const composableTag = `<script data-stx-composables>${composableCode}</script>`, anchor = findScriptBlockByAttribute(result, "data-stx-stores") || findScriptBlockByAttribute(result, "data-stx-runtime");
316
317
  if (anchor)
@@ -555,7 +556,7 @@ async function extractServerScriptVariables(output, context, filePath) {
555
556
  if (!/\bserver\b/.test(attrs) || !scriptContent.trim())
556
557
  continue;
557
558
  try {
558
- const { extractVariables } = await import("./variable-extractor.js");
559
+ const { extractVariables } = await importOnce("stx/variable-extractor", () => import("./variable-extractor.js"));
559
560
  await extractVariables(scriptContent, context, filePath, { preserveExisting: !0 });
560
561
  } catch (e) {
561
562
  const err = e instanceof Error ? e : Error(String(e));
@@ -566,7 +567,7 @@ async function extractServerScriptVariables(output, context, filePath) {
566
567
  }
567
568
  async function interpolateClientScriptExpressions(output, context, filePath) {
568
569
  try {
569
- const { interpolateScriptsInTemplate } = await import("./expressions.js");
570
+ const { interpolateScriptsInTemplate } = await importOnce("stx/expressions", () => import("./expressions.js"));
570
571
  return interpolateScriptsInTemplate(output, context, { skipServer: !0 });
571
572
  } catch (e) {
572
573
  const err = e instanceof Error ? e : Error(String(e));
@@ -588,40 +589,40 @@ async function processOtherDirectives(template, context, filePath, options, depe
588
589
  output = convertSignalLoopsToAttributes(output, context);
589
590
  }
590
591
  output = preEvalLiteralReactiveIfs(output);
591
- const { processStreamDirectives } = await import("./streaming.js");
592
+ const { processStreamDirectives } = await importOnce("stx/streaming", () => import("./streaming.js"));
592
593
  output = processStreamDirectives(output, context);
593
594
  output = processLoops(output, context, filePath, opts);
594
595
  output = await processComponents(output, context, filePath, opts, dependencies);
595
596
  output = await processDynamicComponents(output, context, filePath, opts, dependencies);
596
597
  output = processAnimationDirectives(output, context, filePath, opts);
597
- const { processDeferDirectives } = await import("./defer.js");
598
+ const { processDeferDirectives } = await importOnce("stx/defer", () => import("./defer.js"));
598
599
  output = processDeferDirectives(output, context, filePath);
599
- const { processTeleportDirectives } = await import("./teleport.js");
600
+ const { processTeleportDirectives } = await importOnce("stx/teleport", () => import("./teleport.js"));
600
601
  output = processTeleportDirectives(output, context, filePath);
601
- const { processTransitionDirectives, processTransitionAttributes } = await import("./transitions.js");
602
+ const { processTransitionDirectives, processTransitionAttributes } = await importOnce("stx/transitions", () => import("./transitions.js"));
602
603
  output = processTransitionDirectives(output, context, filePath);
603
604
  output = processTransitionAttributes(output);
604
- const { processErrorBoundaryDirectives } = await import("./error-boundaries.js");
605
+ const { processErrorBoundaryDirectives } = await importOnce("stx/error-boundaries", () => import("./error-boundaries.js"));
605
606
  output = processErrorBoundaryDirectives(output, context, filePath);
606
- const { processSuspenseDirectives } = await import("./suspense.js");
607
+ const { processSuspenseDirectives } = await importOnce("stx/suspense", () => import("./suspense.js"));
607
608
  output = processSuspenseDirectives(output, context, filePath);
608
- const { processAsyncDirectives } = await import("./async-components.js");
609
+ const { processAsyncDirectives } = await importOnce("stx/async-components", () => import("./async-components.js"));
609
610
  output = processAsyncDirectives(output, context, filePath);
610
- const { processKeepAliveDirectives } = await import("./keep-alive.js");
611
+ const { processKeepAliveDirectives } = await importOnce("stx/keep-alive", () => import("./keep-alive.js"));
611
612
  output = processKeepAliveDirectives(output, context, filePath);
612
- const { processVirtualListDirectives, processVirtualGridDirectives, processInfiniteListDirectives } = await import("./virtual-scrolling.js");
613
+ const { processVirtualListDirectives, processVirtualGridDirectives, processInfiniteListDirectives } = await importOnce("stx/virtual-scrolling", () => import("./virtual-scrolling.js"));
613
614
  output = processVirtualListDirectives(output, context, filePath);
614
615
  output = processVirtualGridDirectives(output, context, filePath);
615
616
  output = processInfiniteListDirectives(output, context, filePath);
616
- const { processPartialHydrationDirectives, processStaticDirectives } = await import("./partial-hydration.js");
617
+ const { processPartialHydrationDirectives, processStaticDirectives } = await importOnce("stx/partial-hydration", () => import("./partial-hydration.js"));
617
618
  output = processPartialHydrationDirectives(output, context, filePath);
618
619
  output = processStaticDirectives(output);
619
- const { processComputedDirectives, processWatchDirectives } = await import("./computed.js");
620
+ const { processComputedDirectives, processWatchDirectives } = await importOnce("stx/computed", () => import("./computed.js"));
620
621
  output = processComputedDirectives(output, context, filePath);
621
622
  output = processWatchDirectives(output, context, filePath);
622
- const { processFormValidationDirectives } = await import("./forms-validation.js");
623
+ const { processFormValidationDirectives } = await importOnce("stx/forms-validation", () => import("./forms-validation.js"));
623
624
  output = processFormValidationDirectives(output, context, filePath);
624
- const { processHeadDirective, processTitleDirective, processMetaDirective, resetHead } = await import("./head.js");
625
+ const { processHeadDirective, processTitleDirective, processMetaDirective, resetHead } = await importOnce("stx/head", () => import("./head.js"));
625
626
  if (!context.__stx_head_preset && !context.__stx_runtime_head)
626
627
  resetHead();
627
628
  const headResult = processHeadDirective(output);
@@ -673,14 +674,14 @@ async function processOtherDirectives(template, context, filePath, options, depe
673
674
  output = addCloakToUnresolvedExpressions(output);
674
675
  output = addCloakToConditionalDirectives(output);
675
676
  output = processTemplateBindings(output);
676
- const { processXElementDirectives } = await import("./x-element.js");
677
+ const { processXElementDirectives } = await importOnce("stx/x-element", () => import("./x-element.js"));
677
678
  output = processXElementDirectives(output);
678
679
  const pageFilePath = context.__originalFilePath || filePath, serverData = extractBridgeData(context);
679
680
  output = await processSignals(output, opts, pageFilePath, serverData);
680
681
  output = processAppearanceBootstrapDirective(output, context);
681
682
  output = await runPostProcessingMiddleware(output, context, filePath, opts);
682
683
  if (opts.media?.image?.autoSiblings) {
683
- const publicDir = opts.publicDir || "public", { rewriteImagesWithSiblings } = await import("./image-optimization/auto-sibling.js");
684
+ const publicDir = opts.publicDir || "public", { rewriteImagesWithSiblings } = await importOnce("stx/image-optimization/auto-sibling", () => import("./image-optimization/auto-sibling.js"));
684
685
  output = await rewriteImagesWithSiblings(output, { publicDir });
685
686
  }
686
687
  if (opts.seo?.enabled)
@@ -708,7 +709,7 @@ ${snippet}`);
708
709
  ${snippet}
709
710
  </head>`);
710
711
  return html;
711
- }, { renderHead, getHead } = await import("./head.js"), headConfig = context.__stx_runtime_head ?? getHead();
712
+ }, { renderHead, getHead } = await importOnce("stx/head", () => import("./head.js")), headConfig = context.__stx_runtime_head ?? getHead();
712
713
  if (headConfig.title || headConfig.meta?.length || headConfig.link?.length) {
713
714
  const renderedHead = renderHead(headConfig);
714
715
  if (renderedHead)
@@ -723,7 +724,7 @@ ${snippet}
723
724
  if (opts.heatmap?.enabled)
724
725
  output = injectHeatmap(output, opts);
725
726
  if (opts.pwa?.enabled && opts.pwa.autoInject !== !1) {
726
- const { injectPwaTags } = await import("./pwa/inject.js");
727
+ const { injectPwaTags } = await importOnce("stx/pwa/inject", () => import("./pwa/inject.js"));
727
728
  output = injectPwaTags(output, opts);
728
729
  }
729
730
  const hasClientScripts = /<script\b(?![^>]*\bserver\b)[^>]*>[\s\S]*?<\/script>/i.test(output), hasStxUsage = /\bSTX\.\w+/.test(output), alreadyHasRuntime = /window\.STX\s*=/.test(output);
@@ -748,7 +749,7 @@ ${runtimeScript}`);
748
749
  ` + output;
749
750
  }
750
751
  {
751
- const { scanScriptTags } = await import("./signal-processing.js"), serverRemoveRanges = [];
752
+ const { scanScriptTags } = await importOnce("stx/signal-processing", () => import("./signal-processing.js")), serverRemoveRanges = [];
752
753
  for (const script of scanScriptTags(output)) {
753
754
  if (!/\bserver\b/i.test(script.attrs))
754
755
  continue;
@@ -770,7 +771,7 @@ ${runtimeScript}`);
770
771
  output = scopedResult.html;
771
772
  const eventBindings = context.__stx_event_bindings || [];
772
773
  let clientScriptsTransformed = !1;
773
- const clientScriptMatches = [], hasColonDirectives = /\s:[a-z][\w.-]*\s*=/.test(output), { scanScriptTags } = await import("./signal-processing.js");
774
+ const clientScriptMatches = [], hasColonDirectives = /\s:[a-z][\w.-]*\s*=/.test(output), { scanScriptTags } = await importOnce("stx/signal-processing", () => import("./signal-processing.js"));
774
775
  for (const s of scanScriptTags(output, {
775
776
  skipAttrs: /\bserver\b|\bsrc\s*=|\bdata-stx-scoped\b|\bdata-stx-router\b|\btype\s*=\s*["'](?!(?:text\/javascript|application\/javascript|module)["'])[^"']*["']/
776
777
  }))