elegance-js 2.0.19 → 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/dist/build.mjs +23 -974
- package/dist/client/client.mjs +20 -13
- package/dist/compile_docs.mjs +29 -980
- package/dist/global.d.ts +18 -5
- package/dist/index.mjs +9 -6
- package/dist/page_compiler.d.ts +5 -0
- package/dist/page_compiler.mjs +658 -109
- package/dist/server/generateHTMLTemplate.d.ts +1 -1
- package/dist/server/generateHTMLTemplate.mjs +5 -4
- package/dist/server/server.mjs +874 -317
- package/dist/server/state.d.ts +17 -0
- package/dist/server/state.mjs +9 -6
- package/package.json +2 -2
- package/dist/components/Breakpoint.d.ts +0 -3
- package/dist/components/Breakpoint.mjs +0 -20
- package/dist/dynamic_page.d.ts +0 -2
- package/dist/dynamic_page.mjs +0 -591
- package/dist/server/createReference.d.ts +0 -6
- package/dist/server/createReference.mjs +0 -18
- package/dist/server/createState.d.ts +0 -64
- package/dist/server/createState.mjs +0 -65
- package/dist/server/packModule.d.ts +0 -4
- package/dist/server/packModule.mjs +0 -30
package/dist/page_compiler.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/page_compiler.ts
|
|
2
|
-
import
|
|
2
|
+
import fs2 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 } from "url";
|
|
6
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
7
|
|
|
8
8
|
// src/shared/serverElements.ts
|
|
9
9
|
var createBuildableElement = (tag) => {
|
|
@@ -216,7 +216,7 @@ var generateHTMLTemplate = async ({
|
|
|
216
216
|
serverData = null,
|
|
217
217
|
addPageScriptTag = true,
|
|
218
218
|
name,
|
|
219
|
-
requiredClientModules =
|
|
219
|
+
requiredClientModules = {},
|
|
220
220
|
environment
|
|
221
221
|
}) => {
|
|
222
222
|
let StartTemplate = `<meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
@@ -224,11 +224,12 @@ var generateHTMLTemplate = async ({
|
|
|
224
224
|
StartTemplate += `<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">`;
|
|
225
225
|
}
|
|
226
226
|
StartTemplate += '<meta charset="UTF-8">';
|
|
227
|
-
for (const
|
|
228
|
-
StartTemplate += `<script data-module="true" src="/shipped/${
|
|
227
|
+
for (const [globalName] of Object.entries(requiredClientModules)) {
|
|
228
|
+
StartTemplate += `<script data-module="true" src="/shipped/${globalName}.js" defer="true"></script>`;
|
|
229
229
|
}
|
|
230
230
|
if (addPageScriptTag === true) {
|
|
231
|
-
|
|
231
|
+
const sanitized = pageURL === "" ? "/" : pageURL;
|
|
232
|
+
StartTemplate += `<script data-page="true" type="module" data-pathname="${sanitized}" src="${sanitized}${name}_data.js" defer="true"></script>`;
|
|
232
233
|
}
|
|
233
234
|
StartTemplate += `<script type="module" src="/client.js" defer="true"></script>`;
|
|
234
235
|
let builtHead;
|
|
@@ -247,13 +248,419 @@ var generateHTMLTemplate = async ({
|
|
|
247
248
|
};
|
|
248
249
|
};
|
|
249
250
|
|
|
250
|
-
// src/server/
|
|
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 { resultHTML } = await buildDynamicPage(
|
|
440
|
+
DIST_DIR2,
|
|
441
|
+
pathname,
|
|
442
|
+
pageInfo
|
|
443
|
+
);
|
|
444
|
+
if (resultHTML === false) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
await sendResponse(req2, res2, 200, { "Content-Type": MIME_TYPES[".html"] }, resultHTML);
|
|
448
|
+
} catch (err) {
|
|
449
|
+
log.error("Error building dynamic page -", err);
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
const ext = extname(handlerPath).toLowerCase();
|
|
453
|
+
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
454
|
+
const data = await fs.readFile(handlerPath);
|
|
455
|
+
await sendResponse(req2, res2, 200, { "Content-Type": contentType }, data);
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: false, root, pathname });
|
|
459
|
+
await composed(req, res);
|
|
460
|
+
} catch (err) {
|
|
461
|
+
if (err.message === "Forbidden") {
|
|
462
|
+
await sendResponse(req, res, 403, { "Content-Type": "text/plain; charset=utf-8" }, "Forbidden");
|
|
463
|
+
} else {
|
|
464
|
+
throw err;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async function handleStaticRequest(root, pathname, req, res, DIST_DIR2) {
|
|
469
|
+
try {
|
|
470
|
+
const { filePath, targetDir, stats } = await getTargetInfo(root, pathname);
|
|
471
|
+
const relDir = targetDir.slice(root.length).replace(/^[\/\\]+/, "");
|
|
472
|
+
const parts = relDir.split(/[\\/]/).filter(Boolean);
|
|
473
|
+
const middlewareDirs = getMiddlewareDirs(root, parts);
|
|
474
|
+
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
475
|
+
let handlerPath = filePath;
|
|
476
|
+
if (stats && stats.isDirectory()) {
|
|
477
|
+
handlerPath = join(filePath, "index.html");
|
|
478
|
+
} else {
|
|
479
|
+
handlerPath = filePath;
|
|
480
|
+
}
|
|
481
|
+
let hasHandler = false;
|
|
482
|
+
try {
|
|
483
|
+
await fs.access(handlerPath);
|
|
484
|
+
hasHandler = true;
|
|
485
|
+
} catch {
|
|
486
|
+
}
|
|
487
|
+
const finalHandler = async (req2, res2) => {
|
|
488
|
+
if (!hasHandler) {
|
|
489
|
+
await respondWithErrorPage(root, pathname, 404, req2, res2);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
const ext = extname(handlerPath).toLowerCase();
|
|
493
|
+
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
494
|
+
const data = await fs.readFile(handlerPath);
|
|
495
|
+
await sendResponse(req2, res2, 200, { "Content-Type": contentType }, data);
|
|
496
|
+
};
|
|
497
|
+
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: false, root, pathname });
|
|
498
|
+
await composed(req, res);
|
|
499
|
+
} catch (err) {
|
|
500
|
+
if (err.message === "Forbidden") {
|
|
501
|
+
await sendResponse(req, res, 403, { "Content-Type": "text/plain; charset=utf-8" }, "Forbidden");
|
|
502
|
+
} else {
|
|
503
|
+
throw err;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
async function handleApiRequest(root, pathname, req, res) {
|
|
508
|
+
const apiSubPath = pathname.slice("/api/".length);
|
|
509
|
+
const parts = apiSubPath.split("/").filter(Boolean);
|
|
510
|
+
const middlewareDirs = getMiddlewareDirs(join(root, "api"), parts);
|
|
511
|
+
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
512
|
+
const routeDir = middlewareDirs[middlewareDirs.length - 1];
|
|
513
|
+
const routePath = join(routeDir, "route.mjs");
|
|
514
|
+
let hasRoute = false;
|
|
515
|
+
try {
|
|
516
|
+
await fs.access(routePath);
|
|
517
|
+
hasRoute = true;
|
|
518
|
+
} catch {
|
|
519
|
+
}
|
|
520
|
+
let fn = null;
|
|
521
|
+
let module = null;
|
|
522
|
+
if (hasRoute) {
|
|
523
|
+
try {
|
|
524
|
+
const moduleUrl = pathToFileURL(routePath).href;
|
|
525
|
+
module = await import(moduleUrl);
|
|
526
|
+
fn = module[req.method];
|
|
527
|
+
} catch (err) {
|
|
528
|
+
console.error(err);
|
|
529
|
+
return respondWithJsonError(req, res, 500, "Internal Server Error");
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
const finalHandler = async (req2, res2) => {
|
|
533
|
+
if (!hasRoute) {
|
|
534
|
+
return respondWithJsonError(req2, res2, 404, "Not Found");
|
|
535
|
+
}
|
|
536
|
+
if (typeof fn !== "function") {
|
|
537
|
+
return respondWithJsonError(req2, res2, 405, "Method Not Allowed");
|
|
538
|
+
}
|
|
539
|
+
await fn(req2, res2);
|
|
540
|
+
};
|
|
541
|
+
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: true });
|
|
542
|
+
await composed(req, res);
|
|
543
|
+
}
|
|
544
|
+
function composeMiddlewares(mws, final, options2) {
|
|
545
|
+
return async function(req, res) {
|
|
546
|
+
let index = 0;
|
|
547
|
+
async function dispatch(err) {
|
|
548
|
+
if (err) {
|
|
549
|
+
if (options2.isApi) {
|
|
550
|
+
return respondWithJsonError(req, res, 500, err.message || "Internal Server Error");
|
|
551
|
+
} else {
|
|
552
|
+
return await respondWithErrorPage(options2.root, options2.pathname, 500, req, res);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
if (index >= mws.length) {
|
|
556
|
+
return await final(req, res);
|
|
557
|
+
}
|
|
558
|
+
const thisMw = mws[index++];
|
|
559
|
+
const next = (e) => dispatch(e);
|
|
560
|
+
const onceNext = (nextFn) => {
|
|
561
|
+
let called = false;
|
|
562
|
+
return async (e) => {
|
|
563
|
+
if (called) {
|
|
564
|
+
log.warn("next() was called in a middleware more than once.");
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
called = true;
|
|
568
|
+
await nextFn(e);
|
|
569
|
+
};
|
|
570
|
+
};
|
|
571
|
+
try {
|
|
572
|
+
await thisMw(req, res, onceNext(next));
|
|
573
|
+
} catch (error) {
|
|
574
|
+
await dispatch(error);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
await dispatch();
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
async function respondWithJsonError(req, res, code, message) {
|
|
581
|
+
const body2 = JSON.stringify({ error: message });
|
|
582
|
+
await sendResponse(req, res, code, { "Content-Type": "application/json; charset=utf-8" }, body2);
|
|
583
|
+
}
|
|
584
|
+
async function respondWithErrorPage(root, pathname, code, req, res) {
|
|
585
|
+
let currentPath = normalize(join(root, decodeURIComponent(pathname)));
|
|
586
|
+
let tried = /* @__PURE__ */ new Set();
|
|
587
|
+
let errorFilePath = null;
|
|
588
|
+
while (currentPath.startsWith(root)) {
|
|
589
|
+
const candidate = join(currentPath, `${code}.html`);
|
|
590
|
+
if (!tried.has(candidate)) {
|
|
591
|
+
try {
|
|
592
|
+
await fs.access(candidate);
|
|
593
|
+
errorFilePath = candidate;
|
|
594
|
+
break;
|
|
595
|
+
} catch {
|
|
596
|
+
}
|
|
597
|
+
tried.add(candidate);
|
|
598
|
+
}
|
|
599
|
+
const parent = dirname(currentPath);
|
|
600
|
+
if (parent === currentPath) break;
|
|
601
|
+
currentPath = parent;
|
|
602
|
+
}
|
|
603
|
+
if (!errorFilePath) {
|
|
604
|
+
const fallback = join(root, `${code}.html`);
|
|
605
|
+
try {
|
|
606
|
+
await fs.access(fallback);
|
|
607
|
+
errorFilePath = fallback;
|
|
608
|
+
} catch {
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (errorFilePath) {
|
|
612
|
+
try {
|
|
613
|
+
const html2 = await fs.readFile(errorFilePath, "utf8");
|
|
614
|
+
await sendResponse(req, res, code, { "Content-Type": "text/html; charset=utf-8" }, html2);
|
|
615
|
+
return;
|
|
616
|
+
} catch {
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
await sendResponse(req, res, code, { "Content-Type": "text/plain; charset=utf-8" }, `${code} Error`);
|
|
620
|
+
}
|
|
621
|
+
function isCompressible(contentType) {
|
|
622
|
+
if (!contentType) return false;
|
|
623
|
+
return /text\/|javascript|json|xml|svg/.test(contentType);
|
|
624
|
+
}
|
|
625
|
+
async function sendResponse(req, res, status, headers, body2) {
|
|
626
|
+
if (typeof body2 === "string") {
|
|
627
|
+
body2 = Buffer.from(body2);
|
|
628
|
+
}
|
|
629
|
+
const accept = req.headers["accept-encoding"] || "";
|
|
630
|
+
let encoding = null;
|
|
631
|
+
if (accept.match(/\bgzip\b/)) {
|
|
632
|
+
encoding = "gzip";
|
|
633
|
+
} else if (accept.match(/\bdeflate\b/)) {
|
|
634
|
+
encoding = "deflate";
|
|
635
|
+
}
|
|
636
|
+
if (!encoding || !isCompressible(headers["Content-Type"] || "")) {
|
|
637
|
+
res.writeHead(status, headers);
|
|
638
|
+
res.end(body2);
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
const compressor = encoding === "gzip" ? gzipAsync : deflateAsync;
|
|
642
|
+
try {
|
|
643
|
+
const compressed = await compressor(body2);
|
|
644
|
+
headers["Content-Encoding"] = encoding;
|
|
645
|
+
headers["Vary"] = "Accept-Encoding";
|
|
646
|
+
res.writeHead(status, headers);
|
|
647
|
+
res.end(compressed);
|
|
648
|
+
} catch (err) {
|
|
649
|
+
log.error("Compression error:", err);
|
|
650
|
+
res.writeHead(status, headers);
|
|
651
|
+
res.end(body2);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// src/server/loadHook.ts
|
|
656
|
+
var resetLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__ = [];
|
|
657
|
+
var getLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__;
|
|
658
|
+
|
|
659
|
+
// src/server/state.ts
|
|
251
660
|
if (!globalThis.__SERVER_CURRENT_STATE_ID__) {
|
|
252
661
|
globalThis.__SERVER_CURRENT_STATE_ID__ = 1;
|
|
253
662
|
}
|
|
254
|
-
var initializeState = () =>
|
|
255
|
-
globalThis.__SERVER_CURRENT_STATE__ = [];
|
|
256
|
-
};
|
|
663
|
+
var initializeState = () => globalThis.__SERVER_CURRENT_STATE__ = [];
|
|
257
664
|
var getState = () => {
|
|
258
665
|
return globalThis.__SERVER_CURRENT_STATE__;
|
|
259
666
|
};
|
|
@@ -262,16 +669,12 @@ var getObjectAttributes = () => {
|
|
|
262
669
|
return globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__;
|
|
263
670
|
};
|
|
264
671
|
|
|
265
|
-
// src/server/loadHook.ts
|
|
266
|
-
var resetLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__ = [];
|
|
267
|
-
var getLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__;
|
|
268
|
-
|
|
269
672
|
// src/server/layout.ts
|
|
270
673
|
var resetLayouts = () => globalThis.__SERVER_CURRENT_LAYOUTS__ = /* @__PURE__ */ new Map();
|
|
271
674
|
if (!globalThis.__SERVER_CURRENT_LAYOUT_ID__) globalThis.__SERVER_CURRENT_LAYOUT_ID__ = 1;
|
|
272
675
|
|
|
273
676
|
// src/page_compiler.ts
|
|
274
|
-
var __filename =
|
|
677
|
+
var __filename = fileURLToPath2(import.meta.url);
|
|
275
678
|
var __dirname = path.dirname(__filename);
|
|
276
679
|
setArcTsConfig(__dirname);
|
|
277
680
|
registerLoader();
|
|
@@ -281,6 +684,8 @@ if (packageDir === void 0) {
|
|
|
281
684
|
}
|
|
282
685
|
var clientPath = path.resolve(packageDir, "./dist/client/client.mjs");
|
|
283
686
|
var watcherPath = path.resolve(packageDir, "./dist/client/watcher.mjs");
|
|
687
|
+
var shippedModules = /* @__PURE__ */ new Map();
|
|
688
|
+
var modulesToShip = [];
|
|
284
689
|
var yellow = (text) => {
|
|
285
690
|
return `\x1B[38;2;238;184;68m${text}`;
|
|
286
691
|
};
|
|
@@ -299,15 +704,17 @@ var underline = (text) => {
|
|
|
299
704
|
var white = (text) => {
|
|
300
705
|
return `\x1B[38;2;255;247;229m${text}`;
|
|
301
706
|
};
|
|
302
|
-
var
|
|
707
|
+
var log2 = (...text) => {
|
|
303
708
|
if (options.quiet) return;
|
|
304
709
|
return console.log(text.map((text2) => `${text2}\x1B[0m`).join(""));
|
|
305
710
|
};
|
|
306
711
|
var options = JSON.parse(process.env.OPTIONS);
|
|
307
712
|
var DIST_DIR = process.env.DIST_DIR;
|
|
713
|
+
var PAGE_MAP = /* @__PURE__ */ new Map();
|
|
714
|
+
var LAYOUT_MAP2 = /* @__PURE__ */ new Map();
|
|
308
715
|
var getAllSubdirectories = (dir, baseDir = dir) => {
|
|
309
716
|
let directories = [];
|
|
310
|
-
const items =
|
|
717
|
+
const items = fs2.readdirSync(dir, { withFileTypes: true });
|
|
311
718
|
for (const item of items) {
|
|
312
719
|
if (item.isDirectory()) {
|
|
313
720
|
const fullPath = path.join(dir, item.name);
|
|
@@ -320,10 +727,10 @@ var getAllSubdirectories = (dir, baseDir = dir) => {
|
|
|
320
727
|
};
|
|
321
728
|
var buildClient = async (DIST_DIR2) => {
|
|
322
729
|
let clientString = "window.__name = (func) => func; ";
|
|
323
|
-
clientString +=
|
|
730
|
+
clientString += fs2.readFileSync(clientPath, "utf-8");
|
|
324
731
|
if (options.hotReload !== void 0) {
|
|
325
732
|
clientString += `const watchServerPort = ${options.hotReload.port}`;
|
|
326
|
-
clientString +=
|
|
733
|
+
clientString += fs2.readFileSync(watcherPath, "utf-8");
|
|
327
734
|
}
|
|
328
735
|
const transformedClient = await esbuild.transform(clientString, {
|
|
329
736
|
minify: options.environment === "production",
|
|
@@ -333,7 +740,7 @@ var buildClient = async (DIST_DIR2) => {
|
|
|
333
740
|
platform: "node",
|
|
334
741
|
loader: "ts"
|
|
335
742
|
});
|
|
336
|
-
|
|
743
|
+
fs2.writeFileSync(
|
|
337
744
|
path.join(DIST_DIR2, "/client.js"),
|
|
338
745
|
transformedClient.code
|
|
339
746
|
);
|
|
@@ -512,7 +919,7 @@ ${trace}`);
|
|
|
512
919
|
}
|
|
513
920
|
}
|
|
514
921
|
};
|
|
515
|
-
var pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageName, doWrite = true, requiredClientModules =
|
|
922
|
+
var pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageName, doWrite = true, requiredClientModules = {}, layout, pathname = "") => {
|
|
516
923
|
if (typeof pageElements === "string" || typeof pageElements === "boolean" || typeof pageElements === "number" || Array.isArray(pageElements)) {
|
|
517
924
|
throw new Error(`The root element of a page / layout must be a built element, not just a Child. Received: ${typeof pageElements}.`);
|
|
518
925
|
}
|
|
@@ -524,23 +931,59 @@ var pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageNam
|
|
|
524
931
|
pageLocation
|
|
525
932
|
);
|
|
526
933
|
const { internals, builtMetadata } = await generateHTMLTemplate({
|
|
527
|
-
pageURL:
|
|
934
|
+
pageURL: pathname,
|
|
528
935
|
head: metadata,
|
|
529
|
-
addPageScriptTag:
|
|
936
|
+
addPageScriptTag: doWrite,
|
|
530
937
|
name: pageName,
|
|
531
938
|
requiredClientModules,
|
|
532
939
|
environment: options.environment
|
|
533
940
|
});
|
|
941
|
+
let extraBodyHTML = "";
|
|
942
|
+
if (doWrite === false) {
|
|
943
|
+
const state = getState();
|
|
944
|
+
const pageLoadHooks = getLoadHooks();
|
|
945
|
+
const userObjectAttributes = getObjectAttributes();
|
|
946
|
+
const {
|
|
947
|
+
result
|
|
948
|
+
} = await generateClientPageData(
|
|
949
|
+
pathname,
|
|
950
|
+
state || {},
|
|
951
|
+
[...objectAttributes, ...userObjectAttributes],
|
|
952
|
+
pageLoadHooks || [],
|
|
953
|
+
DIST_DIR2,
|
|
954
|
+
"page",
|
|
955
|
+
"pd",
|
|
956
|
+
false
|
|
957
|
+
);
|
|
958
|
+
const sanitized = pathname === "" ? "/" : pathname;
|
|
959
|
+
extraBodyHTML = `<script data-hook="true" data-pathname="${sanitized}" type="text/plain">${result}</script>`;
|
|
960
|
+
extraBodyHTML += `<script>
|
|
961
|
+
const text = document.querySelector('[data-hook="true"][data-pathname="${sanitized}"][type="text/plain"').textContent;
|
|
962
|
+
const blob = new Blob([text], { type: 'text/javascript' });
|
|
963
|
+
const url = URL.createObjectURL(blob);
|
|
964
|
+
|
|
965
|
+
const script = document.createElement("script");
|
|
966
|
+
script.src = url;
|
|
967
|
+
script.type = "module";
|
|
968
|
+
script.setAttribute("data-page", "true");
|
|
969
|
+
script.setAttribute("data-pathname", "${sanitized}");
|
|
970
|
+
|
|
971
|
+
document.head.appendChild(script);
|
|
972
|
+
|
|
973
|
+
document.currentScript.remove();
|
|
974
|
+
</script>`;
|
|
975
|
+
extraBodyHTML = extraBodyHTML.replace(/\s+/g, " ").replace(/\s*([{}();,:])\s*/g, "$1").trim();
|
|
976
|
+
}
|
|
534
977
|
const headHTML = `<!DOCTYPE html>${layout.metadata.startHTML}${layout.scriptTag}${internals}${builtMetadata}${layout.metadata.endHTML}`;
|
|
535
|
-
const bodyHTML = `${layout.pageContent.startHTML}${renderedPage.bodyHTML}${layout.pageContent.endHTML}`;
|
|
978
|
+
const bodyHTML = `${layout.pageContent.startHTML}${renderedPage.bodyHTML}${extraBodyHTML}${layout.pageContent.endHTML}`;
|
|
536
979
|
const resultHTML = `${headHTML}${bodyHTML}`;
|
|
537
980
|
const htmlLocation = path.join(pageLocation, (pageName === "page" ? "index" : pageName) + ".html");
|
|
538
981
|
if (doWrite) {
|
|
539
|
-
const
|
|
540
|
-
if (
|
|
541
|
-
|
|
982
|
+
const dirname2 = path.dirname(htmlLocation);
|
|
983
|
+
if (fs2.existsSync(dirname2) === false) {
|
|
984
|
+
fs2.mkdirSync(dirname2, { recursive: true });
|
|
542
985
|
}
|
|
543
|
-
|
|
986
|
+
fs2.writeFileSync(
|
|
544
987
|
htmlLocation,
|
|
545
988
|
resultHTML,
|
|
546
989
|
{
|
|
@@ -549,16 +992,14 @@ var pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageNam
|
|
|
549
992
|
}
|
|
550
993
|
);
|
|
551
994
|
return objectAttributes;
|
|
552
|
-
} else {
|
|
553
|
-
return {
|
|
554
|
-
objectAttributes,
|
|
555
|
-
resultHTML
|
|
556
|
-
};
|
|
557
995
|
}
|
|
996
|
+
return resultHTML;
|
|
558
997
|
};
|
|
559
|
-
var generateClientPageData = async (pageLocation, state, objectAttributes, pageLoadHooks, DIST_DIR2, pageName, globalVariableName = "pd") => {
|
|
560
|
-
|
|
561
|
-
|
|
998
|
+
var generateClientPageData = async (pageLocation, state, objectAttributes, pageLoadHooks, DIST_DIR2, pageName, globalVariableName = "pd", write = true) => {
|
|
999
|
+
let clientPageJSText = "";
|
|
1000
|
+
{
|
|
1001
|
+
clientPageJSText += `${globalThis.__SERVER_PAGE_DATA_BANNER__}`;
|
|
1002
|
+
}
|
|
562
1003
|
{
|
|
563
1004
|
clientPageJSText += `export const data = {`;
|
|
564
1005
|
if (state) {
|
|
@@ -600,30 +1041,29 @@ var generateClientPageData = async (pageLocation, state, objectAttributes, pageL
|
|
|
600
1041
|
}
|
|
601
1042
|
if (pageLoadHooks.length > 0) {
|
|
602
1043
|
clientPageJSText += "lh:[";
|
|
603
|
-
for (const
|
|
604
|
-
clientPageJSText += `{fn:${
|
|
1044
|
+
for (const loadHook2 of pageLoadHooks) {
|
|
1045
|
+
clientPageJSText += `{fn:${loadHook2.fn}},`;
|
|
605
1046
|
}
|
|
606
1047
|
clientPageJSText += "],";
|
|
607
1048
|
}
|
|
608
1049
|
clientPageJSText += `};`;
|
|
609
1050
|
}
|
|
610
|
-
|
|
611
|
-
const pageDataPath = path.join(pageLocation, `${pageName}_data.js`);
|
|
1051
|
+
const pageDataPath = path.join(DIST_DIR2, pageLocation, `${pageName}_data.js`);
|
|
612
1052
|
let sendHardReloadInstruction = false;
|
|
613
1053
|
const transformedResult = await esbuild.transform(clientPageJSText, { minify: options.environment === "production" }).catch((error) => {
|
|
614
1054
|
console.error("Failed to transform client page js!", error);
|
|
615
1055
|
});
|
|
616
1056
|
if (!transformedResult) return { sendHardReloadInstruction };
|
|
617
|
-
if (
|
|
618
|
-
const content =
|
|
1057
|
+
if (fs2.existsSync(pageDataPath)) {
|
|
1058
|
+
const content = fs2.readFileSync(pageDataPath).toString();
|
|
619
1059
|
if (content !== transformedResult.code) {
|
|
620
1060
|
sendHardReloadInstruction = true;
|
|
621
1061
|
}
|
|
622
1062
|
}
|
|
623
|
-
|
|
624
|
-
return { sendHardReloadInstruction };
|
|
1063
|
+
if (write) fs2.writeFileSync(pageDataPath, transformedResult.code, "utf-8");
|
|
1064
|
+
return { sendHardReloadInstruction, result: transformedResult.code };
|
|
625
1065
|
};
|
|
626
|
-
var generateLayout = async (DIST_DIR2, filePath, directory, childIndicator) => {
|
|
1066
|
+
var generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, generateDynamic = false) => {
|
|
627
1067
|
initializeState();
|
|
628
1068
|
initializeObjectAttributes();
|
|
629
1069
|
resetLoadHooks();
|
|
@@ -631,24 +1071,30 @@ var generateLayout = async (DIST_DIR2, filePath, directory, childIndicator) => {
|
|
|
631
1071
|
let layoutElements;
|
|
632
1072
|
let metadataElements;
|
|
633
1073
|
let modules = [];
|
|
1074
|
+
let isDynamicLayout = false;
|
|
634
1075
|
try {
|
|
635
1076
|
const {
|
|
636
1077
|
layout,
|
|
637
1078
|
metadata,
|
|
638
1079
|
isDynamic,
|
|
639
|
-
|
|
1080
|
+
shippedModules: shippedModules2
|
|
640
1081
|
} = await import("file://" + filePath);
|
|
641
|
-
if (
|
|
642
|
-
modules =
|
|
1082
|
+
if (shippedModules2 !== void 0) {
|
|
1083
|
+
modules = shippedModules2;
|
|
643
1084
|
}
|
|
644
1085
|
layoutElements = layout;
|
|
645
1086
|
metadataElements = metadata;
|
|
646
1087
|
if (isDynamic === true) {
|
|
647
|
-
|
|
1088
|
+
isDynamicLayout = isDynamic;
|
|
648
1089
|
}
|
|
649
1090
|
} catch (e) {
|
|
650
|
-
throw new Error(`Error in Page: ${directory === "" ? "/" : directory}layout.
|
|
1091
|
+
throw new Error(`Error in Page: ${directory === "" ? "/" : directory}layout.ts - ${e}`);
|
|
651
1092
|
}
|
|
1093
|
+
LAYOUT_MAP2.set(directory === "" ? "/" : directory, {
|
|
1094
|
+
isDynamic: isDynamicLayout,
|
|
1095
|
+
filePath
|
|
1096
|
+
});
|
|
1097
|
+
if (isDynamicLayout === true && generateDynamic === false) return false;
|
|
652
1098
|
{
|
|
653
1099
|
if (!layoutElements) {
|
|
654
1100
|
throw new Error(`WARNING: ${filePath} should export a const layout, which is of type Layout: (child: Child) => AnyBuiltElement.`);
|
|
@@ -683,11 +1129,12 @@ var generateLayout = async (DIST_DIR2, filePath, directory, childIndicator) => {
|
|
|
683
1129
|
const stack = [];
|
|
684
1130
|
const processedPageElements = processPageElements(layoutElements, foundObjectAttributes, 0, stack);
|
|
685
1131
|
const renderedPage = await serverSideRenderPage(
|
|
686
|
-
processedPageElements
|
|
1132
|
+
processedPageElements,
|
|
1133
|
+
directory
|
|
687
1134
|
);
|
|
688
1135
|
const metadataHTML = metadataElements ? renderRecursively(metadataElements) : "";
|
|
689
1136
|
await generateClientPageData(
|
|
690
|
-
|
|
1137
|
+
directory,
|
|
691
1138
|
state || {},
|
|
692
1139
|
[...objectAttributes, ...foundObjectAttributes],
|
|
693
1140
|
pageLoadHooks || [],
|
|
@@ -704,7 +1151,7 @@ var buildLayouts = async () => {
|
|
|
704
1151
|
let shouldClientHardReload = false;
|
|
705
1152
|
for (const directory of subdirectories) {
|
|
706
1153
|
const abs = path.resolve(path.join(pagesDirectory, directory));
|
|
707
|
-
const files =
|
|
1154
|
+
const files = fs2.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
|
|
708
1155
|
for (const file of files) {
|
|
709
1156
|
const filePath = path.join(file.parentPath, file.name);
|
|
710
1157
|
const name = file.name.slice(0, file.name.length - 3);
|
|
@@ -714,6 +1161,7 @@ var buildLayouts = async () => {
|
|
|
714
1161
|
}
|
|
715
1162
|
try {
|
|
716
1163
|
const builtLayout = await buildLayout(filePath, directory);
|
|
1164
|
+
if (!builtLayout) return { shouldClientHardReload: false };
|
|
717
1165
|
builtLayouts.set(filePath, builtLayout);
|
|
718
1166
|
} catch (e) {
|
|
719
1167
|
console.error(e);
|
|
@@ -723,15 +1171,18 @@ var buildLayouts = async () => {
|
|
|
723
1171
|
}
|
|
724
1172
|
return { shouldClientHardReload };
|
|
725
1173
|
};
|
|
726
|
-
var buildLayout = async (filePath, directory) => {
|
|
1174
|
+
var buildLayout = async (filePath, directory, generateDynamic = false) => {
|
|
727
1175
|
const id = globalThis.__SERVER_CURRENT_STATE_ID__ += 1;
|
|
728
1176
|
const childIndicator = `<template layout-id="${id}"></template>`;
|
|
729
|
-
const
|
|
1177
|
+
const result = await generateLayout(
|
|
730
1178
|
DIST_DIR,
|
|
731
1179
|
filePath,
|
|
732
1180
|
directory,
|
|
733
|
-
childIndicator
|
|
1181
|
+
childIndicator,
|
|
1182
|
+
generateDynamic
|
|
734
1183
|
);
|
|
1184
|
+
if (result === false) return false;
|
|
1185
|
+
const { pageContentHTML, metadataHTML } = result;
|
|
735
1186
|
const splitAround = (str, sub) => {
|
|
736
1187
|
const i = str.indexOf(sub);
|
|
737
1188
|
if (i === -1) throw new Error("substring does not exist in parent string");
|
|
@@ -748,23 +1199,30 @@ var buildLayout = async (filePath, directory) => {
|
|
|
748
1199
|
endHTML: str.substring(i)
|
|
749
1200
|
};
|
|
750
1201
|
};
|
|
751
|
-
const
|
|
1202
|
+
const pathname = directory === "" ? "/" : directory;
|
|
752
1203
|
return {
|
|
753
1204
|
pageContent: splitAt(pageContentHTML, childIndicator),
|
|
754
1205
|
metadata: splitAround(metadataHTML, childIndicator),
|
|
755
|
-
scriptTag: `<script data-layout="true" type="module" src="${
|
|
1206
|
+
scriptTag: `<script data-layout="true" type="module" src="${pathname}layout_data.js" data-pathname="${pathname}" defer="true"></script>`
|
|
756
1207
|
};
|
|
757
1208
|
};
|
|
758
|
-
var fetchPageLayoutHTML = async (
|
|
759
|
-
const
|
|
760
|
-
let split =
|
|
1209
|
+
var fetchPageLayoutHTML = async (dirname2) => {
|
|
1210
|
+
const relative2 = path.relative(options.pagesDirectory, dirname2);
|
|
1211
|
+
let split = relative2.split(path.sep).filter(Boolean);
|
|
761
1212
|
split.push("/");
|
|
762
1213
|
split.reverse();
|
|
763
1214
|
let layouts = [];
|
|
764
1215
|
for (const dir of split) {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
1216
|
+
if (LAYOUT_MAP2.has(dir)) {
|
|
1217
|
+
const filePath = path.join(path.resolve(options.pagesDirectory), dir, "layout.ts");
|
|
1218
|
+
const layout = LAYOUT_MAP2.get(dir);
|
|
1219
|
+
if (layout.isDynamic) {
|
|
1220
|
+
const builtLayout = await buildLayout(layout.filePath, dir, true);
|
|
1221
|
+
if (!builtLayout) continue;
|
|
1222
|
+
layouts.push(builtLayout);
|
|
1223
|
+
} else {
|
|
1224
|
+
layouts.push(builtLayouts.get(filePath));
|
|
1225
|
+
}
|
|
768
1226
|
}
|
|
769
1227
|
}
|
|
770
1228
|
const pageContent = {
|
|
@@ -792,7 +1250,7 @@ var buildPages = async (DIST_DIR2) => {
|
|
|
792
1250
|
let shouldClientHardReload = false;
|
|
793
1251
|
for (const directory of subdirectories) {
|
|
794
1252
|
const abs = path.resolve(path.join(pagesDirectory, directory));
|
|
795
|
-
const files =
|
|
1253
|
+
const files = fs2.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
|
|
796
1254
|
for (const file of files) {
|
|
797
1255
|
const filePath = path.join(file.parentPath, file.name);
|
|
798
1256
|
const name = file.name.slice(0, file.name.length - 3);
|
|
@@ -822,32 +1280,43 @@ var buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
|
822
1280
|
globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
|
|
823
1281
|
let pageElements;
|
|
824
1282
|
let metadata;
|
|
825
|
-
let modules =
|
|
1283
|
+
let modules = {};
|
|
826
1284
|
let pageIgnoresLayout = false;
|
|
1285
|
+
let isDynamicPage = false;
|
|
827
1286
|
try {
|
|
828
1287
|
const {
|
|
829
1288
|
page,
|
|
830
1289
|
metadata: pageMetadata,
|
|
831
|
-
|
|
832
|
-
|
|
1290
|
+
isDynamic,
|
|
1291
|
+
shippedModules: shippedModules2,
|
|
833
1292
|
ignoreLayout
|
|
834
1293
|
} = await import("file://" + filePath);
|
|
835
|
-
if (
|
|
836
|
-
modules =
|
|
1294
|
+
if (shippedModules2 !== void 0) {
|
|
1295
|
+
modules = shippedModules2;
|
|
837
1296
|
}
|
|
838
1297
|
if (ignoreLayout) {
|
|
839
1298
|
pageIgnoresLayout = true;
|
|
840
1299
|
}
|
|
841
1300
|
pageElements = page;
|
|
842
1301
|
metadata = pageMetadata;
|
|
843
|
-
if (
|
|
844
|
-
|
|
1302
|
+
if (isDynamic === true) {
|
|
1303
|
+
isDynamicPage = isDynamic;
|
|
845
1304
|
}
|
|
846
1305
|
} catch (e) {
|
|
847
|
-
throw new Error(`Error in Page: ${directory
|
|
1306
|
+
throw new Error(`Error in Page: ${directory}/${name}.ts - ${e}`);
|
|
1307
|
+
}
|
|
1308
|
+
PAGE_MAP.set(directory === "" ? "/" : directory, {
|
|
1309
|
+
isDynamic: isDynamicPage,
|
|
1310
|
+
filePath
|
|
1311
|
+
});
|
|
1312
|
+
if (isDynamicPage) return false;
|
|
1313
|
+
if (modules !== void 0) {
|
|
1314
|
+
for (const [globalName, path2] of Object.entries(modules)) {
|
|
1315
|
+
modulesToShip.push({ globalName, path: path2 });
|
|
1316
|
+
}
|
|
848
1317
|
}
|
|
849
1318
|
if (!metadata || metadata && typeof metadata !== "function") {
|
|
850
|
-
console.warn(`WARNING: ${filePath} does not export a metadata function
|
|
1319
|
+
console.warn(`WARNING: ${filePath} does not export a metadata function.`);
|
|
851
1320
|
}
|
|
852
1321
|
if (!pageElements) {
|
|
853
1322
|
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
@@ -874,12 +1343,13 @@ var buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
|
874
1343
|
name,
|
|
875
1344
|
true,
|
|
876
1345
|
modules,
|
|
877
|
-
layout
|
|
1346
|
+
layout,
|
|
1347
|
+
directory
|
|
878
1348
|
);
|
|
879
1349
|
const {
|
|
880
1350
|
sendHardReloadInstruction
|
|
881
1351
|
} = await generateClientPageData(
|
|
882
|
-
|
|
1352
|
+
directory,
|
|
883
1353
|
state || {},
|
|
884
1354
|
[...objectAttributes, ...foundObjectAttributes],
|
|
885
1355
|
pageLoadHooks || [],
|
|
@@ -888,9 +1358,95 @@ var buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
|
888
1358
|
);
|
|
889
1359
|
return sendHardReloadInstruction === true;
|
|
890
1360
|
};
|
|
891
|
-
var
|
|
892
|
-
|
|
893
|
-
|
|
1361
|
+
var buildDynamicPage = async (DIST_DIR2, directory, pageInfo) => {
|
|
1362
|
+
directory = directory === "/" ? "" : directory;
|
|
1363
|
+
const filePath = pageInfo.filePath;
|
|
1364
|
+
initializeState();
|
|
1365
|
+
initializeObjectAttributes();
|
|
1366
|
+
resetLoadHooks();
|
|
1367
|
+
globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
|
|
1368
|
+
let pageElements = async (props) => body();
|
|
1369
|
+
let metadata = async (props) => html();
|
|
1370
|
+
let modules = {};
|
|
1371
|
+
let pageIgnoresLayout = false;
|
|
1372
|
+
let isDynamicPage = false;
|
|
1373
|
+
try {
|
|
1374
|
+
const {
|
|
1375
|
+
page,
|
|
1376
|
+
metadata: pageMetadata,
|
|
1377
|
+
isDynamic,
|
|
1378
|
+
shippedModules: shippedModules2,
|
|
1379
|
+
ignoreLayout
|
|
1380
|
+
} = await import("file://" + filePath);
|
|
1381
|
+
if (shippedModules2 !== void 0) {
|
|
1382
|
+
modules = shippedModules2;
|
|
1383
|
+
}
|
|
1384
|
+
if (ignoreLayout) {
|
|
1385
|
+
pageIgnoresLayout = true;
|
|
1386
|
+
}
|
|
1387
|
+
pageElements = page;
|
|
1388
|
+
metadata = pageMetadata;
|
|
1389
|
+
if (isDynamic === true) {
|
|
1390
|
+
isDynamicPage = isDynamic;
|
|
1391
|
+
}
|
|
1392
|
+
} catch (e) {
|
|
1393
|
+
throw new Error(`Error in Page: ${directory}/page.ts - ${e}`);
|
|
1394
|
+
}
|
|
1395
|
+
if (modules !== void 0) {
|
|
1396
|
+
for (const [globalName, path2] of Object.entries(modules)) {
|
|
1397
|
+
modulesToShip.push({ globalName, path: path2 });
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
if (!metadata || metadata && typeof metadata !== "function") {
|
|
1401
|
+
console.warn(`WARNING: ${filePath} does not export a metadata function.`);
|
|
1402
|
+
}
|
|
1403
|
+
if (!pageElements) {
|
|
1404
|
+
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
1405
|
+
}
|
|
1406
|
+
const pageProps = {
|
|
1407
|
+
pageName: directory
|
|
1408
|
+
};
|
|
1409
|
+
if (typeof pageElements === "function") {
|
|
1410
|
+
if (pageElements.constructor.name === "AsyncFunction") {
|
|
1411
|
+
pageElements = await pageElements(pageProps);
|
|
1412
|
+
} else {
|
|
1413
|
+
pageElements = pageElements(pageProps);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
const layout = await fetchPageLayoutHTML(path.dirname(filePath));
|
|
1417
|
+
const resultHTML = await pageToHTML(
|
|
1418
|
+
path.join(DIST_DIR2, directory),
|
|
1419
|
+
pageElements,
|
|
1420
|
+
metadata,
|
|
1421
|
+
DIST_DIR2,
|
|
1422
|
+
"page",
|
|
1423
|
+
false,
|
|
1424
|
+
modules,
|
|
1425
|
+
layout,
|
|
1426
|
+
directory
|
|
1427
|
+
);
|
|
1428
|
+
await shipModules();
|
|
1429
|
+
return { resultHTML };
|
|
1430
|
+
};
|
|
1431
|
+
var shipModules = async () => {
|
|
1432
|
+
for (const plugin of modulesToShip) {
|
|
1433
|
+
{
|
|
1434
|
+
if (shippedModules.has(plugin.globalName)) continue;
|
|
1435
|
+
shippedModules.set(plugin.globalName, true);
|
|
1436
|
+
}
|
|
1437
|
+
esbuild.build({
|
|
1438
|
+
entryPoints: [plugin.path],
|
|
1439
|
+
bundle: true,
|
|
1440
|
+
outfile: path.join(DIST_DIR, "shipped", plugin.globalName + ".js"),
|
|
1441
|
+
format: "iife",
|
|
1442
|
+
platform: "browser",
|
|
1443
|
+
globalName: plugin.globalName,
|
|
1444
|
+
minify: true,
|
|
1445
|
+
treeShaking: true
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
modulesToShip = [];
|
|
1449
|
+
};
|
|
894
1450
|
var build = async () => {
|
|
895
1451
|
if (options.quiet === true) {
|
|
896
1452
|
console.log = function() {
|
|
@@ -902,9 +1458,9 @@ var build = async () => {
|
|
|
902
1458
|
}
|
|
903
1459
|
try {
|
|
904
1460
|
{
|
|
905
|
-
|
|
1461
|
+
log2(bold(yellow(" -- Elegance.JS -- ")));
|
|
906
1462
|
if (options.environment === "production") {
|
|
907
|
-
|
|
1463
|
+
log2(
|
|
908
1464
|
" - ",
|
|
909
1465
|
bgYellow(bold(black(" NOTE "))),
|
|
910
1466
|
" : ",
|
|
@@ -912,32 +1468,13 @@ var build = async () => {
|
|
|
912
1468
|
underline("console.log() "),
|
|
913
1469
|
white("statements will be shown on the client, and all code will be minified.")
|
|
914
1470
|
);
|
|
915
|
-
|
|
1471
|
+
log2("");
|
|
916
1472
|
}
|
|
917
1473
|
}
|
|
918
1474
|
if (options.preCompile) {
|
|
919
1475
|
options.preCompile();
|
|
920
1476
|
}
|
|
921
1477
|
const start = performance.now();
|
|
922
|
-
{
|
|
923
|
-
pluginsToShip = [];
|
|
924
|
-
for (const plugin of pluginsToShip) {
|
|
925
|
-
{
|
|
926
|
-
if (shippedPlugins.has(plugin.globalName)) continue;
|
|
927
|
-
shippedPlugins.set(plugin.globalName, true);
|
|
928
|
-
}
|
|
929
|
-
await esbuild.build({
|
|
930
|
-
entryPoints: [plugin.path],
|
|
931
|
-
bundle: true,
|
|
932
|
-
outfile: path.join(DIST_DIR, "shipped", plugin.globalName + ".js"),
|
|
933
|
-
format: "iife",
|
|
934
|
-
platform: "browser",
|
|
935
|
-
globalName: plugin.globalName,
|
|
936
|
-
minify: true,
|
|
937
|
-
treeShaking: true
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
1478
|
let shouldClientHardReload;
|
|
942
1479
|
{
|
|
943
1480
|
const { shouldClientHardReload: doReload } = await buildLayouts();
|
|
@@ -947,24 +1484,33 @@ var build = async () => {
|
|
|
947
1484
|
const { shouldClientHardReload: doReload } = await buildPages(path.resolve(DIST_DIR));
|
|
948
1485
|
if (doReload) shouldClientHardReload = true;
|
|
949
1486
|
}
|
|
1487
|
+
await shipModules();
|
|
950
1488
|
const pagesBuilt = performance.now();
|
|
951
1489
|
await buildClient(DIST_DIR);
|
|
952
1490
|
const end = performance.now();
|
|
953
1491
|
if (options.publicDirectory) {
|
|
954
|
-
|
|
1492
|
+
log2("Recursively copying public directory.. this may take a while.");
|
|
955
1493
|
const src = path.relative(process.cwd(), options.publicDirectory.path);
|
|
956
|
-
if (
|
|
1494
|
+
if (fs2.existsSync(src) === false) {
|
|
957
1495
|
console.warn("WARNING: Public directory not found, an attempt will be made create it..");
|
|
958
|
-
|
|
1496
|
+
fs2.mkdirSync(src, { recursive: true });
|
|
959
1497
|
}
|
|
960
|
-
await
|
|
1498
|
+
await fs2.promises.cp(src, path.join(DIST_DIR), { recursive: true });
|
|
961
1499
|
}
|
|
962
1500
|
{
|
|
963
|
-
|
|
964
|
-
|
|
1501
|
+
log2(`Took ${Math.round(pagesBuilt - start)}ms to Build Pages.`);
|
|
1502
|
+
log2(`Took ${Math.round(end - pagesBuilt)}ms to Build Client.`);
|
|
1503
|
+
}
|
|
1504
|
+
if (options.server != void 0 && options.server.runServer == true) {
|
|
1505
|
+
startServer({
|
|
1506
|
+
root: options.server.root ?? DIST_DIR,
|
|
1507
|
+
environment: options.environment,
|
|
1508
|
+
port: options.server.port ?? 3e3,
|
|
1509
|
+
host: options.server.host ?? "localhost",
|
|
1510
|
+
DIST_DIR
|
|
1511
|
+
});
|
|
965
1512
|
}
|
|
966
|
-
process.send({ event: "message", data: "
|
|
967
|
-
process.send({ event: "message", data: "compile-finish" });
|
|
1513
|
+
process.send?.({ event: "message", data: "compile-finish" });
|
|
968
1514
|
if (shouldClientHardReload) {
|
|
969
1515
|
process.send({ event: "message", data: "hard-reload" });
|
|
970
1516
|
} else {
|
|
@@ -981,5 +1527,8 @@ var build = async () => {
|
|
|
981
1527
|
await build();
|
|
982
1528
|
})();
|
|
983
1529
|
export {
|
|
1530
|
+
LAYOUT_MAP2 as LAYOUT_MAP,
|
|
1531
|
+
PAGE_MAP,
|
|
1532
|
+
buildDynamicPage,
|
|
984
1533
|
processPageElements
|
|
985
1534
|
};
|