@float.js/core 2.0.7 → 2.2.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 +66 -0
- package/dist/cli/index.js +620 -135
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +630 -145
- package/dist/index.js.map +1 -1
- package/dist/router/index.d.ts +4 -0
- package/dist/router/index.js +32 -2
- package/dist/router/index.js.map +1 -1
- package/dist/server/index.js +557 -72
- package/dist/server/index.js.map +1 -1
- package/package.json +12 -1
package/dist/server/index.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
3
9
|
var __esm = (fn, res) => function __init() {
|
|
4
10
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
11
|
};
|
|
@@ -729,7 +735,7 @@ function generateAPIResponse(state) {
|
|
|
729
735
|
function createDevDashboard(options = {}) {
|
|
730
736
|
const {
|
|
731
737
|
enabled = process.env.NODE_ENV !== "production",
|
|
732
|
-
path:
|
|
738
|
+
path: path9 = "/__float",
|
|
733
739
|
auth
|
|
734
740
|
} = options;
|
|
735
741
|
if (!enabled) {
|
|
@@ -737,7 +743,7 @@ function createDevDashboard(options = {}) {
|
|
|
737
743
|
}
|
|
738
744
|
return (req, res, next) => {
|
|
739
745
|
const url = req.url || "";
|
|
740
|
-
if (!url.startsWith(
|
|
746
|
+
if (!url.startsWith(path9)) {
|
|
741
747
|
return next();
|
|
742
748
|
}
|
|
743
749
|
if (auth) {
|
|
@@ -756,7 +762,7 @@ function createDevDashboard(options = {}) {
|
|
|
756
762
|
return;
|
|
757
763
|
}
|
|
758
764
|
}
|
|
759
|
-
const subPath = url.slice(
|
|
765
|
+
const subPath = url.slice(path9.length);
|
|
760
766
|
if (subPath === "" || subPath === "/") {
|
|
761
767
|
res.setHeader("Content-Type", "text/html");
|
|
762
768
|
res.end(generateDashboardHTML(dashboardState));
|
|
@@ -870,9 +876,9 @@ init_esm_shims();
|
|
|
870
876
|
// src/server/dev-server.ts
|
|
871
877
|
init_esm_shims();
|
|
872
878
|
import http from "http";
|
|
873
|
-
import
|
|
874
|
-
import
|
|
875
|
-
import
|
|
879
|
+
import fs5 from "fs";
|
|
880
|
+
import path7 from "path";
|
|
881
|
+
import pc2 from "picocolors";
|
|
876
882
|
import chokidar from "chokidar";
|
|
877
883
|
import { WebSocketServer, WebSocket } from "ws";
|
|
878
884
|
import mime from "mime-types";
|
|
@@ -934,6 +940,26 @@ function findLayouts(routePath, allLayouts) {
|
|
|
934
940
|
}
|
|
935
941
|
return layouts;
|
|
936
942
|
}
|
|
943
|
+
function findLoading(routePath, allLoading) {
|
|
944
|
+
const segments = routePath.split("/").filter(Boolean);
|
|
945
|
+
for (let i = segments.length; i >= 0; i--) {
|
|
946
|
+
const currentPath = i === 0 ? "/" : "/" + segments.slice(0, i).join("/");
|
|
947
|
+
if (allLoading.has(currentPath)) {
|
|
948
|
+
return allLoading.get(currentPath);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
return void 0;
|
|
952
|
+
}
|
|
953
|
+
function findError(routePath, allErrors) {
|
|
954
|
+
const segments = routePath.split("/").filter(Boolean);
|
|
955
|
+
for (let i = segments.length; i >= 0; i--) {
|
|
956
|
+
const currentPath = i === 0 ? "/" : "/" + segments.slice(0, i).join("/");
|
|
957
|
+
if (allErrors.has(currentPath)) {
|
|
958
|
+
return allErrors.get(currentPath);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return void 0;
|
|
962
|
+
}
|
|
937
963
|
async function scanRoutes(rootDir, options = {}) {
|
|
938
964
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
939
965
|
const appDir = path2.join(rootDir, opts.appDir);
|
|
@@ -945,12 +971,20 @@ async function scanRoutes(rootDir, options = {}) {
|
|
|
945
971
|
ignore: ["**/node_modules/**", "**/_*/**"]
|
|
946
972
|
});
|
|
947
973
|
const layoutMap = /* @__PURE__ */ new Map();
|
|
974
|
+
const loadingMap = /* @__PURE__ */ new Map();
|
|
975
|
+
const errorMap = /* @__PURE__ */ new Map();
|
|
948
976
|
for (const file of files) {
|
|
949
977
|
const type = getRouteType(file);
|
|
978
|
+
const { urlPath } = filePathToUrlPath(file, "");
|
|
950
979
|
if (type === "layout") {
|
|
951
|
-
const { urlPath } = filePathToUrlPath(file, "");
|
|
952
980
|
const layoutPath = urlPath === "/" ? "/" : urlPath.replace(/\/layout$/, "") || "/";
|
|
953
981
|
layoutMap.set(layoutPath, path2.join(appDir, file));
|
|
982
|
+
} else if (type === "loading") {
|
|
983
|
+
const loadingPath = urlPath === "/" ? "/" : urlPath.replace(/\/loading$/, "") || "/";
|
|
984
|
+
loadingMap.set(loadingPath, path2.join(appDir, file));
|
|
985
|
+
} else if (type === "error") {
|
|
986
|
+
const errorPath = urlPath === "/" ? "/" : urlPath.replace(/\/error$/, "") || "/";
|
|
987
|
+
errorMap.set(errorPath, path2.join(appDir, file));
|
|
954
988
|
}
|
|
955
989
|
}
|
|
956
990
|
const routes = [];
|
|
@@ -968,7 +1002,9 @@ async function scanRoutes(rootDir, options = {}) {
|
|
|
968
1002
|
params,
|
|
969
1003
|
isCatchAll,
|
|
970
1004
|
isOptionalCatchAll,
|
|
971
|
-
layouts: type === "page" ? findLayouts(urlPath, layoutMap) : []
|
|
1005
|
+
layouts: type === "page" ? findLayouts(urlPath, layoutMap) : [],
|
|
1006
|
+
loading: type === "page" ? findLoading(urlPath, loadingMap) : void 0,
|
|
1007
|
+
error: type === "page" ? findError(urlPath, errorMap) : void 0
|
|
972
1008
|
};
|
|
973
1009
|
routes.push(route);
|
|
974
1010
|
}
|
|
@@ -1026,23 +1062,222 @@ import { Writable } from "stream";
|
|
|
1026
1062
|
// src/build/transform.ts
|
|
1027
1063
|
init_esm_shims();
|
|
1028
1064
|
import * as esbuild from "esbuild";
|
|
1065
|
+
import fs2 from "fs";
|
|
1066
|
+
import path4 from "path";
|
|
1067
|
+
import { pathToFileURL } from "url";
|
|
1068
|
+
|
|
1069
|
+
// src/build/persistent-cache.ts
|
|
1070
|
+
init_esm_shims();
|
|
1029
1071
|
import fs from "fs";
|
|
1030
1072
|
import path3 from "path";
|
|
1031
|
-
import
|
|
1073
|
+
import crypto from "crypto";
|
|
1074
|
+
var PersistentCache = class {
|
|
1075
|
+
cacheDir;
|
|
1076
|
+
manifestPath;
|
|
1077
|
+
manifest;
|
|
1078
|
+
constructor(rootDir = process.cwd()) {
|
|
1079
|
+
this.cacheDir = path3.join(rootDir, ".float", "cache");
|
|
1080
|
+
this.manifestPath = path3.join(this.cacheDir, "manifest.json");
|
|
1081
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
1082
|
+
this.manifest = this.loadManifest();
|
|
1083
|
+
}
|
|
1084
|
+
loadManifest() {
|
|
1085
|
+
if (fs.existsSync(this.manifestPath)) {
|
|
1086
|
+
try {
|
|
1087
|
+
const data = fs.readFileSync(this.manifestPath, "utf-8");
|
|
1088
|
+
return JSON.parse(data);
|
|
1089
|
+
} catch {
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return {
|
|
1093
|
+
version: "1.0",
|
|
1094
|
+
entries: {}
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
saveManifest() {
|
|
1098
|
+
fs.writeFileSync(
|
|
1099
|
+
this.manifestPath,
|
|
1100
|
+
JSON.stringify(this.manifest, null, 2)
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Generate hash for content
|
|
1105
|
+
*/
|
|
1106
|
+
hash(content) {
|
|
1107
|
+
return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Get cache key path
|
|
1111
|
+
*/
|
|
1112
|
+
getKeyPath(key) {
|
|
1113
|
+
const safeKey = key.replace(/[^a-z0-9_-]/gi, "_");
|
|
1114
|
+
return path3.join(this.cacheDir, `${safeKey}.cache`);
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Check if cache entry is valid
|
|
1118
|
+
*/
|
|
1119
|
+
has(key, contentHash) {
|
|
1120
|
+
const entry = this.manifest.entries[key];
|
|
1121
|
+
if (!entry) return false;
|
|
1122
|
+
const cachePath = this.getKeyPath(key);
|
|
1123
|
+
if (!fs.existsSync(cachePath)) {
|
|
1124
|
+
delete this.manifest.entries[key];
|
|
1125
|
+
this.saveManifest();
|
|
1126
|
+
return false;
|
|
1127
|
+
}
|
|
1128
|
+
if (contentHash && entry.hash !== contentHash) {
|
|
1129
|
+
return false;
|
|
1130
|
+
}
|
|
1131
|
+
return true;
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* Get cached value
|
|
1135
|
+
*/
|
|
1136
|
+
get(key) {
|
|
1137
|
+
if (!this.has(key)) return null;
|
|
1138
|
+
try {
|
|
1139
|
+
const cachePath = this.getKeyPath(key);
|
|
1140
|
+
const data = fs.readFileSync(cachePath, "utf-8");
|
|
1141
|
+
const entry = JSON.parse(data);
|
|
1142
|
+
return entry.value;
|
|
1143
|
+
} catch {
|
|
1144
|
+
return null;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Set cache value
|
|
1149
|
+
*/
|
|
1150
|
+
set(key, value, content) {
|
|
1151
|
+
const entry = {
|
|
1152
|
+
key,
|
|
1153
|
+
value,
|
|
1154
|
+
timestamp: Date.now(),
|
|
1155
|
+
hash: content ? this.hash(content) : this.hash(JSON.stringify(value))
|
|
1156
|
+
};
|
|
1157
|
+
const cachePath = this.getKeyPath(key);
|
|
1158
|
+
const data = JSON.stringify(entry);
|
|
1159
|
+
fs.writeFileSync(cachePath, data);
|
|
1160
|
+
this.manifest.entries[key] = {
|
|
1161
|
+
hash: entry.hash,
|
|
1162
|
+
timestamp: entry.timestamp,
|
|
1163
|
+
size: Buffer.byteLength(data)
|
|
1164
|
+
};
|
|
1165
|
+
this.saveManifest();
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Delete cache entry
|
|
1169
|
+
*/
|
|
1170
|
+
delete(key) {
|
|
1171
|
+
const cachePath = this.getKeyPath(key);
|
|
1172
|
+
if (fs.existsSync(cachePath)) {
|
|
1173
|
+
fs.unlinkSync(cachePath);
|
|
1174
|
+
}
|
|
1175
|
+
if (this.manifest.entries[key]) {
|
|
1176
|
+
delete this.manifest.entries[key];
|
|
1177
|
+
this.saveManifest();
|
|
1178
|
+
return true;
|
|
1179
|
+
}
|
|
1180
|
+
return false;
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Clear all cache
|
|
1184
|
+
*/
|
|
1185
|
+
clear() {
|
|
1186
|
+
if (fs.existsSync(this.cacheDir)) {
|
|
1187
|
+
fs.rmSync(this.cacheDir, { recursive: true });
|
|
1188
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
1189
|
+
}
|
|
1190
|
+
this.manifest = {
|
|
1191
|
+
version: "1.0",
|
|
1192
|
+
entries: {}
|
|
1193
|
+
};
|
|
1194
|
+
this.saveManifest();
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Get cache statistics
|
|
1198
|
+
*/
|
|
1199
|
+
stats() {
|
|
1200
|
+
const entries = Object.values(this.manifest.entries);
|
|
1201
|
+
const size = entries.reduce((acc, e) => acc + e.size, 0);
|
|
1202
|
+
const timestamps = entries.map((e) => e.timestamp);
|
|
1203
|
+
return {
|
|
1204
|
+
entries: entries.length,
|
|
1205
|
+
size,
|
|
1206
|
+
oldestEntry: timestamps.length > 0 ? Math.min(...timestamps) : null,
|
|
1207
|
+
newestEntry: timestamps.length > 0 ? Math.max(...timestamps) : null
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Clean old entries (older than maxAge milliseconds)
|
|
1212
|
+
*/
|
|
1213
|
+
prune(maxAge = 7 * 24 * 60 * 60 * 1e3) {
|
|
1214
|
+
const now = Date.now();
|
|
1215
|
+
let cleaned = 0;
|
|
1216
|
+
for (const [key, entry] of Object.entries(this.manifest.entries)) {
|
|
1217
|
+
if (now - entry.timestamp > maxAge) {
|
|
1218
|
+
this.delete(key);
|
|
1219
|
+
cleaned++;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
return cleaned;
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
var globalCache = null;
|
|
1226
|
+
function getCache(rootDir) {
|
|
1227
|
+
if (!globalCache) {
|
|
1228
|
+
globalCache = new PersistentCache(rootDir);
|
|
1229
|
+
}
|
|
1230
|
+
return globalCache;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// src/build/transform.ts
|
|
1032
1234
|
var moduleCache = /* @__PURE__ */ new Map();
|
|
1033
|
-
async function transformFile(filePath) {
|
|
1034
|
-
const absolutePath =
|
|
1035
|
-
if (!
|
|
1235
|
+
async function transformFile(filePath, useCache = true) {
|
|
1236
|
+
const absolutePath = path4.isAbsolute(filePath) ? filePath : path4.resolve(filePath);
|
|
1237
|
+
if (!fs2.existsSync(absolutePath)) {
|
|
1036
1238
|
throw new Error(`File not found: ${absolutePath}`);
|
|
1037
1239
|
}
|
|
1038
|
-
const stats =
|
|
1240
|
+
const stats = fs2.statSync(absolutePath);
|
|
1039
1241
|
const mtime = stats.mtimeMs;
|
|
1040
1242
|
const cached = moduleCache.get(absolutePath);
|
|
1041
1243
|
if (cached && cached.mtime === mtime) {
|
|
1042
1244
|
return cached.module;
|
|
1043
1245
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1246
|
+
if (useCache) {
|
|
1247
|
+
const cache = getCache();
|
|
1248
|
+
const source2 = fs2.readFileSync(absolutePath, "utf-8");
|
|
1249
|
+
const sourceHash = __require("crypto").createHash("sha256").update(source2).digest("hex").slice(0, 16);
|
|
1250
|
+
const cacheKey = `transform_${absolutePath}_${sourceHash}`;
|
|
1251
|
+
if (cache.has(cacheKey)) {
|
|
1252
|
+
const cachedCode = cache.get(cacheKey);
|
|
1253
|
+
if (cachedCode) {
|
|
1254
|
+
const tempDir2 = path4.join(process.cwd(), ".float", ".cache");
|
|
1255
|
+
fs2.mkdirSync(tempDir2, { recursive: true });
|
|
1256
|
+
const tempFile2 = path4.join(tempDir2, `${path4.basename(absolutePath, path4.extname(absolutePath))}_${Date.now()}.mjs`);
|
|
1257
|
+
fs2.writeFileSync(tempFile2, cachedCode);
|
|
1258
|
+
try {
|
|
1259
|
+
const module = await import(pathToFileURL(tempFile2).href);
|
|
1260
|
+
moduleCache.set(absolutePath, { module, mtime });
|
|
1261
|
+
setImmediate(() => {
|
|
1262
|
+
try {
|
|
1263
|
+
fs2.unlinkSync(tempFile2);
|
|
1264
|
+
} catch {
|
|
1265
|
+
}
|
|
1266
|
+
});
|
|
1267
|
+
return module;
|
|
1268
|
+
} catch (error) {
|
|
1269
|
+
setImmediate(() => {
|
|
1270
|
+
try {
|
|
1271
|
+
fs2.unlinkSync(tempFile2);
|
|
1272
|
+
} catch {
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
const source = fs2.readFileSync(absolutePath, "utf-8");
|
|
1280
|
+
const ext = path4.extname(absolutePath);
|
|
1046
1281
|
const loader = getLoader(ext);
|
|
1047
1282
|
const result = await esbuild.transform(source, {
|
|
1048
1283
|
loader,
|
|
@@ -1052,25 +1287,31 @@ async function transformFile(filePath) {
|
|
|
1052
1287
|
sourcemap: "inline",
|
|
1053
1288
|
sourcefile: absolutePath
|
|
1054
1289
|
});
|
|
1055
|
-
const tempDir =
|
|
1056
|
-
|
|
1057
|
-
const tempFile =
|
|
1290
|
+
const tempDir = path4.join(process.cwd(), ".float", ".cache");
|
|
1291
|
+
fs2.mkdirSync(tempDir, { recursive: true });
|
|
1292
|
+
const tempFile = path4.join(tempDir, `${path4.basename(absolutePath, ext)}_${Date.now()}.mjs`);
|
|
1058
1293
|
let code = result.code;
|
|
1059
|
-
code = rewriteImports(code,
|
|
1060
|
-
|
|
1294
|
+
code = rewriteImports(code, path4.dirname(absolutePath));
|
|
1295
|
+
fs2.writeFileSync(tempFile, code);
|
|
1061
1296
|
try {
|
|
1062
1297
|
const module = await import(pathToFileURL(tempFile).href);
|
|
1063
1298
|
moduleCache.set(absolutePath, { module, mtime });
|
|
1299
|
+
if (useCache) {
|
|
1300
|
+
const cache = getCache();
|
|
1301
|
+
const sourceHash = __require("crypto").createHash("sha256").update(source).digest("hex").slice(0, 16);
|
|
1302
|
+
const cacheKey = `transform_${absolutePath}_${sourceHash}`;
|
|
1303
|
+
cache.set(cacheKey, code, source);
|
|
1304
|
+
}
|
|
1064
1305
|
setImmediate(() => {
|
|
1065
1306
|
try {
|
|
1066
|
-
|
|
1307
|
+
fs2.unlinkSync(tempFile);
|
|
1067
1308
|
} catch {
|
|
1068
1309
|
}
|
|
1069
1310
|
});
|
|
1070
1311
|
return module;
|
|
1071
1312
|
} catch (error) {
|
|
1072
1313
|
try {
|
|
1073
|
-
|
|
1314
|
+
fs2.unlinkSync(tempFile);
|
|
1074
1315
|
} catch {
|
|
1075
1316
|
}
|
|
1076
1317
|
throw error;
|
|
@@ -1099,18 +1340,18 @@ function getLoader(ext) {
|
|
|
1099
1340
|
function rewriteImports(code, baseDir) {
|
|
1100
1341
|
const importRegex = /from\s+['"](\.[^'"]+)['"]/g;
|
|
1101
1342
|
return code.replace(importRegex, (match, importPath) => {
|
|
1102
|
-
let resolvedPath =
|
|
1343
|
+
let resolvedPath = path4.resolve(baseDir, importPath);
|
|
1103
1344
|
const extensions = [".tsx", ".ts", ".jsx", ".js", ".mjs", ""];
|
|
1104
1345
|
let found = false;
|
|
1105
1346
|
for (const ext of extensions) {
|
|
1106
1347
|
const tryPath = resolvedPath + ext;
|
|
1107
|
-
if (
|
|
1348
|
+
if (fs2.existsSync(tryPath)) {
|
|
1108
1349
|
resolvedPath = tryPath;
|
|
1109
1350
|
found = true;
|
|
1110
1351
|
break;
|
|
1111
1352
|
}
|
|
1112
|
-
const indexPath =
|
|
1113
|
-
if (
|
|
1353
|
+
const indexPath = path4.join(resolvedPath, `index${ext}`);
|
|
1354
|
+
if (fs2.existsSync(indexPath)) {
|
|
1114
1355
|
resolvedPath = indexPath;
|
|
1115
1356
|
found = true;
|
|
1116
1357
|
break;
|
|
@@ -2494,11 +2735,214 @@ function generateExamplesPage() {
|
|
|
2494
2735
|
` + footer;
|
|
2495
2736
|
}
|
|
2496
2737
|
|
|
2738
|
+
// src/build/css-processor.ts
|
|
2739
|
+
init_esm_shims();
|
|
2740
|
+
import fs4 from "fs";
|
|
2741
|
+
import path6 from "path";
|
|
2742
|
+
|
|
2743
|
+
// src/build/tailwind-setup.ts
|
|
2744
|
+
init_esm_shims();
|
|
2745
|
+
import fs3 from "fs";
|
|
2746
|
+
import path5 from "path";
|
|
2747
|
+
import pc from "picocolors";
|
|
2748
|
+
function checkTailwindSetup(rootDir) {
|
|
2749
|
+
const possibleConfigs = [
|
|
2750
|
+
"tailwind.config.js",
|
|
2751
|
+
"tailwind.config.ts",
|
|
2752
|
+
"tailwind.config.mjs",
|
|
2753
|
+
"tailwind.config.cjs"
|
|
2754
|
+
];
|
|
2755
|
+
let configPath = null;
|
|
2756
|
+
for (const config of possibleConfigs) {
|
|
2757
|
+
const fullPath = path5.join(rootDir, config);
|
|
2758
|
+
if (fs3.existsSync(fullPath)) {
|
|
2759
|
+
configPath = fullPath;
|
|
2760
|
+
break;
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
const globalsPath = path5.join(rootDir, "app", "globals.css");
|
|
2764
|
+
const hasGlobals = fs3.existsSync(globalsPath);
|
|
2765
|
+
return {
|
|
2766
|
+
hasTailwind: !!configPath,
|
|
2767
|
+
configPath,
|
|
2768
|
+
globalsPath: hasGlobals ? globalsPath : null,
|
|
2769
|
+
needsSetup: !configPath || !hasGlobals
|
|
2770
|
+
};
|
|
2771
|
+
}
|
|
2772
|
+
async function setupTailwind(rootDir, options = {}) {
|
|
2773
|
+
const { force = false, silent = false } = options;
|
|
2774
|
+
const config = checkTailwindSetup(rootDir);
|
|
2775
|
+
if (!force && !config.needsSetup) {
|
|
2776
|
+
return;
|
|
2777
|
+
}
|
|
2778
|
+
if (!silent) {
|
|
2779
|
+
console.log(pc.cyan("\n\u{1F3A8} Setting up Tailwind CSS..."));
|
|
2780
|
+
}
|
|
2781
|
+
if (!config.configPath || force) {
|
|
2782
|
+
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
2783
|
+
export default {
|
|
2784
|
+
content: [
|
|
2785
|
+
'./app/**/*.{js,ts,jsx,tsx}',
|
|
2786
|
+
'./components/**/*.{js,ts,jsx,tsx}',
|
|
2787
|
+
],
|
|
2788
|
+
theme: {
|
|
2789
|
+
extend: {},
|
|
2790
|
+
},
|
|
2791
|
+
plugins: [],
|
|
2792
|
+
}
|
|
2793
|
+
`;
|
|
2794
|
+
const configPath = path5.join(rootDir, "tailwind.config.js");
|
|
2795
|
+
fs3.writeFileSync(configPath, tailwindConfig);
|
|
2796
|
+
if (!silent) {
|
|
2797
|
+
console.log(pc.green(" \u2713 Created tailwind.config.js"));
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
const postcssPath = path5.join(rootDir, "postcss.config.js");
|
|
2801
|
+
if (!fs3.existsSync(postcssPath) || force) {
|
|
2802
|
+
const postcssConfig = `export default {
|
|
2803
|
+
plugins: {
|
|
2804
|
+
tailwindcss: {},
|
|
2805
|
+
autoprefixer: {},
|
|
2806
|
+
},
|
|
2807
|
+
}
|
|
2808
|
+
`;
|
|
2809
|
+
fs3.writeFileSync(postcssPath, postcssConfig);
|
|
2810
|
+
if (!silent) {
|
|
2811
|
+
console.log(pc.green(" \u2713 Created postcss.config.js"));
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
const appDir = path5.join(rootDir, "app");
|
|
2815
|
+
if (!fs3.existsSync(appDir)) {
|
|
2816
|
+
fs3.mkdirSync(appDir, { recursive: true });
|
|
2817
|
+
}
|
|
2818
|
+
const globalsPath = path5.join(appDir, "globals.css");
|
|
2819
|
+
if (!fs3.existsSync(globalsPath) || force) {
|
|
2820
|
+
const globalsCss = `@tailwind base;
|
|
2821
|
+
@tailwind components;
|
|
2822
|
+
@tailwind utilities;
|
|
2823
|
+
`;
|
|
2824
|
+
fs3.writeFileSync(globalsPath, globalsCss);
|
|
2825
|
+
if (!silent) {
|
|
2826
|
+
console.log(pc.green(" \u2713 Created app/globals.css"));
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
const layoutPath = path5.join(appDir, "layout.tsx");
|
|
2830
|
+
if (!fs3.existsSync(layoutPath)) {
|
|
2831
|
+
const layoutContent = `import './globals.css'
|
|
2832
|
+
|
|
2833
|
+
export default function RootLayout({
|
|
2834
|
+
children,
|
|
2835
|
+
}: {
|
|
2836
|
+
children: React.ReactNode
|
|
2837
|
+
}) {
|
|
2838
|
+
return (
|
|
2839
|
+
<html lang="en">
|
|
2840
|
+
<body>{children}</body>
|
|
2841
|
+
</html>
|
|
2842
|
+
)
|
|
2843
|
+
}
|
|
2844
|
+
`;
|
|
2845
|
+
fs3.writeFileSync(layoutPath, layoutContent);
|
|
2846
|
+
if (!silent) {
|
|
2847
|
+
console.log(pc.green(" \u2713 Created app/layout.tsx"));
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
if (!silent) {
|
|
2851
|
+
console.log(pc.green("\n\u2728 Tailwind CSS ready!\n"));
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
function checkTailwindDeps(rootDir) {
|
|
2855
|
+
const packageJsonPath = path5.join(rootDir, "package.json");
|
|
2856
|
+
if (!fs3.existsSync(packageJsonPath)) {
|
|
2857
|
+
return {
|
|
2858
|
+
hasPackageJson: false,
|
|
2859
|
+
hasTailwind: false,
|
|
2860
|
+
hasPostCSS: false,
|
|
2861
|
+
hasAutoprefixer: false
|
|
2862
|
+
};
|
|
2863
|
+
}
|
|
2864
|
+
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
2865
|
+
const allDeps = {
|
|
2866
|
+
...packageJson.dependencies,
|
|
2867
|
+
...packageJson.devDependencies
|
|
2868
|
+
};
|
|
2869
|
+
return {
|
|
2870
|
+
hasPackageJson: true,
|
|
2871
|
+
hasTailwind: !!allDeps["tailwindcss"],
|
|
2872
|
+
hasPostCSS: !!allDeps["postcss"],
|
|
2873
|
+
hasAutoprefixer: !!allDeps["autoprefixer"]
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2876
|
+
function getTailwindInstallCommand(rootDir) {
|
|
2877
|
+
const deps = checkTailwindDeps(rootDir);
|
|
2878
|
+
if (!deps.hasPackageJson) {
|
|
2879
|
+
return null;
|
|
2880
|
+
}
|
|
2881
|
+
const missing = [];
|
|
2882
|
+
if (!deps.hasTailwind) missing.push("tailwindcss");
|
|
2883
|
+
if (!deps.hasPostCSS) missing.push("postcss");
|
|
2884
|
+
if (!deps.hasAutoprefixer) missing.push("autoprefixer");
|
|
2885
|
+
if (missing.length === 0) {
|
|
2886
|
+
return null;
|
|
2887
|
+
}
|
|
2888
|
+
const hasYarnLock = fs3.existsSync(path5.join(rootDir, "yarn.lock"));
|
|
2889
|
+
const hasPnpmLock = fs3.existsSync(path5.join(rootDir, "pnpm-lock.yaml"));
|
|
2890
|
+
const hasBunLock = fs3.existsSync(path5.join(rootDir, "bun.lockb"));
|
|
2891
|
+
let pm = "npm install -D";
|
|
2892
|
+
if (hasBunLock) pm = "bun add -d";
|
|
2893
|
+
else if (hasPnpmLock) pm = "pnpm add -D";
|
|
2894
|
+
else if (hasYarnLock) pm = "yarn add -D";
|
|
2895
|
+
return `${pm} ${missing.join(" ")}`;
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
// src/build/css-processor.ts
|
|
2899
|
+
async function processCSS(filePath, rootDir = process.cwd()) {
|
|
2900
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
2901
|
+
const tailwindConfig = checkTailwindSetup(rootDir);
|
|
2902
|
+
if (!tailwindConfig.hasTailwind) {
|
|
2903
|
+
return { code: content };
|
|
2904
|
+
}
|
|
2905
|
+
try {
|
|
2906
|
+
const postcss = await import("postcss").then((m) => m.default);
|
|
2907
|
+
const tailwindcss = await import("tailwindcss").then((m) => m.default);
|
|
2908
|
+
const autoprefixer = await import("autoprefixer").then((m) => m.default);
|
|
2909
|
+
const configPath = tailwindConfig.configPath || path6.join(rootDir, "tailwind.config.js");
|
|
2910
|
+
let tailwindConfigModule = {};
|
|
2911
|
+
if (fs4.existsSync(configPath)) {
|
|
2912
|
+
const configUrl = new URL(`file://${configPath}`);
|
|
2913
|
+
tailwindConfigModule = await import(configUrl.href).then((m) => m.default || m);
|
|
2914
|
+
}
|
|
2915
|
+
const result = await postcss([
|
|
2916
|
+
tailwindcss(tailwindConfigModule),
|
|
2917
|
+
autoprefixer()
|
|
2918
|
+
]).process(content, {
|
|
2919
|
+
from: filePath,
|
|
2920
|
+
to: filePath,
|
|
2921
|
+
map: { inline: false }
|
|
2922
|
+
});
|
|
2923
|
+
return {
|
|
2924
|
+
code: result.css,
|
|
2925
|
+
map: result.map?.toString()
|
|
2926
|
+
};
|
|
2927
|
+
} catch (error) {
|
|
2928
|
+
console.warn("CSS processing failed, serving raw CSS:", error);
|
|
2929
|
+
return { code: content };
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
function needsCSSProcessing(filePath, rootDir) {
|
|
2933
|
+
const config = checkTailwindSetup(rootDir);
|
|
2934
|
+
if (!config.hasTailwind) {
|
|
2935
|
+
return false;
|
|
2936
|
+
}
|
|
2937
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
2938
|
+
return content.includes("@tailwind") || content.includes("@apply");
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2497
2941
|
// src/server/dev-server.ts
|
|
2498
2942
|
async function createDevServer(options) {
|
|
2499
2943
|
const { port, host, open } = options;
|
|
2500
2944
|
const rootDir = process.cwd();
|
|
2501
|
-
const publicDir =
|
|
2945
|
+
const publicDir = path7.join(rootDir, "public");
|
|
2502
2946
|
let routes = [];
|
|
2503
2947
|
let server = null;
|
|
2504
2948
|
let wss = null;
|
|
@@ -2506,9 +2950,20 @@ async function createDevServer(options) {
|
|
|
2506
2950
|
async function refreshRoutes() {
|
|
2507
2951
|
try {
|
|
2508
2952
|
routes = await scanRoutes(rootDir);
|
|
2509
|
-
console.log(
|
|
2953
|
+
console.log(pc2.dim(` \u{1F4C1} Found ${routes.length} routes`));
|
|
2954
|
+
const tailwindConfig = checkTailwindSetup(rootDir);
|
|
2955
|
+
if (tailwindConfig.needsSetup) {
|
|
2956
|
+
console.log(pc2.yellow(" \u26A0\uFE0F Tailwind not configured"));
|
|
2957
|
+
const installCmd = getTailwindInstallCommand(rootDir);
|
|
2958
|
+
if (installCmd) {
|
|
2959
|
+
console.log(pc2.dim(` \u{1F4A1} Run: ${installCmd}`));
|
|
2960
|
+
console.log(pc2.dim(` \u{1F4A1} Then: npx float dev`));
|
|
2961
|
+
} else {
|
|
2962
|
+
await setupTailwind(rootDir);
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2510
2965
|
} catch (error) {
|
|
2511
|
-
console.error(
|
|
2966
|
+
console.error(pc2.red("Failed to scan routes:"), error);
|
|
2512
2967
|
}
|
|
2513
2968
|
}
|
|
2514
2969
|
function notifyClients(type, data) {
|
|
@@ -2569,16 +3024,46 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2569
3024
|
async function handleRequest(req, res) {
|
|
2570
3025
|
const url = new URL(req.url || "/", `http://${host}:${port}`);
|
|
2571
3026
|
const pathname = url.pathname;
|
|
2572
|
-
console.log(
|
|
3027
|
+
console.log(pc2.dim(` ${req.method} ${pathname}`));
|
|
2573
3028
|
try {
|
|
2574
|
-
const publicFilePath =
|
|
2575
|
-
if (
|
|
2576
|
-
const content =
|
|
3029
|
+
const publicFilePath = path7.join(publicDir, pathname);
|
|
3030
|
+
if (fs5.existsSync(publicFilePath) && fs5.statSync(publicFilePath).isFile()) {
|
|
3031
|
+
const content = fs5.readFileSync(publicFilePath);
|
|
2577
3032
|
const contentType = mime.lookup(publicFilePath) || "application/octet-stream";
|
|
2578
3033
|
res.writeHead(200, { "Content-Type": contentType });
|
|
2579
3034
|
res.end(content);
|
|
2580
3035
|
return;
|
|
2581
3036
|
}
|
|
3037
|
+
if (pathname.endsWith(".css")) {
|
|
3038
|
+
const cssPath = path7.join(rootDir, "app", pathname.replace(/^\//, ""));
|
|
3039
|
+
if (fs5.existsSync(cssPath)) {
|
|
3040
|
+
try {
|
|
3041
|
+
const needsProcessing = needsCSSProcessing(cssPath, rootDir);
|
|
3042
|
+
if (needsProcessing) {
|
|
3043
|
+
const result = await processCSS(cssPath, rootDir);
|
|
3044
|
+
res.writeHead(200, {
|
|
3045
|
+
"Content-Type": "text/css",
|
|
3046
|
+
"Cache-Control": "no-cache"
|
|
3047
|
+
});
|
|
3048
|
+
res.end(result.code);
|
|
3049
|
+
} else {
|
|
3050
|
+
const content = fs5.readFileSync(cssPath, "utf-8");
|
|
3051
|
+
res.writeHead(200, {
|
|
3052
|
+
"Content-Type": "text/css",
|
|
3053
|
+
"Cache-Control": "no-cache"
|
|
3054
|
+
});
|
|
3055
|
+
res.end(content);
|
|
3056
|
+
}
|
|
3057
|
+
return;
|
|
3058
|
+
} catch (error) {
|
|
3059
|
+
console.error(pc2.red("CSS processing error:"), error);
|
|
3060
|
+
const content = fs5.readFileSync(cssPath, "utf-8");
|
|
3061
|
+
res.writeHead(200, { "Content-Type": "text/css" });
|
|
3062
|
+
res.end(content);
|
|
3063
|
+
return;
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
2582
3067
|
if (pathname.startsWith("/_float/")) {
|
|
2583
3068
|
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
2584
3069
|
res.end("// Float.js internal asset");
|
|
@@ -2643,7 +3128,7 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2643
3128
|
});
|
|
2644
3129
|
res.end(html);
|
|
2645
3130
|
} catch (error) {
|
|
2646
|
-
console.error(
|
|
3131
|
+
console.error(pc2.red("Request error:"), error);
|
|
2647
3132
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
2648
3133
|
res.end(createErrorPage(error));
|
|
2649
3134
|
}
|
|
@@ -2672,7 +3157,7 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2672
3157
|
const responseBody = await response.text();
|
|
2673
3158
|
res.end(responseBody);
|
|
2674
3159
|
} catch (error) {
|
|
2675
|
-
console.error(
|
|
3160
|
+
console.error(pc2.red("API route error:"), error);
|
|
2676
3161
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2677
3162
|
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
2678
3163
|
}
|
|
@@ -2687,9 +3172,9 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2687
3172
|
});
|
|
2688
3173
|
const watcher = chokidar.watch(
|
|
2689
3174
|
[
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
3175
|
+
path7.join(rootDir, "app/**/*.{ts,tsx,js,jsx}"),
|
|
3176
|
+
path7.join(rootDir, "components/**/*.{ts,tsx,js,jsx}"),
|
|
3177
|
+
path7.join(rootDir, "lib/**/*.{ts,tsx,js,jsx}")
|
|
2693
3178
|
],
|
|
2694
3179
|
{
|
|
2695
3180
|
ignored: /node_modules/,
|
|
@@ -2697,8 +3182,8 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2697
3182
|
}
|
|
2698
3183
|
);
|
|
2699
3184
|
watcher.on("change", async (filePath) => {
|
|
2700
|
-
console.log(
|
|
2701
|
-
\u26A1 File changed: ${
|
|
3185
|
+
console.log(pc2.yellow(`
|
|
3186
|
+
\u26A1 File changed: ${path7.relative(rootDir, filePath)}`));
|
|
2702
3187
|
if (filePath.includes("/app/")) {
|
|
2703
3188
|
await refreshRoutes();
|
|
2704
3189
|
}
|
|
@@ -2706,31 +3191,31 @@ ${FLOAT_ERROR_OVERLAY}
|
|
|
2706
3191
|
});
|
|
2707
3192
|
watcher.on("add", async (filePath) => {
|
|
2708
3193
|
if (filePath.includes("/app/")) {
|
|
2709
|
-
console.log(
|
|
2710
|
-
\u2795 File added: ${
|
|
3194
|
+
console.log(pc2.green(`
|
|
3195
|
+
\u2795 File added: ${path7.relative(rootDir, filePath)}`));
|
|
2711
3196
|
await refreshRoutes();
|
|
2712
3197
|
notifyClients("reload");
|
|
2713
3198
|
}
|
|
2714
3199
|
});
|
|
2715
3200
|
watcher.on("unlink", async (filePath) => {
|
|
2716
3201
|
if (filePath.includes("/app/")) {
|
|
2717
|
-
console.log(
|
|
2718
|
-
\u2796 File removed: ${
|
|
3202
|
+
console.log(pc2.red(`
|
|
3203
|
+
\u2796 File removed: ${path7.relative(rootDir, filePath)}`));
|
|
2719
3204
|
await refreshRoutes();
|
|
2720
3205
|
notifyClients("reload");
|
|
2721
3206
|
}
|
|
2722
3207
|
});
|
|
2723
3208
|
return new Promise((resolve, reject) => {
|
|
2724
3209
|
server.listen(port, host, () => {
|
|
2725
|
-
console.log(
|
|
2726
|
-
console.log(
|
|
3210
|
+
console.log(pc2.green(` \u2705 Server running at ${pc2.cyan(`http://${host}:${port}`)}`));
|
|
3211
|
+
console.log(pc2.dim(` \u26A1 HMR enabled on ws://${host}:${port + 1}
|
|
2727
3212
|
`));
|
|
2728
|
-
console.log(
|
|
3213
|
+
console.log(pc2.bold(" Routes:"));
|
|
2729
3214
|
routes.forEach((route) => {
|
|
2730
3215
|
if (route.type === "page") {
|
|
2731
|
-
console.log(
|
|
3216
|
+
console.log(pc2.dim(` ${pc2.green("\u25CF")} ${route.path}`));
|
|
2732
3217
|
} else if (route.type === "api") {
|
|
2733
|
-
console.log(
|
|
3218
|
+
console.log(pc2.dim(` ${pc2.blue("\u25C6")} ${route.path} (API)`));
|
|
2734
3219
|
}
|
|
2735
3220
|
});
|
|
2736
3221
|
console.log("");
|
|
@@ -2850,45 +3335,45 @@ function escapeHtml2(text) {
|
|
|
2850
3335
|
// src/server/prod-server.ts
|
|
2851
3336
|
init_esm_shims();
|
|
2852
3337
|
import http2 from "http";
|
|
2853
|
-
import
|
|
2854
|
-
import
|
|
2855
|
-
import
|
|
3338
|
+
import fs6 from "fs";
|
|
3339
|
+
import path8 from "path";
|
|
3340
|
+
import pc3 from "picocolors";
|
|
2856
3341
|
import mime2 from "mime-types";
|
|
2857
3342
|
var cachedRoutes = [];
|
|
2858
3343
|
var pageCache = /* @__PURE__ */ new Map();
|
|
2859
3344
|
async function startProductionServer(options) {
|
|
2860
3345
|
const { port, host } = options;
|
|
2861
3346
|
const rootDir = process.cwd();
|
|
2862
|
-
const distDir =
|
|
2863
|
-
const publicDir =
|
|
2864
|
-
const manifestPath =
|
|
2865
|
-
if (
|
|
2866
|
-
const manifest = JSON.parse(
|
|
3347
|
+
const distDir = path8.join(rootDir, ".float");
|
|
3348
|
+
const publicDir = path8.join(rootDir, "public");
|
|
3349
|
+
const manifestPath = path8.join(distDir, "routes-manifest.json");
|
|
3350
|
+
if (fs6.existsSync(manifestPath)) {
|
|
3351
|
+
const manifest = JSON.parse(fs6.readFileSync(manifestPath, "utf-8"));
|
|
2867
3352
|
cachedRoutes = manifest.routes;
|
|
2868
|
-
console.log(
|
|
3353
|
+
console.log(pc3.dim(` \u{1F4E6} Loaded ${cachedRoutes.length} routes from manifest`));
|
|
2869
3354
|
} else {
|
|
2870
|
-
console.error(
|
|
3355
|
+
console.error(pc3.red(" \u274C No build manifest found. Run `float build` first."));
|
|
2871
3356
|
process.exit(1);
|
|
2872
3357
|
}
|
|
2873
|
-
const pagesDir =
|
|
2874
|
-
if (
|
|
2875
|
-
const prerenderedFiles =
|
|
3358
|
+
const pagesDir = path8.join(distDir, "pages");
|
|
3359
|
+
if (fs6.existsSync(pagesDir)) {
|
|
3360
|
+
const prerenderedFiles = fs6.readdirSync(pagesDir, { recursive: true });
|
|
2876
3361
|
for (const file of prerenderedFiles) {
|
|
2877
3362
|
if (file.endsWith(".html")) {
|
|
2878
3363
|
const routePath = "/" + file.replace(/\.html$/, "").replace(/index$/, "");
|
|
2879
|
-
const content =
|
|
3364
|
+
const content = fs6.readFileSync(path8.join(pagesDir, file), "utf-8");
|
|
2880
3365
|
pageCache.set(routePath, content);
|
|
2881
3366
|
}
|
|
2882
3367
|
}
|
|
2883
|
-
console.log(
|
|
3368
|
+
console.log(pc3.dim(` \u{1F4C4} Loaded ${pageCache.size} pre-rendered pages`));
|
|
2884
3369
|
}
|
|
2885
3370
|
const server = http2.createServer(async (req, res) => {
|
|
2886
3371
|
const url = new URL(req.url || "/", `http://${host}:${port}`);
|
|
2887
3372
|
const pathname = url.pathname;
|
|
2888
3373
|
try {
|
|
2889
|
-
const staticPath =
|
|
2890
|
-
if (
|
|
2891
|
-
const content =
|
|
3374
|
+
const staticPath = path8.join(distDir, "static", pathname);
|
|
3375
|
+
if (fs6.existsSync(staticPath) && fs6.statSync(staticPath).isFile()) {
|
|
3376
|
+
const content = fs6.readFileSync(staticPath);
|
|
2892
3377
|
const contentType = mime2.lookup(staticPath) || "application/octet-stream";
|
|
2893
3378
|
res.writeHead(200, {
|
|
2894
3379
|
"Content-Type": contentType,
|
|
@@ -2897,9 +3382,9 @@ async function startProductionServer(options) {
|
|
|
2897
3382
|
res.end(content);
|
|
2898
3383
|
return;
|
|
2899
3384
|
}
|
|
2900
|
-
const publicFilePath =
|
|
2901
|
-
if (
|
|
2902
|
-
const content =
|
|
3385
|
+
const publicFilePath = path8.join(publicDir, pathname);
|
|
3386
|
+
if (fs6.existsSync(publicFilePath) && fs6.statSync(publicFilePath).isFile()) {
|
|
3387
|
+
const content = fs6.readFileSync(publicFilePath);
|
|
2903
3388
|
const contentType = mime2.lookup(publicFilePath) || "application/octet-stream";
|
|
2904
3389
|
res.writeHead(200, { "Content-Type": contentType });
|
|
2905
3390
|
res.end(content);
|
|
@@ -2932,13 +3417,13 @@ async function startProductionServer(options) {
|
|
|
2932
3417
|
});
|
|
2933
3418
|
res.end(html);
|
|
2934
3419
|
} catch (error) {
|
|
2935
|
-
console.error(
|
|
3420
|
+
console.error(pc3.red("Request error:"), error);
|
|
2936
3421
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
2937
3422
|
res.end("<h1>500 - Internal Server Error</h1>");
|
|
2938
3423
|
}
|
|
2939
3424
|
});
|
|
2940
3425
|
server.listen(port, host, () => {
|
|
2941
|
-
console.log(
|
|
3426
|
+
console.log(pc3.green(` \u2705 Production server running at ${pc3.cyan(`http://${host}:${port}`)}
|
|
2942
3427
|
`));
|
|
2943
3428
|
});
|
|
2944
3429
|
}
|