@float.js/core 2.0.7 → 2.1.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 +28 -0
- package/dist/cli/index.js +358 -114
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +368 -124
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +296 -52
- package/dist/server/index.js.map +1 -1
- package/package.json +12 -1
package/dist/server/index.js
CHANGED
|
@@ -729,7 +729,7 @@ function generateAPIResponse(state) {
|
|
|
729
729
|
function createDevDashboard(options = {}) {
|
|
730
730
|
const {
|
|
731
731
|
enabled = process.env.NODE_ENV !== "production",
|
|
732
|
-
path:
|
|
732
|
+
path: path8 = "/__float",
|
|
733
733
|
auth
|
|
734
734
|
} = options;
|
|
735
735
|
if (!enabled) {
|
|
@@ -737,7 +737,7 @@ function createDevDashboard(options = {}) {
|
|
|
737
737
|
}
|
|
738
738
|
return (req, res, next) => {
|
|
739
739
|
const url = req.url || "";
|
|
740
|
-
if (!url.startsWith(
|
|
740
|
+
if (!url.startsWith(path8)) {
|
|
741
741
|
return next();
|
|
742
742
|
}
|
|
743
743
|
if (auth) {
|
|
@@ -756,7 +756,7 @@ function createDevDashboard(options = {}) {
|
|
|
756
756
|
return;
|
|
757
757
|
}
|
|
758
758
|
}
|
|
759
|
-
const subPath = url.slice(
|
|
759
|
+
const subPath = url.slice(path8.length);
|
|
760
760
|
if (subPath === "" || subPath === "/") {
|
|
761
761
|
res.setHeader("Content-Type", "text/html");
|
|
762
762
|
res.end(generateDashboardHTML(dashboardState));
|
|
@@ -870,9 +870,9 @@ init_esm_shims();
|
|
|
870
870
|
// src/server/dev-server.ts
|
|
871
871
|
init_esm_shims();
|
|
872
872
|
import http from "http";
|
|
873
|
-
import
|
|
874
|
-
import
|
|
875
|
-
import
|
|
873
|
+
import fs4 from "fs";
|
|
874
|
+
import path6 from "path";
|
|
875
|
+
import pc2 from "picocolors";
|
|
876
876
|
import chokidar from "chokidar";
|
|
877
877
|
import { WebSocketServer, WebSocket } from "ws";
|
|
878
878
|
import mime from "mime-types";
|
|
@@ -2494,11 +2494,214 @@ function generateExamplesPage() {
|
|
|
2494
2494
|
` + footer;
|
|
2495
2495
|
}
|
|
2496
2496
|
|
|
2497
|
+
// src/build/css-processor.ts
|
|
2498
|
+
init_esm_shims();
|
|
2499
|
+
import fs3 from "fs";
|
|
2500
|
+
import path5 from "path";
|
|
2501
|
+
|
|
2502
|
+
// src/build/tailwind-setup.ts
|
|
2503
|
+
init_esm_shims();
|
|
2504
|
+
import fs2 from "fs";
|
|
2505
|
+
import path4 from "path";
|
|
2506
|
+
import pc from "picocolors";
|
|
2507
|
+
function checkTailwindSetup(rootDir) {
|
|
2508
|
+
const possibleConfigs = [
|
|
2509
|
+
"tailwind.config.js",
|
|
2510
|
+
"tailwind.config.ts",
|
|
2511
|
+
"tailwind.config.mjs",
|
|
2512
|
+
"tailwind.config.cjs"
|
|
2513
|
+
];
|
|
2514
|
+
let configPath = null;
|
|
2515
|
+
for (const config of possibleConfigs) {
|
|
2516
|
+
const fullPath = path4.join(rootDir, config);
|
|
2517
|
+
if (fs2.existsSync(fullPath)) {
|
|
2518
|
+
configPath = fullPath;
|
|
2519
|
+
break;
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
const globalsPath = path4.join(rootDir, "app", "globals.css");
|
|
2523
|
+
const hasGlobals = fs2.existsSync(globalsPath);
|
|
2524
|
+
return {
|
|
2525
|
+
hasTailwind: !!configPath,
|
|
2526
|
+
configPath,
|
|
2527
|
+
globalsPath: hasGlobals ? globalsPath : null,
|
|
2528
|
+
needsSetup: !configPath || !hasGlobals
|
|
2529
|
+
};
|
|
2530
|
+
}
|
|
2531
|
+
async function setupTailwind(rootDir, options = {}) {
|
|
2532
|
+
const { force = false, silent = false } = options;
|
|
2533
|
+
const config = checkTailwindSetup(rootDir);
|
|
2534
|
+
if (!force && !config.needsSetup) {
|
|
2535
|
+
return;
|
|
2536
|
+
}
|
|
2537
|
+
if (!silent) {
|
|
2538
|
+
console.log(pc.cyan("\n\u{1F3A8} Setting up Tailwind CSS..."));
|
|
2539
|
+
}
|
|
2540
|
+
if (!config.configPath || force) {
|
|
2541
|
+
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
2542
|
+
export default {
|
|
2543
|
+
content: [
|
|
2544
|
+
'./app/**/*.{js,ts,jsx,tsx}',
|
|
2545
|
+
'./components/**/*.{js,ts,jsx,tsx}',
|
|
2546
|
+
],
|
|
2547
|
+
theme: {
|
|
2548
|
+
extend: {},
|
|
2549
|
+
},
|
|
2550
|
+
plugins: [],
|
|
2551
|
+
}
|
|
2552
|
+
`;
|
|
2553
|
+
const configPath = path4.join(rootDir, "tailwind.config.js");
|
|
2554
|
+
fs2.writeFileSync(configPath, tailwindConfig);
|
|
2555
|
+
if (!silent) {
|
|
2556
|
+
console.log(pc.green(" \u2713 Created tailwind.config.js"));
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
const postcssPath = path4.join(rootDir, "postcss.config.js");
|
|
2560
|
+
if (!fs2.existsSync(postcssPath) || force) {
|
|
2561
|
+
const postcssConfig = `export default {
|
|
2562
|
+
plugins: {
|
|
2563
|
+
tailwindcss: {},
|
|
2564
|
+
autoprefixer: {},
|
|
2565
|
+
},
|
|
2566
|
+
}
|
|
2567
|
+
`;
|
|
2568
|
+
fs2.writeFileSync(postcssPath, postcssConfig);
|
|
2569
|
+
if (!silent) {
|
|
2570
|
+
console.log(pc.green(" \u2713 Created postcss.config.js"));
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
const appDir = path4.join(rootDir, "app");
|
|
2574
|
+
if (!fs2.existsSync(appDir)) {
|
|
2575
|
+
fs2.mkdirSync(appDir, { recursive: true });
|
|
2576
|
+
}
|
|
2577
|
+
const globalsPath = path4.join(appDir, "globals.css");
|
|
2578
|
+
if (!fs2.existsSync(globalsPath) || force) {
|
|
2579
|
+
const globalsCss = `@tailwind base;
|
|
2580
|
+
@tailwind components;
|
|
2581
|
+
@tailwind utilities;
|
|
2582
|
+
`;
|
|
2583
|
+
fs2.writeFileSync(globalsPath, globalsCss);
|
|
2584
|
+
if (!silent) {
|
|
2585
|
+
console.log(pc.green(" \u2713 Created app/globals.css"));
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
const layoutPath = path4.join(appDir, "layout.tsx");
|
|
2589
|
+
if (!fs2.existsSync(layoutPath)) {
|
|
2590
|
+
const layoutContent = `import './globals.css'
|
|
2591
|
+
|
|
2592
|
+
export default function RootLayout({
|
|
2593
|
+
children,
|
|
2594
|
+
}: {
|
|
2595
|
+
children: React.ReactNode
|
|
2596
|
+
}) {
|
|
2597
|
+
return (
|
|
2598
|
+
<html lang="en">
|
|
2599
|
+
<body>{children}</body>
|
|
2600
|
+
</html>
|
|
2601
|
+
)
|
|
2602
|
+
}
|
|
2603
|
+
`;
|
|
2604
|
+
fs2.writeFileSync(layoutPath, layoutContent);
|
|
2605
|
+
if (!silent) {
|
|
2606
|
+
console.log(pc.green(" \u2713 Created app/layout.tsx"));
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
if (!silent) {
|
|
2610
|
+
console.log(pc.green("\n\u2728 Tailwind CSS ready!\n"));
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
function checkTailwindDeps(rootDir) {
|
|
2614
|
+
const packageJsonPath = path4.join(rootDir, "package.json");
|
|
2615
|
+
if (!fs2.existsSync(packageJsonPath)) {
|
|
2616
|
+
return {
|
|
2617
|
+
hasPackageJson: false,
|
|
2618
|
+
hasTailwind: false,
|
|
2619
|
+
hasPostCSS: false,
|
|
2620
|
+
hasAutoprefixer: false
|
|
2621
|
+
};
|
|
2622
|
+
}
|
|
2623
|
+
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
|
|
2624
|
+
const allDeps = {
|
|
2625
|
+
...packageJson.dependencies,
|
|
2626
|
+
...packageJson.devDependencies
|
|
2627
|
+
};
|
|
2628
|
+
return {
|
|
2629
|
+
hasPackageJson: true,
|
|
2630
|
+
hasTailwind: !!allDeps["tailwindcss"],
|
|
2631
|
+
hasPostCSS: !!allDeps["postcss"],
|
|
2632
|
+
hasAutoprefixer: !!allDeps["autoprefixer"]
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2635
|
+
function getTailwindInstallCommand(rootDir) {
|
|
2636
|
+
const deps = checkTailwindDeps(rootDir);
|
|
2637
|
+
if (!deps.hasPackageJson) {
|
|
2638
|
+
return null;
|
|
2639
|
+
}
|
|
2640
|
+
const missing = [];
|
|
2641
|
+
if (!deps.hasTailwind) missing.push("tailwindcss");
|
|
2642
|
+
if (!deps.hasPostCSS) missing.push("postcss");
|
|
2643
|
+
if (!deps.hasAutoprefixer) missing.push("autoprefixer");
|
|
2644
|
+
if (missing.length === 0) {
|
|
2645
|
+
return null;
|
|
2646
|
+
}
|
|
2647
|
+
const hasYarnLock = fs2.existsSync(path4.join(rootDir, "yarn.lock"));
|
|
2648
|
+
const hasPnpmLock = fs2.existsSync(path4.join(rootDir, "pnpm-lock.yaml"));
|
|
2649
|
+
const hasBunLock = fs2.existsSync(path4.join(rootDir, "bun.lockb"));
|
|
2650
|
+
let pm = "npm install -D";
|
|
2651
|
+
if (hasBunLock) pm = "bun add -d";
|
|
2652
|
+
else if (hasPnpmLock) pm = "pnpm add -D";
|
|
2653
|
+
else if (hasYarnLock) pm = "yarn add -D";
|
|
2654
|
+
return `${pm} ${missing.join(" ")}`;
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
// src/build/css-processor.ts
|
|
2658
|
+
async function processCSS(filePath, rootDir = process.cwd()) {
|
|
2659
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
2660
|
+
const tailwindConfig = checkTailwindSetup(rootDir);
|
|
2661
|
+
if (!tailwindConfig.hasTailwind) {
|
|
2662
|
+
return { code: content };
|
|
2663
|
+
}
|
|
2664
|
+
try {
|
|
2665
|
+
const postcss = await import("postcss").then((m) => m.default);
|
|
2666
|
+
const tailwindcss = await import("tailwindcss").then((m) => m.default);
|
|
2667
|
+
const autoprefixer = await import("autoprefixer").then((m) => m.default);
|
|
2668
|
+
const configPath = tailwindConfig.configPath || path5.join(rootDir, "tailwind.config.js");
|
|
2669
|
+
let tailwindConfigModule = {};
|
|
2670
|
+
if (fs3.existsSync(configPath)) {
|
|
2671
|
+
const configUrl = new URL(`file://${configPath}`);
|
|
2672
|
+
tailwindConfigModule = await import(configUrl.href).then((m) => m.default || m);
|
|
2673
|
+
}
|
|
2674
|
+
const result = await postcss([
|
|
2675
|
+
tailwindcss(tailwindConfigModule),
|
|
2676
|
+
autoprefixer()
|
|
2677
|
+
]).process(content, {
|
|
2678
|
+
from: filePath,
|
|
2679
|
+
to: filePath,
|
|
2680
|
+
map: { inline: false }
|
|
2681
|
+
});
|
|
2682
|
+
return {
|
|
2683
|
+
code: result.css,
|
|
2684
|
+
map: result.map?.toString()
|
|
2685
|
+
};
|
|
2686
|
+
} catch (error) {
|
|
2687
|
+
console.warn("CSS processing failed, serving raw CSS:", error);
|
|
2688
|
+
return { code: content };
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
function needsCSSProcessing(filePath, rootDir) {
|
|
2692
|
+
const config = checkTailwindSetup(rootDir);
|
|
2693
|
+
if (!config.hasTailwind) {
|
|
2694
|
+
return false;
|
|
2695
|
+
}
|
|
2696
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
2697
|
+
return content.includes("@tailwind") || content.includes("@apply");
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2497
2700
|
// src/server/dev-server.ts
|
|
2498
2701
|
async function createDevServer(options) {
|
|
2499
2702
|
const { port, host, open } = options;
|
|
2500
2703
|
const rootDir = process.cwd();
|
|
2501
|
-
const publicDir =
|
|
2704
|
+
const publicDir = path6.join(rootDir, "public");
|
|
2502
2705
|
let routes = [];
|
|
2503
2706
|
let server = null;
|
|
2504
2707
|
let wss = null;
|
|
@@ -2506,9 +2709,20 @@ async function createDevServer(options) {
|
|
|
2506
2709
|
async function refreshRoutes() {
|
|
2507
2710
|
try {
|
|
2508
2711
|
routes = await scanRoutes(rootDir);
|
|
2509
|
-
console.log(
|
|
2712
|
+
console.log(pc2.dim(` \u{1F4C1} Found ${routes.length} routes`));
|
|
2713
|
+
const tailwindConfig = checkTailwindSetup(rootDir);
|
|
2714
|
+
if (tailwindConfig.needsSetup) {
|
|
2715
|
+
console.log(pc2.yellow(" \u26A0\uFE0F Tailwind not configured"));
|
|
2716
|
+
const installCmd = getTailwindInstallCommand(rootDir);
|
|
2717
|
+
if (installCmd) {
|
|
2718
|
+
console.log(pc2.dim(` \u{1F4A1} Run: ${installCmd}`));
|
|
2719
|
+
console.log(pc2.dim(` \u{1F4A1} Then: npx float dev`));
|
|
2720
|
+
} else {
|
|
2721
|
+
await setupTailwind(rootDir);
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2510
2724
|
} catch (error) {
|
|
2511
|
-
console.error(
|
|
2725
|
+
console.error(pc2.red("Failed to scan routes:"), error);
|
|
2512
2726
|
}
|
|
2513
2727
|
}
|
|
2514
2728
|
function notifyClients(type, data) {
|
|
@@ -2569,16 +2783,46 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2569
2783
|
async function handleRequest(req, res) {
|
|
2570
2784
|
const url = new URL(req.url || "/", `http://${host}:${port}`);
|
|
2571
2785
|
const pathname = url.pathname;
|
|
2572
|
-
console.log(
|
|
2786
|
+
console.log(pc2.dim(` ${req.method} ${pathname}`));
|
|
2573
2787
|
try {
|
|
2574
|
-
const publicFilePath =
|
|
2575
|
-
if (
|
|
2576
|
-
const content =
|
|
2788
|
+
const publicFilePath = path6.join(publicDir, pathname);
|
|
2789
|
+
if (fs4.existsSync(publicFilePath) && fs4.statSync(publicFilePath).isFile()) {
|
|
2790
|
+
const content = fs4.readFileSync(publicFilePath);
|
|
2577
2791
|
const contentType = mime.lookup(publicFilePath) || "application/octet-stream";
|
|
2578
2792
|
res.writeHead(200, { "Content-Type": contentType });
|
|
2579
2793
|
res.end(content);
|
|
2580
2794
|
return;
|
|
2581
2795
|
}
|
|
2796
|
+
if (pathname.endsWith(".css")) {
|
|
2797
|
+
const cssPath = path6.join(rootDir, "app", pathname.replace(/^\//, ""));
|
|
2798
|
+
if (fs4.existsSync(cssPath)) {
|
|
2799
|
+
try {
|
|
2800
|
+
const needsProcessing = needsCSSProcessing(cssPath, rootDir);
|
|
2801
|
+
if (needsProcessing) {
|
|
2802
|
+
const result = await processCSS(cssPath, rootDir);
|
|
2803
|
+
res.writeHead(200, {
|
|
2804
|
+
"Content-Type": "text/css",
|
|
2805
|
+
"Cache-Control": "no-cache"
|
|
2806
|
+
});
|
|
2807
|
+
res.end(result.code);
|
|
2808
|
+
} else {
|
|
2809
|
+
const content = fs4.readFileSync(cssPath, "utf-8");
|
|
2810
|
+
res.writeHead(200, {
|
|
2811
|
+
"Content-Type": "text/css",
|
|
2812
|
+
"Cache-Control": "no-cache"
|
|
2813
|
+
});
|
|
2814
|
+
res.end(content);
|
|
2815
|
+
}
|
|
2816
|
+
return;
|
|
2817
|
+
} catch (error) {
|
|
2818
|
+
console.error(pc2.red("CSS processing error:"), error);
|
|
2819
|
+
const content = fs4.readFileSync(cssPath, "utf-8");
|
|
2820
|
+
res.writeHead(200, { "Content-Type": "text/css" });
|
|
2821
|
+
res.end(content);
|
|
2822
|
+
return;
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2582
2826
|
if (pathname.startsWith("/_float/")) {
|
|
2583
2827
|
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
2584
2828
|
res.end("// Float.js internal asset");
|
|
@@ -2643,7 +2887,7 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2643
2887
|
});
|
|
2644
2888
|
res.end(html);
|
|
2645
2889
|
} catch (error) {
|
|
2646
|
-
console.error(
|
|
2890
|
+
console.error(pc2.red("Request error:"), error);
|
|
2647
2891
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
2648
2892
|
res.end(createErrorPage(error));
|
|
2649
2893
|
}
|
|
@@ -2672,7 +2916,7 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2672
2916
|
const responseBody = await response.text();
|
|
2673
2917
|
res.end(responseBody);
|
|
2674
2918
|
} catch (error) {
|
|
2675
|
-
console.error(
|
|
2919
|
+
console.error(pc2.red("API route error:"), error);
|
|
2676
2920
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2677
2921
|
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
2678
2922
|
}
|
|
@@ -2687,9 +2931,9 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2687
2931
|
});
|
|
2688
2932
|
const watcher = chokidar.watch(
|
|
2689
2933
|
[
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2934
|
+
path6.join(rootDir, "app/**/*.{ts,tsx,js,jsx}"),
|
|
2935
|
+
path6.join(rootDir, "components/**/*.{ts,tsx,js,jsx}"),
|
|
2936
|
+
path6.join(rootDir, "lib/**/*.{ts,tsx,js,jsx}")
|
|
2693
2937
|
],
|
|
2694
2938
|
{
|
|
2695
2939
|
ignored: /node_modules/,
|
|
@@ -2697,8 +2941,8 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2697
2941
|
}
|
|
2698
2942
|
);
|
|
2699
2943
|
watcher.on("change", async (filePath) => {
|
|
2700
|
-
console.log(
|
|
2701
|
-
\u26A1 File changed: ${
|
|
2944
|
+
console.log(pc2.yellow(`
|
|
2945
|
+
\u26A1 File changed: ${path6.relative(rootDir, filePath)}`));
|
|
2702
2946
|
if (filePath.includes("/app/")) {
|
|
2703
2947
|
await refreshRoutes();
|
|
2704
2948
|
}
|
|
@@ -2706,31 +2950,31 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2706
2950
|
});
|
|
2707
2951
|
watcher.on("add", async (filePath) => {
|
|
2708
2952
|
if (filePath.includes("/app/")) {
|
|
2709
|
-
console.log(
|
|
2710
|
-
\u2795 File added: ${
|
|
2953
|
+
console.log(pc2.green(`
|
|
2954
|
+
\u2795 File added: ${path6.relative(rootDir, filePath)}`));
|
|
2711
2955
|
await refreshRoutes();
|
|
2712
2956
|
notifyClients("reload");
|
|
2713
2957
|
}
|
|
2714
2958
|
});
|
|
2715
2959
|
watcher.on("unlink", async (filePath) => {
|
|
2716
2960
|
if (filePath.includes("/app/")) {
|
|
2717
|
-
console.log(
|
|
2718
|
-
\u2796 File removed: ${
|
|
2961
|
+
console.log(pc2.red(`
|
|
2962
|
+
\u2796 File removed: ${path6.relative(rootDir, filePath)}`));
|
|
2719
2963
|
await refreshRoutes();
|
|
2720
2964
|
notifyClients("reload");
|
|
2721
2965
|
}
|
|
2722
2966
|
});
|
|
2723
2967
|
return new Promise((resolve, reject) => {
|
|
2724
2968
|
server.listen(port, host, () => {
|
|
2725
|
-
console.log(
|
|
2726
|
-
console.log(
|
|
2969
|
+
console.log(pc2.green(` \u2705 Server running at ${pc2.cyan(`http://${host}:${port}`)}`));
|
|
2970
|
+
console.log(pc2.dim(` \u26A1 HMR enabled on ws://${host}:${port + 1}
|
|
2727
2971
|
`));
|
|
2728
|
-
console.log(
|
|
2972
|
+
console.log(pc2.bold(" Routes:"));
|
|
2729
2973
|
routes.forEach((route) => {
|
|
2730
2974
|
if (route.type === "page") {
|
|
2731
|
-
console.log(
|
|
2975
|
+
console.log(pc2.dim(` ${pc2.green("\u25CF")} ${route.path}`));
|
|
2732
2976
|
} else if (route.type === "api") {
|
|
2733
|
-
console.log(
|
|
2977
|
+
console.log(pc2.dim(` ${pc2.blue("\u25C6")} ${route.path} (API)`));
|
|
2734
2978
|
}
|
|
2735
2979
|
});
|
|
2736
2980
|
console.log("");
|
|
@@ -2850,45 +3094,45 @@ function escapeHtml2(text) {
|
|
|
2850
3094
|
// src/server/prod-server.ts
|
|
2851
3095
|
init_esm_shims();
|
|
2852
3096
|
import http2 from "http";
|
|
2853
|
-
import
|
|
2854
|
-
import
|
|
2855
|
-
import
|
|
3097
|
+
import fs5 from "fs";
|
|
3098
|
+
import path7 from "path";
|
|
3099
|
+
import pc3 from "picocolors";
|
|
2856
3100
|
import mime2 from "mime-types";
|
|
2857
3101
|
var cachedRoutes = [];
|
|
2858
3102
|
var pageCache = /* @__PURE__ */ new Map();
|
|
2859
3103
|
async function startProductionServer(options) {
|
|
2860
3104
|
const { port, host } = options;
|
|
2861
3105
|
const rootDir = process.cwd();
|
|
2862
|
-
const distDir =
|
|
2863
|
-
const publicDir =
|
|
2864
|
-
const manifestPath =
|
|
2865
|
-
if (
|
|
2866
|
-
const manifest = JSON.parse(
|
|
3106
|
+
const distDir = path7.join(rootDir, ".float");
|
|
3107
|
+
const publicDir = path7.join(rootDir, "public");
|
|
3108
|
+
const manifestPath = path7.join(distDir, "routes-manifest.json");
|
|
3109
|
+
if (fs5.existsSync(manifestPath)) {
|
|
3110
|
+
const manifest = JSON.parse(fs5.readFileSync(manifestPath, "utf-8"));
|
|
2867
3111
|
cachedRoutes = manifest.routes;
|
|
2868
|
-
console.log(
|
|
3112
|
+
console.log(pc3.dim(` \u{1F4E6} Loaded ${cachedRoutes.length} routes from manifest`));
|
|
2869
3113
|
} else {
|
|
2870
|
-
console.error(
|
|
3114
|
+
console.error(pc3.red(" \u274C No build manifest found. Run `float build` first."));
|
|
2871
3115
|
process.exit(1);
|
|
2872
3116
|
}
|
|
2873
|
-
const pagesDir =
|
|
2874
|
-
if (
|
|
2875
|
-
const prerenderedFiles =
|
|
3117
|
+
const pagesDir = path7.join(distDir, "pages");
|
|
3118
|
+
if (fs5.existsSync(pagesDir)) {
|
|
3119
|
+
const prerenderedFiles = fs5.readdirSync(pagesDir, { recursive: true });
|
|
2876
3120
|
for (const file of prerenderedFiles) {
|
|
2877
3121
|
if (file.endsWith(".html")) {
|
|
2878
3122
|
const routePath = "/" + file.replace(/\.html$/, "").replace(/index$/, "");
|
|
2879
|
-
const content =
|
|
3123
|
+
const content = fs5.readFileSync(path7.join(pagesDir, file), "utf-8");
|
|
2880
3124
|
pageCache.set(routePath, content);
|
|
2881
3125
|
}
|
|
2882
3126
|
}
|
|
2883
|
-
console.log(
|
|
3127
|
+
console.log(pc3.dim(` \u{1F4C4} Loaded ${pageCache.size} pre-rendered pages`));
|
|
2884
3128
|
}
|
|
2885
3129
|
const server = http2.createServer(async (req, res) => {
|
|
2886
3130
|
const url = new URL(req.url || "/", `http://${host}:${port}`);
|
|
2887
3131
|
const pathname = url.pathname;
|
|
2888
3132
|
try {
|
|
2889
|
-
const staticPath =
|
|
2890
|
-
if (
|
|
2891
|
-
const content =
|
|
3133
|
+
const staticPath = path7.join(distDir, "static", pathname);
|
|
3134
|
+
if (fs5.existsSync(staticPath) && fs5.statSync(staticPath).isFile()) {
|
|
3135
|
+
const content = fs5.readFileSync(staticPath);
|
|
2892
3136
|
const contentType = mime2.lookup(staticPath) || "application/octet-stream";
|
|
2893
3137
|
res.writeHead(200, {
|
|
2894
3138
|
"Content-Type": contentType,
|
|
@@ -2897,9 +3141,9 @@ async function startProductionServer(options) {
|
|
|
2897
3141
|
res.end(content);
|
|
2898
3142
|
return;
|
|
2899
3143
|
}
|
|
2900
|
-
const publicFilePath =
|
|
2901
|
-
if (
|
|
2902
|
-
const content =
|
|
3144
|
+
const publicFilePath = path7.join(publicDir, pathname);
|
|
3145
|
+
if (fs5.existsSync(publicFilePath) && fs5.statSync(publicFilePath).isFile()) {
|
|
3146
|
+
const content = fs5.readFileSync(publicFilePath);
|
|
2903
3147
|
const contentType = mime2.lookup(publicFilePath) || "application/octet-stream";
|
|
2904
3148
|
res.writeHead(200, { "Content-Type": contentType });
|
|
2905
3149
|
res.end(content);
|
|
@@ -2932,13 +3176,13 @@ async function startProductionServer(options) {
|
|
|
2932
3176
|
});
|
|
2933
3177
|
res.end(html);
|
|
2934
3178
|
} catch (error) {
|
|
2935
|
-
console.error(
|
|
3179
|
+
console.error(pc3.red("Request error:"), error);
|
|
2936
3180
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
2937
3181
|
res.end("<h1>500 - Internal Server Error</h1>");
|
|
2938
3182
|
}
|
|
2939
3183
|
});
|
|
2940
3184
|
server.listen(port, host, () => {
|
|
2941
|
-
console.log(
|
|
3185
|
+
console.log(pc3.green(` \u2705 Production server running at ${pc3.cyan(`http://${host}:${port}`)}
|
|
2942
3186
|
`));
|
|
2943
3187
|
});
|
|
2944
3188
|
}
|