elegance-js 2.1.7 → 2.1.10
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 +49 -60
- package/dist/client/client.mjs +36 -165
- package/dist/client/processPageElements.mjs +7 -7
- package/dist/client/render.mjs +1 -2
- package/dist/client/watcher.mjs +1 -2
- package/dist/compile_docs.mjs +8 -224
- package/dist/components/Link.mjs +3 -51
- package/dist/global.d.ts +4 -1
- package/dist/helpers/ObjectAttributeType.mjs +0 -1
- package/dist/helpers/camelToKebab.mjs +1 -2
- package/dist/index.mjs +3 -215
- package/dist/internal/deprecate.mjs +1 -2
- package/dist/log.mjs +2 -3
- package/dist/page_compiler.d.ts +1 -3
- package/dist/page_compiler.mjs +85 -780
- package/dist/server/generateHTMLTemplate.mjs +2 -194
- package/dist/server/layout.mjs +3 -4
- package/dist/server/loadHook.mjs +5 -11
- package/dist/server/observe.mjs +3 -3
- package/dist/server/render.mjs +3 -149
- package/dist/server/server.mjs +128 -1230
- package/dist/server/state.mjs +13 -34
- package/dist/shared/bindServerElements.mjs +1 -143
- package/dist/shared/serverElements.mjs +8 -9
- package/package.json +2 -2
package/dist/page_compiler.mjs
CHANGED
|
@@ -1,729 +1,56 @@
|
|
|
1
|
-
|
|
2
|
-
import fs2 from "fs";
|
|
1
|
+
import fs from "fs";
|
|
3
2
|
import path from "path";
|
|
3
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = path.dirname(__filename);
|
|
4
5
|
import { registerLoader, setArcTsConfig } from "ts-arc";
|
|
5
|
-
import esbuild from "esbuild";
|
|
6
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
|
-
|
|
8
|
-
// src/shared/serverElements.ts
|
|
9
|
-
var createBuildableElement = (tag) => {
|
|
10
|
-
return (options2, ...children) => ({
|
|
11
|
-
tag,
|
|
12
|
-
options: options2 || {},
|
|
13
|
-
children
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
var createChildrenlessBuildableElement = (tag) => {
|
|
17
|
-
return (options2) => ({
|
|
18
|
-
tag,
|
|
19
|
-
options: options2 || {},
|
|
20
|
-
children: null
|
|
21
|
-
});
|
|
22
|
-
};
|
|
23
|
-
var childrenlessElementTags = [
|
|
24
|
-
"area",
|
|
25
|
-
"base",
|
|
26
|
-
"br",
|
|
27
|
-
"col",
|
|
28
|
-
"embed",
|
|
29
|
-
"hr",
|
|
30
|
-
"img",
|
|
31
|
-
"input",
|
|
32
|
-
"link",
|
|
33
|
-
"meta",
|
|
34
|
-
"source",
|
|
35
|
-
"track",
|
|
36
|
-
"path",
|
|
37
|
-
"rect"
|
|
38
|
-
];
|
|
39
|
-
var elementTags = [
|
|
40
|
-
"a",
|
|
41
|
-
"address",
|
|
42
|
-
"article",
|
|
43
|
-
"aside",
|
|
44
|
-
"audio",
|
|
45
|
-
"blockquote",
|
|
46
|
-
"body",
|
|
47
|
-
"button",
|
|
48
|
-
"canvas",
|
|
49
|
-
"caption",
|
|
50
|
-
"colgroup",
|
|
51
|
-
"data",
|
|
52
|
-
"datalist",
|
|
53
|
-
"dd",
|
|
54
|
-
"del",
|
|
55
|
-
"details",
|
|
56
|
-
"dialog",
|
|
57
|
-
"div",
|
|
58
|
-
"dl",
|
|
59
|
-
"dt",
|
|
60
|
-
"fieldset",
|
|
61
|
-
"figcaption",
|
|
62
|
-
"figure",
|
|
63
|
-
"footer",
|
|
64
|
-
"form",
|
|
65
|
-
"h1",
|
|
66
|
-
"h2",
|
|
67
|
-
"h3",
|
|
68
|
-
"h4",
|
|
69
|
-
"h5",
|
|
70
|
-
"h6",
|
|
71
|
-
"head",
|
|
72
|
-
"header",
|
|
73
|
-
"hgroup",
|
|
74
|
-
"html",
|
|
75
|
-
"iframe",
|
|
76
|
-
"ins",
|
|
77
|
-
"label",
|
|
78
|
-
"legend",
|
|
79
|
-
"li",
|
|
80
|
-
"main",
|
|
81
|
-
"map",
|
|
82
|
-
"meter",
|
|
83
|
-
"nav",
|
|
84
|
-
"noscript",
|
|
85
|
-
"object",
|
|
86
|
-
"ol",
|
|
87
|
-
"optgroup",
|
|
88
|
-
"option",
|
|
89
|
-
"output",
|
|
90
|
-
"p",
|
|
91
|
-
"picture",
|
|
92
|
-
"pre",
|
|
93
|
-
"progress",
|
|
94
|
-
"q",
|
|
95
|
-
"section",
|
|
96
|
-
"select",
|
|
97
|
-
"summary",
|
|
98
|
-
"table",
|
|
99
|
-
"tbody",
|
|
100
|
-
"td",
|
|
101
|
-
"template",
|
|
102
|
-
"textarea",
|
|
103
|
-
"tfoot",
|
|
104
|
-
"th",
|
|
105
|
-
"thead",
|
|
106
|
-
"time",
|
|
107
|
-
"tr",
|
|
108
|
-
"ul",
|
|
109
|
-
"video",
|
|
110
|
-
"span",
|
|
111
|
-
"script",
|
|
112
|
-
"abbr",
|
|
113
|
-
"b",
|
|
114
|
-
"bdi",
|
|
115
|
-
"bdo",
|
|
116
|
-
"cite",
|
|
117
|
-
"code",
|
|
118
|
-
"dfn",
|
|
119
|
-
"em",
|
|
120
|
-
"i",
|
|
121
|
-
"kbd",
|
|
122
|
-
"mark",
|
|
123
|
-
"rp",
|
|
124
|
-
"rt",
|
|
125
|
-
"ruby",
|
|
126
|
-
"s",
|
|
127
|
-
"samp",
|
|
128
|
-
"small",
|
|
129
|
-
"strong",
|
|
130
|
-
"sub",
|
|
131
|
-
"sup",
|
|
132
|
-
"u",
|
|
133
|
-
"wbr",
|
|
134
|
-
"title",
|
|
135
|
-
"svg"
|
|
136
|
-
];
|
|
137
|
-
var elements = {};
|
|
138
|
-
var childrenlessElements = {};
|
|
139
|
-
for (const element of elementTags) {
|
|
140
|
-
elements[element] = createBuildableElement(element);
|
|
141
|
-
}
|
|
142
|
-
for (const element of childrenlessElementTags) {
|
|
143
|
-
childrenlessElements[element] = createChildrenlessBuildableElement(element);
|
|
144
|
-
}
|
|
145
|
-
var allElements = {
|
|
146
|
-
...elements,
|
|
147
|
-
...childrenlessElements
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// src/shared/bindServerElements.ts
|
|
151
|
-
Object.assign(globalThis, elements);
|
|
152
|
-
Object.assign(globalThis, childrenlessElements);
|
|
153
|
-
|
|
154
|
-
// src/server/render.ts
|
|
155
|
-
var renderRecursively = (element) => {
|
|
156
|
-
let returnString = "";
|
|
157
|
-
if (typeof element === "boolean") return returnString;
|
|
158
|
-
else if (typeof element === "number" || typeof element === "string") {
|
|
159
|
-
return returnString + element;
|
|
160
|
-
} else if (Array.isArray(element)) {
|
|
161
|
-
return returnString + element.join(", ");
|
|
162
|
-
}
|
|
163
|
-
returnString += `<${element.tag}`;
|
|
164
|
-
if (typeof element.options === "object") {
|
|
165
|
-
const {
|
|
166
|
-
tag: elementTag,
|
|
167
|
-
options: elementOptions,
|
|
168
|
-
children: elementChildren
|
|
169
|
-
} = element.options;
|
|
170
|
-
if (elementTag !== void 0 && elementOptions !== void 0 && elementChildren !== void 0) {
|
|
171
|
-
const children = element.children;
|
|
172
|
-
element.children = [
|
|
173
|
-
element.options,
|
|
174
|
-
...children
|
|
175
|
-
];
|
|
176
|
-
element.options = {};
|
|
177
|
-
} else {
|
|
178
|
-
for (const [attrName, attrValue] of Object.entries(element.options)) {
|
|
179
|
-
if (typeof attrValue === "object") {
|
|
180
|
-
throw `Attr ${attrName}, for element ${element.tag} has obj type. Got: ${JSON.stringify(element, null, 2)}`;
|
|
181
|
-
}
|
|
182
|
-
returnString += ` ${attrName.toLowerCase()}="${attrValue}"`;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
} else if (typeof element.options !== "object" && element.options !== void 0) {
|
|
186
|
-
element.children = [element.options, ...element.children || []];
|
|
187
|
-
}
|
|
188
|
-
if (element.children === null) {
|
|
189
|
-
returnString += "/>";
|
|
190
|
-
return returnString;
|
|
191
|
-
}
|
|
192
|
-
returnString += ">";
|
|
193
|
-
for (const child of element.children) {
|
|
194
|
-
returnString += renderRecursively(child);
|
|
195
|
-
}
|
|
196
|
-
returnString += `</${element.tag}>`;
|
|
197
|
-
return returnString;
|
|
198
|
-
};
|
|
199
|
-
var serverSideRenderPage = async (page, pathname) => {
|
|
200
|
-
if (!page) {
|
|
201
|
-
throw `No Page Provided.`;
|
|
202
|
-
}
|
|
203
|
-
if (typeof page === "function") {
|
|
204
|
-
throw `Unbuilt page provided to ssr page.`;
|
|
205
|
-
}
|
|
206
|
-
const bodyHTML = renderRecursively(page);
|
|
207
|
-
return {
|
|
208
|
-
bodyHTML
|
|
209
|
-
};
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
// src/server/generateHTMLTemplate.ts
|
|
213
|
-
var generateHTMLTemplate = async ({
|
|
214
|
-
pageURL,
|
|
215
|
-
head: head2,
|
|
216
|
-
serverData = null,
|
|
217
|
-
addPageScriptTag = true,
|
|
218
|
-
name,
|
|
219
|
-
requiredClientModules = {},
|
|
220
|
-
environment
|
|
221
|
-
}) => {
|
|
222
|
-
let StartTemplate = `<meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
223
|
-
if (environment === "production") {
|
|
224
|
-
StartTemplate += `<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">`;
|
|
225
|
-
}
|
|
226
|
-
StartTemplate += '<meta charset="UTF-8">';
|
|
227
|
-
for (const [globalName] of Object.entries(requiredClientModules)) {
|
|
228
|
-
StartTemplate += `<script data-module="true" src="/shipped/${globalName}.js" defer="true"></script>`;
|
|
229
|
-
}
|
|
230
|
-
if (addPageScriptTag === true) {
|
|
231
|
-
const sanitized = pageURL === "" ? "/" : `/${pageURL}`;
|
|
232
|
-
StartTemplate += `<script data-page="true" type="module" data-pathname="${sanitized}" src="${sanitized.endsWith("/") ? sanitized : sanitized + "/"}${name}_data.js" defer="true"></script>`;
|
|
233
|
-
}
|
|
234
|
-
StartTemplate += `<script type="module" src="/client.js" defer="true"></script>`;
|
|
235
|
-
let builtHead;
|
|
236
|
-
if (head2.constructor.name === "AsyncFunction") {
|
|
237
|
-
builtHead = await head2();
|
|
238
|
-
} else {
|
|
239
|
-
builtHead = head2();
|
|
240
|
-
}
|
|
241
|
-
let HTMLTemplate = renderRecursively(builtHead);
|
|
242
|
-
if (serverData) {
|
|
243
|
-
HTMLTemplate += serverData;
|
|
244
|
-
}
|
|
245
|
-
return {
|
|
246
|
-
internals: StartTemplate,
|
|
247
|
-
builtMetadata: HTMLTemplate
|
|
248
|
-
};
|
|
249
|
-
};
|
|
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
|
-
pagesDirectory,
|
|
311
|
-
port = 3e3,
|
|
312
|
-
host = "localhost",
|
|
313
|
-
environment = "production",
|
|
314
|
-
DIST_DIR: DIST_DIR2
|
|
315
|
-
}) {
|
|
316
|
-
if (!root) throw new Error("Root directory must be specified.");
|
|
317
|
-
if (!pagesDirectory) throw new Error("Pages directory must be specified.");
|
|
318
|
-
root = normalize(root).replace(/[\\/]+$/, "");
|
|
319
|
-
pagesDirectory = normalize(pagesDirectory).replace(/[\\/]+$/, "");
|
|
320
|
-
const requestHandler = async (req, res) => {
|
|
321
|
-
try {
|
|
322
|
-
if (!req.url) {
|
|
323
|
-
await sendResponse(req, res, 400, { "Content-Type": "text/plain; charset=utf-8" }, "Bad Request");
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
327
|
-
res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
|
|
328
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
329
|
-
if (req.method === "OPTIONS") {
|
|
330
|
-
res.writeHead(204);
|
|
331
|
-
res.end();
|
|
332
|
-
if (environment === "development") {
|
|
333
|
-
log.info(req.method, "::", req.url, "-", res.statusCode);
|
|
334
|
-
}
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
338
|
-
if (url.pathname.startsWith("/api/")) {
|
|
339
|
-
await handleApiRequest(pagesDirectory, url.pathname, req, res);
|
|
340
|
-
} else if (PAGE_MAP.has(url.pathname)) {
|
|
341
|
-
await handlePageRequest(root, pagesDirectory, url.pathname, req, res, DIST_DIR2, PAGE_MAP.get(url.pathname));
|
|
342
|
-
} else {
|
|
343
|
-
await handleStaticRequest(root, pagesDirectory, url.pathname, req, res, DIST_DIR2);
|
|
344
|
-
}
|
|
345
|
-
if (environment === "development") {
|
|
346
|
-
log.info(req.method, "::", req.url, "-", res.statusCode);
|
|
347
|
-
}
|
|
348
|
-
} catch (err) {
|
|
349
|
-
log.error(err);
|
|
350
|
-
await sendResponse(req, res, 500, { "Content-Type": "text/plain; charset=utf-8" }, "Internal Server Error");
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
function attemptListen(p) {
|
|
354
|
-
const server = createHttpServer(requestHandler);
|
|
355
|
-
server.on("error", (err) => {
|
|
356
|
-
if (err.code === "EADDRINUSE") {
|
|
357
|
-
attemptListen(p + 1);
|
|
358
|
-
} else {
|
|
359
|
-
console.error(err);
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
server.listen(p, host, () => {
|
|
363
|
-
log.info(`Server running at http://${host}:${p}/`);
|
|
364
|
-
});
|
|
365
|
-
return server;
|
|
366
|
-
}
|
|
367
|
-
return attemptListen(port);
|
|
368
|
-
}
|
|
369
|
-
async function getTargetInfo(root, pathname) {
|
|
370
|
-
const originalPathname = pathname;
|
|
371
|
-
const filePath = normalize(join(root, decodeURIComponent(pathname))).replace(/[\\/]+$/, "");
|
|
372
|
-
if (!filePath.startsWith(root)) {
|
|
373
|
-
throw new Error("Forbidden");
|
|
374
|
-
}
|
|
375
|
-
let stats;
|
|
376
|
-
try {
|
|
377
|
-
stats = await fs.stat(filePath);
|
|
378
|
-
} catch {
|
|
379
|
-
}
|
|
380
|
-
let targetDir;
|
|
381
|
-
if (stats) {
|
|
382
|
-
targetDir = stats.isDirectory() ? filePath : dirname(filePath);
|
|
383
|
-
} else {
|
|
384
|
-
targetDir = originalPathname.endsWith("/") ? filePath : dirname(filePath);
|
|
385
|
-
}
|
|
386
|
-
return { filePath, targetDir, stats };
|
|
387
|
-
}
|
|
388
|
-
function getMiddlewareDirs(base, parts) {
|
|
389
|
-
const middlewareDirs = [];
|
|
390
|
-
let current = base;
|
|
391
|
-
middlewareDirs.push(current);
|
|
392
|
-
for (const part of parts) {
|
|
393
|
-
current = join(current, part);
|
|
394
|
-
middlewareDirs.push(current);
|
|
395
|
-
}
|
|
396
|
-
return middlewareDirs;
|
|
397
|
-
}
|
|
398
|
-
async function collectMiddlewares(dirs) {
|
|
399
|
-
const middlewares = [];
|
|
400
|
-
for (const dir of dirs) {
|
|
401
|
-
const mwPath = join(dir, "middleware.ts");
|
|
402
|
-
let mwModule;
|
|
403
|
-
try {
|
|
404
|
-
await fs.access(mwPath);
|
|
405
|
-
const url = pathToFileURL(mwPath).href;
|
|
406
|
-
mwModule = await import(url);
|
|
407
|
-
} catch {
|
|
408
|
-
continue;
|
|
409
|
-
}
|
|
410
|
-
const mwKeys = Object.keys(mwModule).sort();
|
|
411
|
-
for (const key of mwKeys) {
|
|
412
|
-
const f = mwModule[key];
|
|
413
|
-
if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
|
|
414
|
-
middlewares.push(f);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
return middlewares;
|
|
419
|
-
}
|
|
420
|
-
async function handlePageRequest(root, pagesDirectory, pathname, req, res, DIST_DIR2, pageInfo) {
|
|
421
|
-
try {
|
|
422
|
-
const { filePath, targetDir, stats } = await getTargetInfo(root, pathname);
|
|
423
|
-
const relDir = targetDir.slice(root.length).replace(/^[\/\\]+/, "");
|
|
424
|
-
const parts = relDir.split(/[\\/]/).filter(Boolean);
|
|
425
|
-
const middlewareDirs = getMiddlewareDirs(pagesDirectory, parts);
|
|
426
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
427
|
-
let isDynamic = pageInfo.isDynamic;
|
|
428
|
-
const handlerPath = isDynamic ? pageInfo.filePath : join(filePath, "index.html");
|
|
429
|
-
let hasHandler = false;
|
|
430
|
-
try {
|
|
431
|
-
await fs.access(handlerPath);
|
|
432
|
-
hasHandler = true;
|
|
433
|
-
} catch {
|
|
434
|
-
}
|
|
435
|
-
const finalHandler = async (req2, res2) => {
|
|
436
|
-
if (!hasHandler) {
|
|
437
|
-
await respondWithErrorPage(root, pathname, 404, req2, res2);
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
if (isDynamic) {
|
|
441
|
-
try {
|
|
442
|
-
const result = await buildDynamicPage(
|
|
443
|
-
DIST_DIR2,
|
|
444
|
-
pathname,
|
|
445
|
-
pageInfo,
|
|
446
|
-
req2,
|
|
447
|
-
res2
|
|
448
|
-
);
|
|
449
|
-
if (result === false) {
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
const { resultHTML } = result;
|
|
453
|
-
if (resultHTML === false) {
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
await sendResponse(req2, res2, 200, { "Content-Type": MIME_TYPES[".html"] }, resultHTML);
|
|
457
|
-
} catch (err) {
|
|
458
|
-
log.error("Error building dynamic page -", err);
|
|
459
|
-
}
|
|
460
|
-
} else {
|
|
461
|
-
const ext = extname(handlerPath).toLowerCase();
|
|
462
|
-
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
463
|
-
const data = await fs.readFile(handlerPath);
|
|
464
|
-
await sendResponse(req2, res2, 200, { "Content-Type": contentType }, data);
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: false, root, pathname });
|
|
468
|
-
await composed(req, res);
|
|
469
|
-
} catch (err) {
|
|
470
|
-
if (err.message === "Forbidden") {
|
|
471
|
-
await sendResponse(req, res, 403, { "Content-Type": "text/plain; charset=utf-8" }, "Forbidden");
|
|
472
|
-
} else {
|
|
473
|
-
throw err;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
async function handleStaticRequest(root, pagesDirectory, pathname, req, res, DIST_DIR2) {
|
|
478
|
-
try {
|
|
479
|
-
const { filePath, targetDir, stats } = await getTargetInfo(root, pathname);
|
|
480
|
-
const relDir = targetDir.slice(root.length).replace(/^[\/\\]+/, "");
|
|
481
|
-
const parts = relDir.split(/[\\/]/).filter(Boolean);
|
|
482
|
-
const middlewareDirs = getMiddlewareDirs(pagesDirectory, parts);
|
|
483
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
484
|
-
let handlerPath = filePath;
|
|
485
|
-
if (stats && stats.isDirectory()) {
|
|
486
|
-
handlerPath = join(filePath, "index.html");
|
|
487
|
-
} else {
|
|
488
|
-
handlerPath = filePath;
|
|
489
|
-
}
|
|
490
|
-
let hasHandler = false;
|
|
491
|
-
try {
|
|
492
|
-
await fs.access(handlerPath);
|
|
493
|
-
hasHandler = true;
|
|
494
|
-
} catch {
|
|
495
|
-
}
|
|
496
|
-
const finalHandler = async (req2, res2) => {
|
|
497
|
-
if (!hasHandler) {
|
|
498
|
-
await respondWithErrorPage(root, pathname, 404, req2, res2);
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
|
-
const ext = extname(handlerPath).toLowerCase();
|
|
502
|
-
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
503
|
-
const data = await fs.readFile(handlerPath);
|
|
504
|
-
await sendResponse(req2, res2, 200, { "Content-Type": contentType }, data);
|
|
505
|
-
};
|
|
506
|
-
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: false, root, pathname });
|
|
507
|
-
await composed(req, res);
|
|
508
|
-
} catch (err) {
|
|
509
|
-
if (err.message === "Forbidden") {
|
|
510
|
-
await sendResponse(req, res, 403, { "Content-Type": "text/plain; charset=utf-8" }, "Forbidden");
|
|
511
|
-
} else {
|
|
512
|
-
throw err;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
async function handleApiRequest(pagesDirectory, pathname, req, res) {
|
|
517
|
-
const apiSubPath = pathname.slice("/api/".length);
|
|
518
|
-
const parts = apiSubPath.split("/").filter(Boolean);
|
|
519
|
-
const middlewareDirs = getMiddlewareDirs(join(pagesDirectory, "api"), parts);
|
|
520
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
521
|
-
const routeDir = middlewareDirs[middlewareDirs.length - 1];
|
|
522
|
-
const routePath = join(routeDir, "route.ts");
|
|
523
|
-
let hasRoute = false;
|
|
524
|
-
try {
|
|
525
|
-
await fs.access(routePath);
|
|
526
|
-
hasRoute = true;
|
|
527
|
-
} catch {
|
|
528
|
-
}
|
|
529
|
-
let fn = null;
|
|
530
|
-
let module = null;
|
|
531
|
-
if (hasRoute) {
|
|
532
|
-
try {
|
|
533
|
-
const moduleUrl = pathToFileURL(routePath).href;
|
|
534
|
-
module = await import(moduleUrl);
|
|
535
|
-
fn = module[req.method];
|
|
536
|
-
} catch (err) {
|
|
537
|
-
console.error(err);
|
|
538
|
-
return respondWithJsonError(req, res, 500, "Internal Server Error");
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
const finalHandler = async (req2, res2) => {
|
|
542
|
-
if (!hasRoute) {
|
|
543
|
-
return respondWithJsonError(req2, res2, 404, "Not Found");
|
|
544
|
-
}
|
|
545
|
-
if (typeof fn !== "function") {
|
|
546
|
-
return respondWithJsonError(req2, res2, 405, "Method Not Allowed");
|
|
547
|
-
}
|
|
548
|
-
await fn(req2, res2);
|
|
549
|
-
};
|
|
550
|
-
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: true });
|
|
551
|
-
await composed(req, res);
|
|
552
|
-
}
|
|
553
|
-
function composeMiddlewares(mws, final, options2) {
|
|
554
|
-
return async function(req, res) {
|
|
555
|
-
let index = 0;
|
|
556
|
-
async function dispatch(err) {
|
|
557
|
-
if (err) {
|
|
558
|
-
if (options2.isApi) {
|
|
559
|
-
return respondWithJsonError(req, res, 500, err.message || "Internal Server Error");
|
|
560
|
-
} else {
|
|
561
|
-
return await respondWithErrorPage(options2.root, options2.pathname, 500, req, res);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
if (index >= mws.length) {
|
|
565
|
-
return await final(req, res);
|
|
566
|
-
}
|
|
567
|
-
const thisMw = mws[index++];
|
|
568
|
-
const next = (e) => dispatch(e);
|
|
569
|
-
const onceNext = (nextFn) => {
|
|
570
|
-
let called = false;
|
|
571
|
-
return async (e) => {
|
|
572
|
-
if (called) {
|
|
573
|
-
log.warn("next() was called in a middleware more than once.");
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
called = true;
|
|
577
|
-
await nextFn(e);
|
|
578
|
-
};
|
|
579
|
-
};
|
|
580
|
-
try {
|
|
581
|
-
await thisMw(req, res, onceNext(next));
|
|
582
|
-
} catch (error) {
|
|
583
|
-
await dispatch(error);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
await dispatch();
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
async function respondWithJsonError(req, res, code, message) {
|
|
590
|
-
const body2 = JSON.stringify({ error: message });
|
|
591
|
-
await sendResponse(req, res, code, { "Content-Type": "application/json; charset=utf-8" }, body2);
|
|
592
|
-
}
|
|
593
|
-
async function respondWithErrorPage(root, pathname, code, req, res) {
|
|
594
|
-
let currentPath = normalize(join(root, decodeURIComponent(pathname)));
|
|
595
|
-
let tried = /* @__PURE__ */ new Set();
|
|
596
|
-
let errorFilePath = null;
|
|
597
|
-
while (currentPath.startsWith(root)) {
|
|
598
|
-
const candidate = join(currentPath, `${code}.html`);
|
|
599
|
-
if (!tried.has(candidate)) {
|
|
600
|
-
try {
|
|
601
|
-
await fs.access(candidate);
|
|
602
|
-
errorFilePath = candidate;
|
|
603
|
-
break;
|
|
604
|
-
} catch {
|
|
605
|
-
}
|
|
606
|
-
tried.add(candidate);
|
|
607
|
-
}
|
|
608
|
-
const parent = dirname(currentPath);
|
|
609
|
-
if (parent === currentPath) break;
|
|
610
|
-
currentPath = parent;
|
|
611
|
-
}
|
|
612
|
-
if (!errorFilePath) {
|
|
613
|
-
const fallback = join(root, `${code}.html`);
|
|
614
|
-
try {
|
|
615
|
-
await fs.access(fallback);
|
|
616
|
-
errorFilePath = fallback;
|
|
617
|
-
} catch {
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
if (errorFilePath) {
|
|
621
|
-
try {
|
|
622
|
-
const html2 = await fs.readFile(errorFilePath, "utf8");
|
|
623
|
-
await sendResponse(req, res, code, { "Content-Type": "text/html; charset=utf-8" }, html2);
|
|
624
|
-
return;
|
|
625
|
-
} catch {
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
await sendResponse(req, res, code, { "Content-Type": "text/plain; charset=utf-8" }, `${code} Error`);
|
|
629
|
-
}
|
|
630
|
-
function isCompressible(contentType) {
|
|
631
|
-
if (!contentType) return false;
|
|
632
|
-
return /text\/|javascript|json|xml|svg/.test(contentType);
|
|
633
|
-
}
|
|
634
|
-
async function sendResponse(req, res, status, headers, body2) {
|
|
635
|
-
if (typeof body2 === "string") {
|
|
636
|
-
body2 = Buffer.from(body2);
|
|
637
|
-
}
|
|
638
|
-
const accept = req.headers["accept-encoding"] || "";
|
|
639
|
-
let encoding = null;
|
|
640
|
-
if (accept.match(/\bgzip\b/)) {
|
|
641
|
-
encoding = "gzip";
|
|
642
|
-
} else if (accept.match(/\bdeflate\b/)) {
|
|
643
|
-
encoding = "deflate";
|
|
644
|
-
}
|
|
645
|
-
if (!encoding || !isCompressible(headers["Content-Type"] || "")) {
|
|
646
|
-
res.writeHead(status, headers);
|
|
647
|
-
res.end(body2);
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
const compressor = encoding === "gzip" ? gzipAsync : deflateAsync;
|
|
651
|
-
try {
|
|
652
|
-
const compressed = await compressor(body2);
|
|
653
|
-
headers["Content-Encoding"] = encoding;
|
|
654
|
-
headers["Vary"] = "Accept-Encoding";
|
|
655
|
-
res.writeHead(status, headers);
|
|
656
|
-
res.end(compressed);
|
|
657
|
-
} catch (err) {
|
|
658
|
-
log.error("Compression error:", err);
|
|
659
|
-
res.writeHead(status, headers);
|
|
660
|
-
res.end(body2);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
// src/server/loadHook.ts
|
|
665
|
-
var resetLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__ = [];
|
|
666
|
-
var getLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__;
|
|
667
|
-
|
|
668
|
-
// src/server/state.ts
|
|
669
|
-
if (!globalThis.__SERVER_CURRENT_STATE_ID__) {
|
|
670
|
-
globalThis.__SERVER_CURRENT_STATE_ID__ = 1;
|
|
671
|
-
}
|
|
672
|
-
var initializeState = () => globalThis.__SERVER_CURRENT_STATE__ = [];
|
|
673
|
-
var getState = () => {
|
|
674
|
-
return globalThis.__SERVER_CURRENT_STATE__;
|
|
675
|
-
};
|
|
676
|
-
var initializeObjectAttributes = () => globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__ = [];
|
|
677
|
-
var getObjectAttributes = () => {
|
|
678
|
-
return globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__;
|
|
679
|
-
};
|
|
680
|
-
|
|
681
|
-
// src/server/layout.ts
|
|
682
|
-
var resetLayouts = () => globalThis.__SERVER_CURRENT_LAYOUTS__ = /* @__PURE__ */ new Map();
|
|
683
|
-
if (!globalThis.__SERVER_CURRENT_LAYOUT_ID__) globalThis.__SERVER_CURRENT_LAYOUT_ID__ = 1;
|
|
684
|
-
|
|
685
|
-
// src/page_compiler.ts
|
|
686
|
-
var __filename = fileURLToPath2(import.meta.url);
|
|
687
|
-
var __dirname = path.dirname(__filename);
|
|
688
6
|
setArcTsConfig(__dirname);
|
|
689
7
|
registerLoader();
|
|
690
|
-
|
|
8
|
+
import esbuild from "esbuild";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
import { generateHTMLTemplate } from "./server/generateHTMLTemplate";
|
|
11
|
+
import { ObjectAttributeType } from "./helpers/ObjectAttributeType";
|
|
12
|
+
import { serverSideRenderPage } from "./server/render";
|
|
13
|
+
import { getState, initializeState, initializeObjectAttributes, getObjectAttributes } from "./server/state";
|
|
14
|
+
import { getLoadHooks, resetLoadHooks } from "./server/loadHook";
|
|
15
|
+
import { resetLayouts } from "./server/layout";
|
|
16
|
+
import { renderRecursively } from "./server/render";
|
|
17
|
+
let packageDir = process.env.PACKAGE_PATH;
|
|
691
18
|
if (packageDir === void 0) {
|
|
692
19
|
packageDir = path.resolve(__dirname, "..");
|
|
693
20
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
21
|
+
const clientPath = path.resolve(packageDir, "./dist/client/client.mjs");
|
|
22
|
+
const watcherPath = path.resolve(packageDir, "./dist/client/watcher.mjs");
|
|
23
|
+
const shippedModules = /* @__PURE__ */ new Map();
|
|
24
|
+
let modulesToShip = [];
|
|
25
|
+
const yellow = (text) => {
|
|
699
26
|
return `\x1B[38;2;238;184;68m${text}`;
|
|
700
27
|
};
|
|
701
|
-
|
|
28
|
+
const black = (text) => {
|
|
702
29
|
return `\x1B[38;2;0;0;0m${text}`;
|
|
703
30
|
};
|
|
704
|
-
|
|
31
|
+
const bgYellow = (text) => {
|
|
705
32
|
return `\x1B[48;2;238;184;68m${text}`;
|
|
706
33
|
};
|
|
707
|
-
|
|
34
|
+
const bold = (text) => {
|
|
708
35
|
return `\x1B[1m${text}`;
|
|
709
36
|
};
|
|
710
|
-
|
|
37
|
+
const underline = (text) => {
|
|
711
38
|
return `\x1B[4m${text}`;
|
|
712
39
|
};
|
|
713
|
-
|
|
40
|
+
const white = (text) => {
|
|
714
41
|
return `\x1B[38;2;255;247;229m${text}`;
|
|
715
42
|
};
|
|
716
|
-
|
|
43
|
+
const log = (...text) => {
|
|
717
44
|
if (options.quiet) return;
|
|
718
45
|
return console.log(text.map((text2) => `${text2}\x1B[0m`).join(""));
|
|
719
46
|
};
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
47
|
+
let options = JSON.parse(process.env.OPTIONS || "{}");
|
|
48
|
+
const DIST_DIR = process.env.DIST_DIR;
|
|
49
|
+
const PAGE_MAP = /* @__PURE__ */ new Map();
|
|
50
|
+
const LAYOUT_MAP = /* @__PURE__ */ new Map();
|
|
51
|
+
const getAllSubdirectories = (dir, baseDir = dir) => {
|
|
725
52
|
let directories = [];
|
|
726
|
-
const items =
|
|
53
|
+
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
727
54
|
for (const item of items) {
|
|
728
55
|
if (item.isDirectory()) {
|
|
729
56
|
const fullPath = path.join(dir, item.name);
|
|
@@ -734,12 +61,12 @@ var getAllSubdirectories = (dir, baseDir = dir) => {
|
|
|
734
61
|
}
|
|
735
62
|
return directories;
|
|
736
63
|
};
|
|
737
|
-
|
|
64
|
+
const buildClient = async (DIST_DIR2) => {
|
|
738
65
|
let clientString = "window.__name = (func) => func; ";
|
|
739
|
-
clientString +=
|
|
66
|
+
clientString += fs.readFileSync(clientPath, "utf-8");
|
|
740
67
|
if (options.hotReload !== void 0) {
|
|
741
68
|
clientString += `const watchServerPort = ${options.hotReload.port}`;
|
|
742
|
-
clientString +=
|
|
69
|
+
clientString += fs.readFileSync(watcherPath, "utf-8");
|
|
743
70
|
}
|
|
744
71
|
const transformedClient = await esbuild.transform(clientString, {
|
|
745
72
|
minify: options.environment === "production",
|
|
@@ -749,13 +76,13 @@ var buildClient = async (DIST_DIR2) => {
|
|
|
749
76
|
platform: "node",
|
|
750
77
|
loader: "ts"
|
|
751
78
|
});
|
|
752
|
-
|
|
79
|
+
fs.writeFileSync(
|
|
753
80
|
path.join(DIST_DIR2, "/client.js"),
|
|
754
81
|
transformedClient.code
|
|
755
82
|
);
|
|
756
83
|
};
|
|
757
|
-
|
|
758
|
-
|
|
84
|
+
let elementKey = 0;
|
|
85
|
+
const processOptionAsObjectAttribute = (element, optionName, optionValue, objectAttributes) => {
|
|
759
86
|
const lcOptionName = optionName.toLowerCase();
|
|
760
87
|
const options2 = element.options;
|
|
761
88
|
let key = options2.key;
|
|
@@ -768,7 +95,7 @@ var processOptionAsObjectAttribute = (element, optionName, optionValue, objectAt
|
|
|
768
95
|
}
|
|
769
96
|
let optionFinal = lcOptionName;
|
|
770
97
|
switch (optionValue.type) {
|
|
771
|
-
case
|
|
98
|
+
case ObjectAttributeType.STATE:
|
|
772
99
|
const SOA = optionValue;
|
|
773
100
|
if (typeof SOA.value === "function") {
|
|
774
101
|
delete options2[optionName];
|
|
@@ -782,7 +109,7 @@ var processOptionAsObjectAttribute = (element, optionName, optionValue, objectAt
|
|
|
782
109
|
options2[lcOptionName] = SOA.value;
|
|
783
110
|
}
|
|
784
111
|
break;
|
|
785
|
-
case
|
|
112
|
+
case ObjectAttributeType.OBSERVER:
|
|
786
113
|
const OOA = optionValue;
|
|
787
114
|
const firstValue = OOA.update(...OOA.initialValues);
|
|
788
115
|
if (lcOptionName === "innertext" || lcOptionName === "innerhtml") {
|
|
@@ -794,7 +121,7 @@ var processOptionAsObjectAttribute = (element, optionName, optionValue, objectAt
|
|
|
794
121
|
}
|
|
795
122
|
optionFinal = optionName;
|
|
796
123
|
break;
|
|
797
|
-
case
|
|
124
|
+
case ObjectAttributeType.REFERENCE:
|
|
798
125
|
options2["ref"] = optionValue.value;
|
|
799
126
|
break;
|
|
800
127
|
}
|
|
@@ -835,7 +162,7 @@ function buildTrace(stack, indent = 4) {
|
|
|
835
162
|
return "Could not build stack-trace.";
|
|
836
163
|
}
|
|
837
164
|
}
|
|
838
|
-
|
|
165
|
+
const processPageElements = (element, objectAttributes, recursionLevel, stack = []) => {
|
|
839
166
|
stack.push(element);
|
|
840
167
|
try {
|
|
841
168
|
if (typeof element === "boolean" || typeof element === "number" || Array.isArray(element)) {
|
|
@@ -928,7 +255,7 @@ ${trace}`);
|
|
|
928
255
|
}
|
|
929
256
|
}
|
|
930
257
|
};
|
|
931
|
-
|
|
258
|
+
const pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageName, doWrite = true, requiredClientModules = {}, layout, pathname = "") => {
|
|
932
259
|
if (typeof pageElements === "string" || typeof pageElements === "boolean" || typeof pageElements === "number" || Array.isArray(pageElements)) {
|
|
933
260
|
throw new Error(`The root element of a page / layout must be a built element, not just a Child. Received: ${typeof pageElements}.`);
|
|
934
261
|
}
|
|
@@ -988,11 +315,11 @@ var pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageNam
|
|
|
988
315
|
const resultHTML = `${headHTML}${bodyHTML}`;
|
|
989
316
|
const htmlLocation = path.join(pageLocation, (pageName === "page" ? "index" : pageName) + ".html");
|
|
990
317
|
if (doWrite) {
|
|
991
|
-
const
|
|
992
|
-
if (
|
|
993
|
-
|
|
318
|
+
const dirname = path.dirname(htmlLocation);
|
|
319
|
+
if (fs.existsSync(dirname) === false) {
|
|
320
|
+
fs.mkdirSync(dirname, { recursive: true });
|
|
994
321
|
}
|
|
995
|
-
|
|
322
|
+
fs.writeFileSync(
|
|
996
323
|
htmlLocation,
|
|
997
324
|
resultHTML,
|
|
998
325
|
{
|
|
@@ -1004,7 +331,7 @@ var pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageNam
|
|
|
1004
331
|
}
|
|
1005
332
|
return resultHTML;
|
|
1006
333
|
};
|
|
1007
|
-
|
|
334
|
+
const generateClientPageData = async (pageLocation, state, objectAttributes, pageLoadHooks, DIST_DIR2, pageName, globalVariableName = "pd", write = true) => {
|
|
1008
335
|
let clientPageJSText = "";
|
|
1009
336
|
{
|
|
1010
337
|
clientPageJSText += `${globalThis.__SERVER_PAGE_DATA_BANNER__}`;
|
|
@@ -1025,7 +352,7 @@ var generateClientPageData = async (pageLocation, state, objectAttributes, pageL
|
|
|
1025
352
|
}
|
|
1026
353
|
clientPageJSText += `],`;
|
|
1027
354
|
}
|
|
1028
|
-
const stateObjectAttributes = objectAttributes.filter((oa) => oa.type ===
|
|
355
|
+
const stateObjectAttributes = objectAttributes.filter((oa) => oa.type === ObjectAttributeType.STATE);
|
|
1029
356
|
if (stateObjectAttributes.length > 0) {
|
|
1030
357
|
const processed = [...stateObjectAttributes].map((soa) => {
|
|
1031
358
|
delete soa.type;
|
|
@@ -1033,7 +360,7 @@ var generateClientPageData = async (pageLocation, state, objectAttributes, pageL
|
|
|
1033
360
|
});
|
|
1034
361
|
clientPageJSText += `soa:${JSON.stringify(processed)},`;
|
|
1035
362
|
}
|
|
1036
|
-
const observerObjectAttributes = objectAttributes.filter((oa) => oa.type ===
|
|
363
|
+
const observerObjectAttributes = objectAttributes.filter((oa) => oa.type === ObjectAttributeType.OBSERVER);
|
|
1037
364
|
if (observerObjectAttributes.length > 0) {
|
|
1038
365
|
let observerObjectAttributeString = "ooa:[";
|
|
1039
366
|
for (const observerObjectAttribute of observerObjectAttributes) {
|
|
@@ -1050,8 +377,8 @@ var generateClientPageData = async (pageLocation, state, objectAttributes, pageL
|
|
|
1050
377
|
}
|
|
1051
378
|
if (pageLoadHooks.length > 0) {
|
|
1052
379
|
clientPageJSText += "lh:[";
|
|
1053
|
-
for (const
|
|
1054
|
-
clientPageJSText += `{fn:${
|
|
380
|
+
for (const loadHook of pageLoadHooks) {
|
|
381
|
+
clientPageJSText += `{fn:${loadHook.fn}},`;
|
|
1055
382
|
}
|
|
1056
383
|
clientPageJSText += "],";
|
|
1057
384
|
}
|
|
@@ -1063,16 +390,16 @@ var generateClientPageData = async (pageLocation, state, objectAttributes, pageL
|
|
|
1063
390
|
console.error("Failed to transform client page js!", error);
|
|
1064
391
|
});
|
|
1065
392
|
if (!transformedResult) return { sendHardReloadInstruction };
|
|
1066
|
-
if (
|
|
1067
|
-
const content =
|
|
393
|
+
if (fs.existsSync(pageDataPath)) {
|
|
394
|
+
const content = fs.readFileSync(pageDataPath).toString();
|
|
1068
395
|
if (content !== transformedResult.code) {
|
|
1069
396
|
sendHardReloadInstruction = true;
|
|
1070
397
|
}
|
|
1071
398
|
}
|
|
1072
|
-
if (write)
|
|
399
|
+
if (write) fs.writeFileSync(pageDataPath, transformedResult.code, "utf-8");
|
|
1073
400
|
return { sendHardReloadInstruction, result: transformedResult.code };
|
|
1074
401
|
};
|
|
1075
|
-
|
|
402
|
+
const generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, generateDynamic = false) => {
|
|
1076
403
|
initializeState();
|
|
1077
404
|
initializeObjectAttributes();
|
|
1078
405
|
resetLoadHooks();
|
|
@@ -1099,7 +426,7 @@ var generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, gene
|
|
|
1099
426
|
} catch (e) {
|
|
1100
427
|
throw new Error(`Error in Page: ${directory === "" ? "/" : directory}layout.ts - ${e}`);
|
|
1101
428
|
}
|
|
1102
|
-
|
|
429
|
+
LAYOUT_MAP.set(directory === "" ? "/" : `/${directory}`, {
|
|
1103
430
|
isDynamic: isDynamicLayout,
|
|
1104
431
|
filePath
|
|
1105
432
|
});
|
|
@@ -1153,14 +480,14 @@ var generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, gene
|
|
|
1153
480
|
);
|
|
1154
481
|
return { pageContentHTML: renderedPage.bodyHTML, metadataHTML };
|
|
1155
482
|
};
|
|
1156
|
-
|
|
1157
|
-
|
|
483
|
+
const builtLayouts = /* @__PURE__ */ new Map();
|
|
484
|
+
const buildLayouts = async () => {
|
|
1158
485
|
const pagesDirectory = path.resolve(options.pagesDirectory);
|
|
1159
486
|
const subdirectories = [...getAllSubdirectories(pagesDirectory), ""];
|
|
1160
487
|
let shouldClientHardReload = false;
|
|
1161
488
|
for (const directory of subdirectories) {
|
|
1162
489
|
const abs = path.resolve(path.join(pagesDirectory, directory));
|
|
1163
|
-
const files =
|
|
490
|
+
const files = fs.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
|
|
1164
491
|
for (const file of files) {
|
|
1165
492
|
const filePath = path.join(file.parentPath, file.name);
|
|
1166
493
|
const name = file.name.slice(0, file.name.length - 3);
|
|
@@ -1180,7 +507,7 @@ var buildLayouts = async () => {
|
|
|
1180
507
|
}
|
|
1181
508
|
return { shouldClientHardReload };
|
|
1182
509
|
};
|
|
1183
|
-
|
|
510
|
+
const buildLayout = async (filePath, directory, generateDynamic = false) => {
|
|
1184
511
|
const id = globalThis.__SERVER_CURRENT_STATE_ID__ += 1;
|
|
1185
512
|
const childIndicator = `<template layout-id="${id}"></template>`;
|
|
1186
513
|
const result = await generateLayout(
|
|
@@ -1215,16 +542,16 @@ var buildLayout = async (filePath, directory, generateDynamic = false) => {
|
|
|
1215
542
|
scriptTag: `<script data-layout="true" type="module" src="${pathname}layout_data.js" data-pathname="${pathname}" defer="true"></script>`
|
|
1216
543
|
};
|
|
1217
544
|
};
|
|
1218
|
-
|
|
1219
|
-
const
|
|
1220
|
-
let split =
|
|
545
|
+
const fetchPageLayoutHTML = async (dirname) => {
|
|
546
|
+
const relative = path.relative(options.pagesDirectory, dirname);
|
|
547
|
+
let split = relative.split(path.sep).filter(Boolean);
|
|
1221
548
|
split.push("/");
|
|
1222
549
|
split.reverse();
|
|
1223
550
|
let layouts = [];
|
|
1224
551
|
for (const dir of split) {
|
|
1225
|
-
if (
|
|
552
|
+
if (LAYOUT_MAP.has(dir)) {
|
|
1226
553
|
const filePath = path.join(path.resolve(options.pagesDirectory), dir, "layout.ts");
|
|
1227
|
-
const layout =
|
|
554
|
+
const layout = LAYOUT_MAP.get(dir);
|
|
1228
555
|
if (layout.isDynamic) {
|
|
1229
556
|
const builtLayout = await buildLayout(layout.filePath, dir, true);
|
|
1230
557
|
if (!builtLayout) continue;
|
|
@@ -1252,14 +579,14 @@ var fetchPageLayoutHTML = async (dirname2) => {
|
|
|
1252
579
|
}
|
|
1253
580
|
return { pageContent, metadata, scriptTag: scriptTags };
|
|
1254
581
|
};
|
|
1255
|
-
|
|
582
|
+
const buildPages = async (DIST_DIR2) => {
|
|
1256
583
|
resetLayouts();
|
|
1257
584
|
const pagesDirectory = path.resolve(options.pagesDirectory);
|
|
1258
585
|
const subdirectories = [...getAllSubdirectories(pagesDirectory), ""];
|
|
1259
586
|
let shouldClientHardReload = false;
|
|
1260
587
|
for (const directory of subdirectories) {
|
|
1261
588
|
const abs = path.resolve(path.join(pagesDirectory, directory));
|
|
1262
|
-
const files =
|
|
589
|
+
const files = fs.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
|
|
1263
590
|
for (const file of files) {
|
|
1264
591
|
const filePath = path.join(file.parentPath, file.name);
|
|
1265
592
|
const name = file.name.slice(0, file.name.length - 3);
|
|
@@ -1282,7 +609,7 @@ var buildPages = async (DIST_DIR2) => {
|
|
|
1282
609
|
shouldClientHardReload
|
|
1283
610
|
};
|
|
1284
611
|
};
|
|
1285
|
-
|
|
612
|
+
const buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
1286
613
|
initializeState();
|
|
1287
614
|
initializeObjectAttributes();
|
|
1288
615
|
resetLoadHooks();
|
|
@@ -1331,7 +658,8 @@ var buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
|
1331
658
|
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
1332
659
|
}
|
|
1333
660
|
const pageProps = {
|
|
1334
|
-
pageName: directory
|
|
661
|
+
pageName: directory,
|
|
662
|
+
middlewareData: {}
|
|
1335
663
|
};
|
|
1336
664
|
if (typeof pageElements === "function") {
|
|
1337
665
|
if (pageElements.constructor.name === "AsyncFunction") {
|
|
@@ -1367,7 +695,7 @@ var buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
|
1367
695
|
);
|
|
1368
696
|
return sendHardReloadInstruction === true;
|
|
1369
697
|
};
|
|
1370
|
-
|
|
698
|
+
const buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res, middlewareData) => {
|
|
1371
699
|
directory = directory === "/" ? "" : directory;
|
|
1372
700
|
const filePath = pageInfo.filePath;
|
|
1373
701
|
initializeState();
|
|
@@ -1378,12 +706,10 @@ var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res) => {
|
|
|
1378
706
|
let metadata = async (props) => html();
|
|
1379
707
|
let modules = {};
|
|
1380
708
|
let pageIgnoresLayout = false;
|
|
1381
|
-
let isDynamicPage = false;
|
|
1382
709
|
try {
|
|
1383
710
|
const {
|
|
1384
711
|
page,
|
|
1385
712
|
metadata: pageMetadata,
|
|
1386
|
-
isDynamic,
|
|
1387
713
|
shippedModules: shippedModules2,
|
|
1388
714
|
ignoreLayout,
|
|
1389
715
|
requestHook
|
|
@@ -1403,9 +729,6 @@ var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res) => {
|
|
|
1403
729
|
}
|
|
1404
730
|
pageElements = page;
|
|
1405
731
|
metadata = pageMetadata;
|
|
1406
|
-
if (isDynamic === true) {
|
|
1407
|
-
isDynamicPage = isDynamic;
|
|
1408
|
-
}
|
|
1409
732
|
} catch (e) {
|
|
1410
733
|
throw new Error(`Error in Page: ${directory}/page.ts - ${e}`);
|
|
1411
734
|
}
|
|
@@ -1421,7 +744,8 @@ var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res) => {
|
|
|
1421
744
|
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
1422
745
|
}
|
|
1423
746
|
const pageProps = {
|
|
1424
|
-
pageName: directory
|
|
747
|
+
pageName: directory,
|
|
748
|
+
middlewareData
|
|
1425
749
|
};
|
|
1426
750
|
if (typeof pageElements === "function") {
|
|
1427
751
|
if (pageElements.constructor.name === "AsyncFunction") {
|
|
@@ -1445,7 +769,7 @@ var buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res) => {
|
|
|
1445
769
|
await shipModules();
|
|
1446
770
|
return { resultHTML };
|
|
1447
771
|
};
|
|
1448
|
-
|
|
772
|
+
const shipModules = async () => {
|
|
1449
773
|
for (const plugin of modulesToShip) {
|
|
1450
774
|
{
|
|
1451
775
|
if (shippedModules.has(plugin.globalName)) continue;
|
|
@@ -1464,20 +788,12 @@ var shipModules = async () => {
|
|
|
1464
788
|
}
|
|
1465
789
|
modulesToShip = [];
|
|
1466
790
|
};
|
|
1467
|
-
|
|
1468
|
-
if (options.quiet === true) {
|
|
1469
|
-
console.log = function() {
|
|
1470
|
-
};
|
|
1471
|
-
console.error = function() {
|
|
1472
|
-
};
|
|
1473
|
-
console.warn = function() {
|
|
1474
|
-
};
|
|
1475
|
-
}
|
|
791
|
+
const build = async () => {
|
|
1476
792
|
try {
|
|
1477
793
|
{
|
|
1478
|
-
|
|
794
|
+
log(bold(yellow(" -- Elegance.JS -- ")));
|
|
1479
795
|
if (options.environment === "production") {
|
|
1480
|
-
|
|
796
|
+
log(
|
|
1481
797
|
" - ",
|
|
1482
798
|
bgYellow(bold(black(" NOTE "))),
|
|
1483
799
|
" : ",
|
|
@@ -1485,7 +801,7 @@ var build = async () => {
|
|
|
1485
801
|
underline("console.log() "),
|
|
1486
802
|
white("statements will be shown on the client, and all code will be minified.")
|
|
1487
803
|
);
|
|
1488
|
-
|
|
804
|
+
log("");
|
|
1489
805
|
}
|
|
1490
806
|
}
|
|
1491
807
|
if (options.preCompile) {
|
|
@@ -1506,28 +822,19 @@ var build = async () => {
|
|
|
1506
822
|
await buildClient(DIST_DIR);
|
|
1507
823
|
const end = performance.now();
|
|
1508
824
|
if (options.publicDirectory) {
|
|
1509
|
-
|
|
825
|
+
log("Recursively copying public directory.. this may take a while.");
|
|
1510
826
|
const src = path.relative(process.cwd(), options.publicDirectory.path);
|
|
1511
|
-
if (
|
|
827
|
+
if (fs.existsSync(src) === false) {
|
|
1512
828
|
console.warn("WARNING: Public directory not found, an attempt will be made create it..");
|
|
1513
|
-
|
|
829
|
+
fs.mkdirSync(src, { recursive: true });
|
|
1514
830
|
}
|
|
1515
|
-
await
|
|
831
|
+
await fs.promises.cp(src, path.join(DIST_DIR), { recursive: true });
|
|
1516
832
|
}
|
|
1517
833
|
{
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
}
|
|
1521
|
-
if (options.server != void 0 && options.server.runServer == true) {
|
|
1522
|
-
startServer({
|
|
1523
|
-
root: options.server.root ?? DIST_DIR,
|
|
1524
|
-
environment: options.environment,
|
|
1525
|
-
port: options.server.port ?? 3e3,
|
|
1526
|
-
host: options.server.host ?? "localhost",
|
|
1527
|
-
DIST_DIR,
|
|
1528
|
-
pagesDirectory: options.pagesDirectory
|
|
1529
|
-
});
|
|
834
|
+
log(`Took ${Math.round(pagesBuilt - start)}ms to Build Pages.`);
|
|
835
|
+
log(`Took ${Math.round(end - pagesBuilt)}ms to Build Client.`);
|
|
1530
836
|
}
|
|
837
|
+
process.send?.({ event: "message", data: "set-pages-and-layouts", content: JSON.stringify({ pageMap: Array.from(PAGE_MAP), layoutMap: Array.from(LAYOUT_MAP) }) });
|
|
1531
838
|
process.send?.({ event: "message", data: "compile-finish" });
|
|
1532
839
|
if (shouldClientHardReload) {
|
|
1533
840
|
process.send({ event: "message", data: "hard-reload" });
|
|
@@ -1542,11 +849,9 @@ var build = async () => {
|
|
|
1542
849
|
return true;
|
|
1543
850
|
};
|
|
1544
851
|
(async () => {
|
|
1545
|
-
await build();
|
|
852
|
+
if (process.env.DO_BUILD === "true") await build();
|
|
1546
853
|
})();
|
|
1547
854
|
export {
|
|
1548
|
-
LAYOUT_MAP2 as LAYOUT_MAP,
|
|
1549
|
-
PAGE_MAP,
|
|
1550
855
|
buildDynamicPage,
|
|
1551
856
|
processPageElements
|
|
1552
857
|
};
|