@absolutejs/absolute 0.19.0-beta.170 → 0.19.0-beta.172

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/cli/index.js CHANGED
@@ -526,6 +526,105 @@ var init_devCert = __esm(() => {
526
526
  KEY_PATH = join3(CERT_DIR, "key.pem");
527
527
  });
528
528
 
529
+ // src/core/prerender.ts
530
+ var exports_prerender = {};
531
+ __export(exports_prerender, {
532
+ prerenderWithServer: () => prerenderWithServer,
533
+ prerender: () => prerender
534
+ });
535
+ import { mkdirSync as mkdirSync3 } from "fs";
536
+ import { join as join5 } from "path";
537
+ var routeToFilename = (route) => route === "/" ? "index.html" : `${route.slice(1).replace(/\//g, "-")}.html`, crawlRoutes = async (baseUrl, log) => {
538
+ const visited = new Set;
539
+ const queue = ["/"];
540
+ const routes = [];
541
+ while (queue.length > 0) {
542
+ const path = queue.shift();
543
+ if (visited.has(path))
544
+ continue;
545
+ visited.add(path);
546
+ try {
547
+ const res = await fetch(`${baseUrl}${path}`);
548
+ if (!res.ok)
549
+ continue;
550
+ const contentType = res.headers.get("content-type") ?? "";
551
+ if (!contentType.includes("text/html"))
552
+ continue;
553
+ const html = await res.text();
554
+ routes.push(path);
555
+ const linkRegex = /href=["'](\/[^"']*?)["']/g;
556
+ let match;
557
+ while ((match = linkRegex.exec(html)) !== null) {
558
+ const href = match[1] ?? "";
559
+ if (!href || href.includes(".") || href.includes("#") || visited.has(href))
560
+ continue;
561
+ queue.push(href);
562
+ }
563
+ } catch {}
564
+ }
565
+ return routes;
566
+ }, prerender = async (port, outDir, staticConfig, log) => {
567
+ const prerenderDir = join5(outDir, "_prerendered");
568
+ mkdirSync3(prerenderDir, { recursive: true });
569
+ const baseUrl = `http://localhost:${port}`;
570
+ let routes;
571
+ if (staticConfig.routes === "all") {
572
+ log?.("Crawling routes...");
573
+ routes = await crawlRoutes(baseUrl, log);
574
+ } else {
575
+ routes = staticConfig.routes;
576
+ }
577
+ const result = {
578
+ routes: new Map,
579
+ dir: prerenderDir
580
+ };
581
+ for (const route of routes) {
582
+ try {
583
+ const res = await fetch(`${baseUrl}${route}`);
584
+ if (!res.ok) {
585
+ log?.(` Skipped ${route} (HTTP ${res.status})`);
586
+ continue;
587
+ }
588
+ const html = await res.text();
589
+ const fileName = routeToFilename(route);
590
+ const filePath = join5(prerenderDir, fileName);
591
+ await Bun.write(filePath, html);
592
+ result.routes.set(route, filePath);
593
+ log?.(` Pre-rendered ${route} \u2192 ${fileName} (${html.length} bytes)`);
594
+ } catch {
595
+ log?.(` Failed to pre-render ${route}`);
596
+ }
597
+ }
598
+ return result;
599
+ }, prerenderWithServer = async (serverBundlePath, port, outDir, staticConfig, env2, log) => {
600
+ const serverProcess = Bun.spawn(["bun", "run", serverBundlePath], {
601
+ cwd: process.cwd(),
602
+ env: { ...process.env, ...env2, PORT: String(port) },
603
+ stdout: "pipe",
604
+ stderr: "pipe"
605
+ });
606
+ let ready = false;
607
+ for (let i = 0;i < 50; i++) {
608
+ try {
609
+ const res = await fetch(`http://localhost:${port}/`);
610
+ if (res.ok) {
611
+ ready = true;
612
+ break;
613
+ }
614
+ } catch {}
615
+ await Bun.sleep(100);
616
+ }
617
+ if (!ready) {
618
+ serverProcess.kill();
619
+ throw new Error("Server failed to start for pre-rendering");
620
+ }
621
+ const result = await prerender(port, outDir, staticConfig, log);
622
+ serverProcess.kill();
623
+ await serverProcess.exited;
624
+ return result;
625
+ };
626
+ var init_prerender = () => {};
627
+
529
628
  // src/cli/scripts/compile.ts
530
629
  var exports_compile = {};
531
630
  __export(exports_compile, {
@@ -534,16 +633,15 @@ __export(exports_compile, {
534
633
  var {env: env3 } = globalThis.Bun;
535
634
  import {
536
635
  existsSync as existsSync8,
537
- mkdirSync as mkdirSync3,
538
636
  readdirSync,
539
637
  readFileSync as readFileSync7,
540
638
  unlinkSync
541
639
  } from "fs";
542
- import { basename as basename2, join as join5, relative, resolve as resolve6 } from "path";
640
+ import { basename as basename3, join as join6, relative, resolve as resolve6 } from "path";
543
641
  var cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, collectFiles2 = (dir) => {
544
642
  const results = [];
545
643
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
546
- const fullPath = join5(dir, entry.name);
644
+ const fullPath = join6(dir, entry.name);
547
645
  if (entry.isDirectory()) {
548
646
  results.push(...collectFiles2(fullPath));
549
647
  } else {
@@ -568,45 +666,9 @@ var cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
568
666
  } catch {}
569
667
  }
570
668
  return;
571
- }, prerender = async (port, outDir) => {
572
- const prerenderDir = join5(outDir, "_prerendered");
573
- mkdirSync3(prerenderDir, { recursive: true });
574
- const baseUrl = `http://localhost:${port}`;
575
- const visited = new Set;
576
- const queue = ["/"];
577
- const savedFiles = [];
578
- while (queue.length > 0) {
579
- const path = queue.shift();
580
- if (visited.has(path))
581
- continue;
582
- visited.add(path);
583
- try {
584
- const res = await fetch(`${baseUrl}${path}`);
585
- if (!res.ok)
586
- continue;
587
- const contentType = res.headers.get("content-type") ?? "";
588
- if (!contentType.includes("text/html"))
589
- continue;
590
- const html = await res.text();
591
- const fileName = path === "/" ? "index.html" : `${path.slice(1).replace(/\//g, "-")}.html`;
592
- const filePath = join5(prerenderDir, fileName);
593
- await Bun.write(filePath, html);
594
- savedFiles.push(filePath);
595
- console.log(cliTag3("\x1B[36m", ` Pre-rendered ${path} \u2192 ${fileName} (${html.length} bytes)`));
596
- const linkRegex = /href=["'](\/[^"']*?)["']/g;
597
- let match;
598
- while ((match = linkRegex.exec(html)) !== null) {
599
- const href = match[1] ?? "";
600
- if (!href || href.includes(".") || href.includes("#") || visited.has(href))
601
- continue;
602
- queue.push(href);
603
- }
604
- } catch {}
605
- }
606
- return savedFiles;
607
- }, generateEntrypoint = (distDir, serverEntry, prerenderMap) => {
669
+ }, generateEntrypoint = (distDir, serverEntry, prerenderMap, version2) => {
608
670
  const allFiles = collectFiles2(distDir);
609
- const serverBundleName = basename2(serverEntry).replace(/\.[^.]+$/, "") + ".js";
671
+ const serverBundleName = basename3(serverEntry).replace(/\.[^.]+$/, "") + ".js";
610
672
  const skip = new Set([
611
673
  serverBundleName,
612
674
  "manifest.json",
@@ -714,12 +776,11 @@ const app = new Elysia()
714
776
  const assetCount = Object.keys(ASSETS).length;
715
777
  const pageCount = Object.keys(PAGES).length;
716
778
  console.log(\`
717
- \\x1b[36m\\x1b[1mABSOLUTEJS\\x1b[0m \\x1b[2mcompiled executable\\x1b[0m
779
+ \\x1b[36m\\x1b[1mABSOLUTEJS\\x1b[0m \\x1b[2mv${version2}\\x1b[0m \\x1b[2mcompiled executable\\x1b[0m
718
780
 
719
781
  \\x1b[32m\u279C\\x1b[0m \\x1b[1mLocal:\\x1b[0m http://localhost:\${port}/
720
782
 
721
783
  \\x1b[2m\${pageCount} pre-rendered pages, \${assetCount} embedded assets\\x1b[0m
722
- \\x1b[2mNo external files needed\\x1b[0m
723
784
  \`);
724
785
  `;
725
786
  }, createStubPlugin = () => ({
@@ -776,7 +837,7 @@ console.log(\`
776
837
  }), FRAMEWORK_EXTERNALS, compile = async (serverEntry, outdir, outfile, configPath2) => {
777
838
  const prerenderPort = Number(env3.COMPILE_PORT) || Number(env3.PORT) || DEFAULT_PORT + 1;
778
839
  killStaleProcesses(prerenderPort);
779
- const entryName = basename2(serverEntry).replace(/\.[^.]+$/, "");
840
+ const entryName = basename3(serverEntry).replace(/\.[^.]+$/, "");
780
841
  const resolvedOutdir = resolve6(outdir ?? "dist");
781
842
  const resolvedOutfile = resolve6(outfile ?? "compiled-server");
782
843
  const absoluteVersion = resolvePackageVersion2([
@@ -826,50 +887,20 @@ console.log(\`
826
887
  console.log(` \x1B[2m(${getDurationString(performance.now() - bundleStart)})\x1B[0m`);
827
888
  const prerenderStart = performance.now();
828
889
  console.log(cliTag3("\x1B[36m", "Pre-rendering pages..."));
829
- const serverProcess = Bun.spawn(["bun", "run", outputPath], {
830
- cwd: process.cwd(),
831
- env: {
832
- ...process.env,
833
- ABSOLUTE_BUILD_DIR: resolvedOutdir,
834
- ABSOLUTE_VERSION: absoluteVersion,
835
- FORCE_COLOR: "0",
836
- NODE_ENV: "production",
837
- PORT: String(prerenderPort),
838
- ...configPath2 ? { ABSOLUTE_CONFIG: configPath2 } : {}
839
- },
840
- stdout: "pipe",
841
- stderr: "pipe"
842
- });
843
- let ready = false;
844
- for (let i = 0;i < 50; i++) {
845
- try {
846
- const res = await fetch(`http://localhost:${prerenderPort}/`);
847
- if (res.ok) {
848
- ready = true;
849
- break;
850
- }
851
- } catch {}
852
- await Bun.sleep(100);
853
- }
854
- if (!ready) {
855
- serverProcess.kill();
856
- console.error(cliTag3("\x1B[31m", "Server failed to start for pre-rendering."));
857
- process.exit(1);
858
- }
859
- const prerenderFiles = await prerender(prerenderPort, resolvedOutdir);
860
- serverProcess.kill();
861
- await serverProcess.exited;
862
- const prerenderMap = new Map;
863
- for (const filePath of prerenderFiles) {
864
- const fileName = basename2(filePath, ".html");
865
- const route = fileName === "index" ? "/" : `/${fileName}`;
866
- prerenderMap.set(route, filePath);
867
- }
890
+ const staticConfig = buildConfig.static ?? { routes: "all" };
891
+ const prerenderResult = await prerenderWithServer(outputPath, prerenderPort, resolvedOutdir, staticConfig, {
892
+ ABSOLUTE_BUILD_DIR: resolvedOutdir,
893
+ ABSOLUTE_VERSION: absoluteVersion,
894
+ FORCE_COLOR: "0",
895
+ NODE_ENV: "production",
896
+ ...configPath2 ? { ABSOLUTE_CONFIG: configPath2 } : {}
897
+ }, (msg) => console.log(cliTag3("\x1B[36m", msg)));
898
+ const prerenderMap = prerenderResult.routes;
868
899
  console.log(cliTag3("\x1B[36m", `Pre-rendered ${prerenderMap.size} pages (${getDurationString(performance.now() - prerenderStart)})`));
869
900
  const compileStart = performance.now();
870
901
  process.stdout.write(cliTag3("\x1B[36m", "Compiling standalone executable"));
871
- const entrypointCode = generateEntrypoint(resolvedOutdir, serverEntry, prerenderMap);
872
- const entrypointPath = join5(resolvedOutdir, "_compile_entrypoint.ts");
902
+ const entrypointCode = generateEntrypoint(resolvedOutdir, serverEntry, prerenderMap, absoluteVersion);
903
+ const entrypointPath = join6(resolvedOutdir, "_compile_entrypoint.ts");
873
904
  await Bun.write(entrypointPath, entrypointCode);
874
905
  const result = await Bun.build({
875
906
  entrypoints: [entrypointPath],
@@ -889,7 +920,7 @@ console.log(\`
889
920
  const size = (Bun.file(resolvedOutfile).size / 1048576).toFixed(0);
890
921
  const totalDuration = getDurationString(performance.now() - totalStart);
891
922
  console.log(cliTag3("\x1B[32m", `Compiled to ${resolvedOutfile} (${size}MB) in ${totalDuration}`));
892
- console.log(cliTag3("\x1B[2m", `Run with: ./${basename2(resolvedOutfile)}`));
923
+ console.log(cliTag3("\x1B[2m", `Run with: ./${basename3(resolvedOutfile)}`));
893
924
  sendTelemetryEvent("compile:complete", {
894
925
  durationMs: Math.round(performance.now() - totalStart),
895
926
  entry: serverEntry,
@@ -898,6 +929,7 @@ console.log(\`
898
929
  };
899
930
  var init_compile = __esm(() => {
900
931
  init_constants();
932
+ init_prerender();
901
933
  init_getDurationString();
902
934
  init_loadConfig();
903
935
  init_startupBanner();
@@ -1771,7 +1803,7 @@ init_telemetryEvent();
1771
1803
  init_utils();
1772
1804
  var {env: env2 } = globalThis.Bun;
1773
1805
  import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
1774
- import { basename, resolve as resolve5 } from "path";
1806
+ import { basename as basename2, resolve as resolve5 } from "path";
1775
1807
  var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`;
1776
1808
  var resolvePackageVersion = (candidates) => {
1777
1809
  for (const candidate of candidates) {
@@ -1825,7 +1857,7 @@ var handleBundleFailure = (serverBundle, bundleStart, serverEntry) => {
1825
1857
  var start = async (serverEntry, outdir, configPath2) => {
1826
1858
  const port = Number(env2.PORT) || DEFAULT_PORT;
1827
1859
  killStaleProcesses(port);
1828
- const entryName = basename(serverEntry).replace(/\.[^.]+$/, "");
1860
+ const entryName = basename2(serverEntry).replace(/\.[^.]+$/, "");
1829
1861
  const resolvedOutdir = resolve5(outdir ?? "dist");
1830
1862
  const absoluteVersion = resolvePackageVersion([
1831
1863
  resolve5(import.meta.dir, "..", "..", "..", "package.json"),
@@ -1955,6 +1987,27 @@ var start = async (serverEntry, outdir, configPath2) => {
1955
1987
  durationMs: bundleDurationMs,
1956
1988
  entry: serverEntry
1957
1989
  });
1990
+ if (buildConfig.static) {
1991
+ const prerenderStart = performance.now();
1992
+ console.log(cliTag2("\x1B[36m", "Pre-rendering static pages..."));
1993
+ const { prerenderWithServer: prerenderWithServer2 } = await Promise.resolve().then(() => (init_prerender(), exports_prerender));
1994
+ const prerenderPort = port + 1;
1995
+ try {
1996
+ killStaleProcesses(prerenderPort);
1997
+ const result = await prerenderWithServer2(outputPath, prerenderPort, resolvedOutdir, buildConfig.static, {
1998
+ ABSOLUTE_BUILD_DIR: resolvedOutdir,
1999
+ ABSOLUTE_VERSION: absoluteVersion,
2000
+ FORCE_COLOR: "0",
2001
+ NODE_ENV: "production",
2002
+ ...configPath2 ? { ABSOLUTE_CONFIG: configPath2 } : {}
2003
+ }, (msg) => console.log(cliTag2("\x1B[36m", msg)));
2004
+ const prerenderDuration = getDurationString(performance.now() - prerenderStart);
2005
+ console.log(cliTag2("\x1B[36m", `Pre-rendered ${result.routes.size} pages (${prerenderDuration})`));
2006
+ } catch (err) {
2007
+ console.error(cliTag2("\x1B[33m", "Pre-rendering failed, pages will use SSR."));
2008
+ console.error(err);
2009
+ }
2010
+ }
1958
2011
  const usesDocker = existsSync7(resolve5(COMPOSE_PATH));
1959
2012
  const scripts = usesDocker ? await readDbScripts() : null;
1960
2013
  if (scripts)
package/dist/index.js CHANGED
@@ -205641,7 +205641,7 @@ __export(exports_devCert, {
205641
205641
  });
205642
205642
  import { existsSync as existsSync17, mkdirSync as mkdirSync10, readFileSync as readFileSync11, rmSync as rmSync2 } from "fs";
205643
205643
  import { platform as platform3 } from "os";
205644
- import { join as join17 } from "path";
205644
+ import { join as join18 } from "path";
205645
205645
  var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[36m[dev]\x1B[0m ${msg}`), devWarn = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[33m[dev]\x1B[0m \x1B[33m${msg}\x1B[0m`), certFilesExist = () => existsSync17(CERT_PATH) && existsSync17(KEY_PATH), isCertExpired = () => {
205646
205646
  try {
205647
205647
  const certPem = readFileSync11(CERT_PATH, "utf-8");
@@ -205847,9 +205847,9 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, devLog = (msg) => c
205847
205847
  return true;
205848
205848
  };
205849
205849
  var init_devCert = __esm(() => {
205850
- CERT_DIR = join17(process.cwd(), ".absolutejs");
205851
- CERT_PATH = join17(CERT_DIR, "cert.pem");
205852
- KEY_PATH = join17(CERT_DIR, "key.pem");
205850
+ CERT_DIR = join18(process.cwd(), ".absolutejs");
205851
+ CERT_PATH = join18(CERT_DIR, "cert.pem");
205852
+ KEY_PATH = join18(CERT_DIR, "key.pem");
205853
205853
  });
205854
205854
  // types/client.ts
205855
205855
  var hmrState = {
@@ -205876,8 +205876,8 @@ var {file } = globalThis.Bun;
205876
205876
  var handleHTMLPageRequest = (pagePath) => file(pagePath);
205877
205877
  var handleHTMXPageRequest = (pagePath) => file(pagePath);
205878
205878
  // src/core/prepare.ts
205879
- import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
205880
- import { relative as relative10, resolve as resolve23 } from "path";
205879
+ import { existsSync as existsSync16, readdirSync as readdirSync2, readFileSync as readFileSync10 } from "fs";
205880
+ import { basename as basename9, join as join17, relative as relative10, resolve as resolve23 } from "path";
205881
205881
 
205882
205882
  // src/utils/loadConfig.ts
205883
205883
  import { resolve } from "path";
@@ -206005,6 +206005,21 @@ var prepareDev = async (config, buildDir) => {
206005
206005
  absolutejs: (app) => hmrPlugin(app.use(staticPlugin({ assets: buildDir, prefix: "" })))
206006
206006
  };
206007
206007
  };
206008
+ var loadPrerenderMap = (prerenderDir) => {
206009
+ const map = new Map;
206010
+ if (!existsSync16(prerenderDir))
206011
+ return map;
206012
+ try {
206013
+ for (const entry of readdirSync2(prerenderDir)) {
206014
+ if (!entry.endsWith(".html"))
206015
+ continue;
206016
+ const name = basename9(entry, ".html");
206017
+ const route = name === "index" ? "/" : `/${name}`;
206018
+ map.set(route, join17(prerenderDir, entry));
206019
+ }
206020
+ } catch {}
206021
+ return map;
206022
+ };
206008
206023
  var prepare = async (configOrPath) => {
206009
206024
  const config = await loadConfig(configOrPath);
206010
206025
  const nodeEnv = process.env["NODE_ENV"];
@@ -206014,8 +206029,24 @@ var prepare = async (configOrPath) => {
206014
206029
  return prepareDev(config, buildDir);
206015
206030
  const manifest = JSON.parse(readFileSync10(`${buildDir}/manifest.json`, "utf-8"));
206016
206031
  const { staticPlugin } = await import("@elysiajs/static");
206017
- const absolutejs = staticPlugin({ assets: buildDir, prefix: "" });
206018
- return { absolutejs, manifest };
206032
+ const staticFiles = staticPlugin({ assets: buildDir, prefix: "" });
206033
+ const prerenderDir = join17(buildDir, "_prerendered");
206034
+ const prerenderMap = loadPrerenderMap(prerenderDir);
206035
+ if (prerenderMap.size > 0) {
206036
+ const { Elysia } = await import("elysia");
206037
+ const prerenderPlugin = new Elysia({ name: "prerendered-pages" }).onRequest(({ request }) => {
206038
+ const url = new URL(request.url);
206039
+ const filePath = prerenderMap.get(url.pathname);
206040
+ if (!filePath)
206041
+ return;
206042
+ return new Response(Bun.file(filePath), {
206043
+ headers: { "content-type": "text/html; charset=utf-8" }
206044
+ });
206045
+ });
206046
+ const absolutejs = (app) => app.use(prerenderPlugin).use(staticFiles);
206047
+ return { absolutejs, manifest };
206048
+ }
206049
+ return { absolutejs: staticFiles, manifest };
206019
206050
  };
206020
206051
  // src/plugins/pageRouter.ts
206021
206052
  var pageRouterPlugin = () => {
@@ -206198,5 +206229,5 @@ export {
206198
206229
  ANGULAR_INIT_TIMEOUT_MS
206199
206230
  };
206200
206231
 
206201
- //# debugId=8D9238CCCF55663464756E2164756E21
206232
+ //# debugId=B51D68800393AB0664756E2164756E21
206202
206233
  //# sourceMappingURL=index.js.map