@astroscope/node 2.1.0 → 3.0.0
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/README.md +8 -5
- package/dist/boot.d.ts +2 -2
- package/dist/boot.d.ts.map +1 -1
- package/dist/csrf-middleware-entrypoint.d.ts +1 -2
- package/dist/csrf-middleware-entrypoint.d.ts.map +1 -1
- package/dist/csrf-middleware-entrypoint.js +1 -1
- package/dist/dev-middleware-entrypoint.d.ts +1 -2
- package/dist/dev-middleware-entrypoint.d.ts.map +1 -1
- package/dist/{prepare-CXZsyAVk.js → duplicate-slashes-C6hmOLl9.js} +94 -38
- package/dist/duplicate-slashes-C6hmOLl9.js.map +1 -0
- package/dist/{excludes-pE23EbmQ.js → excludes-10eDopVB.js} +18 -4
- package/dist/excludes-10eDopVB.js.map +1 -0
- package/dist/{excludes-BDiE3eyp.d.ts → excludes-rvkVGg6B.d.ts} +11 -3
- package/dist/excludes-rvkVGg6B.d.ts.map +1 -0
- package/dist/excludes.d.ts +2 -2
- package/dist/excludes.js +2 -2
- package/dist/graph-DdAxiaxa.js +35 -0
- package/dist/graph-DdAxiaxa.js.map +1 -0
- package/dist/health.d.ts +3 -4
- package/dist/health.d.ts.map +1 -1
- package/dist/image-endpoint.d.ts +1 -2
- package/dist/image-endpoint.d.ts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -122
- package/dist/index.js.map +1 -1
- package/dist/islands-middleware-entrypoint.d.ts +1 -2
- package/dist/islands-middleware-entrypoint.d.ts.map +1 -1
- package/dist/islands-middleware-entrypoint.js +3 -1
- package/dist/islands-middleware-entrypoint.js.map +1 -1
- package/dist/islands-runtime.iife.js +1 -1
- package/dist/islands.d.ts +57 -2
- package/dist/islands.d.ts.map +1 -0
- package/dist/islands.js +3 -1
- package/dist/log/index.d.ts +5 -5
- package/dist/log/index.d.ts.map +1 -1
- package/dist/native.d.ts +5 -6
- package/dist/native.d.ts.map +1 -1
- package/dist/{prerendered-DVjzWNbW.js → prerendered-Z-Qi-FFK.js} +4 -4
- package/dist/prerendered-Z-Qi-FFK.js.map +1 -0
- package/dist/request-route-DcnZOOM4.js.map +1 -1
- package/dist/route-islands-B53rE5MH.js +73 -0
- package/dist/route-islands-B53rE5MH.js.map +1 -0
- package/dist/route-middleware-entrypoint.d.ts +1 -2
- package/dist/route-middleware-entrypoint.d.ts.map +1 -1
- package/dist/{route-store-CSYR4G5e.d.ts → route-store-neUA2nBb.d.ts} +10 -14
- package/dist/route-store-neUA2nBb.d.ts.map +1 -0
- package/dist/routes-D1o_WrJ5.js +39 -0
- package/dist/routes-D1o_WrJ5.js.map +1 -0
- package/dist/server.d.ts +2 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +68 -45
- package/dist/server.js.map +1 -1
- package/dist/telemetry-B9aziFyQ.js +202 -0
- package/dist/telemetry-B9aziFyQ.js.map +1 -0
- package/dist/telemetry.d.ts +68 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +2 -0
- package/dist/transform-Bz5z5w2Y.js +594 -0
- package/dist/transform-Bz5z5w2Y.js.map +1 -0
- package/package.json +13 -11
- package/dist/excludes-BDiE3eyp.d.ts.map +0 -1
- package/dist/excludes-pE23EbmQ.js.map +0 -1
- package/dist/prepare-CXZsyAVk.js.map +0 -1
- package/dist/prerendered-DVjzWNbW.js.map +0 -1
- package/dist/route-store-CSYR4G5e.d.ts.map +0 -1
- package/dist/strip-build-paths-C6eb1QdG.js +0 -63
- package/dist/strip-build-paths-C6eb1QdG.js.map +0 -1
- package/dist/transform-BqV8SOEm.js +0 -195
- package/dist/transform-BqV8SOEm.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import { n as setBootContext } from "./context-Bkg-FnnQ.js";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as createRequestInstrumentation, n as preparePlatform, o as runShutdown, s as runStartup, t as redirectDuplicateSlashes } from "./duplicate-slashes-C6hmOLl9.js";
|
|
3
3
|
import { n as dispatchNativeMount, t as clearNativeMounts } from "./native-mount-DjYEnO4X.js";
|
|
4
4
|
import { n as getCurrentGeneration, r as incrementGeneration, t as GEN_HEADER } from "./generation-Bp2IA0jf.js";
|
|
5
|
-
import { r as RECOMMENDED_EXCLUDES } from "./excludes-
|
|
5
|
+
import { r as RECOMMENDED_EXCLUDES, s as serializeExcludePatterns } from "./excludes-10eDopVB.js";
|
|
6
|
+
import { n as routeEntrypoints, r as stripQuery, t as collectRouteIslands } from "./route-islands-B53rE5MH.js";
|
|
6
7
|
import { i as registerIslandEmitter } from "./emitters-C20tjKLp.js";
|
|
7
8
|
import { t as getRequestRouteData } from "./route-store-DdxGePj2.js";
|
|
8
9
|
import fs, { readFileSync } from "node:fs";
|
|
9
10
|
import path from "node:path";
|
|
10
11
|
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { defined } from "@entwico/dash";
|
|
11
13
|
import { parse } from "@astrojs/compiler-rs";
|
|
12
|
-
import { Parser } from "acorn";
|
|
13
|
-
import MagicString from "magic-string";
|
|
14
14
|
//#region src/dev-mode/island-warmup.ts
|
|
15
15
|
function isAstNode(value) {
|
|
16
16
|
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
17
17
|
}
|
|
18
|
-
function walk
|
|
18
|
+
function walk(node, visit) {
|
|
19
19
|
if (Array.isArray(node)) {
|
|
20
|
-
for (const item of node) walk
|
|
20
|
+
for (const item of node) walk(item, visit);
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
if (typeof node !== "object" || node === null) return;
|
|
24
24
|
if (isAstNode(node)) visit(node);
|
|
25
|
-
for (const value of Object.values(node)) walk
|
|
25
|
+
for (const value of Object.values(node)) walk(value, visit);
|
|
26
26
|
}
|
|
27
27
|
/** local binding name → import specifier, from the frontmatter program */
|
|
28
28
|
function collectImports(program) {
|
|
29
29
|
const imports = /* @__PURE__ */ new Map();
|
|
30
|
-
walk
|
|
30
|
+
walk(program, (node) => {
|
|
31
31
|
if (node.type !== "ImportDeclaration") return;
|
|
32
32
|
const decl = node;
|
|
33
33
|
if (decl.importKind === "type") return;
|
|
@@ -68,7 +68,7 @@ function scanAstroSource(source) {
|
|
|
68
68
|
const imports = collectImports(root.frontmatter?.program);
|
|
69
69
|
if (imports.size === 0) return [];
|
|
70
70
|
const specifiers = /* @__PURE__ */ new Set();
|
|
71
|
-
walk
|
|
71
|
+
walk(root.body, (node) => {
|
|
72
72
|
if (node.type !== "JSXOpeningElement") return;
|
|
73
73
|
const element = node;
|
|
74
74
|
if (!hasClientDirective(element.attributes)) return;
|
|
@@ -568,25 +568,16 @@ function createDevMachinery(options) {
|
|
|
568
568
|
}
|
|
569
569
|
}];
|
|
570
570
|
}
|
|
571
|
-
//#endregion
|
|
572
|
-
//#region src/excludes/serialize.ts
|
|
573
|
-
/**
|
|
574
|
-
* Serialize exclude patterns to JavaScript code for use in virtual modules.
|
|
575
|
-
* Handles RegExp objects which JSON.stringify cannot serialize.
|
|
576
|
-
*/
|
|
577
|
-
function serializeExcludePatterns(patterns) {
|
|
578
|
-
return `[${patterns.map((p) => "pattern" in p ? `{ pattern: ${p.pattern.toString()} }` : JSON.stringify(p)).join(", ")}]`;
|
|
579
|
-
}
|
|
580
571
|
const RESOLVED_ISLANDS_VIRTUAL_MODULE_ID = `\0virtual:@astroscope/node/islands-manifest`;
|
|
581
572
|
const MANIFEST_FILE_NAME = "islands-manifest.json";
|
|
582
573
|
/**
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
* the
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
574
|
+
* Build side of island preloading: the server build attributes islands to routes
|
|
575
|
+
* (its module graph is the only place a page's components are visible together),
|
|
576
|
+
* the client build records the chunk import graph (direct static and dynamic edges
|
|
577
|
+
* per chunk), embeds the gate runtime source (inlined into documents rather than
|
|
578
|
+
* shipped as an asset — an external fetch would install the gates a round-trip
|
|
579
|
+
* after astro's inline island machinery), and drops the manifest next to the
|
|
580
|
+
* server chunks, mirroring the i18n manifest.
|
|
590
581
|
*
|
|
591
582
|
* The client build runs after the server build, so the SSR bundle can only carry
|
|
592
583
|
* code that reads the file lazily; in dev there is no manifest and the middleware
|
|
@@ -594,6 +585,7 @@ const MANIFEST_FILE_NAME = "islands-manifest.json";
|
|
|
594
585
|
*/
|
|
595
586
|
function createIslandsManifestPlugin(options) {
|
|
596
587
|
let isBuild = false;
|
|
588
|
+
const routeIslands = /* @__PURE__ */ new Map();
|
|
597
589
|
return {
|
|
598
590
|
name: "@astroscope/node/islands-manifest",
|
|
599
591
|
configResolved(config) {
|
|
@@ -630,21 +622,31 @@ for (const candidate of [
|
|
|
630
622
|
export { manifest };
|
|
631
623
|
`;
|
|
632
624
|
},
|
|
625
|
+
async generateBundle() {
|
|
626
|
+
if (!options.enabled || this.environment.name === "client") return;
|
|
627
|
+
const { routes } = await collectRouteIslands(this, options.pages());
|
|
628
|
+
for (const [pattern, islands] of routes) routeIslands.set(pattern, islands);
|
|
629
|
+
},
|
|
633
630
|
writeBundle(outputOptions, bundle) {
|
|
634
631
|
if (!options.enabled || this.environment.name !== "client" || !outputOptions.dir) return;
|
|
635
632
|
const chunks = {};
|
|
633
|
+
const entryByComponent = /* @__PURE__ */ new Map();
|
|
636
634
|
for (const chunk of Object.values(bundle)) {
|
|
637
635
|
if (chunk.type !== "chunk") continue;
|
|
638
636
|
chunks[chunk.fileName] = {
|
|
639
637
|
...chunk.imports.length > 0 && { i: chunk.imports },
|
|
640
638
|
...chunk.dynamicImports.length > 0 && { d: chunk.dynamicImports }
|
|
641
639
|
};
|
|
640
|
+
if (chunk.isEntry && chunk.facadeModuleId) entryByComponent.set(stripQuery(chunk.facadeModuleId), chunk.fileName);
|
|
642
641
|
}
|
|
642
|
+
const routes = {};
|
|
643
|
+
for (const [pattern, islands] of routeIslands) routes[pattern] = [...islands].map((component) => entryByComponent.get(component)).filter(defined);
|
|
643
644
|
const runtimeSource = fs.readFileSync(new URL("./islands-runtime.iife.js", import.meta.url), "utf-8").trim();
|
|
644
645
|
if (runtimeSource.toLowerCase().includes("<\/script")) throw new Error("islands gate runtime must not contain \"<\/script\"");
|
|
645
646
|
const manifest = {
|
|
646
647
|
runtimeSource,
|
|
647
|
-
chunks
|
|
648
|
+
chunks,
|
|
649
|
+
routes
|
|
648
650
|
};
|
|
649
651
|
const chunksDir = path.resolve(outputOptions.dir, "..", "server", "chunks");
|
|
650
652
|
if (fs.existsSync(chunksDir)) fs.writeFileSync(path.join(chunksDir, MANIFEST_FILE_NAME), JSON.stringify(manifest));
|
|
@@ -673,94 +675,6 @@ function ssrSourcemapPlugin() {
|
|
|
673
675
|
};
|
|
674
676
|
}
|
|
675
677
|
//#endregion
|
|
676
|
-
//#region src/tweaks/strip-effects.ts
|
|
677
|
-
const HOOK_NAMES = /* @__PURE__ */ new Set([
|
|
678
|
-
"useEffect",
|
|
679
|
-
"useLayoutEffect",
|
|
680
|
-
"useInsertionEffect"
|
|
681
|
-
]);
|
|
682
|
-
const REACT_SOURCE = /^react(\/.*)?$/;
|
|
683
|
-
const TRANSFORMABLE = /\.(?:[mc]?[jt]sx?)$/;
|
|
684
|
-
const EMPTY_FN = "(()=>{})";
|
|
685
|
-
/**
|
|
686
|
-
* in SSR builds, react effect hooks never execute. emptying their callbacks
|
|
687
|
-
* lets rolldown drop dead branches — including dynamic imports of client-only
|
|
688
|
-
* libs (maplibre-gl, hls.js, etc.) — from the server bundle, which in turn
|
|
689
|
-
* stops nft from tracing them at docker-image time.
|
|
690
|
-
*
|
|
691
|
-
* scope is deliberately narrow: first-party code only (no node_modules), only
|
|
692
|
-
* in the SSR pass, and binding-aware (the React import must resolve to the
|
|
693
|
-
* real react package). raw chunks where bundling has erased the binding are
|
|
694
|
-
* left alone — that's NFT's domain, not ours.
|
|
695
|
-
*/
|
|
696
|
-
function stripSsrEffectsPlugin() {
|
|
697
|
-
return {
|
|
698
|
-
name: "@astroscope/node/tweaks/strip-effects",
|
|
699
|
-
enforce: "post",
|
|
700
|
-
transform(code, id, options) {
|
|
701
|
-
if (!options?.ssr) return null;
|
|
702
|
-
if (id.includes("/node_modules/")) return null;
|
|
703
|
-
const cleanId = id.split("?")[0] ?? id;
|
|
704
|
-
if (!TRANSFORMABLE.test(cleanId)) return null;
|
|
705
|
-
if (!code.includes("useEffect") && !code.includes("useLayoutEffect") && !code.includes("useInsertionEffect")) return null;
|
|
706
|
-
let ast;
|
|
707
|
-
try {
|
|
708
|
-
ast = Parser.parse(code, {
|
|
709
|
-
ecmaVersion: "latest",
|
|
710
|
-
sourceType: "module",
|
|
711
|
-
allowReturnOutsideFunction: true,
|
|
712
|
-
allowAwaitOutsideFunction: true,
|
|
713
|
-
allowImportExportEverywhere: true,
|
|
714
|
-
allowHashBang: true
|
|
715
|
-
});
|
|
716
|
-
} catch {
|
|
717
|
-
return null;
|
|
718
|
-
}
|
|
719
|
-
const directHooks = /* @__PURE__ */ new Set();
|
|
720
|
-
const namespaceHooks = /* @__PURE__ */ new Set();
|
|
721
|
-
walk(ast, (node) => {
|
|
722
|
-
if (node.type !== "ImportDeclaration") return;
|
|
723
|
-
const src = node.source?.value;
|
|
724
|
-
if (typeof src !== "string" || !REACT_SOURCE.test(src)) return;
|
|
725
|
-
for (const spec of node.specifiers ?? []) if (spec.type === "ImportSpecifier") {
|
|
726
|
-
const imported = spec.imported?.name ?? spec.imported?.value;
|
|
727
|
-
if (HOOK_NAMES.has(imported)) directHooks.add(spec.local.name);
|
|
728
|
-
} else if (spec.type === "ImportDefaultSpecifier" || spec.type === "ImportNamespaceSpecifier") namespaceHooks.add(spec.local.name);
|
|
729
|
-
});
|
|
730
|
-
if (directHooks.size === 0 && namespaceHooks.size === 0) return null;
|
|
731
|
-
const replacements = [];
|
|
732
|
-
walk(ast, (node) => {
|
|
733
|
-
if (node.type !== "CallExpression" || !node.arguments?.length) return;
|
|
734
|
-
const callee = node.callee;
|
|
735
|
-
const isDirect = callee.type === "Identifier" && directHooks.has(callee.name);
|
|
736
|
-
const isMember = callee.type === "MemberExpression" && !callee.computed && callee.object?.type === "Identifier" && namespaceHooks.has(callee.object.name) && callee.property?.type === "Identifier" && HOOK_NAMES.has(callee.property.name);
|
|
737
|
-
if (!isDirect && !isMember) return;
|
|
738
|
-
const arg = node.arguments[0];
|
|
739
|
-
replacements.push({
|
|
740
|
-
start: arg.start,
|
|
741
|
-
end: arg.end
|
|
742
|
-
});
|
|
743
|
-
});
|
|
744
|
-
if (replacements.length === 0) return null;
|
|
745
|
-
const s = new MagicString(code);
|
|
746
|
-
for (const { start, end } of replacements) s.overwrite(start, end, EMPTY_FN);
|
|
747
|
-
return {
|
|
748
|
-
code: s.toString(),
|
|
749
|
-
map: s.generateMap({ hires: true }).toString()
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
};
|
|
753
|
-
}
|
|
754
|
-
function walk(node, visit) {
|
|
755
|
-
if (!node || typeof node !== "object") return;
|
|
756
|
-
if (typeof node.type === "string") visit(node);
|
|
757
|
-
for (const key of Object.keys(node)) {
|
|
758
|
-
const v = node[key];
|
|
759
|
-
if (Array.isArray(v)) for (const item of v) walk(item, visit);
|
|
760
|
-
else if (v && typeof v === "object") walk(v, visit);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
//#endregion
|
|
764
678
|
//#region src/integration/integration.ts
|
|
765
679
|
const CONFIG_VIRTUAL_MODULE_ID = "virtual:@astroscope/node/config";
|
|
766
680
|
const BOOT_VIRTUAL_MODULE_ID = "virtual:@astroscope/node/boot";
|
|
@@ -815,6 +729,7 @@ function node(options = {}) {
|
|
|
815
729
|
const loggingExclude = loggingOptions ? loggingOptions.exclude ?? DEFAULT_REQUEST_EXCLUDES : [];
|
|
816
730
|
const telemetryExclude = telemetryOptions ? telemetryOptions.exclude ?? DEFAULT_REQUEST_EXCLUDES : [];
|
|
817
731
|
let astroConfig = null;
|
|
732
|
+
let resolvedRoutes = [];
|
|
818
733
|
let bootEntry;
|
|
819
734
|
let configSeam;
|
|
820
735
|
let instrumentationSeam;
|
|
@@ -847,7 +762,7 @@ function node(options = {}) {
|
|
|
847
762
|
const devMachinery = command === "dev" && bootOptions !== false ? createDevMachinery({
|
|
848
763
|
entry: bootEntry ? path.relative(root, bootEntry) : void 0,
|
|
849
764
|
watch,
|
|
850
|
-
watchEntries: [relativeSeam(configSeam), relativeSeam(logSeam)].filter(
|
|
765
|
+
watchEntries: [relativeSeam(configSeam), relativeSeam(logSeam)].filter(defined),
|
|
851
766
|
prepare: (importModule) => preparePlatform({
|
|
852
767
|
dev: true,
|
|
853
768
|
telemetry: telemetryOptions && telemetryOptions.dev ? { prometheus: telemetryOptions.prometheus ?? {} } : false,
|
|
@@ -893,10 +808,10 @@ function node(options = {}) {
|
|
|
893
808
|
...islandWarmup,
|
|
894
809
|
createIslandsManifestPlugin({
|
|
895
810
|
logger,
|
|
896
|
-
enabled: islandsEnabled
|
|
811
|
+
enabled: islandsEnabled,
|
|
812
|
+
pages: () => routeEntrypoints(root, resolvedRoutes)
|
|
897
813
|
}),
|
|
898
814
|
ssrSourcemapPlugin(),
|
|
899
|
-
stripSsrEffectsPlugin(),
|
|
900
815
|
{
|
|
901
816
|
name: "@astroscope/node",
|
|
902
817
|
configEnvironment(environmentName) {
|
|
@@ -953,6 +868,7 @@ function node(options = {}) {
|
|
|
953
868
|
}) : void 0;
|
|
954
869
|
server.middlewares.use((req, res, next) => {
|
|
955
870
|
const inner = () => {
|
|
871
|
+
if (redirectDuplicateSlashes(req, res)) return;
|
|
956
872
|
if (!dispatchNativeMount(req, res)) next();
|
|
957
873
|
};
|
|
958
874
|
if (instrument) instrument(req, res, inner);
|
|
@@ -980,20 +896,20 @@ function node(options = {}) {
|
|
|
980
896
|
}
|
|
981
897
|
});
|
|
982
898
|
},
|
|
899
|
+
"astro:routes:resolved": ({ routes }) => {
|
|
900
|
+
resolvedRoutes = routes;
|
|
901
|
+
},
|
|
983
902
|
"astro:build:done": async ({ logger }) => {
|
|
984
903
|
if (!astroConfig) return;
|
|
985
904
|
if (islandsEnabled) {
|
|
986
905
|
const manifestPath = path.join(fileURLToPath(astroConfig.build.server), "chunks", "islands-manifest.json");
|
|
987
906
|
if (fs.existsSync(manifestPath)) {
|
|
988
|
-
const { transformPrerenderedHtml } = await import("./prerendered-
|
|
907
|
+
const { transformPrerenderedHtml } = await import("./prerendered-Z-Qi-FFK.js");
|
|
989
908
|
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
990
|
-
const transformed =
|
|
909
|
+
const transformed = transformPrerenderedHtml(fileURLToPath(astroConfig.build.client), manifest);
|
|
991
910
|
if (transformed > 0) logger.info(`island preloading applied to ${transformed} prerendered page(s)`);
|
|
992
911
|
}
|
|
993
912
|
}
|
|
994
|
-
const { stripBuildPaths } = await import("./strip-build-paths-C6eb1QdG.js");
|
|
995
|
-
const stripped = stripBuildPaths(fileURLToPath(astroConfig.build.server), fileURLToPath(astroConfig.root));
|
|
996
|
-
if (stripped > 0) logger.info(`build machine paths stripped from ${stripped} server file(s)`);
|
|
997
913
|
const { compressClientDir } = await import("./compress-B11aeRHQ.js");
|
|
998
914
|
await compressClientDir(fileURLToPath(astroConfig.build.client), logger);
|
|
999
915
|
}
|