elegance-js 2.1.6 → 2.1.9
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/build.d.ts +2 -0
- package/dist/build.mjs +1726 -46
- package/dist/compile_docs.mjs +1731 -53
- package/dist/global.d.ts +4 -1
- package/dist/page_compiler.d.ts +1 -3
- package/dist/page_compiler.mjs +42 -464
- package/dist/server/server.d.ts +2 -1
- package/dist/server/server.mjs +1264 -1110
- package/package.json +1 -1
package/dist/page_compiler.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/page_compiler.ts
|
|
2
|
-
import
|
|
2
|
+
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { registerLoader, setArcTsConfig } from "ts-arc";
|
|
5
5
|
import esbuild from "esbuild";
|
|
6
|
-
import { fileURLToPath
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
8
|
// src/shared/serverElements.ts
|
|
9
9
|
var createBuildableElement = (tag) => {
|
|
@@ -248,416 +248,6 @@ var generateHTMLTemplate = async ({
|
|
|
248
248
|
};
|
|
249
249
|
};
|
|
250
250
|
|
|
251
|
-
// src/server/server.ts
|
|
252
|
-
import { createServer as createHttpServer } from "http";
|
|
253
|
-
import { promises as fs } from "fs";
|
|
254
|
-
import { join, normalize, extname, dirname } from "path";
|
|
255
|
-
import { pathToFileURL } from "url";
|
|
256
|
-
|
|
257
|
-
// src/log.ts
|
|
258
|
-
var quiet = false;
|
|
259
|
-
function getTimestamp() {
|
|
260
|
-
const now = /* @__PURE__ */ new Date();
|
|
261
|
-
return now.toLocaleString(void 0, {
|
|
262
|
-
year: "2-digit",
|
|
263
|
-
month: "2-digit",
|
|
264
|
-
day: "2-digit",
|
|
265
|
-
hour: "2-digit",
|
|
266
|
-
minute: "2-digit",
|
|
267
|
-
second: "2-digit"
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
function color(text, code) {
|
|
271
|
-
return `\x1B[${code}m${text}\x1B[0m`;
|
|
272
|
-
}
|
|
273
|
-
function logInfo(...args) {
|
|
274
|
-
if (quiet) return;
|
|
275
|
-
console.info(`Elegance.JS: ${getTimestamp()} ${color("[INFO]:", 34)}`, ...args);
|
|
276
|
-
}
|
|
277
|
-
function logWarn(...args) {
|
|
278
|
-
if (quiet) return;
|
|
279
|
-
console.warn(`Elegance.JS: ${getTimestamp()} ${color("[WARN]:", 33)}`, ...args);
|
|
280
|
-
}
|
|
281
|
-
function logError(...args) {
|
|
282
|
-
console.error(`Elegance.JS: ${getTimestamp()} ${color("[ERROR]:", 31)}`, ...args);
|
|
283
|
-
}
|
|
284
|
-
var log = {
|
|
285
|
-
info: logInfo,
|
|
286
|
-
warn: logWarn,
|
|
287
|
-
error: logError
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
// src/server/server.ts
|
|
291
|
-
import { gzip, deflate } from "zlib";
|
|
292
|
-
import { promisify } from "util";
|
|
293
|
-
var gzipAsync = promisify(gzip);
|
|
294
|
-
var deflateAsync = promisify(deflate);
|
|
295
|
-
var MIME_TYPES = {
|
|
296
|
-
".html": "text/html; charset=utf-8",
|
|
297
|
-
".css": "text/css; charset=utf-8",
|
|
298
|
-
".js": "application/javascript; charset=utf-8",
|
|
299
|
-
".json": "application/json; charset=utf-8",
|
|
300
|
-
".png": "image/png",
|
|
301
|
-
".jpg": "image/jpeg",
|
|
302
|
-
".jpeg": "image/jpeg",
|
|
303
|
-
".gif": "image/gif",
|
|
304
|
-
".svg": "image/svg+xml",
|
|
305
|
-
".ico": "image/x-icon",
|
|
306
|
-
".txt": "text/plain; charset=utf-8"
|
|
307
|
-
};
|
|
308
|
-
function startServer({
|
|
309
|
-
root,
|
|
310
|
-
port = 3e3,
|
|
311
|
-
host = "localhost",
|
|
312
|
-
environment = "production",
|
|
313
|
-
DIST_DIR: DIST_DIR2
|
|
314
|
-
}) {
|
|
315
|
-
if (!root) throw new Error("Root directory must be specified.");
|
|
316
|
-
root = normalize(root).replace(/[\\/]+$/, "");
|
|
317
|
-
const requestHandler = async (req, res) => {
|
|
318
|
-
try {
|
|
319
|
-
if (!req.url) {
|
|
320
|
-
await sendResponse(req, res, 400, { "Content-Type": "text/plain; charset=utf-8" }, "Bad Request");
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
324
|
-
res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
|
|
325
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
326
|
-
if (req.method === "OPTIONS") {
|
|
327
|
-
res.writeHead(204);
|
|
328
|
-
res.end();
|
|
329
|
-
if (environment === "development") {
|
|
330
|
-
log.info(req.method, "::", req.url, "-", res.statusCode);
|
|
331
|
-
}
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
335
|
-
if (url.pathname.startsWith("/api/")) {
|
|
336
|
-
await handleApiRequest(root, url.pathname, req, res);
|
|
337
|
-
} else if (PAGE_MAP.has(url.pathname)) {
|
|
338
|
-
await handlePageRequest(root, url.pathname, req, res, DIST_DIR2, PAGE_MAP.get(url.pathname));
|
|
339
|
-
} else {
|
|
340
|
-
await handleStaticRequest(root, url.pathname, req, res, DIST_DIR2);
|
|
341
|
-
}
|
|
342
|
-
if (environment === "development") {
|
|
343
|
-
log.info(req.method, "::", req.url, "-", res.statusCode);
|
|
344
|
-
}
|
|
345
|
-
} catch (err) {
|
|
346
|
-
log.error(err);
|
|
347
|
-
await sendResponse(req, res, 500, { "Content-Type": "text/plain; charset=utf-8" }, "Internal Server Error");
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
function attemptListen(p) {
|
|
351
|
-
const server = createHttpServer(requestHandler);
|
|
352
|
-
server.on("error", (err) => {
|
|
353
|
-
if (err.code === "EADDRINUSE") {
|
|
354
|
-
attemptListen(p + 1);
|
|
355
|
-
} else {
|
|
356
|
-
console.error(err);
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
server.listen(p, host, () => {
|
|
360
|
-
log.info(`Server running at http://${host}:${p}/`);
|
|
361
|
-
});
|
|
362
|
-
return server;
|
|
363
|
-
}
|
|
364
|
-
return attemptListen(port);
|
|
365
|
-
}
|
|
366
|
-
async function getTargetInfo(root, pathname) {
|
|
367
|
-
const originalPathname = pathname;
|
|
368
|
-
const filePath = normalize(join(root, decodeURIComponent(pathname))).replace(/[\\/]+$/, "");
|
|
369
|
-
if (!filePath.startsWith(root)) {
|
|
370
|
-
throw new Error("Forbidden");
|
|
371
|
-
}
|
|
372
|
-
let stats;
|
|
373
|
-
try {
|
|
374
|
-
stats = await fs.stat(filePath);
|
|
375
|
-
} catch {
|
|
376
|
-
}
|
|
377
|
-
let targetDir;
|
|
378
|
-
if (stats) {
|
|
379
|
-
targetDir = stats.isDirectory() ? filePath : dirname(filePath);
|
|
380
|
-
} else {
|
|
381
|
-
targetDir = originalPathname.endsWith("/") ? filePath : dirname(filePath);
|
|
382
|
-
}
|
|
383
|
-
return { filePath, targetDir, stats };
|
|
384
|
-
}
|
|
385
|
-
function getMiddlewareDirs(base, parts) {
|
|
386
|
-
const middlewareDirs = [];
|
|
387
|
-
let current = base;
|
|
388
|
-
middlewareDirs.push(current);
|
|
389
|
-
for (const part of parts) {
|
|
390
|
-
current = join(current, part);
|
|
391
|
-
middlewareDirs.push(current);
|
|
392
|
-
}
|
|
393
|
-
return middlewareDirs;
|
|
394
|
-
}
|
|
395
|
-
async function collectMiddlewares(dirs) {
|
|
396
|
-
const middlewares = [];
|
|
397
|
-
for (const dir of dirs) {
|
|
398
|
-
const mwPath = join(dir, "middleware.mjs");
|
|
399
|
-
let mwModule;
|
|
400
|
-
try {
|
|
401
|
-
await fs.access(mwPath);
|
|
402
|
-
const url = pathToFileURL(mwPath).href;
|
|
403
|
-
mwModule = await import(url);
|
|
404
|
-
} catch {
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
const mwKeys = Object.keys(mwModule).sort();
|
|
408
|
-
for (const key of mwKeys) {
|
|
409
|
-
const f = mwModule[key];
|
|
410
|
-
if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
|
|
411
|
-
middlewares.push(f);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
return middlewares;
|
|
416
|
-
}
|
|
417
|
-
async function handlePageRequest(root, pathname, req, res, DIST_DIR2, pageInfo) {
|
|
418
|
-
try {
|
|
419
|
-
const { filePath, targetDir, stats } = await getTargetInfo(root, pathname);
|
|
420
|
-
const relDir = targetDir.slice(root.length).replace(/^[\/\\]+/, "");
|
|
421
|
-
const parts = relDir.split(/[\\/]/).filter(Boolean);
|
|
422
|
-
const middlewareDirs = getMiddlewareDirs(root, parts);
|
|
423
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
424
|
-
let isDynamic = pageInfo.isDynamic;
|
|
425
|
-
const handlerPath = isDynamic ? pageInfo.filePath : join(filePath, "index.html");
|
|
426
|
-
let hasHandler = false;
|
|
427
|
-
try {
|
|
428
|
-
await fs.access(handlerPath);
|
|
429
|
-
hasHandler = true;
|
|
430
|
-
} catch {
|
|
431
|
-
}
|
|
432
|
-
const finalHandler = async (req2, res2) => {
|
|
433
|
-
if (!hasHandler) {
|
|
434
|
-
await respondWithErrorPage(root, pathname, 404, req2, res2);
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
if (isDynamic) {
|
|
438
|
-
try {
|
|
439
|
-
const result = await buildDynamicPage(
|
|
440
|
-
DIST_DIR2,
|
|
441
|
-
pathname,
|
|
442
|
-
pageInfo,
|
|
443
|
-
req2,
|
|
444
|
-
res2
|
|
445
|
-
);
|
|
446
|
-
if (result === false) {
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
const { resultHTML } = result;
|
|
450
|
-
if (resultHTML === false) {
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
await sendResponse(req2, res2, 200, { "Content-Type": MIME_TYPES[".html"] }, resultHTML);
|
|
454
|
-
} catch (err) {
|
|
455
|
-
log.error("Error building dynamic page -", err);
|
|
456
|
-
}
|
|
457
|
-
} else {
|
|
458
|
-
const ext = extname(handlerPath).toLowerCase();
|
|
459
|
-
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
460
|
-
const data = await fs.readFile(handlerPath);
|
|
461
|
-
await sendResponse(req2, res2, 200, { "Content-Type": contentType }, data);
|
|
462
|
-
}
|
|
463
|
-
};
|
|
464
|
-
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: false, root, pathname });
|
|
465
|
-
await composed(req, res);
|
|
466
|
-
} catch (err) {
|
|
467
|
-
if (err.message === "Forbidden") {
|
|
468
|
-
await sendResponse(req, res, 403, { "Content-Type": "text/plain; charset=utf-8" }, "Forbidden");
|
|
469
|
-
} else {
|
|
470
|
-
throw err;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
async function handleStaticRequest(root, pathname, req, res, DIST_DIR2) {
|
|
475
|
-
try {
|
|
476
|
-
const { filePath, targetDir, stats } = await getTargetInfo(root, pathname);
|
|
477
|
-
const relDir = targetDir.slice(root.length).replace(/^[\/\\]+/, "");
|
|
478
|
-
const parts = relDir.split(/[\\/]/).filter(Boolean);
|
|
479
|
-
const middlewareDirs = getMiddlewareDirs(root, parts);
|
|
480
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
481
|
-
let handlerPath = filePath;
|
|
482
|
-
if (stats && stats.isDirectory()) {
|
|
483
|
-
handlerPath = join(filePath, "index.html");
|
|
484
|
-
} else {
|
|
485
|
-
handlerPath = filePath;
|
|
486
|
-
}
|
|
487
|
-
let hasHandler = false;
|
|
488
|
-
try {
|
|
489
|
-
await fs.access(handlerPath);
|
|
490
|
-
hasHandler = true;
|
|
491
|
-
} catch {
|
|
492
|
-
}
|
|
493
|
-
const finalHandler = async (req2, res2) => {
|
|
494
|
-
if (!hasHandler) {
|
|
495
|
-
await respondWithErrorPage(root, pathname, 404, req2, res2);
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
|
-
const ext = extname(handlerPath).toLowerCase();
|
|
499
|
-
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
500
|
-
const data = await fs.readFile(handlerPath);
|
|
501
|
-
await sendResponse(req2, res2, 200, { "Content-Type": contentType }, data);
|
|
502
|
-
};
|
|
503
|
-
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: false, root, pathname });
|
|
504
|
-
await composed(req, res);
|
|
505
|
-
} catch (err) {
|
|
506
|
-
if (err.message === "Forbidden") {
|
|
507
|
-
await sendResponse(req, res, 403, { "Content-Type": "text/plain; charset=utf-8" }, "Forbidden");
|
|
508
|
-
} else {
|
|
509
|
-
throw err;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
async function handleApiRequest(root, pathname, req, res) {
|
|
514
|
-
const apiSubPath = pathname.slice("/api/".length);
|
|
515
|
-
const parts = apiSubPath.split("/").filter(Boolean);
|
|
516
|
-
const middlewareDirs = getMiddlewareDirs(join(root, "api"), parts);
|
|
517
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
518
|
-
const routeDir = middlewareDirs[middlewareDirs.length - 1];
|
|
519
|
-
const routePath = join(routeDir, "route.mjs");
|
|
520
|
-
let hasRoute = false;
|
|
521
|
-
try {
|
|
522
|
-
await fs.access(routePath);
|
|
523
|
-
hasRoute = true;
|
|
524
|
-
} catch {
|
|
525
|
-
}
|
|
526
|
-
let fn = null;
|
|
527
|
-
let module = null;
|
|
528
|
-
if (hasRoute) {
|
|
529
|
-
try {
|
|
530
|
-
const moduleUrl = pathToFileURL(routePath).href;
|
|
531
|
-
module = await import(moduleUrl);
|
|
532
|
-
fn = module[req.method];
|
|
533
|
-
} catch (err) {
|
|
534
|
-
console.error(err);
|
|
535
|
-
return respondWithJsonError(req, res, 500, "Internal Server Error");
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
const finalHandler = async (req2, res2) => {
|
|
539
|
-
if (!hasRoute) {
|
|
540
|
-
return respondWithJsonError(req2, res2, 404, "Not Found");
|
|
541
|
-
}
|
|
542
|
-
if (typeof fn !== "function") {
|
|
543
|
-
return respondWithJsonError(req2, res2, 405, "Method Not Allowed");
|
|
544
|
-
}
|
|
545
|
-
await fn(req2, res2);
|
|
546
|
-
};
|
|
547
|
-
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: true });
|
|
548
|
-
await composed(req, res);
|
|
549
|
-
}
|
|
550
|
-
function composeMiddlewares(mws, final, options2) {
|
|
551
|
-
return async function(req, res) {
|
|
552
|
-
let index = 0;
|
|
553
|
-
async function dispatch(err) {
|
|
554
|
-
if (err) {
|
|
555
|
-
if (options2.isApi) {
|
|
556
|
-
return respondWithJsonError(req, res, 500, err.message || "Internal Server Error");
|
|
557
|
-
} else {
|
|
558
|
-
return await respondWithErrorPage(options2.root, options2.pathname, 500, req, res);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
if (index >= mws.length) {
|
|
562
|
-
return await final(req, res);
|
|
563
|
-
}
|
|
564
|
-
const thisMw = mws[index++];
|
|
565
|
-
const next = (e) => dispatch(e);
|
|
566
|
-
const onceNext = (nextFn) => {
|
|
567
|
-
let called = false;
|
|
568
|
-
return async (e) => {
|
|
569
|
-
if (called) {
|
|
570
|
-
log.warn("next() was called in a middleware more than once.");
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
called = true;
|
|
574
|
-
await nextFn(e);
|
|
575
|
-
};
|
|
576
|
-
};
|
|
577
|
-
try {
|
|
578
|
-
await thisMw(req, res, onceNext(next));
|
|
579
|
-
} catch (error) {
|
|
580
|
-
await dispatch(error);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
await dispatch();
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
async function respondWithJsonError(req, res, code, message) {
|
|
587
|
-
const body2 = JSON.stringify({ error: message });
|
|
588
|
-
await sendResponse(req, res, code, { "Content-Type": "application/json; charset=utf-8" }, body2);
|
|
589
|
-
}
|
|
590
|
-
async function respondWithErrorPage(root, pathname, code, req, res) {
|
|
591
|
-
let currentPath = normalize(join(root, decodeURIComponent(pathname)));
|
|
592
|
-
let tried = /* @__PURE__ */ new Set();
|
|
593
|
-
let errorFilePath = null;
|
|
594
|
-
while (currentPath.startsWith(root)) {
|
|
595
|
-
const candidate = join(currentPath, `${code}.html`);
|
|
596
|
-
if (!tried.has(candidate)) {
|
|
597
|
-
try {
|
|
598
|
-
await fs.access(candidate);
|
|
599
|
-
errorFilePath = candidate;
|
|
600
|
-
break;
|
|
601
|
-
} catch {
|
|
602
|
-
}
|
|
603
|
-
tried.add(candidate);
|
|
604
|
-
}
|
|
605
|
-
const parent = dirname(currentPath);
|
|
606
|
-
if (parent === currentPath) break;
|
|
607
|
-
currentPath = parent;
|
|
608
|
-
}
|
|
609
|
-
if (!errorFilePath) {
|
|
610
|
-
const fallback = join(root, `${code}.html`);
|
|
611
|
-
try {
|
|
612
|
-
await fs.access(fallback);
|
|
613
|
-
errorFilePath = fallback;
|
|
614
|
-
} catch {
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
if (errorFilePath) {
|
|
618
|
-
try {
|
|
619
|
-
const html2 = await fs.readFile(errorFilePath, "utf8");
|
|
620
|
-
await sendResponse(req, res, code, { "Content-Type": "text/html; charset=utf-8" }, html2);
|
|
621
|
-
return;
|
|
622
|
-
} catch {
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
await sendResponse(req, res, code, { "Content-Type": "text/plain; charset=utf-8" }, `${code} Error`);
|
|
626
|
-
}
|
|
627
|
-
function isCompressible(contentType) {
|
|
628
|
-
if (!contentType) return false;
|
|
629
|
-
return /text\/|javascript|json|xml|svg/.test(contentType);
|
|
630
|
-
}
|
|
631
|
-
async function sendResponse(req, res, status, headers, body2) {
|
|
632
|
-
if (typeof body2 === "string") {
|
|
633
|
-
body2 = Buffer.from(body2);
|
|
634
|
-
}
|
|
635
|
-
const accept = req.headers["accept-encoding"] || "";
|
|
636
|
-
let encoding = null;
|
|
637
|
-
if (accept.match(/\bgzip\b/)) {
|
|
638
|
-
encoding = "gzip";
|
|
639
|
-
} else if (accept.match(/\bdeflate\b/)) {
|
|
640
|
-
encoding = "deflate";
|
|
641
|
-
}
|
|
642
|
-
if (!encoding || !isCompressible(headers["Content-Type"] || "")) {
|
|
643
|
-
res.writeHead(status, headers);
|
|
644
|
-
res.end(body2);
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
const compressor = encoding === "gzip" ? gzipAsync : deflateAsync;
|
|
648
|
-
try {
|
|
649
|
-
const compressed = await compressor(body2);
|
|
650
|
-
headers["Content-Encoding"] = encoding;
|
|
651
|
-
headers["Vary"] = "Accept-Encoding";
|
|
652
|
-
res.writeHead(status, headers);
|
|
653
|
-
res.end(compressed);
|
|
654
|
-
} catch (err) {
|
|
655
|
-
log.error("Compression error:", err);
|
|
656
|
-
res.writeHead(status, headers);
|
|
657
|
-
res.end(body2);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
|
|
661
251
|
// src/server/loadHook.ts
|
|
662
252
|
var resetLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__ = [];
|
|
663
253
|
var getLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__;
|
|
@@ -680,7 +270,7 @@ var resetLayouts = () => globalThis.__SERVER_CURRENT_LAYOUTS__ = /* @__PURE__ */
|
|
|
680
270
|
if (!globalThis.__SERVER_CURRENT_LAYOUT_ID__) globalThis.__SERVER_CURRENT_LAYOUT_ID__ = 1;
|
|
681
271
|
|
|
682
272
|
// src/page_compiler.ts
|
|
683
|
-
var __filename =
|
|
273
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
684
274
|
var __dirname = path.dirname(__filename);
|
|
685
275
|
setArcTsConfig(__dirname);
|
|
686
276
|
registerLoader();
|
|
@@ -710,17 +300,18 @@ var underline = (text) => {
|
|
|
710
300
|
var white = (text) => {
|
|
711
301
|
return `\x1B[38;2;255;247;229m${text}`;
|
|
712
302
|
};
|
|
713
|
-
var
|
|
303
|
+
var log = (...text) => {
|
|
714
304
|
if (options.quiet) return;
|
|
715
305
|
return console.log(text.map((text2) => `${text2}\x1B[0m`).join(""));
|
|
716
306
|
};
|
|
717
|
-
var options = JSON.parse(process.env.OPTIONS);
|
|
307
|
+
var options = JSON.parse(process.env.OPTIONS || "{}");
|
|
308
|
+
console.log(options);
|
|
718
309
|
var DIST_DIR = process.env.DIST_DIR;
|
|
719
310
|
var PAGE_MAP = /* @__PURE__ */ new Map();
|
|
720
|
-
var
|
|
311
|
+
var LAYOUT_MAP = /* @__PURE__ */ new Map();
|
|
721
312
|
var getAllSubdirectories = (dir, baseDir = dir) => {
|
|
722
313
|
let directories = [];
|
|
723
|
-
const items =
|
|
314
|
+
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
724
315
|
for (const item of items) {
|
|
725
316
|
if (item.isDirectory()) {
|
|
726
317
|
const fullPath = path.join(dir, item.name);
|
|
@@ -733,10 +324,10 @@ var getAllSubdirectories = (dir, baseDir = dir) => {
|
|
|
733
324
|
};
|
|
734
325
|
var buildClient = async (DIST_DIR2) => {
|
|
735
326
|
let clientString = "window.__name = (func) => func; ";
|
|
736
|
-
clientString +=
|
|
327
|
+
clientString += fs.readFileSync(clientPath, "utf-8");
|
|
737
328
|
if (options.hotReload !== void 0) {
|
|
738
329
|
clientString += `const watchServerPort = ${options.hotReload.port}`;
|
|
739
|
-
clientString +=
|
|
330
|
+
clientString += fs.readFileSync(watcherPath, "utf-8");
|
|
740
331
|
}
|
|
741
332
|
const transformedClient = await esbuild.transform(clientString, {
|
|
742
333
|
minify: options.environment === "production",
|
|
@@ -746,7 +337,7 @@ var buildClient = async (DIST_DIR2) => {
|
|
|
746
337
|
platform: "node",
|
|
747
338
|
loader: "ts"
|
|
748
339
|
});
|
|
749
|
-
|
|
340
|
+
fs.writeFileSync(
|
|
750
341
|
path.join(DIST_DIR2, "/client.js"),
|
|
751
342
|
transformedClient.code
|
|
752
343
|
);
|
|
@@ -985,11 +576,11 @@ var pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageNam
|
|
|
985
576
|
const resultHTML = `${headHTML}${bodyHTML}`;
|
|
986
577
|
const htmlLocation = path.join(pageLocation, (pageName === "page" ? "index" : pageName) + ".html");
|
|
987
578
|
if (doWrite) {
|
|
988
|
-
const
|
|
989
|
-
if (
|
|
990
|
-
|
|
579
|
+
const dirname = path.dirname(htmlLocation);
|
|
580
|
+
if (fs.existsSync(dirname) === false) {
|
|
581
|
+
fs.mkdirSync(dirname, { recursive: true });
|
|
991
582
|
}
|
|
992
|
-
|
|
583
|
+
fs.writeFileSync(
|
|
993
584
|
htmlLocation,
|
|
994
585
|
resultHTML,
|
|
995
586
|
{
|
|
@@ -1060,13 +651,13 @@ var generateClientPageData = async (pageLocation, state, objectAttributes, pageL
|
|
|
1060
651
|
console.error("Failed to transform client page js!", error);
|
|
1061
652
|
});
|
|
1062
653
|
if (!transformedResult) return { sendHardReloadInstruction };
|
|
1063
|
-
if (
|
|
1064
|
-
const content =
|
|
654
|
+
if (fs.existsSync(pageDataPath)) {
|
|
655
|
+
const content = fs.readFileSync(pageDataPath).toString();
|
|
1065
656
|
if (content !== transformedResult.code) {
|
|
1066
657
|
sendHardReloadInstruction = true;
|
|
1067
658
|
}
|
|
1068
659
|
}
|
|
1069
|
-
if (write)
|
|
660
|
+
if (write) fs.writeFileSync(pageDataPath, transformedResult.code, "utf-8");
|
|
1070
661
|
return { sendHardReloadInstruction, result: transformedResult.code };
|
|
1071
662
|
};
|
|
1072
663
|
var generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, generateDynamic = false) => {
|
|
@@ -1096,7 +687,7 @@ var generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, gene
|
|
|
1096
687
|
} catch (e) {
|
|
1097
688
|
throw new Error(`Error in Page: ${directory === "" ? "/" : directory}layout.ts - ${e}`);
|
|
1098
689
|
}
|
|
1099
|
-
|
|
690
|
+
LAYOUT_MAP.set(directory === "" ? "/" : `/${directory}`, {
|
|
1100
691
|
isDynamic: isDynamicLayout,
|
|
1101
692
|
filePath
|
|
1102
693
|
});
|
|
@@ -1157,7 +748,7 @@ var buildLayouts = async () => {
|
|
|
1157
748
|
let shouldClientHardReload = false;
|
|
1158
749
|
for (const directory of subdirectories) {
|
|
1159
750
|
const abs = path.resolve(path.join(pagesDirectory, directory));
|
|
1160
|
-
const files =
|
|
751
|
+
const files = fs.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
|
|
1161
752
|
for (const file of files) {
|
|
1162
753
|
const filePath = path.join(file.parentPath, file.name);
|
|
1163
754
|
const name = file.name.slice(0, file.name.length - 3);
|
|
@@ -1212,16 +803,16 @@ var buildLayout = async (filePath, directory, generateDynamic = false) => {
|
|
|
1212
803
|
scriptTag: `<script data-layout="true" type="module" src="${pathname}layout_data.js" data-pathname="${pathname}" defer="true"></script>`
|
|
1213
804
|
};
|
|
1214
805
|
};
|
|
1215
|
-
var fetchPageLayoutHTML = async (
|
|
1216
|
-
const
|
|
1217
|
-
let split =
|
|
806
|
+
var fetchPageLayoutHTML = async (dirname) => {
|
|
807
|
+
const relative = path.relative(options.pagesDirectory, dirname);
|
|
808
|
+
let split = relative.split(path.sep).filter(Boolean);
|
|
1218
809
|
split.push("/");
|
|
1219
810
|
split.reverse();
|
|
1220
811
|
let layouts = [];
|
|
1221
812
|
for (const dir of split) {
|
|
1222
|
-
if (
|
|
813
|
+
if (LAYOUT_MAP.has(dir)) {
|
|
1223
814
|
const filePath = path.join(path.resolve(options.pagesDirectory), dir, "layout.ts");
|
|
1224
|
-
const layout =
|
|
815
|
+
const layout = LAYOUT_MAP.get(dir);
|
|
1225
816
|
if (layout.isDynamic) {
|
|
1226
817
|
const builtLayout = await buildLayout(layout.filePath, dir, true);
|
|
1227
818
|
if (!builtLayout) continue;
|
|
@@ -1256,7 +847,7 @@ var buildPages = async (DIST_DIR2) => {
|
|
|
1256
847
|
let shouldClientHardReload = false;
|
|
1257
848
|
for (const directory of subdirectories) {
|
|
1258
849
|
const abs = path.resolve(path.join(pagesDirectory, directory));
|
|
1259
|
-
const files =
|
|
850
|
+
const files = fs.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
|
|
1260
851
|
for (const file of files) {
|
|
1261
852
|
const filePath = path.join(file.parentPath, file.name);
|
|
1262
853
|
const name = file.name.slice(0, file.name.length - 3);
|
|
@@ -1328,7 +919,8 @@ var buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
|
1328
919
|
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
1329
920
|
}
|
|
1330
921
|
const pageProps = {
|
|
1331
|
-
pageName: directory
|
|
922
|
+
pageName: directory,
|
|
923
|
+
middlewareData: {}
|
|
1332
924
|
};
|
|
1333
925
|
if (typeof pageElements === "function") {
|
|
1334
926
|
if (pageElements.constructor.name === "AsyncFunction") {
|
|
@@ -1364,7 +956,7 @@ var buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
|
1364
956
|
);
|
|
1365
957
|
return sendHardReloadInstruction === true;
|
|
1366
958
|
};
|
|
1367
|
-
var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res) => {
|
|
959
|
+
var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res, middlewareData) => {
|
|
1368
960
|
directory = directory === "/" ? "" : directory;
|
|
1369
961
|
const filePath = pageInfo.filePath;
|
|
1370
962
|
initializeState();
|
|
@@ -1375,12 +967,10 @@ var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res) => {
|
|
|
1375
967
|
let metadata = async (props) => html();
|
|
1376
968
|
let modules = {};
|
|
1377
969
|
let pageIgnoresLayout = false;
|
|
1378
|
-
let isDynamicPage = false;
|
|
1379
970
|
try {
|
|
1380
971
|
const {
|
|
1381
972
|
page,
|
|
1382
973
|
metadata: pageMetadata,
|
|
1383
|
-
isDynamic,
|
|
1384
974
|
shippedModules: shippedModules2,
|
|
1385
975
|
ignoreLayout,
|
|
1386
976
|
requestHook
|
|
@@ -1400,9 +990,6 @@ var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res) => {
|
|
|
1400
990
|
}
|
|
1401
991
|
pageElements = page;
|
|
1402
992
|
metadata = pageMetadata;
|
|
1403
|
-
if (isDynamic === true) {
|
|
1404
|
-
isDynamicPage = isDynamic;
|
|
1405
|
-
}
|
|
1406
993
|
} catch (e) {
|
|
1407
994
|
throw new Error(`Error in Page: ${directory}/page.ts - ${e}`);
|
|
1408
995
|
}
|
|
@@ -1418,7 +1005,8 @@ var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res) => {
|
|
|
1418
1005
|
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
1419
1006
|
}
|
|
1420
1007
|
const pageProps = {
|
|
1421
|
-
pageName: directory
|
|
1008
|
+
pageName: directory,
|
|
1009
|
+
middlewareData
|
|
1422
1010
|
};
|
|
1423
1011
|
if (typeof pageElements === "function") {
|
|
1424
1012
|
if (pageElements.constructor.name === "AsyncFunction") {
|
|
@@ -1472,9 +1060,9 @@ var build = async () => {
|
|
|
1472
1060
|
}
|
|
1473
1061
|
try {
|
|
1474
1062
|
{
|
|
1475
|
-
|
|
1063
|
+
log(bold(yellow(" -- Elegance.JS -- ")));
|
|
1476
1064
|
if (options.environment === "production") {
|
|
1477
|
-
|
|
1065
|
+
log(
|
|
1478
1066
|
" - ",
|
|
1479
1067
|
bgYellow(bold(black(" NOTE "))),
|
|
1480
1068
|
" : ",
|
|
@@ -1482,7 +1070,7 @@ var build = async () => {
|
|
|
1482
1070
|
underline("console.log() "),
|
|
1483
1071
|
white("statements will be shown on the client, and all code will be minified.")
|
|
1484
1072
|
);
|
|
1485
|
-
|
|
1073
|
+
log("");
|
|
1486
1074
|
}
|
|
1487
1075
|
}
|
|
1488
1076
|
if (options.preCompile) {
|
|
@@ -1503,27 +1091,19 @@ var build = async () => {
|
|
|
1503
1091
|
await buildClient(DIST_DIR);
|
|
1504
1092
|
const end = performance.now();
|
|
1505
1093
|
if (options.publicDirectory) {
|
|
1506
|
-
|
|
1094
|
+
log("Recursively copying public directory.. this may take a while.");
|
|
1507
1095
|
const src = path.relative(process.cwd(), options.publicDirectory.path);
|
|
1508
|
-
if (
|
|
1096
|
+
if (fs.existsSync(src) === false) {
|
|
1509
1097
|
console.warn("WARNING: Public directory not found, an attempt will be made create it..");
|
|
1510
|
-
|
|
1098
|
+
fs.mkdirSync(src, { recursive: true });
|
|
1511
1099
|
}
|
|
1512
|
-
await
|
|
1100
|
+
await fs.promises.cp(src, path.join(DIST_DIR), { recursive: true });
|
|
1513
1101
|
}
|
|
1514
1102
|
{
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
}
|
|
1518
|
-
if (options.server != void 0 && options.server.runServer == true) {
|
|
1519
|
-
startServer({
|
|
1520
|
-
root: options.server.root ?? DIST_DIR,
|
|
1521
|
-
environment: options.environment,
|
|
1522
|
-
port: options.server.port ?? 3e3,
|
|
1523
|
-
host: options.server.host ?? "localhost",
|
|
1524
|
-
DIST_DIR
|
|
1525
|
-
});
|
|
1103
|
+
log(`Took ${Math.round(pagesBuilt - start)}ms to Build Pages.`);
|
|
1104
|
+
log(`Took ${Math.round(end - pagesBuilt)}ms to Build Client.`);
|
|
1526
1105
|
}
|
|
1106
|
+
process.send?.({ event: "message", data: "set-pages-and-layouts", content: JSON.stringify({ pageMap: Array.from(PAGE_MAP), layoutMap: Array.from(LAYOUT_MAP) }) });
|
|
1527
1107
|
process.send?.({ event: "message", data: "compile-finish" });
|
|
1528
1108
|
if (shouldClientHardReload) {
|
|
1529
1109
|
process.send({ event: "message", data: "hard-reload" });
|
|
@@ -1538,11 +1118,9 @@ var build = async () => {
|
|
|
1538
1118
|
return true;
|
|
1539
1119
|
};
|
|
1540
1120
|
(async () => {
|
|
1541
|
-
await build();
|
|
1121
|
+
if (process.env.DO_BUILD === "true") await build();
|
|
1542
1122
|
})();
|
|
1543
1123
|
export {
|
|
1544
|
-
LAYOUT_MAP2 as LAYOUT_MAP,
|
|
1545
|
-
PAGE_MAP,
|
|
1546
1124
|
buildDynamicPage,
|
|
1547
1125
|
processPageElements
|
|
1548
1126
|
};
|
package/dist/server/server.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from 'http';
|
|
2
2
|
interface ServerOptions {
|
|
3
3
|
root: string;
|
|
4
|
+
pagesDirectory: string;
|
|
4
5
|
port?: number;
|
|
5
6
|
host?: string;
|
|
6
7
|
environment?: 'production' | 'development';
|
|
7
8
|
DIST_DIR: string;
|
|
8
9
|
}
|
|
9
|
-
export declare function startServer({ root, port, host, environment, DIST_DIR }: ServerOptions): import("http").Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
10
|
+
export declare function startServer({ root, pagesDirectory, port, host, environment, DIST_DIR }: ServerOptions): import("http").Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
10
11
|
export {};
|