elegance-js 2.1.9 → 2.1.11
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 +72 -1763
- 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 -1902
- package/dist/components/Link.mjs +3 -51
- 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.mjs +51 -320
- 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 +38 -1290
- package/dist/server/state.mjs +13 -34
- package/dist/shared/bindServerElements.mjs +1 -143
- package/dist/shared/serverElements.mjs +8 -9
- package/package.json +3 -3
package/dist/build.mjs
CHANGED
|
@@ -1,1740 +1,49 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __esm = (fn, res) => function __init() {
|
|
4
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
-
};
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
// src/shared/serverElements.ts
|
|
12
|
-
var createBuildableElement, createChildrenlessBuildableElement, childrenlessElementTags, elementTags, elements, childrenlessElements, allElements;
|
|
13
|
-
var init_serverElements = __esm({
|
|
14
|
-
"src/shared/serverElements.ts"() {
|
|
15
|
-
"use strict";
|
|
16
|
-
createBuildableElement = (tag) => {
|
|
17
|
-
return (options3, ...children) => ({
|
|
18
|
-
tag,
|
|
19
|
-
options: options3 || {},
|
|
20
|
-
children
|
|
21
|
-
});
|
|
22
|
-
};
|
|
23
|
-
createChildrenlessBuildableElement = (tag) => {
|
|
24
|
-
return (options3) => ({
|
|
25
|
-
tag,
|
|
26
|
-
options: options3 || {},
|
|
27
|
-
children: null
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
childrenlessElementTags = [
|
|
31
|
-
"area",
|
|
32
|
-
"base",
|
|
33
|
-
"br",
|
|
34
|
-
"col",
|
|
35
|
-
"embed",
|
|
36
|
-
"hr",
|
|
37
|
-
"img",
|
|
38
|
-
"input",
|
|
39
|
-
"link",
|
|
40
|
-
"meta",
|
|
41
|
-
"source",
|
|
42
|
-
"track",
|
|
43
|
-
"path",
|
|
44
|
-
"rect"
|
|
45
|
-
];
|
|
46
|
-
elementTags = [
|
|
47
|
-
"a",
|
|
48
|
-
"address",
|
|
49
|
-
"article",
|
|
50
|
-
"aside",
|
|
51
|
-
"audio",
|
|
52
|
-
"blockquote",
|
|
53
|
-
"body",
|
|
54
|
-
"button",
|
|
55
|
-
"canvas",
|
|
56
|
-
"caption",
|
|
57
|
-
"colgroup",
|
|
58
|
-
"data",
|
|
59
|
-
"datalist",
|
|
60
|
-
"dd",
|
|
61
|
-
"del",
|
|
62
|
-
"details",
|
|
63
|
-
"dialog",
|
|
64
|
-
"div",
|
|
65
|
-
"dl",
|
|
66
|
-
"dt",
|
|
67
|
-
"fieldset",
|
|
68
|
-
"figcaption",
|
|
69
|
-
"figure",
|
|
70
|
-
"footer",
|
|
71
|
-
"form",
|
|
72
|
-
"h1",
|
|
73
|
-
"h2",
|
|
74
|
-
"h3",
|
|
75
|
-
"h4",
|
|
76
|
-
"h5",
|
|
77
|
-
"h6",
|
|
78
|
-
"head",
|
|
79
|
-
"header",
|
|
80
|
-
"hgroup",
|
|
81
|
-
"html",
|
|
82
|
-
"iframe",
|
|
83
|
-
"ins",
|
|
84
|
-
"label",
|
|
85
|
-
"legend",
|
|
86
|
-
"li",
|
|
87
|
-
"main",
|
|
88
|
-
"map",
|
|
89
|
-
"meter",
|
|
90
|
-
"nav",
|
|
91
|
-
"noscript",
|
|
92
|
-
"object",
|
|
93
|
-
"ol",
|
|
94
|
-
"optgroup",
|
|
95
|
-
"option",
|
|
96
|
-
"output",
|
|
97
|
-
"p",
|
|
98
|
-
"picture",
|
|
99
|
-
"pre",
|
|
100
|
-
"progress",
|
|
101
|
-
"q",
|
|
102
|
-
"section",
|
|
103
|
-
"select",
|
|
104
|
-
"summary",
|
|
105
|
-
"table",
|
|
106
|
-
"tbody",
|
|
107
|
-
"td",
|
|
108
|
-
"template",
|
|
109
|
-
"textarea",
|
|
110
|
-
"tfoot",
|
|
111
|
-
"th",
|
|
112
|
-
"thead",
|
|
113
|
-
"time",
|
|
114
|
-
"tr",
|
|
115
|
-
"ul",
|
|
116
|
-
"video",
|
|
117
|
-
"span",
|
|
118
|
-
"script",
|
|
119
|
-
"abbr",
|
|
120
|
-
"b",
|
|
121
|
-
"bdi",
|
|
122
|
-
"bdo",
|
|
123
|
-
"cite",
|
|
124
|
-
"code",
|
|
125
|
-
"dfn",
|
|
126
|
-
"em",
|
|
127
|
-
"i",
|
|
128
|
-
"kbd",
|
|
129
|
-
"mark",
|
|
130
|
-
"rp",
|
|
131
|
-
"rt",
|
|
132
|
-
"ruby",
|
|
133
|
-
"s",
|
|
134
|
-
"samp",
|
|
135
|
-
"small",
|
|
136
|
-
"strong",
|
|
137
|
-
"sub",
|
|
138
|
-
"sup",
|
|
139
|
-
"u",
|
|
140
|
-
"wbr",
|
|
141
|
-
"title",
|
|
142
|
-
"svg"
|
|
143
|
-
];
|
|
144
|
-
elements = {};
|
|
145
|
-
childrenlessElements = {};
|
|
146
|
-
for (const element of elementTags) {
|
|
147
|
-
elements[element] = createBuildableElement(element);
|
|
148
|
-
}
|
|
149
|
-
for (const element of childrenlessElementTags) {
|
|
150
|
-
childrenlessElements[element] = createChildrenlessBuildableElement(element);
|
|
151
|
-
}
|
|
152
|
-
allElements = {
|
|
153
|
-
...elements,
|
|
154
|
-
...childrenlessElements
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
// src/shared/bindServerElements.ts
|
|
160
|
-
var init_bindServerElements = __esm({
|
|
161
|
-
"src/shared/bindServerElements.ts"() {
|
|
162
|
-
"use strict";
|
|
163
|
-
init_serverElements();
|
|
164
|
-
Object.assign(globalThis, elements);
|
|
165
|
-
Object.assign(globalThis, childrenlessElements);
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// src/server/render.ts
|
|
170
|
-
var renderRecursively, serverSideRenderPage;
|
|
171
|
-
var init_render = __esm({
|
|
172
|
-
"src/server/render.ts"() {
|
|
173
|
-
"use strict";
|
|
174
|
-
init_bindServerElements();
|
|
175
|
-
renderRecursively = (element) => {
|
|
176
|
-
let returnString = "";
|
|
177
|
-
if (typeof element === "boolean") return returnString;
|
|
178
|
-
else if (typeof element === "number" || typeof element === "string") {
|
|
179
|
-
return returnString + element;
|
|
180
|
-
} else if (Array.isArray(element)) {
|
|
181
|
-
return returnString + element.join(", ");
|
|
182
|
-
}
|
|
183
|
-
returnString += `<${element.tag}`;
|
|
184
|
-
if (typeof element.options === "object") {
|
|
185
|
-
const {
|
|
186
|
-
tag: elementTag,
|
|
187
|
-
options: elementOptions,
|
|
188
|
-
children: elementChildren
|
|
189
|
-
} = element.options;
|
|
190
|
-
if (elementTag !== void 0 && elementOptions !== void 0 && elementChildren !== void 0) {
|
|
191
|
-
const children = element.children;
|
|
192
|
-
element.children = [
|
|
193
|
-
element.options,
|
|
194
|
-
...children
|
|
195
|
-
];
|
|
196
|
-
element.options = {};
|
|
197
|
-
} else {
|
|
198
|
-
for (const [attrName, attrValue] of Object.entries(element.options)) {
|
|
199
|
-
if (typeof attrValue === "object") {
|
|
200
|
-
throw `Attr ${attrName}, for element ${element.tag} has obj type. Got: ${JSON.stringify(element, null, 2)}`;
|
|
201
|
-
}
|
|
202
|
-
returnString += ` ${attrName.toLowerCase()}="${attrValue}"`;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
} else if (typeof element.options !== "object" && element.options !== void 0) {
|
|
206
|
-
element.children = [element.options, ...element.children || []];
|
|
207
|
-
}
|
|
208
|
-
if (element.children === null) {
|
|
209
|
-
returnString += "/>";
|
|
210
|
-
return returnString;
|
|
211
|
-
}
|
|
212
|
-
returnString += ">";
|
|
213
|
-
for (const child2 of element.children) {
|
|
214
|
-
returnString += renderRecursively(child2);
|
|
215
|
-
}
|
|
216
|
-
returnString += `</${element.tag}>`;
|
|
217
|
-
return returnString;
|
|
218
|
-
};
|
|
219
|
-
serverSideRenderPage = async (page, pathname) => {
|
|
220
|
-
if (!page) {
|
|
221
|
-
throw `No Page Provided.`;
|
|
222
|
-
}
|
|
223
|
-
if (typeof page === "function") {
|
|
224
|
-
throw `Unbuilt page provided to ssr page.`;
|
|
225
|
-
}
|
|
226
|
-
const bodyHTML = renderRecursively(page);
|
|
227
|
-
return {
|
|
228
|
-
bodyHTML
|
|
229
|
-
};
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// src/server/generateHTMLTemplate.ts
|
|
235
|
-
var generateHTMLTemplate;
|
|
236
|
-
var init_generateHTMLTemplate = __esm({
|
|
237
|
-
"src/server/generateHTMLTemplate.ts"() {
|
|
238
|
-
"use strict";
|
|
239
|
-
init_render();
|
|
240
|
-
generateHTMLTemplate = async ({
|
|
241
|
-
pageURL,
|
|
242
|
-
head: head2,
|
|
243
|
-
serverData = null,
|
|
244
|
-
addPageScriptTag = true,
|
|
245
|
-
name,
|
|
246
|
-
requiredClientModules = {},
|
|
247
|
-
environment
|
|
248
|
-
}) => {
|
|
249
|
-
let StartTemplate = `<meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
250
|
-
if (environment === "production") {
|
|
251
|
-
StartTemplate += `<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">`;
|
|
252
|
-
}
|
|
253
|
-
StartTemplate += '<meta charset="UTF-8">';
|
|
254
|
-
for (const [globalName] of Object.entries(requiredClientModules)) {
|
|
255
|
-
StartTemplate += `<script data-module="true" src="/shipped/${globalName}.js" defer="true"></script>`;
|
|
256
|
-
}
|
|
257
|
-
if (addPageScriptTag === true) {
|
|
258
|
-
const sanitized = pageURL === "" ? "/" : `/${pageURL}`;
|
|
259
|
-
StartTemplate += `<script data-page="true" type="module" data-pathname="${sanitized}" src="${sanitized.endsWith("/") ? sanitized : sanitized + "/"}${name}_data.js" defer="true"></script>`;
|
|
260
|
-
}
|
|
261
|
-
StartTemplate += `<script type="module" src="/client.js" defer="true"></script>`;
|
|
262
|
-
let builtHead;
|
|
263
|
-
if (head2.constructor.name === "AsyncFunction") {
|
|
264
|
-
builtHead = await head2();
|
|
265
|
-
} else {
|
|
266
|
-
builtHead = head2();
|
|
267
|
-
}
|
|
268
|
-
let HTMLTemplate = renderRecursively(builtHead);
|
|
269
|
-
if (serverData) {
|
|
270
|
-
HTMLTemplate += serverData;
|
|
271
|
-
}
|
|
272
|
-
return {
|
|
273
|
-
internals: StartTemplate,
|
|
274
|
-
builtMetadata: HTMLTemplate
|
|
275
|
-
};
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
// src/helpers/ObjectAttributeType.ts
|
|
281
|
-
var init_ObjectAttributeType = __esm({
|
|
282
|
-
"src/helpers/ObjectAttributeType.ts"() {
|
|
283
|
-
"use strict";
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
// src/internal/deprecate.ts
|
|
288
|
-
var init_deprecate = __esm({
|
|
289
|
-
"src/internal/deprecate.ts"() {
|
|
290
|
-
"use strict";
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
// src/server/loadHook.ts
|
|
295
|
-
var resetLoadHooks, getLoadHooks;
|
|
296
|
-
var init_loadHook = __esm({
|
|
297
|
-
"src/server/loadHook.ts"() {
|
|
298
|
-
"use strict";
|
|
299
|
-
init_deprecate();
|
|
300
|
-
resetLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__ = [];
|
|
301
|
-
getLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__;
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
// src/server/state.ts
|
|
306
|
-
var initializeState, getState, initializeObjectAttributes, getObjectAttributes;
|
|
307
|
-
var init_state = __esm({
|
|
308
|
-
"src/server/state.ts"() {
|
|
309
|
-
"use strict";
|
|
310
|
-
init_ObjectAttributeType();
|
|
311
|
-
init_loadHook();
|
|
312
|
-
if (!globalThis.__SERVER_CURRENT_STATE_ID__) {
|
|
313
|
-
globalThis.__SERVER_CURRENT_STATE_ID__ = 1;
|
|
314
|
-
}
|
|
315
|
-
initializeState = () => globalThis.__SERVER_CURRENT_STATE__ = [];
|
|
316
|
-
getState = () => {
|
|
317
|
-
return globalThis.__SERVER_CURRENT_STATE__;
|
|
318
|
-
};
|
|
319
|
-
initializeObjectAttributes = () => globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__ = [];
|
|
320
|
-
getObjectAttributes = () => {
|
|
321
|
-
return globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__;
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
// src/server/layout.ts
|
|
327
|
-
var resetLayouts;
|
|
328
|
-
var init_layout = __esm({
|
|
329
|
-
"src/server/layout.ts"() {
|
|
330
|
-
"use strict";
|
|
331
|
-
resetLayouts = () => globalThis.__SERVER_CURRENT_LAYOUTS__ = /* @__PURE__ */ new Map();
|
|
332
|
-
if (!globalThis.__SERVER_CURRENT_LAYOUT_ID__) globalThis.__SERVER_CURRENT_LAYOUT_ID__ = 1;
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
// src/page_compiler.ts
|
|
337
|
-
var page_compiler_exports = {};
|
|
338
|
-
__export(page_compiler_exports, {
|
|
339
|
-
buildDynamicPage: () => buildDynamicPage,
|
|
340
|
-
processPageElements: () => processPageElements
|
|
341
|
-
});
|
|
342
1
|
import fs from "fs";
|
|
343
2
|
import path from "path";
|
|
344
|
-
import { registerLoader, setArcTsConfig } from "ts-arc";
|
|
345
|
-
import esbuild from "esbuild";
|
|
346
3
|
import { fileURLToPath } from "url";
|
|
347
|
-
function buildTrace(stack, indent = 4) {
|
|
348
|
-
try {
|
|
349
|
-
if (!stack || stack.length === 0) return "[]";
|
|
350
|
-
let traceObj = stack[stack.length - 1] && typeof stack[stack.length - 1] === "object" ? JSON.parse(JSON.stringify(stack[stack.length - 1])) : { value: stack[stack.length - 1] };
|
|
351
|
-
traceObj._error = "This is the element where the error occurred";
|
|
352
|
-
for (let i = stack.length - 2; i >= 0; i--) {
|
|
353
|
-
const parent = stack[i];
|
|
354
|
-
const child2 = stack[i + 1];
|
|
355
|
-
if (!parent || typeof parent !== "object") {
|
|
356
|
-
traceObj = { value: parent, _errorChild: traceObj };
|
|
357
|
-
continue;
|
|
358
|
-
}
|
|
359
|
-
let parentClone;
|
|
360
|
-
try {
|
|
361
|
-
parentClone = JSON.parse(JSON.stringify(parent));
|
|
362
|
-
} catch {
|
|
363
|
-
parentClone = { value: parent };
|
|
364
|
-
}
|
|
365
|
-
let index = -1;
|
|
366
|
-
if (Array.isArray(parentClone.children)) {
|
|
367
|
-
index = parentClone.children.findIndex((c) => c === child2);
|
|
368
|
-
}
|
|
369
|
-
if (index !== -1 && parentClone.children) {
|
|
370
|
-
parentClone.children = parentClone.children.slice(0, index + 1);
|
|
371
|
-
parentClone.children[index] = traceObj;
|
|
372
|
-
} else {
|
|
373
|
-
parentClone._errorChild = traceObj;
|
|
374
|
-
}
|
|
375
|
-
traceObj = parentClone;
|
|
376
|
-
}
|
|
377
|
-
return JSON.stringify(traceObj, null, indent).replace(/^/gm, " ".repeat(indent));
|
|
378
|
-
} catch {
|
|
379
|
-
return "Could not build stack-trace.";
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
var __filename, __dirname, packageDir, clientPath, watcherPath, shippedModules, modulesToShip, yellow, black, bgYellow, bold, underline, white, log2, options, DIST_DIR, PAGE_MAP, LAYOUT_MAP, getAllSubdirectories, buildClient, elementKey, processOptionAsObjectAttribute, processPageElements, pageToHTML, generateClientPageData, generateLayout, builtLayouts, buildLayouts, buildLayout, fetchPageLayoutHTML, buildPages, buildPage, buildDynamicPage, shipModules, build;
|
|
383
|
-
var init_page_compiler = __esm({
|
|
384
|
-
"src/page_compiler.ts"() {
|
|
385
|
-
"use strict";
|
|
386
|
-
init_generateHTMLTemplate();
|
|
387
|
-
init_ObjectAttributeType();
|
|
388
|
-
init_render();
|
|
389
|
-
init_state();
|
|
390
|
-
init_loadHook();
|
|
391
|
-
init_layout();
|
|
392
|
-
init_render();
|
|
393
|
-
__filename = fileURLToPath(import.meta.url);
|
|
394
|
-
__dirname = path.dirname(__filename);
|
|
395
|
-
setArcTsConfig(__dirname);
|
|
396
|
-
registerLoader();
|
|
397
|
-
packageDir = process.env.PACKAGE_PATH;
|
|
398
|
-
if (packageDir === void 0) {
|
|
399
|
-
packageDir = path.resolve(__dirname, "..");
|
|
400
|
-
}
|
|
401
|
-
clientPath = path.resolve(packageDir, "./dist/client/client.mjs");
|
|
402
|
-
watcherPath = path.resolve(packageDir, "./dist/client/watcher.mjs");
|
|
403
|
-
shippedModules = /* @__PURE__ */ new Map();
|
|
404
|
-
modulesToShip = [];
|
|
405
|
-
yellow = (text) => {
|
|
406
|
-
return `\x1B[38;2;238;184;68m${text}`;
|
|
407
|
-
};
|
|
408
|
-
black = (text) => {
|
|
409
|
-
return `\x1B[38;2;0;0;0m${text}`;
|
|
410
|
-
};
|
|
411
|
-
bgYellow = (text) => {
|
|
412
|
-
return `\x1B[48;2;238;184;68m${text}`;
|
|
413
|
-
};
|
|
414
|
-
bold = (text) => {
|
|
415
|
-
return `\x1B[1m${text}`;
|
|
416
|
-
};
|
|
417
|
-
underline = (text) => {
|
|
418
|
-
return `\x1B[4m${text}`;
|
|
419
|
-
};
|
|
420
|
-
white = (text) => {
|
|
421
|
-
return `\x1B[38;2;255;247;229m${text}`;
|
|
422
|
-
};
|
|
423
|
-
log2 = (...text) => {
|
|
424
|
-
if (options.quiet) return;
|
|
425
|
-
return console.log(text.map((text2) => `${text2}\x1B[0m`).join(""));
|
|
426
|
-
};
|
|
427
|
-
options = JSON.parse(process.env.OPTIONS || "{}");
|
|
428
|
-
console.log(options);
|
|
429
|
-
DIST_DIR = process.env.DIST_DIR;
|
|
430
|
-
PAGE_MAP = /* @__PURE__ */ new Map();
|
|
431
|
-
LAYOUT_MAP = /* @__PURE__ */ new Map();
|
|
432
|
-
getAllSubdirectories = (dir, baseDir = dir) => {
|
|
433
|
-
let directories = [];
|
|
434
|
-
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
435
|
-
for (const item of items) {
|
|
436
|
-
if (item.isDirectory()) {
|
|
437
|
-
const fullPath = path.join(dir, item.name);
|
|
438
|
-
const relativePath = path.relative(baseDir, fullPath);
|
|
439
|
-
directories.push(relativePath);
|
|
440
|
-
directories = directories.concat(getAllSubdirectories(fullPath, baseDir));
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
return directories;
|
|
444
|
-
};
|
|
445
|
-
buildClient = async (DIST_DIR2) => {
|
|
446
|
-
let clientString = "window.__name = (func) => func; ";
|
|
447
|
-
clientString += fs.readFileSync(clientPath, "utf-8");
|
|
448
|
-
if (options.hotReload !== void 0) {
|
|
449
|
-
clientString += `const watchServerPort = ${options.hotReload.port}`;
|
|
450
|
-
clientString += fs.readFileSync(watcherPath, "utf-8");
|
|
451
|
-
}
|
|
452
|
-
const transformedClient = await esbuild.transform(clientString, {
|
|
453
|
-
minify: options.environment === "production",
|
|
454
|
-
drop: options.environment === "production" ? ["console", "debugger"] : void 0,
|
|
455
|
-
keepNames: false,
|
|
456
|
-
format: "iife",
|
|
457
|
-
platform: "node",
|
|
458
|
-
loader: "ts"
|
|
459
|
-
});
|
|
460
|
-
fs.writeFileSync(
|
|
461
|
-
path.join(DIST_DIR2, "/client.js"),
|
|
462
|
-
transformedClient.code
|
|
463
|
-
);
|
|
464
|
-
};
|
|
465
|
-
elementKey = 0;
|
|
466
|
-
processOptionAsObjectAttribute = (element, optionName, optionValue, objectAttributes) => {
|
|
467
|
-
const lcOptionName = optionName.toLowerCase();
|
|
468
|
-
const options3 = element.options;
|
|
469
|
-
let key = options3.key;
|
|
470
|
-
if (key == void 0) {
|
|
471
|
-
key = elementKey += 1;
|
|
472
|
-
options3.key = key;
|
|
473
|
-
}
|
|
474
|
-
if (!optionValue.type) {
|
|
475
|
-
throw `ObjectAttributeType is missing from object attribute. ${element.tag}: ${optionName}/${optionValue}`;
|
|
476
|
-
}
|
|
477
|
-
let optionFinal = lcOptionName;
|
|
478
|
-
switch (optionValue.type) {
|
|
479
|
-
case 1 /* STATE */:
|
|
480
|
-
const SOA = optionValue;
|
|
481
|
-
if (typeof SOA.value === "function") {
|
|
482
|
-
delete options3[optionName];
|
|
483
|
-
break;
|
|
484
|
-
}
|
|
485
|
-
if (lcOptionName === "innertext" || lcOptionName === "innerhtml") {
|
|
486
|
-
element.children = [SOA.value];
|
|
487
|
-
delete options3[optionName];
|
|
488
|
-
} else {
|
|
489
|
-
delete options3[optionName];
|
|
490
|
-
options3[lcOptionName] = SOA.value;
|
|
491
|
-
}
|
|
492
|
-
break;
|
|
493
|
-
case 2 /* OBSERVER */:
|
|
494
|
-
const OOA = optionValue;
|
|
495
|
-
const firstValue = OOA.update(...OOA.initialValues);
|
|
496
|
-
if (lcOptionName === "innertext" || lcOptionName === "innerhtml") {
|
|
497
|
-
element.children = [firstValue];
|
|
498
|
-
delete options3[optionName];
|
|
499
|
-
} else {
|
|
500
|
-
delete options3[optionName];
|
|
501
|
-
options3[lcOptionName] = firstValue;
|
|
502
|
-
}
|
|
503
|
-
optionFinal = optionName;
|
|
504
|
-
break;
|
|
505
|
-
case 4 /* REFERENCE */:
|
|
506
|
-
options3["ref"] = optionValue.value;
|
|
507
|
-
break;
|
|
508
|
-
}
|
|
509
|
-
objectAttributes.push({ ...optionValue, key, attribute: optionFinal });
|
|
510
|
-
};
|
|
511
|
-
processPageElements = (element, objectAttributes, recursionLevel, stack = []) => {
|
|
512
|
-
stack.push(element);
|
|
513
|
-
try {
|
|
514
|
-
if (typeof element === "boolean" || typeof element === "number" || Array.isArray(element)) {
|
|
515
|
-
stack.pop();
|
|
516
|
-
return element;
|
|
517
|
-
}
|
|
518
|
-
if (typeof element === "string") {
|
|
519
|
-
stack.pop();
|
|
520
|
-
return element;
|
|
521
|
-
}
|
|
522
|
-
const processElementOptionsAsChildAndReturn = () => {
|
|
523
|
-
try {
|
|
524
|
-
const children = element.children;
|
|
525
|
-
element.children = [
|
|
526
|
-
element.options,
|
|
527
|
-
...children
|
|
528
|
-
];
|
|
529
|
-
element.options = {};
|
|
530
|
-
for (let i = 0; i < children.length + 1; i++) {
|
|
531
|
-
const child2 = element.children[i];
|
|
532
|
-
const processedChild = processPageElements(child2, objectAttributes, recursionLevel + 1, stack);
|
|
533
|
-
element.children[i] = processedChild;
|
|
534
|
-
}
|
|
535
|
-
return {
|
|
536
|
-
...element,
|
|
537
|
-
options: {}
|
|
538
|
-
};
|
|
539
|
-
} catch (e) {
|
|
540
|
-
const errorString = `Could not process element options as a child. ${e}.`;
|
|
541
|
-
throw new Error(errorString);
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
if (typeof element.options !== "object") {
|
|
545
|
-
const result = processElementOptionsAsChildAndReturn();
|
|
546
|
-
stack.pop();
|
|
547
|
-
return result;
|
|
548
|
-
}
|
|
549
|
-
const {
|
|
550
|
-
tag: elementTag,
|
|
551
|
-
options: elementOptions,
|
|
552
|
-
children: elementChildren
|
|
553
|
-
} = element.options;
|
|
554
|
-
if (elementTag && elementOptions && elementChildren) {
|
|
555
|
-
const result = processElementOptionsAsChildAndReturn();
|
|
556
|
-
stack.pop();
|
|
557
|
-
return result;
|
|
558
|
-
}
|
|
559
|
-
const options3 = element.options;
|
|
560
|
-
for (const [optionName, optionValue] of Object.entries(options3)) {
|
|
561
|
-
const lcOptionName = optionName.toLowerCase();
|
|
562
|
-
if (typeof optionValue !== "object") {
|
|
563
|
-
if (lcOptionName === "innertext") {
|
|
564
|
-
delete options3[optionName];
|
|
565
|
-
if (element.children === null) {
|
|
566
|
-
throw `Cannot use innerText or innerHTML on childrenless elements.`;
|
|
567
|
-
}
|
|
568
|
-
element.children = [optionValue, ...element.children];
|
|
569
|
-
continue;
|
|
570
|
-
} else if (lcOptionName === "innerhtml") {
|
|
571
|
-
if (element.children === null) {
|
|
572
|
-
throw `Cannot use innerText or innerHTML on childrenless elements.`;
|
|
573
|
-
}
|
|
574
|
-
delete options3[optionName];
|
|
575
|
-
element.children = [optionValue];
|
|
576
|
-
continue;
|
|
577
|
-
}
|
|
578
|
-
continue;
|
|
579
|
-
}
|
|
580
|
-
;
|
|
581
|
-
processOptionAsObjectAttribute(element, optionName, optionValue, objectAttributes);
|
|
582
|
-
}
|
|
583
|
-
if (element.children) {
|
|
584
|
-
for (let i = 0; i < element.children.length; i++) {
|
|
585
|
-
const child2 = element.children[i];
|
|
586
|
-
const processedChild = processPageElements(child2, objectAttributes, recursionLevel + 1, stack);
|
|
587
|
-
element.children[i] = processedChild;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
stack.pop();
|
|
591
|
-
return element;
|
|
592
|
-
} catch (e) {
|
|
593
|
-
const trace = buildTrace(stack);
|
|
594
|
-
if (recursionLevel === 0) {
|
|
595
|
-
throw new Error(`${e}
|
|
596
|
-
|
|
597
|
-
Trace:
|
|
598
|
-
${trace}`);
|
|
599
|
-
} else {
|
|
600
|
-
throw e;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
};
|
|
604
|
-
pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageName, doWrite = true, requiredClientModules = {}, layout, pathname = "") => {
|
|
605
|
-
if (typeof pageElements === "string" || typeof pageElements === "boolean" || typeof pageElements === "number" || Array.isArray(pageElements)) {
|
|
606
|
-
throw new Error(`The root element of a page / layout must be a built element, not just a Child. Received: ${typeof pageElements}.`);
|
|
607
|
-
}
|
|
608
|
-
const objectAttributes = [];
|
|
609
|
-
const stack = [];
|
|
610
|
-
const processedPageElements = processPageElements(pageElements, objectAttributes, 0, stack);
|
|
611
|
-
const renderedPage = await serverSideRenderPage(
|
|
612
|
-
processedPageElements,
|
|
613
|
-
pageLocation
|
|
614
|
-
);
|
|
615
|
-
const { internals, builtMetadata } = await generateHTMLTemplate({
|
|
616
|
-
pageURL: pathname,
|
|
617
|
-
head: metadata,
|
|
618
|
-
addPageScriptTag: doWrite,
|
|
619
|
-
name: pageName,
|
|
620
|
-
requiredClientModules,
|
|
621
|
-
environment: options.environment
|
|
622
|
-
});
|
|
623
|
-
let extraBodyHTML = "";
|
|
624
|
-
if (doWrite === false) {
|
|
625
|
-
const state = getState();
|
|
626
|
-
const pageLoadHooks = getLoadHooks();
|
|
627
|
-
const userObjectAttributes = getObjectAttributes();
|
|
628
|
-
const {
|
|
629
|
-
result
|
|
630
|
-
} = await generateClientPageData(
|
|
631
|
-
pathname,
|
|
632
|
-
state || {},
|
|
633
|
-
[...objectAttributes, ...userObjectAttributes],
|
|
634
|
-
pageLoadHooks || [],
|
|
635
|
-
DIST_DIR2,
|
|
636
|
-
"page",
|
|
637
|
-
"pd",
|
|
638
|
-
false
|
|
639
|
-
);
|
|
640
|
-
const sanitized = pathname === "" ? "/" : `/${pathname}`;
|
|
641
|
-
extraBodyHTML = `<script data-hook="true" data-pathname="${sanitized}" type="text/plain">${result}</script>`;
|
|
642
|
-
extraBodyHTML += `<script>
|
|
643
|
-
const text = document.querySelector('[data-hook="true"][data-pathname="${sanitized}"][type="text/plain"').textContent;
|
|
644
|
-
const blob = new Blob([text], { type: 'text/javascript' });
|
|
645
|
-
const url = URL.createObjectURL(blob);
|
|
646
|
-
|
|
647
|
-
const script = document.createElement("script");
|
|
648
|
-
script.src = url;
|
|
649
|
-
script.type = "module";
|
|
650
|
-
script.setAttribute("data-page", "true");
|
|
651
|
-
script.setAttribute("data-pathname", "${sanitized}");
|
|
652
|
-
|
|
653
|
-
document.head.appendChild(script);
|
|
654
|
-
|
|
655
|
-
document.currentScript.remove();
|
|
656
|
-
</script>`;
|
|
657
|
-
extraBodyHTML = extraBodyHTML.replace(/\s+/g, " ").replace(/\s*([{}();,:])\s*/g, "$1").trim();
|
|
658
|
-
}
|
|
659
|
-
const headHTML = `<!DOCTYPE html>${layout.metadata.startHTML}${layout.scriptTag}${internals}${builtMetadata}${layout.metadata.endHTML}`;
|
|
660
|
-
const bodyHTML = `${layout.pageContent.startHTML}${renderedPage.bodyHTML}${extraBodyHTML}${layout.pageContent.endHTML}`;
|
|
661
|
-
const resultHTML = `${headHTML}${bodyHTML}`;
|
|
662
|
-
const htmlLocation = path.join(pageLocation, (pageName === "page" ? "index" : pageName) + ".html");
|
|
663
|
-
if (doWrite) {
|
|
664
|
-
const dirname2 = path.dirname(htmlLocation);
|
|
665
|
-
if (fs.existsSync(dirname2) === false) {
|
|
666
|
-
fs.mkdirSync(dirname2, { recursive: true });
|
|
667
|
-
}
|
|
668
|
-
fs.writeFileSync(
|
|
669
|
-
htmlLocation,
|
|
670
|
-
resultHTML,
|
|
671
|
-
{
|
|
672
|
-
encoding: "utf-8",
|
|
673
|
-
flag: "w"
|
|
674
|
-
}
|
|
675
|
-
);
|
|
676
|
-
return objectAttributes;
|
|
677
|
-
}
|
|
678
|
-
return resultHTML;
|
|
679
|
-
};
|
|
680
|
-
generateClientPageData = async (pageLocation, state, objectAttributes, pageLoadHooks, DIST_DIR2, pageName, globalVariableName = "pd", write = true) => {
|
|
681
|
-
let clientPageJSText = "";
|
|
682
|
-
{
|
|
683
|
-
clientPageJSText += `${globalThis.__SERVER_PAGE_DATA_BANNER__}`;
|
|
684
|
-
}
|
|
685
|
-
{
|
|
686
|
-
clientPageJSText += `export const data = {`;
|
|
687
|
-
if (state) {
|
|
688
|
-
clientPageJSText += `state:[`;
|
|
689
|
-
for (const subject of state) {
|
|
690
|
-
if (typeof subject.value === "string") {
|
|
691
|
-
const stringified = JSON.stringify(subject.value);
|
|
692
|
-
clientPageJSText += `{id:${subject.id},value:${stringified}},`;
|
|
693
|
-
} else if (typeof subject.value === "function") {
|
|
694
|
-
clientPageJSText += `{id:${subject.id},value:${subject.value.toString()}},`;
|
|
695
|
-
} else {
|
|
696
|
-
clientPageJSText += `{id:${subject.id},value:${JSON.stringify(subject.value)}},`;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
clientPageJSText += `],`;
|
|
700
|
-
}
|
|
701
|
-
const stateObjectAttributes = objectAttributes.filter((oa) => oa.type === 1 /* STATE */);
|
|
702
|
-
if (stateObjectAttributes.length > 0) {
|
|
703
|
-
const processed = [...stateObjectAttributes].map((soa) => {
|
|
704
|
-
delete soa.type;
|
|
705
|
-
return soa;
|
|
706
|
-
});
|
|
707
|
-
clientPageJSText += `soa:${JSON.stringify(processed)},`;
|
|
708
|
-
}
|
|
709
|
-
const observerObjectAttributes = objectAttributes.filter((oa) => oa.type === 2 /* OBSERVER */);
|
|
710
|
-
if (observerObjectAttributes.length > 0) {
|
|
711
|
-
let observerObjectAttributeString = "ooa:[";
|
|
712
|
-
for (const observerObjectAttribute of observerObjectAttributes) {
|
|
713
|
-
const ooa = observerObjectAttribute;
|
|
714
|
-
observerObjectAttributeString += `{key:${ooa.key},attribute:"${ooa.attribute}",update:${ooa.update.toString()},`;
|
|
715
|
-
observerObjectAttributeString += `refs:[`;
|
|
716
|
-
for (const ref of ooa.refs) {
|
|
717
|
-
observerObjectAttributeString += `{id:${ref.id}},`;
|
|
718
|
-
}
|
|
719
|
-
observerObjectAttributeString += "]},";
|
|
720
|
-
}
|
|
721
|
-
observerObjectAttributeString += "],";
|
|
722
|
-
clientPageJSText += observerObjectAttributeString;
|
|
723
|
-
}
|
|
724
|
-
if (pageLoadHooks.length > 0) {
|
|
725
|
-
clientPageJSText += "lh:[";
|
|
726
|
-
for (const loadHook2 of pageLoadHooks) {
|
|
727
|
-
clientPageJSText += `{fn:${loadHook2.fn}},`;
|
|
728
|
-
}
|
|
729
|
-
clientPageJSText += "],";
|
|
730
|
-
}
|
|
731
|
-
clientPageJSText += `};`;
|
|
732
|
-
}
|
|
733
|
-
const pageDataPath = path.join(DIST_DIR2, pageLocation, `${pageName}_data.js`);
|
|
734
|
-
let sendHardReloadInstruction = false;
|
|
735
|
-
const transformedResult = await esbuild.transform(clientPageJSText, { minify: options.environment === "production" }).catch((error) => {
|
|
736
|
-
console.error("Failed to transform client page js!", error);
|
|
737
|
-
});
|
|
738
|
-
if (!transformedResult) return { sendHardReloadInstruction };
|
|
739
|
-
if (fs.existsSync(pageDataPath)) {
|
|
740
|
-
const content = fs.readFileSync(pageDataPath).toString();
|
|
741
|
-
if (content !== transformedResult.code) {
|
|
742
|
-
sendHardReloadInstruction = true;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
if (write) fs.writeFileSync(pageDataPath, transformedResult.code, "utf-8");
|
|
746
|
-
return { sendHardReloadInstruction, result: transformedResult.code };
|
|
747
|
-
};
|
|
748
|
-
generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, generateDynamic = false) => {
|
|
749
|
-
initializeState();
|
|
750
|
-
initializeObjectAttributes();
|
|
751
|
-
resetLoadHooks();
|
|
752
|
-
globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
|
|
753
|
-
let layoutElements;
|
|
754
|
-
let metadataElements;
|
|
755
|
-
let modules = [];
|
|
756
|
-
let isDynamicLayout = false;
|
|
757
|
-
try {
|
|
758
|
-
const {
|
|
759
|
-
layout,
|
|
760
|
-
metadata,
|
|
761
|
-
isDynamic,
|
|
762
|
-
shippedModules: shippedModules2
|
|
763
|
-
} = await import("file://" + filePath);
|
|
764
|
-
if (shippedModules2 !== void 0) {
|
|
765
|
-
modules = shippedModules2;
|
|
766
|
-
}
|
|
767
|
-
layoutElements = layout;
|
|
768
|
-
metadataElements = metadata;
|
|
769
|
-
if (isDynamic === true) {
|
|
770
|
-
isDynamicLayout = isDynamic;
|
|
771
|
-
}
|
|
772
|
-
} catch (e) {
|
|
773
|
-
throw new Error(`Error in Page: ${directory === "" ? "/" : directory}layout.ts - ${e}`);
|
|
774
|
-
}
|
|
775
|
-
LAYOUT_MAP.set(directory === "" ? "/" : `/${directory}`, {
|
|
776
|
-
isDynamic: isDynamicLayout,
|
|
777
|
-
filePath
|
|
778
|
-
});
|
|
779
|
-
if (isDynamicLayout === true && generateDynamic === false) return false;
|
|
780
|
-
{
|
|
781
|
-
if (!layoutElements) {
|
|
782
|
-
throw new Error(`WARNING: ${filePath} should export a const layout, which is of type Layout: (child: Child) => AnyBuiltElement.`);
|
|
783
|
-
}
|
|
784
|
-
if (typeof layoutElements === "function") {
|
|
785
|
-
if (layoutElements.constructor.name === "AsyncFunction") {
|
|
786
|
-
layoutElements = await layoutElements(childIndicator);
|
|
787
|
-
} else {
|
|
788
|
-
layoutElements = layoutElements(childIndicator);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
{
|
|
793
|
-
if (!metadataElements) {
|
|
794
|
-
throw new Error(`WARNING: ${filePath} should export a const metadata, which is of type LayoutMetadata: (child: Child) => AnyBuiltElement.`);
|
|
795
|
-
}
|
|
796
|
-
if (typeof metadataElements === "function") {
|
|
797
|
-
if (metadataElements.constructor.name === "AsyncFunction") {
|
|
798
|
-
metadataElements = await metadataElements(childIndicator);
|
|
799
|
-
} else {
|
|
800
|
-
metadataElements = metadataElements(childIndicator);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
const state = getState();
|
|
805
|
-
const pageLoadHooks = getLoadHooks();
|
|
806
|
-
const objectAttributes = getObjectAttributes();
|
|
807
|
-
if (typeof layoutElements === "string" || typeof layoutElements === "boolean" || typeof layoutElements === "number" || Array.isArray(layoutElements)) {
|
|
808
|
-
throw new Error(`The root element of a page / layout must be a built element, not just a Child. Received: ${typeof layoutElements}.`);
|
|
809
|
-
}
|
|
810
|
-
const foundObjectAttributes = [];
|
|
811
|
-
const stack = [];
|
|
812
|
-
const processedPageElements = processPageElements(layoutElements, foundObjectAttributes, 0, stack);
|
|
813
|
-
const renderedPage = await serverSideRenderPage(
|
|
814
|
-
processedPageElements,
|
|
815
|
-
directory
|
|
816
|
-
);
|
|
817
|
-
const metadataHTML = metadataElements ? renderRecursively(metadataElements) : "";
|
|
818
|
-
await generateClientPageData(
|
|
819
|
-
directory,
|
|
820
|
-
state || {},
|
|
821
|
-
[...objectAttributes, ...foundObjectAttributes],
|
|
822
|
-
pageLoadHooks || [],
|
|
823
|
-
DIST_DIR2,
|
|
824
|
-
"layout",
|
|
825
|
-
"ld"
|
|
826
|
-
);
|
|
827
|
-
return { pageContentHTML: renderedPage.bodyHTML, metadataHTML };
|
|
828
|
-
};
|
|
829
|
-
builtLayouts = /* @__PURE__ */ new Map();
|
|
830
|
-
buildLayouts = async () => {
|
|
831
|
-
const pagesDirectory = path.resolve(options.pagesDirectory);
|
|
832
|
-
const subdirectories = [...getAllSubdirectories(pagesDirectory), ""];
|
|
833
|
-
let shouldClientHardReload = false;
|
|
834
|
-
for (const directory of subdirectories) {
|
|
835
|
-
const abs = path.resolve(path.join(pagesDirectory, directory));
|
|
836
|
-
const files = fs.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
|
|
837
|
-
for (const file of files) {
|
|
838
|
-
const filePath = path.join(file.parentPath, file.name);
|
|
839
|
-
const name = file.name.slice(0, file.name.length - 3);
|
|
840
|
-
const isLayout = name === "layout";
|
|
841
|
-
if (isLayout == false) {
|
|
842
|
-
continue;
|
|
843
|
-
}
|
|
844
|
-
try {
|
|
845
|
-
const builtLayout = await buildLayout(filePath, directory);
|
|
846
|
-
if (!builtLayout) return { shouldClientHardReload: false };
|
|
847
|
-
builtLayouts.set(filePath, builtLayout);
|
|
848
|
-
} catch (e) {
|
|
849
|
-
console.error(e);
|
|
850
|
-
continue;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
return { shouldClientHardReload };
|
|
855
|
-
};
|
|
856
|
-
buildLayout = async (filePath, directory, generateDynamic = false) => {
|
|
857
|
-
const id = globalThis.__SERVER_CURRENT_STATE_ID__ += 1;
|
|
858
|
-
const childIndicator = `<template layout-id="${id}"></template>`;
|
|
859
|
-
const result = await generateLayout(
|
|
860
|
-
DIST_DIR,
|
|
861
|
-
filePath,
|
|
862
|
-
directory,
|
|
863
|
-
childIndicator,
|
|
864
|
-
generateDynamic
|
|
865
|
-
);
|
|
866
|
-
if (result === false) return false;
|
|
867
|
-
const { pageContentHTML, metadataHTML } = result;
|
|
868
|
-
const splitAround = (str, sub) => {
|
|
869
|
-
const i = str.indexOf(sub);
|
|
870
|
-
if (i === -1) throw new Error("substring does not exist in parent string");
|
|
871
|
-
return {
|
|
872
|
-
startHTML: str.substring(0, i),
|
|
873
|
-
endHTML: str.substring(i + sub.length)
|
|
874
|
-
};
|
|
875
|
-
};
|
|
876
|
-
const splitAt = (str, sub) => {
|
|
877
|
-
const i = str.indexOf(sub) + sub.length;
|
|
878
|
-
if (i === -1) throw new Error("substring does not exist in parent string");
|
|
879
|
-
return {
|
|
880
|
-
startHTML: str.substring(0, i),
|
|
881
|
-
endHTML: str.substring(i)
|
|
882
|
-
};
|
|
883
|
-
};
|
|
884
|
-
const pathname = directory === "" ? "/" : directory;
|
|
885
|
-
return {
|
|
886
|
-
pageContent: splitAt(pageContentHTML, childIndicator),
|
|
887
|
-
metadata: splitAround(metadataHTML, childIndicator),
|
|
888
|
-
scriptTag: `<script data-layout="true" type="module" src="${pathname}layout_data.js" data-pathname="${pathname}" defer="true"></script>`
|
|
889
|
-
};
|
|
890
|
-
};
|
|
891
|
-
fetchPageLayoutHTML = async (dirname2) => {
|
|
892
|
-
const relative2 = path.relative(options.pagesDirectory, dirname2);
|
|
893
|
-
let split = relative2.split(path.sep).filter(Boolean);
|
|
894
|
-
split.push("/");
|
|
895
|
-
split.reverse();
|
|
896
|
-
let layouts = [];
|
|
897
|
-
for (const dir of split) {
|
|
898
|
-
if (LAYOUT_MAP.has(dir)) {
|
|
899
|
-
const filePath = path.join(path.resolve(options.pagesDirectory), dir, "layout.ts");
|
|
900
|
-
const layout = LAYOUT_MAP.get(dir);
|
|
901
|
-
if (layout.isDynamic) {
|
|
902
|
-
const builtLayout = await buildLayout(layout.filePath, dir, true);
|
|
903
|
-
if (!builtLayout) continue;
|
|
904
|
-
layouts.push(builtLayout);
|
|
905
|
-
} else {
|
|
906
|
-
layouts.push(builtLayouts.get(filePath));
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
const pageContent = {
|
|
911
|
-
startHTML: "",
|
|
912
|
-
endHTML: ""
|
|
913
|
-
};
|
|
914
|
-
const metadata = {
|
|
915
|
-
startHTML: "",
|
|
916
|
-
endHTML: ""
|
|
917
|
-
};
|
|
918
|
-
let scriptTags = "";
|
|
919
|
-
for (const layout of layouts) {
|
|
920
|
-
pageContent.startHTML += layout.pageContent.startHTML;
|
|
921
|
-
metadata.startHTML += layout.metadata.startHTML;
|
|
922
|
-
scriptTags += layout.scriptTag;
|
|
923
|
-
pageContent.endHTML += layout.pageContent.endHTML;
|
|
924
|
-
metadata.endHTML += layout.metadata.endHTML;
|
|
925
|
-
}
|
|
926
|
-
return { pageContent, metadata, scriptTag: scriptTags };
|
|
927
|
-
};
|
|
928
|
-
buildPages = async (DIST_DIR2) => {
|
|
929
|
-
resetLayouts();
|
|
930
|
-
const pagesDirectory = path.resolve(options.pagesDirectory);
|
|
931
|
-
const subdirectories = [...getAllSubdirectories(pagesDirectory), ""];
|
|
932
|
-
let shouldClientHardReload = false;
|
|
933
|
-
for (const directory of subdirectories) {
|
|
934
|
-
const abs = path.resolve(path.join(pagesDirectory, directory));
|
|
935
|
-
const files = fs.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
|
|
936
|
-
for (const file of files) {
|
|
937
|
-
const filePath = path.join(file.parentPath, file.name);
|
|
938
|
-
const name = file.name.slice(0, file.name.length - 3);
|
|
939
|
-
const isPage = name === "page";
|
|
940
|
-
if (isPage == false) {
|
|
941
|
-
continue;
|
|
942
|
-
}
|
|
943
|
-
try {
|
|
944
|
-
const hardReloadForPage = await buildPage(DIST_DIR2, directory, filePath, name);
|
|
945
|
-
if (hardReloadForPage) {
|
|
946
|
-
shouldClientHardReload = true;
|
|
947
|
-
}
|
|
948
|
-
} catch (e) {
|
|
949
|
-
console.error(e);
|
|
950
|
-
continue;
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
return {
|
|
955
|
-
shouldClientHardReload
|
|
956
|
-
};
|
|
957
|
-
};
|
|
958
|
-
buildPage = async (DIST_DIR2, directory, filePath, name) => {
|
|
959
|
-
initializeState();
|
|
960
|
-
initializeObjectAttributes();
|
|
961
|
-
resetLoadHooks();
|
|
962
|
-
globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
|
|
963
|
-
let pageElements;
|
|
964
|
-
let metadata;
|
|
965
|
-
let modules = {};
|
|
966
|
-
let pageIgnoresLayout = false;
|
|
967
|
-
let isDynamicPage = false;
|
|
968
|
-
try {
|
|
969
|
-
const {
|
|
970
|
-
page,
|
|
971
|
-
metadata: pageMetadata,
|
|
972
|
-
isDynamic,
|
|
973
|
-
shippedModules: shippedModules2,
|
|
974
|
-
ignoreLayout
|
|
975
|
-
} = await import("file://" + filePath);
|
|
976
|
-
if (shippedModules2 !== void 0) {
|
|
977
|
-
modules = shippedModules2;
|
|
978
|
-
}
|
|
979
|
-
if (ignoreLayout) {
|
|
980
|
-
pageIgnoresLayout = true;
|
|
981
|
-
}
|
|
982
|
-
pageElements = page;
|
|
983
|
-
metadata = pageMetadata;
|
|
984
|
-
if (isDynamic === true) {
|
|
985
|
-
isDynamicPage = isDynamic;
|
|
986
|
-
}
|
|
987
|
-
} catch (e) {
|
|
988
|
-
throw new Error(`Error in Page: ${directory}/${name}.ts - ${e}`);
|
|
989
|
-
}
|
|
990
|
-
PAGE_MAP.set(directory === "" ? "/" : `/${directory}`, {
|
|
991
|
-
isDynamic: isDynamicPage,
|
|
992
|
-
filePath
|
|
993
|
-
});
|
|
994
|
-
if (isDynamicPage) return false;
|
|
995
|
-
if (modules !== void 0) {
|
|
996
|
-
for (const [globalName, path3] of Object.entries(modules)) {
|
|
997
|
-
modulesToShip.push({ globalName, path: path3 });
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
if (!metadata || metadata && typeof metadata !== "function") {
|
|
1001
|
-
console.warn(`WARNING: ${filePath} does not export a metadata function.`);
|
|
1002
|
-
}
|
|
1003
|
-
if (!pageElements) {
|
|
1004
|
-
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
1005
|
-
}
|
|
1006
|
-
const pageProps = {
|
|
1007
|
-
pageName: directory,
|
|
1008
|
-
middlewareData: {}
|
|
1009
|
-
};
|
|
1010
|
-
if (typeof pageElements === "function") {
|
|
1011
|
-
if (pageElements.constructor.name === "AsyncFunction") {
|
|
1012
|
-
pageElements = await pageElements(pageProps);
|
|
1013
|
-
} else {
|
|
1014
|
-
pageElements = pageElements(pageProps);
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
const state = getState();
|
|
1018
|
-
const pageLoadHooks = getLoadHooks();
|
|
1019
|
-
const objectAttributes = getObjectAttributes();
|
|
1020
|
-
const layout = await fetchPageLayoutHTML(path.dirname(filePath));
|
|
1021
|
-
const foundObjectAttributes = await pageToHTML(
|
|
1022
|
-
path.join(DIST_DIR2, directory),
|
|
1023
|
-
pageElements || body(),
|
|
1024
|
-
metadata ?? (() => head()),
|
|
1025
|
-
DIST_DIR2,
|
|
1026
|
-
name,
|
|
1027
|
-
true,
|
|
1028
|
-
modules,
|
|
1029
|
-
layout,
|
|
1030
|
-
directory
|
|
1031
|
-
);
|
|
1032
|
-
const {
|
|
1033
|
-
sendHardReloadInstruction
|
|
1034
|
-
} = await generateClientPageData(
|
|
1035
|
-
directory,
|
|
1036
|
-
state || {},
|
|
1037
|
-
[...objectAttributes, ...foundObjectAttributes],
|
|
1038
|
-
pageLoadHooks || [],
|
|
1039
|
-
DIST_DIR2,
|
|
1040
|
-
name
|
|
1041
|
-
);
|
|
1042
|
-
return sendHardReloadInstruction === true;
|
|
1043
|
-
};
|
|
1044
|
-
buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res, middlewareData) => {
|
|
1045
|
-
directory = directory === "/" ? "" : directory;
|
|
1046
|
-
const filePath = pageInfo.filePath;
|
|
1047
|
-
initializeState();
|
|
1048
|
-
initializeObjectAttributes();
|
|
1049
|
-
resetLoadHooks();
|
|
1050
|
-
globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
|
|
1051
|
-
let pageElements = async (props) => body();
|
|
1052
|
-
let metadata = async (props) => html();
|
|
1053
|
-
let modules = {};
|
|
1054
|
-
let pageIgnoresLayout = false;
|
|
1055
|
-
try {
|
|
1056
|
-
const {
|
|
1057
|
-
page,
|
|
1058
|
-
metadata: pageMetadata,
|
|
1059
|
-
shippedModules: shippedModules2,
|
|
1060
|
-
ignoreLayout,
|
|
1061
|
-
requestHook
|
|
1062
|
-
} = await import("file://" + filePath);
|
|
1063
|
-
if (requestHook) {
|
|
1064
|
-
const hook = requestHook;
|
|
1065
|
-
const doContinue = await hook(req, res);
|
|
1066
|
-
if (!doContinue) {
|
|
1067
|
-
return false;
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
if (shippedModules2 !== void 0) {
|
|
1071
|
-
modules = shippedModules2;
|
|
1072
|
-
}
|
|
1073
|
-
if (ignoreLayout) {
|
|
1074
|
-
pageIgnoresLayout = true;
|
|
1075
|
-
}
|
|
1076
|
-
pageElements = page;
|
|
1077
|
-
metadata = pageMetadata;
|
|
1078
|
-
} catch (e) {
|
|
1079
|
-
throw new Error(`Error in Page: ${directory}/page.ts - ${e}`);
|
|
1080
|
-
}
|
|
1081
|
-
if (modules !== void 0) {
|
|
1082
|
-
for (const [globalName, path3] of Object.entries(modules)) {
|
|
1083
|
-
modulesToShip.push({ globalName, path: path3 });
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
if (!metadata || metadata && typeof metadata !== "function") {
|
|
1087
|
-
console.warn(`WARNING: ${filePath} does not export a metadata function.`);
|
|
1088
|
-
}
|
|
1089
|
-
if (!pageElements) {
|
|
1090
|
-
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
1091
|
-
}
|
|
1092
|
-
const pageProps = {
|
|
1093
|
-
pageName: directory,
|
|
1094
|
-
middlewareData
|
|
1095
|
-
};
|
|
1096
|
-
if (typeof pageElements === "function") {
|
|
1097
|
-
if (pageElements.constructor.name === "AsyncFunction") {
|
|
1098
|
-
pageElements = await pageElements(pageProps);
|
|
1099
|
-
} else {
|
|
1100
|
-
pageElements = pageElements(pageProps);
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
const layout = await fetchPageLayoutHTML(path.dirname(filePath));
|
|
1104
|
-
const resultHTML = await pageToHTML(
|
|
1105
|
-
path.join(DIST_DIR2, directory),
|
|
1106
|
-
pageElements,
|
|
1107
|
-
metadata,
|
|
1108
|
-
DIST_DIR2,
|
|
1109
|
-
"page",
|
|
1110
|
-
false,
|
|
1111
|
-
modules,
|
|
1112
|
-
layout,
|
|
1113
|
-
directory
|
|
1114
|
-
);
|
|
1115
|
-
await shipModules();
|
|
1116
|
-
return { resultHTML };
|
|
1117
|
-
};
|
|
1118
|
-
shipModules = async () => {
|
|
1119
|
-
for (const plugin of modulesToShip) {
|
|
1120
|
-
{
|
|
1121
|
-
if (shippedModules.has(plugin.globalName)) continue;
|
|
1122
|
-
shippedModules.set(plugin.globalName, true);
|
|
1123
|
-
}
|
|
1124
|
-
esbuild.build({
|
|
1125
|
-
entryPoints: [plugin.path],
|
|
1126
|
-
bundle: true,
|
|
1127
|
-
outfile: path.join(DIST_DIR, "shipped", plugin.globalName + ".js"),
|
|
1128
|
-
format: "iife",
|
|
1129
|
-
platform: "browser",
|
|
1130
|
-
globalName: plugin.globalName,
|
|
1131
|
-
minify: true,
|
|
1132
|
-
treeShaking: true
|
|
1133
|
-
});
|
|
1134
|
-
}
|
|
1135
|
-
modulesToShip = [];
|
|
1136
|
-
};
|
|
1137
|
-
build = async () => {
|
|
1138
|
-
if (options.quiet === true) {
|
|
1139
|
-
console.log = function() {
|
|
1140
|
-
};
|
|
1141
|
-
console.error = function() {
|
|
1142
|
-
};
|
|
1143
|
-
console.warn = function() {
|
|
1144
|
-
};
|
|
1145
|
-
}
|
|
1146
|
-
try {
|
|
1147
|
-
{
|
|
1148
|
-
log2(bold(yellow(" -- Elegance.JS -- ")));
|
|
1149
|
-
if (options.environment === "production") {
|
|
1150
|
-
log2(
|
|
1151
|
-
" - ",
|
|
1152
|
-
bgYellow(bold(black(" NOTE "))),
|
|
1153
|
-
" : ",
|
|
1154
|
-
white("In production mode, no "),
|
|
1155
|
-
underline("console.log() "),
|
|
1156
|
-
white("statements will be shown on the client, and all code will be minified.")
|
|
1157
|
-
);
|
|
1158
|
-
log2("");
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
if (options.preCompile) {
|
|
1162
|
-
options.preCompile();
|
|
1163
|
-
}
|
|
1164
|
-
const start = performance.now();
|
|
1165
|
-
let shouldClientHardReload;
|
|
1166
|
-
{
|
|
1167
|
-
const { shouldClientHardReload: doReload } = await buildLayouts();
|
|
1168
|
-
if (doReload) shouldClientHardReload = true;
|
|
1169
|
-
}
|
|
1170
|
-
{
|
|
1171
|
-
const { shouldClientHardReload: doReload } = await buildPages(path.resolve(DIST_DIR));
|
|
1172
|
-
if (doReload) shouldClientHardReload = true;
|
|
1173
|
-
}
|
|
1174
|
-
await shipModules();
|
|
1175
|
-
const pagesBuilt = performance.now();
|
|
1176
|
-
await buildClient(DIST_DIR);
|
|
1177
|
-
const end = performance.now();
|
|
1178
|
-
if (options.publicDirectory) {
|
|
1179
|
-
log2("Recursively copying public directory.. this may take a while.");
|
|
1180
|
-
const src = path.relative(process.cwd(), options.publicDirectory.path);
|
|
1181
|
-
if (fs.existsSync(src) === false) {
|
|
1182
|
-
console.warn("WARNING: Public directory not found, an attempt will be made create it..");
|
|
1183
|
-
fs.mkdirSync(src, { recursive: true });
|
|
1184
|
-
}
|
|
1185
|
-
await fs.promises.cp(src, path.join(DIST_DIR), { recursive: true });
|
|
1186
|
-
}
|
|
1187
|
-
{
|
|
1188
|
-
log2(`Took ${Math.round(pagesBuilt - start)}ms to Build Pages.`);
|
|
1189
|
-
log2(`Took ${Math.round(end - pagesBuilt)}ms to Build Client.`);
|
|
1190
|
-
}
|
|
1191
|
-
process.send?.({ event: "message", data: "set-pages-and-layouts", content: JSON.stringify({ pageMap: Array.from(PAGE_MAP), layoutMap: Array.from(LAYOUT_MAP) }) });
|
|
1192
|
-
process.send?.({ event: "message", data: "compile-finish" });
|
|
1193
|
-
if (shouldClientHardReload) {
|
|
1194
|
-
process.send({ event: "message", data: "hard-reload" });
|
|
1195
|
-
} else {
|
|
1196
|
-
process.send({ event: "message", data: "soft-reload" });
|
|
1197
|
-
}
|
|
1198
|
-
} catch (e) {
|
|
1199
|
-
console.error("Build Failed! Received Error:");
|
|
1200
|
-
console.error(e);
|
|
1201
|
-
return false;
|
|
1202
|
-
}
|
|
1203
|
-
return true;
|
|
1204
|
-
};
|
|
1205
|
-
(async () => {
|
|
1206
|
-
if (process.env.DO_BUILD === "true") await build();
|
|
1207
|
-
})();
|
|
1208
|
-
}
|
|
1209
|
-
});
|
|
1210
|
-
|
|
1211
|
-
// src/build.ts
|
|
1212
|
-
import fs3 from "fs";
|
|
1213
|
-
import path2 from "path";
|
|
1214
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1215
4
|
import child_process from "node:child_process";
|
|
1216
5
|
import http from "http";
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
import
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
} from "fs";
|
|
1225
|
-
import {
|
|
1226
|
-
join,
|
|
1227
|
-
normalize,
|
|
1228
|
-
extname,
|
|
1229
|
-
dirname
|
|
1230
|
-
} from "path";
|
|
1231
|
-
import {
|
|
1232
|
-
pathToFileURL
|
|
1233
|
-
} from "url";
|
|
1234
|
-
|
|
1235
|
-
// src/log.ts
|
|
1236
|
-
var quiet = false;
|
|
1237
|
-
function setQuiet(value) {
|
|
1238
|
-
quiet = value;
|
|
1239
|
-
}
|
|
1240
|
-
function getTimestamp() {
|
|
1241
|
-
const now = /* @__PURE__ */ new Date();
|
|
1242
|
-
return now.toLocaleString(void 0, {
|
|
1243
|
-
year: "2-digit",
|
|
1244
|
-
month: "2-digit",
|
|
1245
|
-
day: "2-digit",
|
|
1246
|
-
hour: "2-digit",
|
|
1247
|
-
minute: "2-digit",
|
|
1248
|
-
second: "2-digit"
|
|
1249
|
-
});
|
|
1250
|
-
}
|
|
1251
|
-
function color(text, code) {
|
|
1252
|
-
return `\x1B[${code}m${text}\x1B[0m`;
|
|
1253
|
-
}
|
|
1254
|
-
function logInfo(...args) {
|
|
1255
|
-
if (quiet) return;
|
|
1256
|
-
console.info(`Elegance.JS: ${getTimestamp()} ${color("[INFO]:", 34)}`, ...args);
|
|
1257
|
-
}
|
|
1258
|
-
function logWarn(...args) {
|
|
1259
|
-
if (quiet) return;
|
|
1260
|
-
console.warn(`Elegance.JS: ${getTimestamp()} ${color("[WARN]:", 33)}`, ...args);
|
|
1261
|
-
}
|
|
1262
|
-
function logError(...args) {
|
|
1263
|
-
console.error(`Elegance.JS: ${getTimestamp()} ${color("[ERROR]:", 31)}`, ...args);
|
|
1264
|
-
}
|
|
1265
|
-
var log = {
|
|
1266
|
-
info: logInfo,
|
|
1267
|
-
warn: logWarn,
|
|
1268
|
-
error: logError
|
|
1269
|
-
};
|
|
1270
|
-
|
|
1271
|
-
// src/server/server.ts
|
|
1272
|
-
import {
|
|
1273
|
-
gzip,
|
|
1274
|
-
deflate
|
|
1275
|
-
} from "zlib";
|
|
1276
|
-
import {
|
|
1277
|
-
promisify
|
|
1278
|
-
} from "util";
|
|
1279
|
-
var gzipAsync = promisify(gzip);
|
|
1280
|
-
var deflateAsync = promisify(deflate);
|
|
1281
|
-
var MIME_TYPES = {
|
|
1282
|
-
".html": "text/html; charset=utf-8",
|
|
1283
|
-
".css": "text/css; charset=utf-8",
|
|
1284
|
-
".js": "application/javascript; charset=utf-8",
|
|
1285
|
-
".json": "application/json; charset=utf-8",
|
|
1286
|
-
".png": "image/png",
|
|
1287
|
-
".jpg": "image/jpeg",
|
|
1288
|
-
".jpeg": "image/jpeg",
|
|
1289
|
-
".gif": "image/gif",
|
|
1290
|
-
".svg": "image/svg+xml",
|
|
1291
|
-
".ico": "image/x-icon",
|
|
1292
|
-
".txt": "text/plain; charset=utf-8"
|
|
1293
|
-
};
|
|
1294
|
-
function startServer({
|
|
1295
|
-
root,
|
|
1296
|
-
pagesDirectory,
|
|
1297
|
-
port = 3e3,
|
|
1298
|
-
host = "localhost",
|
|
1299
|
-
environment = "production",
|
|
1300
|
-
DIST_DIR: DIST_DIR2
|
|
1301
|
-
}) {
|
|
1302
|
-
if (!root) throw new Error("Root directory must be specified.");
|
|
1303
|
-
if (!pagesDirectory) throw new Error("Pages directory must be specified.");
|
|
1304
|
-
root = normalize(root).replace(/[\\/]+$/, "");
|
|
1305
|
-
pagesDirectory = normalize(pagesDirectory).replace(/[\\/]+$/, "");
|
|
1306
|
-
const requestHandler = async (req, res) => {
|
|
1307
|
-
try {
|
|
1308
|
-
if (!req.url) {
|
|
1309
|
-
await sendResponse(req, res, 400, {
|
|
1310
|
-
"Content-Type": "text/plain; charset=utf-8"
|
|
1311
|
-
}, "Bad Request");
|
|
1312
|
-
return;
|
|
1313
|
-
}
|
|
1314
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1315
|
-
res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
|
|
1316
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
1317
|
-
if (req.method === "OPTIONS") {
|
|
1318
|
-
res.writeHead(204);
|
|
1319
|
-
res.end();
|
|
1320
|
-
if (environment === "development") {
|
|
1321
|
-
log.info(req.method, "::", req.url, "-", res.statusCode);
|
|
1322
|
-
}
|
|
1323
|
-
return;
|
|
1324
|
-
}
|
|
1325
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
1326
|
-
if (url.pathname.startsWith("/api/")) {
|
|
1327
|
-
await handleApiRequest(pagesDirectory, url.pathname, req, res);
|
|
1328
|
-
} else if (PAGE_MAP2.has(url.pathname)) {
|
|
1329
|
-
await handlePageRequest(root, pagesDirectory, url.pathname, req, res, DIST_DIR2, PAGE_MAP2.get(url.pathname));
|
|
1330
|
-
} else {
|
|
1331
|
-
await handleStaticRequest(root, pagesDirectory, url.pathname, req, res, DIST_DIR2);
|
|
1332
|
-
}
|
|
1333
|
-
if (environment === "development") {
|
|
1334
|
-
log.info(req.method, "::", req.url, "-", res.statusCode);
|
|
1335
|
-
}
|
|
1336
|
-
} catch (err) {
|
|
1337
|
-
log.error(err);
|
|
1338
|
-
await sendResponse(req, res, 500, {
|
|
1339
|
-
"Content-Type": "text/plain; charset=utf-8"
|
|
1340
|
-
}, "Internal Server Error");
|
|
1341
|
-
}
|
|
1342
|
-
};
|
|
1343
|
-
function attemptListen(p) {
|
|
1344
|
-
const server = createHttpServer(requestHandler);
|
|
1345
|
-
server.on("error", (err) => {
|
|
1346
|
-
if (err.code === "EADDRINUSE") {
|
|
1347
|
-
attemptListen(p + 1);
|
|
1348
|
-
} else {
|
|
1349
|
-
console.error(err);
|
|
1350
|
-
}
|
|
1351
|
-
});
|
|
1352
|
-
server.listen(p, host, () => {
|
|
1353
|
-
log.info(`Server running at http://${host}:${p}/`);
|
|
1354
|
-
});
|
|
1355
|
-
return server;
|
|
1356
|
-
}
|
|
1357
|
-
return attemptListen(port);
|
|
1358
|
-
}
|
|
1359
|
-
async function getTargetInfo(root, pathname) {
|
|
1360
|
-
const originalPathname = pathname;
|
|
1361
|
-
const filePath = normalize(join(root, decodeURIComponent(pathname))).replace(/[\\/]+$/, "");
|
|
1362
|
-
if (!filePath.startsWith(root)) {
|
|
1363
|
-
throw new Error("Forbidden");
|
|
1364
|
-
}
|
|
1365
|
-
let stats;
|
|
1366
|
-
try {
|
|
1367
|
-
stats = await fs2.stat(filePath);
|
|
1368
|
-
} catch {
|
|
1369
|
-
}
|
|
1370
|
-
let targetDir;
|
|
1371
|
-
if (stats) {
|
|
1372
|
-
targetDir = stats.isDirectory() ? filePath : dirname(filePath);
|
|
1373
|
-
} else {
|
|
1374
|
-
targetDir = originalPathname.endsWith("/") ? filePath : dirname(filePath);
|
|
1375
|
-
}
|
|
1376
|
-
return {
|
|
1377
|
-
filePath,
|
|
1378
|
-
targetDir,
|
|
1379
|
-
stats
|
|
1380
|
-
};
|
|
1381
|
-
}
|
|
1382
|
-
function getMiddlewareDirs(base, parts) {
|
|
1383
|
-
const middlewareDirs = [];
|
|
1384
|
-
let current = base;
|
|
1385
|
-
middlewareDirs.push(current);
|
|
1386
|
-
for (const part of parts) {
|
|
1387
|
-
current = join(current, part);
|
|
1388
|
-
middlewareDirs.push(current);
|
|
1389
|
-
}
|
|
1390
|
-
return middlewareDirs;
|
|
1391
|
-
}
|
|
1392
|
-
async function collectMiddlewares(dirs) {
|
|
1393
|
-
const middlewares = [];
|
|
1394
|
-
for (const dir of dirs) {
|
|
1395
|
-
const mwPath = join(dir, "middleware.ts");
|
|
1396
|
-
let mwModule;
|
|
1397
|
-
try {
|
|
1398
|
-
await fs2.access(mwPath);
|
|
1399
|
-
const url = pathToFileURL(mwPath).href;
|
|
1400
|
-
mwModule = await import(url);
|
|
1401
|
-
} catch {
|
|
1402
|
-
continue;
|
|
1403
|
-
}
|
|
1404
|
-
const mwKeys = Object.keys(mwModule).sort();
|
|
1405
|
-
for (const key of mwKeys) {
|
|
1406
|
-
const f = mwModule[key];
|
|
1407
|
-
if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
|
|
1408
|
-
middlewares.push(f);
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
return middlewares;
|
|
1413
|
-
}
|
|
1414
|
-
async function handlePageRequest(root, pagesDirectory, pathname, req, res, DIST_DIR2, pageInfo) {
|
|
1415
|
-
try {
|
|
1416
|
-
const {
|
|
1417
|
-
filePath,
|
|
1418
|
-
targetDir,
|
|
1419
|
-
stats
|
|
1420
|
-
} = await getTargetInfo(root, pathname);
|
|
1421
|
-
const relDir = targetDir.slice(root.length).replace(/^[\/\\]+/, "");
|
|
1422
|
-
const parts = relDir.split(/[\\/]/).filter(Boolean);
|
|
1423
|
-
const middlewareDirs = getMiddlewareDirs(pagesDirectory, parts);
|
|
1424
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
1425
|
-
const data = {};
|
|
1426
|
-
const isDynamic = pageInfo.isDynamic;
|
|
1427
|
-
const handlerPath = isDynamic ? pageInfo.filePath : join(filePath, "index.html");
|
|
1428
|
-
let hasHandler = false;
|
|
1429
|
-
try {
|
|
1430
|
-
await fs2.access(handlerPath);
|
|
1431
|
-
hasHandler = true;
|
|
1432
|
-
} catch {
|
|
1433
|
-
}
|
|
1434
|
-
const finalHandler = async (req2, res2) => {
|
|
1435
|
-
if (!hasHandler) {
|
|
1436
|
-
await respondWithErrorPage(root, pathname, 404, req2, res2);
|
|
1437
|
-
return;
|
|
1438
|
-
}
|
|
1439
|
-
if (isDynamic) {
|
|
1440
|
-
try {
|
|
1441
|
-
const {
|
|
1442
|
-
buildDynamicPage: buildDynamicPage2
|
|
1443
|
-
} = await Promise.resolve().then(() => (init_page_compiler(), page_compiler_exports));
|
|
1444
|
-
const result = await buildDynamicPage2(
|
|
1445
|
-
DIST_DIR2,
|
|
1446
|
-
pathname,
|
|
1447
|
-
pageInfo,
|
|
1448
|
-
req2,
|
|
1449
|
-
res2,
|
|
1450
|
-
data
|
|
1451
|
-
);
|
|
1452
|
-
if (result === false) {
|
|
1453
|
-
return;
|
|
1454
|
-
}
|
|
1455
|
-
const {
|
|
1456
|
-
resultHTML
|
|
1457
|
-
} = result;
|
|
1458
|
-
if (resultHTML === false) {
|
|
1459
|
-
return;
|
|
1460
|
-
}
|
|
1461
|
-
await sendResponse(req2, res2, 200, {
|
|
1462
|
-
"Content-Type": MIME_TYPES[".html"]
|
|
1463
|
-
}, resultHTML);
|
|
1464
|
-
} catch (err) {
|
|
1465
|
-
log.error("Error building dynamic page -", err);
|
|
1466
|
-
}
|
|
1467
|
-
} else {
|
|
1468
|
-
const ext = extname(handlerPath).toLowerCase();
|
|
1469
|
-
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
1470
|
-
const fileData = await fs2.readFile(handlerPath);
|
|
1471
|
-
await sendResponse(req2, res2, 200, {
|
|
1472
|
-
"Content-Type": contentType
|
|
1473
|
-
}, fileData);
|
|
1474
|
-
}
|
|
1475
|
-
};
|
|
1476
|
-
const composed = composeMiddlewares(middlewares, finalHandler, {
|
|
1477
|
-
isApi: false,
|
|
1478
|
-
root,
|
|
1479
|
-
pathname,
|
|
1480
|
-
data
|
|
1481
|
-
});
|
|
1482
|
-
await composed(req, res);
|
|
1483
|
-
} catch (err) {
|
|
1484
|
-
if (err.message === "Forbidden") {
|
|
1485
|
-
await sendResponse(req, res, 403, {
|
|
1486
|
-
"Content-Type": "text/plain; charset=utf-8"
|
|
1487
|
-
}, "Forbidden");
|
|
1488
|
-
} else {
|
|
1489
|
-
throw err;
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
async function handleStaticRequest(root, pagesDirectory, pathname, req, res, DIST_DIR2) {
|
|
1494
|
-
try {
|
|
1495
|
-
const {
|
|
1496
|
-
filePath,
|
|
1497
|
-
targetDir,
|
|
1498
|
-
stats
|
|
1499
|
-
} = await getTargetInfo(root, pathname);
|
|
1500
|
-
const relDir = targetDir.slice(root.length).replace(/^[\/\\]+/, "");
|
|
1501
|
-
const parts = relDir.split(/[\\/]/).filter(Boolean);
|
|
1502
|
-
const middlewareDirs = getMiddlewareDirs(pagesDirectory, parts);
|
|
1503
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
1504
|
-
let handlerPath = filePath;
|
|
1505
|
-
if (stats && stats.isDirectory()) {
|
|
1506
|
-
handlerPath = join(filePath, "index.html");
|
|
1507
|
-
}
|
|
1508
|
-
let hasHandler = false;
|
|
1509
|
-
try {
|
|
1510
|
-
await fs2.access(handlerPath);
|
|
1511
|
-
hasHandler = true;
|
|
1512
|
-
} catch {
|
|
1513
|
-
}
|
|
1514
|
-
const finalHandler = async (req2, res2) => {
|
|
1515
|
-
if (!hasHandler) {
|
|
1516
|
-
await respondWithErrorPage(root, pathname, 404, req2, res2);
|
|
1517
|
-
return;
|
|
1518
|
-
}
|
|
1519
|
-
const ext = extname(handlerPath).toLowerCase();
|
|
1520
|
-
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
1521
|
-
const fileData = await fs2.readFile(handlerPath);
|
|
1522
|
-
await sendResponse(req2, res2, 200, {
|
|
1523
|
-
"Content-Type": contentType
|
|
1524
|
-
}, fileData);
|
|
1525
|
-
};
|
|
1526
|
-
const composed = composeMiddlewares(middlewares, finalHandler, {
|
|
1527
|
-
isApi: false,
|
|
1528
|
-
root,
|
|
1529
|
-
pathname
|
|
1530
|
-
});
|
|
1531
|
-
await composed(req, res);
|
|
1532
|
-
} catch (err) {
|
|
1533
|
-
if (err.message === "Forbidden") {
|
|
1534
|
-
await sendResponse(req, res, 403, {
|
|
1535
|
-
"Content-Type": "text/plain; charset=utf-8"
|
|
1536
|
-
}, "Forbidden");
|
|
1537
|
-
} else {
|
|
1538
|
-
throw err;
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
async function handleApiRequest(pagesDirectory, pathname, req, res) {
|
|
1543
|
-
const apiSubPath = pathname.slice("/api/".length);
|
|
1544
|
-
const parts = apiSubPath.split("/").filter(Boolean);
|
|
1545
|
-
const middlewareDirs = getMiddlewareDirs(join(pagesDirectory, "api"), parts);
|
|
1546
|
-
const middlewares = await collectMiddlewares(middlewareDirs);
|
|
1547
|
-
const routeDir = middlewareDirs[middlewareDirs.length - 1];
|
|
1548
|
-
const routePath = join(routeDir, "route.ts");
|
|
1549
|
-
let hasRoute = false;
|
|
1550
|
-
try {
|
|
1551
|
-
await fs2.access(routePath);
|
|
1552
|
-
hasRoute = true;
|
|
1553
|
-
} catch {
|
|
1554
|
-
}
|
|
1555
|
-
let fn = null;
|
|
1556
|
-
let module = null;
|
|
1557
|
-
if (hasRoute) {
|
|
1558
|
-
try {
|
|
1559
|
-
const moduleUrl = pathToFileURL(routePath).href;
|
|
1560
|
-
module = await import(moduleUrl);
|
|
1561
|
-
fn = module[req.method];
|
|
1562
|
-
} catch (err) {
|
|
1563
|
-
console.error(err);
|
|
1564
|
-
return respondWithJsonError(req, res, 500, "Internal Server Error");
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
const finalHandler = async (req2, res2) => {
|
|
1568
|
-
if (!hasRoute) {
|
|
1569
|
-
return respondWithJsonError(req2, res2, 404, "Not Found");
|
|
1570
|
-
}
|
|
1571
|
-
if (typeof fn !== "function") {
|
|
1572
|
-
return respondWithJsonError(req2, res2, 405, "Method Not Allowed");
|
|
1573
|
-
}
|
|
1574
|
-
await fn(req2, res2);
|
|
1575
|
-
};
|
|
1576
|
-
const composed = composeMiddlewares(middlewares, finalHandler, {
|
|
1577
|
-
isApi: true
|
|
1578
|
-
});
|
|
1579
|
-
await composed(req, res);
|
|
1580
|
-
}
|
|
1581
|
-
function composeMiddlewares(mws, final, options3) {
|
|
1582
|
-
return async function(req, res) {
|
|
1583
|
-
let index = 0;
|
|
1584
|
-
async function dispatch(err) {
|
|
1585
|
-
if (err) {
|
|
1586
|
-
if (options3.isApi) {
|
|
1587
|
-
return respondWithJsonError(req, res, 500, err.message || "Internal Server Error");
|
|
1588
|
-
} else {
|
|
1589
|
-
return await respondWithErrorPage(options3.root, options3.pathname, 500, req, res);
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
if (index >= mws.length) {
|
|
1593
|
-
return await final(req, res);
|
|
1594
|
-
}
|
|
1595
|
-
const thisMw = mws[index++];
|
|
1596
|
-
const next = (e) => dispatch(e);
|
|
1597
|
-
const onceNext = (nextFn) => {
|
|
1598
|
-
let called = false;
|
|
1599
|
-
return async (e) => {
|
|
1600
|
-
if (called) {
|
|
1601
|
-
log.warn("next() was called in a middleware more than once.");
|
|
1602
|
-
return;
|
|
1603
|
-
}
|
|
1604
|
-
called = true;
|
|
1605
|
-
await nextFn(e);
|
|
1606
|
-
};
|
|
1607
|
-
};
|
|
1608
|
-
try {
|
|
1609
|
-
await thisMw(req, res, onceNext(next), options3.data || {});
|
|
1610
|
-
} catch (error) {
|
|
1611
|
-
await dispatch(error);
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
await dispatch();
|
|
1615
|
-
};
|
|
1616
|
-
}
|
|
1617
|
-
async function respondWithJsonError(req, res, code, message) {
|
|
1618
|
-
const body2 = JSON.stringify({
|
|
1619
|
-
error: message
|
|
1620
|
-
});
|
|
1621
|
-
await sendResponse(req, res, code, {
|
|
1622
|
-
"Content-Type": "application/json; charset=utf-8"
|
|
1623
|
-
}, body2);
|
|
1624
|
-
}
|
|
1625
|
-
async function respondWithErrorPage(root, pathname, code, req, res) {
|
|
1626
|
-
let currentPath = normalize(join(root, decodeURIComponent(pathname)));
|
|
1627
|
-
let tried = /* @__PURE__ */ new Set();
|
|
1628
|
-
let errorFilePath = null;
|
|
1629
|
-
while (currentPath.startsWith(root)) {
|
|
1630
|
-
const candidate = join(currentPath, `${code}.html`);
|
|
1631
|
-
if (!tried.has(candidate)) {
|
|
1632
|
-
try {
|
|
1633
|
-
await fs2.access(candidate);
|
|
1634
|
-
errorFilePath = candidate;
|
|
1635
|
-
break;
|
|
1636
|
-
} catch {
|
|
1637
|
-
}
|
|
1638
|
-
tried.add(candidate);
|
|
1639
|
-
}
|
|
1640
|
-
const parent = dirname(currentPath);
|
|
1641
|
-
if (parent === currentPath) break;
|
|
1642
|
-
currentPath = parent;
|
|
1643
|
-
}
|
|
1644
|
-
if (!errorFilePath) {
|
|
1645
|
-
const fallback = join(root, `${code}.html`);
|
|
1646
|
-
try {
|
|
1647
|
-
await fs2.access(fallback);
|
|
1648
|
-
errorFilePath = fallback;
|
|
1649
|
-
} catch {
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
if (errorFilePath) {
|
|
1653
|
-
try {
|
|
1654
|
-
const html2 = await fs2.readFile(errorFilePath, "utf8");
|
|
1655
|
-
await sendResponse(req, res, code, {
|
|
1656
|
-
"Content-Type": "text/html; charset=utf-8"
|
|
1657
|
-
}, html2);
|
|
1658
|
-
return;
|
|
1659
|
-
} catch {
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
await sendResponse(req, res, code, {
|
|
1663
|
-
"Content-Type": "text/plain; charset=utf-8"
|
|
1664
|
-
}, `${code} Error`);
|
|
1665
|
-
}
|
|
1666
|
-
function isCompressible(contentType) {
|
|
1667
|
-
if (!contentType) return false;
|
|
1668
|
-
return /text\/|javascript|json|xml|svg/.test(contentType);
|
|
1669
|
-
}
|
|
1670
|
-
async function sendResponse(req, res, status, headers, body2) {
|
|
1671
|
-
let bufferBody = typeof body2 === "string" ? Buffer.from(body2) : body2;
|
|
1672
|
-
const accept = req.headers["accept-encoding"] || "";
|
|
1673
|
-
let encoding = null;
|
|
1674
|
-
if (accept.match(/\bgzip\b/)) {
|
|
1675
|
-
encoding = "gzip";
|
|
1676
|
-
} else if (accept.match(/\bdeflate\b/)) {
|
|
1677
|
-
encoding = "deflate";
|
|
1678
|
-
}
|
|
1679
|
-
if (!encoding || !isCompressible(headers["Content-Type"] || "")) {
|
|
1680
|
-
res.writeHead(status, headers);
|
|
1681
|
-
res.end(bufferBody);
|
|
1682
|
-
return;
|
|
1683
|
-
}
|
|
1684
|
-
const compressor = encoding === "gzip" ? gzipAsync : deflateAsync;
|
|
1685
|
-
try {
|
|
1686
|
-
const compressed = await compressor(bufferBody);
|
|
1687
|
-
headers["Content-Encoding"] = encoding;
|
|
1688
|
-
headers["Vary"] = "Accept-Encoding";
|
|
1689
|
-
res.writeHead(status, headers);
|
|
1690
|
-
res.end(compressed);
|
|
1691
|
-
} catch (err) {
|
|
1692
|
-
log.error("Compression error:", err);
|
|
1693
|
-
res.writeHead(status, headers);
|
|
1694
|
-
res.end(bufferBody);
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
// src/build.ts
|
|
1699
|
-
var __filename2 = fileURLToPath3(import.meta.url);
|
|
1700
|
-
var __dirname2 = path2.dirname(__filename2);
|
|
1701
|
-
var packageDir2 = path2.resolve(__dirname2, "..");
|
|
1702
|
-
var builderPath = path2.resolve(packageDir2, "./dist/page_compiler.mjs");
|
|
1703
|
-
var yellow2 = (text) => {
|
|
6
|
+
import { startServer } from "./server/server";
|
|
7
|
+
import { log, setQuiet } from "./log";
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
const packageDir = path.resolve(__dirname, "..");
|
|
11
|
+
const builderPath = path.resolve(packageDir, "./dist/page_compiler.mjs");
|
|
12
|
+
const yellow = (text) => {
|
|
1704
13
|
return `\x1B[38;2;238;184;68m${text}`;
|
|
1705
14
|
};
|
|
1706
|
-
|
|
15
|
+
const bold = (text) => {
|
|
1707
16
|
return `\x1B[1m${text}`;
|
|
1708
17
|
};
|
|
1709
|
-
|
|
18
|
+
const white = (text) => {
|
|
1710
19
|
return `\x1B[38;2;255;247;229m${text}`;
|
|
1711
20
|
};
|
|
1712
|
-
|
|
21
|
+
const green = (text) => {
|
|
1713
22
|
return `\x1B[38;2;65;224;108m${text}`;
|
|
1714
23
|
};
|
|
1715
|
-
|
|
24
|
+
const finishLog = (...text) => {
|
|
1716
25
|
log.info(text.map((text2) => `${text2}\x1B[0m`).join(""));
|
|
1717
26
|
};
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
27
|
+
let PAGE_MAP = /* @__PURE__ */ new Map();
|
|
28
|
+
let LAYOUT_MAP = /* @__PURE__ */ new Map();
|
|
29
|
+
let options = process.env.OPTIONS;
|
|
30
|
+
const getAllSubdirectories = (dir, baseDir = dir) => {
|
|
1722
31
|
let directories = [];
|
|
1723
|
-
const items =
|
|
32
|
+
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
1724
33
|
for (const item of items) {
|
|
1725
34
|
if (item.isDirectory()) {
|
|
1726
|
-
const fullPath =
|
|
1727
|
-
const relativePath =
|
|
35
|
+
const fullPath = path.join(dir, item.name);
|
|
36
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
1728
37
|
directories.push(relativePath);
|
|
1729
|
-
directories = directories.concat(
|
|
38
|
+
directories = directories.concat(getAllSubdirectories(fullPath, baseDir));
|
|
1730
39
|
}
|
|
1731
40
|
}
|
|
1732
41
|
return directories;
|
|
1733
42
|
};
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
const optionsString = JSON.stringify(
|
|
43
|
+
let child = void 0;
|
|
44
|
+
let isBuilding = false;
|
|
45
|
+
const runBuild = (filepath, DIST_DIR) => {
|
|
46
|
+
const optionsString = JSON.stringify(options);
|
|
1738
47
|
if (isBuilding) {
|
|
1739
48
|
return;
|
|
1740
49
|
}
|
|
@@ -1742,18 +51,18 @@ var runBuild = (filepath, DIST_DIR2) => {
|
|
|
1742
51
|
child.removeAllListeners();
|
|
1743
52
|
child.kill("SIGKILL");
|
|
1744
53
|
}
|
|
1745
|
-
child = child_process.spawn("node", [filepath], {
|
|
54
|
+
child = child_process.spawn("node", ["--import", "ts-arc/register", filepath], {
|
|
1746
55
|
stdio: ["inherit", "inherit", "inherit", "ipc"],
|
|
1747
56
|
env: {
|
|
1748
57
|
...process.env,
|
|
1749
|
-
DIST_DIR
|
|
58
|
+
DIST_DIR,
|
|
1750
59
|
OPTIONS: optionsString,
|
|
1751
|
-
PACKAGE_PATH:
|
|
60
|
+
PACKAGE_PATH: packageDir,
|
|
1752
61
|
DO_BUILD: "true"
|
|
1753
62
|
}
|
|
1754
63
|
});
|
|
1755
64
|
process.env.OPTIONS = optionsString;
|
|
1756
|
-
process.env.DIST_DIR =
|
|
65
|
+
process.env.DIST_DIR = DIST_DIR;
|
|
1757
66
|
child.on("error", () => {
|
|
1758
67
|
log.error("Failed to start child process.");
|
|
1759
68
|
});
|
|
@@ -1773,29 +82,29 @@ var runBuild = (filepath, DIST_DIR2) => {
|
|
|
1773
82
|
`);
|
|
1774
83
|
} else if (data === "compile-finish") {
|
|
1775
84
|
isBuilding = false;
|
|
1776
|
-
if (
|
|
85
|
+
if (options.postCompile) {
|
|
1777
86
|
finishLog(
|
|
1778
|
-
|
|
87
|
+
white("Calling post-compile hook..")
|
|
1779
88
|
);
|
|
1780
|
-
|
|
89
|
+
options.postCompile();
|
|
1781
90
|
}
|
|
1782
91
|
} else if (data === "set-pages-and-layouts") {
|
|
1783
92
|
const { pageMap, layoutMap } = JSON.parse(message.content);
|
|
1784
|
-
|
|
1785
|
-
|
|
93
|
+
PAGE_MAP = new Map(pageMap);
|
|
94
|
+
LAYOUT_MAP = new Map(layoutMap);
|
|
1786
95
|
}
|
|
1787
96
|
});
|
|
1788
97
|
};
|
|
1789
|
-
|
|
1790
|
-
runBuild(builderPath,
|
|
98
|
+
const build = (DIST_DIR) => {
|
|
99
|
+
runBuild(builderPath, DIST_DIR);
|
|
1791
100
|
};
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
101
|
+
let isTimedOut = false;
|
|
102
|
+
const currentWatchers = [];
|
|
103
|
+
let httpStream;
|
|
104
|
+
const registerListener = async () => {
|
|
1796
105
|
const server = http.createServer((req, res) => {
|
|
1797
106
|
if (req.url === "/events") {
|
|
1798
|
-
finishLog(
|
|
107
|
+
finishLog(white("Client listening for changes.."));
|
|
1799
108
|
res.writeHead(200, {
|
|
1800
109
|
"Content-Type": "text/event-stream",
|
|
1801
110
|
"Cache-Control": "no-cache",
|
|
@@ -1816,39 +125,39 @@ var registerListener = async () => {
|
|
|
1816
125
|
res.end("Not Found");
|
|
1817
126
|
}
|
|
1818
127
|
});
|
|
1819
|
-
server.listen(
|
|
1820
|
-
finishLog(
|
|
128
|
+
server.listen(options.hotReload.port, () => {
|
|
129
|
+
finishLog(bold(green("Hot-Reload server online!")));
|
|
1821
130
|
});
|
|
1822
131
|
};
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
setQuiet(
|
|
1826
|
-
const watch =
|
|
1827
|
-
const BUILD_FLAG =
|
|
1828
|
-
if (!
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
132
|
+
const compile = async (props) => {
|
|
133
|
+
options = props;
|
|
134
|
+
setQuiet(options.quiet ?? false);
|
|
135
|
+
const watch = options.hotReload !== void 0;
|
|
136
|
+
const BUILD_FLAG = path.join(options.outputDirectory, "ELEGANCE_BUILD_FLAG");
|
|
137
|
+
if (!fs.existsSync(options.outputDirectory)) {
|
|
138
|
+
fs.mkdirSync(options.outputDirectory, { recursive: true });
|
|
139
|
+
fs.writeFileSync(
|
|
140
|
+
path.join(BUILD_FLAG),
|
|
1832
141
|
"This file just marks this directory as one containing an Elegance Build.",
|
|
1833
142
|
"utf-8"
|
|
1834
143
|
);
|
|
1835
144
|
} else {
|
|
1836
|
-
if (!
|
|
145
|
+
if (!fs.existsSync(BUILD_FLAG)) {
|
|
1837
146
|
throw `The output directory already exists, but is not an Elegance Build directory.`;
|
|
1838
147
|
}
|
|
1839
148
|
}
|
|
1840
|
-
const
|
|
1841
|
-
if (!
|
|
1842
|
-
|
|
149
|
+
const DIST_DIR = path.join(props.outputDirectory, "dist");
|
|
150
|
+
if (!fs.existsSync(DIST_DIR)) {
|
|
151
|
+
fs.mkdirSync(DIST_DIR, { recursive: true });
|
|
1843
152
|
}
|
|
1844
|
-
if (
|
|
153
|
+
if (options.server != void 0 && options.server.runServer == true) {
|
|
1845
154
|
startServer({
|
|
1846
|
-
root:
|
|
1847
|
-
environment:
|
|
1848
|
-
port:
|
|
1849
|
-
host:
|
|
1850
|
-
DIST_DIR
|
|
1851
|
-
pagesDirectory:
|
|
155
|
+
root: options.server.root ?? DIST_DIR,
|
|
156
|
+
environment: options.environment,
|
|
157
|
+
port: options.server.port ?? 3e3,
|
|
158
|
+
host: options.server.host ?? "localhost",
|
|
159
|
+
DIST_DIR,
|
|
160
|
+
pagesDirectory: options.pagesDirectory
|
|
1852
161
|
});
|
|
1853
162
|
}
|
|
1854
163
|
if (watch) {
|
|
@@ -1857,29 +166,29 @@ var compile = async (props) => {
|
|
|
1857
166
|
watcher.close();
|
|
1858
167
|
}
|
|
1859
168
|
let extra = [];
|
|
1860
|
-
if (
|
|
1861
|
-
const dirs =
|
|
169
|
+
if (options.hotReload?.extraWatchDirectories) {
|
|
170
|
+
const dirs = options.hotReload?.extraWatchDirectories ?? [];
|
|
1862
171
|
if (dirs.length !== 0) {
|
|
1863
172
|
for (const dir of dirs) {
|
|
1864
|
-
const subdirs =
|
|
173
|
+
const subdirs = getAllSubdirectories(dir).map((f) => path.join(dir, f));
|
|
1865
174
|
extra.push(...subdirs);
|
|
1866
175
|
}
|
|
1867
176
|
}
|
|
1868
177
|
}
|
|
1869
|
-
const pagesSubDirs =
|
|
1870
|
-
const subdirectories = [...pagesSubDirs,
|
|
1871
|
-
finishLog(
|
|
178
|
+
const pagesSubDirs = getAllSubdirectories(options.pagesDirectory).map((f) => path.join(options.pagesDirectory, f));
|
|
179
|
+
const subdirectories = [...pagesSubDirs, options.pagesDirectory, ...extra];
|
|
180
|
+
finishLog(yellow("Hot-Reload Watching Subdirectories: "), ...subdirectories.join(", "));
|
|
1872
181
|
const watcherFn = async () => {
|
|
1873
182
|
if (isTimedOut) return;
|
|
1874
183
|
isTimedOut = true;
|
|
1875
184
|
process.stdout.write("\x1Bc");
|
|
1876
185
|
setTimeout(async () => {
|
|
1877
|
-
|
|
186
|
+
build(DIST_DIR);
|
|
1878
187
|
isTimedOut = false;
|
|
1879
188
|
}, 100);
|
|
1880
189
|
};
|
|
1881
190
|
for (const directory of subdirectories) {
|
|
1882
|
-
const watcher =
|
|
191
|
+
const watcher = fs.watch(
|
|
1883
192
|
directory,
|
|
1884
193
|
{},
|
|
1885
194
|
watcherFn
|
|
@@ -1887,10 +196,10 @@ var compile = async (props) => {
|
|
|
1887
196
|
currentWatchers.push(watcher);
|
|
1888
197
|
}
|
|
1889
198
|
}
|
|
1890
|
-
|
|
199
|
+
build(DIST_DIR);
|
|
1891
200
|
};
|
|
1892
201
|
export {
|
|
1893
|
-
|
|
1894
|
-
|
|
202
|
+
LAYOUT_MAP,
|
|
203
|
+
PAGE_MAP,
|
|
1895
204
|
compile
|
|
1896
205
|
};
|