elegance-js 2.0.19 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.mjs +23 -974
- package/dist/client/client.mjs +20 -13
- package/dist/compile_docs.mjs +29 -980
- package/dist/global.d.ts +18 -5
- package/dist/index.mjs +9 -6
- package/dist/page_compiler.d.ts +5 -0
- package/dist/page_compiler.mjs +658 -109
- package/dist/server/generateHTMLTemplate.d.ts +1 -1
- package/dist/server/generateHTMLTemplate.mjs +5 -4
- package/dist/server/server.mjs +874 -317
- package/dist/server/state.d.ts +17 -0
- package/dist/server/state.mjs +9 -6
- package/package.json +2 -2
- package/dist/components/Breakpoint.d.ts +0 -3
- package/dist/components/Breakpoint.mjs +0 -20
- package/dist/dynamic_page.d.ts +0 -2
- package/dist/dynamic_page.mjs +0 -591
- package/dist/server/createReference.d.ts +0 -6
- package/dist/server/createReference.mjs +0 -18
- package/dist/server/createState.d.ts +0 -64
- package/dist/server/createState.mjs +0 -65
- package/dist/server/packModule.d.ts +0 -4
- package/dist/server/packModule.mjs +0 -30
package/dist/build.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/build.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { fileURLToPath
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
5
|
import child_process from "node:child_process";
|
|
6
6
|
import http from "http";
|
|
7
7
|
|
|
@@ -41,950 +41,11 @@ var log = {
|
|
|
41
41
|
error: logError
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
// src/dynamic_page.ts
|
|
45
|
-
import fs from "fs";
|
|
46
|
-
import path from "path";
|
|
47
|
-
import esbuild from "esbuild";
|
|
48
|
-
import { fileURLToPath } from "url";
|
|
49
|
-
|
|
50
|
-
// src/shared/serverElements.ts
|
|
51
|
-
var createBuildableElement = (tag) => {
|
|
52
|
-
return (options2, ...children) => ({
|
|
53
|
-
tag,
|
|
54
|
-
options: options2 || {},
|
|
55
|
-
children
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
var createChildrenlessBuildableElement = (tag) => {
|
|
59
|
-
return (options2) => ({
|
|
60
|
-
tag,
|
|
61
|
-
options: options2 || {},
|
|
62
|
-
children: null
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
var childrenlessElementTags = [
|
|
66
|
-
"area",
|
|
67
|
-
"base",
|
|
68
|
-
"br",
|
|
69
|
-
"col",
|
|
70
|
-
"embed",
|
|
71
|
-
"hr",
|
|
72
|
-
"img",
|
|
73
|
-
"input",
|
|
74
|
-
"link",
|
|
75
|
-
"meta",
|
|
76
|
-
"source",
|
|
77
|
-
"track",
|
|
78
|
-
"path",
|
|
79
|
-
"rect"
|
|
80
|
-
];
|
|
81
|
-
var elementTags = [
|
|
82
|
-
"a",
|
|
83
|
-
"address",
|
|
84
|
-
"article",
|
|
85
|
-
"aside",
|
|
86
|
-
"audio",
|
|
87
|
-
"blockquote",
|
|
88
|
-
"body",
|
|
89
|
-
"button",
|
|
90
|
-
"canvas",
|
|
91
|
-
"caption",
|
|
92
|
-
"colgroup",
|
|
93
|
-
"data",
|
|
94
|
-
"datalist",
|
|
95
|
-
"dd",
|
|
96
|
-
"del",
|
|
97
|
-
"details",
|
|
98
|
-
"dialog",
|
|
99
|
-
"div",
|
|
100
|
-
"dl",
|
|
101
|
-
"dt",
|
|
102
|
-
"fieldset",
|
|
103
|
-
"figcaption",
|
|
104
|
-
"figure",
|
|
105
|
-
"footer",
|
|
106
|
-
"form",
|
|
107
|
-
"h1",
|
|
108
|
-
"h2",
|
|
109
|
-
"h3",
|
|
110
|
-
"h4",
|
|
111
|
-
"h5",
|
|
112
|
-
"h6",
|
|
113
|
-
"head",
|
|
114
|
-
"header",
|
|
115
|
-
"hgroup",
|
|
116
|
-
"html",
|
|
117
|
-
"iframe",
|
|
118
|
-
"ins",
|
|
119
|
-
"label",
|
|
120
|
-
"legend",
|
|
121
|
-
"li",
|
|
122
|
-
"main",
|
|
123
|
-
"map",
|
|
124
|
-
"meter",
|
|
125
|
-
"nav",
|
|
126
|
-
"noscript",
|
|
127
|
-
"object",
|
|
128
|
-
"ol",
|
|
129
|
-
"optgroup",
|
|
130
|
-
"option",
|
|
131
|
-
"output",
|
|
132
|
-
"p",
|
|
133
|
-
"picture",
|
|
134
|
-
"pre",
|
|
135
|
-
"progress",
|
|
136
|
-
"q",
|
|
137
|
-
"section",
|
|
138
|
-
"select",
|
|
139
|
-
"summary",
|
|
140
|
-
"table",
|
|
141
|
-
"tbody",
|
|
142
|
-
"td",
|
|
143
|
-
"template",
|
|
144
|
-
"textarea",
|
|
145
|
-
"tfoot",
|
|
146
|
-
"th",
|
|
147
|
-
"thead",
|
|
148
|
-
"time",
|
|
149
|
-
"tr",
|
|
150
|
-
"ul",
|
|
151
|
-
"video",
|
|
152
|
-
"span",
|
|
153
|
-
"script",
|
|
154
|
-
"abbr",
|
|
155
|
-
"b",
|
|
156
|
-
"bdi",
|
|
157
|
-
"bdo",
|
|
158
|
-
"cite",
|
|
159
|
-
"code",
|
|
160
|
-
"dfn",
|
|
161
|
-
"em",
|
|
162
|
-
"i",
|
|
163
|
-
"kbd",
|
|
164
|
-
"mark",
|
|
165
|
-
"rp",
|
|
166
|
-
"rt",
|
|
167
|
-
"ruby",
|
|
168
|
-
"s",
|
|
169
|
-
"samp",
|
|
170
|
-
"small",
|
|
171
|
-
"strong",
|
|
172
|
-
"sub",
|
|
173
|
-
"sup",
|
|
174
|
-
"u",
|
|
175
|
-
"wbr",
|
|
176
|
-
"title",
|
|
177
|
-
"svg"
|
|
178
|
-
];
|
|
179
|
-
var elements = {};
|
|
180
|
-
var childrenlessElements = {};
|
|
181
|
-
for (const element of elementTags) {
|
|
182
|
-
elements[element] = createBuildableElement(element);
|
|
183
|
-
}
|
|
184
|
-
for (const element of childrenlessElementTags) {
|
|
185
|
-
childrenlessElements[element] = createChildrenlessBuildableElement(element);
|
|
186
|
-
}
|
|
187
|
-
var allElements = {
|
|
188
|
-
...elements,
|
|
189
|
-
...childrenlessElements
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
// src/shared/bindServerElements.ts
|
|
193
|
-
Object.assign(globalThis, elements);
|
|
194
|
-
Object.assign(globalThis, childrenlessElements);
|
|
195
|
-
|
|
196
|
-
// src/server/render.ts
|
|
197
|
-
var renderRecursively = (element) => {
|
|
198
|
-
let returnString = "";
|
|
199
|
-
if (typeof element === "boolean") return returnString;
|
|
200
|
-
else if (typeof element === "number" || typeof element === "string") {
|
|
201
|
-
return returnString + element;
|
|
202
|
-
} else if (Array.isArray(element)) {
|
|
203
|
-
return returnString + element.join(", ");
|
|
204
|
-
}
|
|
205
|
-
returnString += `<${element.tag}`;
|
|
206
|
-
if (typeof element.options === "object") {
|
|
207
|
-
const {
|
|
208
|
-
tag: elementTag,
|
|
209
|
-
options: elementOptions,
|
|
210
|
-
children: elementChildren
|
|
211
|
-
} = element.options;
|
|
212
|
-
if (elementTag !== void 0 && elementOptions !== void 0 && elementChildren !== void 0) {
|
|
213
|
-
const children = element.children;
|
|
214
|
-
element.children = [
|
|
215
|
-
element.options,
|
|
216
|
-
...children
|
|
217
|
-
];
|
|
218
|
-
element.options = {};
|
|
219
|
-
} else {
|
|
220
|
-
for (const [attrName, attrValue] of Object.entries(element.options)) {
|
|
221
|
-
if (typeof attrValue === "object") {
|
|
222
|
-
throw `Attr ${attrName}, for element ${element.tag} has obj type. Got: ${JSON.stringify(element, null, 2)}`;
|
|
223
|
-
}
|
|
224
|
-
returnString += ` ${attrName.toLowerCase()}="${attrValue}"`;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
} else if (typeof element.options !== "object" && element.options !== void 0) {
|
|
228
|
-
element.children = [element.options, ...element.children || []];
|
|
229
|
-
}
|
|
230
|
-
if (element.children === null) {
|
|
231
|
-
returnString += "/>";
|
|
232
|
-
return returnString;
|
|
233
|
-
}
|
|
234
|
-
returnString += ">";
|
|
235
|
-
for (const child2 of element.children) {
|
|
236
|
-
returnString += renderRecursively(child2);
|
|
237
|
-
}
|
|
238
|
-
returnString += `</${element.tag}>`;
|
|
239
|
-
return returnString;
|
|
240
|
-
};
|
|
241
|
-
var serverSideRenderPage = async (page, pathname) => {
|
|
242
|
-
if (!page) {
|
|
243
|
-
throw `No Page Provided.`;
|
|
244
|
-
}
|
|
245
|
-
if (typeof page === "function") {
|
|
246
|
-
throw `Unbuilt page provided to ssr page.`;
|
|
247
|
-
}
|
|
248
|
-
const bodyHTML = renderRecursively(page);
|
|
249
|
-
return {
|
|
250
|
-
bodyHTML
|
|
251
|
-
};
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
// src/server/generateHTMLTemplate.ts
|
|
255
|
-
var generateHTMLTemplate = async ({
|
|
256
|
-
pageURL,
|
|
257
|
-
head: head2,
|
|
258
|
-
serverData = null,
|
|
259
|
-
addPageScriptTag = true,
|
|
260
|
-
name,
|
|
261
|
-
requiredClientModules = [],
|
|
262
|
-
environment
|
|
263
|
-
}) => {
|
|
264
|
-
let StartTemplate = `<meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
265
|
-
if (environment === "production") {
|
|
266
|
-
StartTemplate += `<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">`;
|
|
267
|
-
}
|
|
268
|
-
StartTemplate += '<meta charset="UTF-8">';
|
|
269
|
-
for (const module of requiredClientModules) {
|
|
270
|
-
StartTemplate += `<script data-module="true" src="/shipped/${module}.js" defer="true"></script>`;
|
|
271
|
-
}
|
|
272
|
-
if (addPageScriptTag === true) {
|
|
273
|
-
StartTemplate += `<script data-page="true" type="module" src="${pageURL === "" ? "" : "/"}${pageURL}/${name}_data.js" defer="true"></script>`;
|
|
274
|
-
}
|
|
275
|
-
StartTemplate += `<script type="module" src="/client.js" defer="true"></script>`;
|
|
276
|
-
let builtHead;
|
|
277
|
-
if (head2.constructor.name === "AsyncFunction") {
|
|
278
|
-
builtHead = await head2();
|
|
279
|
-
} else {
|
|
280
|
-
builtHead = head2();
|
|
281
|
-
}
|
|
282
|
-
let HTMLTemplate = renderRecursively(builtHead);
|
|
283
|
-
if (serverData) {
|
|
284
|
-
HTMLTemplate += serverData;
|
|
285
|
-
}
|
|
286
|
-
return {
|
|
287
|
-
internals: StartTemplate,
|
|
288
|
-
builtMetadata: HTMLTemplate
|
|
289
|
-
};
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
// src/server/createState.ts
|
|
293
|
-
if (!globalThis.__SERVER_CURRENT_STATE_ID__) {
|
|
294
|
-
globalThis.__SERVER_CURRENT_STATE_ID__ = 1;
|
|
295
|
-
}
|
|
296
|
-
var initializeState = () => {
|
|
297
|
-
globalThis.__SERVER_CURRENT_STATE__ = [];
|
|
298
|
-
};
|
|
299
|
-
var getState = () => {
|
|
300
|
-
return globalThis.__SERVER_CURRENT_STATE__;
|
|
301
|
-
};
|
|
302
|
-
var initializeObjectAttributes = () => globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__ = [];
|
|
303
|
-
var getObjectAttributes = () => {
|
|
304
|
-
return globalThis.__SERVER_CURRENT_OBJECT_ATTRIBUTES__;
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
// src/server/loadHook.ts
|
|
308
|
-
var resetLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__ = [];
|
|
309
|
-
var getLoadHooks = () => globalThis.__SERVER_CURRENT_LOADHOOKS__;
|
|
310
|
-
|
|
311
|
-
// src/dynamic_page.ts
|
|
312
|
-
var packageDir = process.env.PACKAGE_PATH;
|
|
313
|
-
if (packageDir === void 0) {
|
|
314
|
-
const __filename2 = fileURLToPath(import.meta.url);
|
|
315
|
-
const __dirname2 = path.dirname(__filename2);
|
|
316
|
-
packageDir = path.resolve(__dirname2, "..");
|
|
317
|
-
}
|
|
318
|
-
var elementKey = 0;
|
|
319
|
-
var processOptionAsObjectAttribute = (element, optionName, optionValue, objectAttributes) => {
|
|
320
|
-
const lcOptionName = optionName.toLowerCase();
|
|
321
|
-
const options2 = element.options;
|
|
322
|
-
let key = options2.key;
|
|
323
|
-
if (key == void 0) {
|
|
324
|
-
key = elementKey += 1;
|
|
325
|
-
options2.key = key;
|
|
326
|
-
}
|
|
327
|
-
if (!optionValue.type) {
|
|
328
|
-
throw `ObjectAttributeType is missing from object attribute. ${element.tag}: ${optionName}/${optionValue}`;
|
|
329
|
-
}
|
|
330
|
-
let optionFinal = lcOptionName;
|
|
331
|
-
switch (optionValue.type) {
|
|
332
|
-
case 1 /* STATE */:
|
|
333
|
-
const SOA = optionValue;
|
|
334
|
-
if (typeof SOA.value === "function") {
|
|
335
|
-
delete options2[optionName];
|
|
336
|
-
break;
|
|
337
|
-
}
|
|
338
|
-
if (lcOptionName === "innertext" || lcOptionName === "innerhtml") {
|
|
339
|
-
element.children = [SOA.value];
|
|
340
|
-
delete options2[optionName];
|
|
341
|
-
} else {
|
|
342
|
-
delete options2[optionName];
|
|
343
|
-
options2[lcOptionName] = SOA.value;
|
|
344
|
-
}
|
|
345
|
-
break;
|
|
346
|
-
case 2 /* OBSERVER */:
|
|
347
|
-
const OOA = optionValue;
|
|
348
|
-
const firstValue = OOA.update(...OOA.initialValues);
|
|
349
|
-
if (lcOptionName === "innertext" || lcOptionName === "innerhtml") {
|
|
350
|
-
element.children = [firstValue];
|
|
351
|
-
delete options2[optionName];
|
|
352
|
-
} else {
|
|
353
|
-
delete options2[optionName];
|
|
354
|
-
options2[lcOptionName] = firstValue;
|
|
355
|
-
}
|
|
356
|
-
optionFinal = optionName;
|
|
357
|
-
break;
|
|
358
|
-
case 4 /* REFERENCE */:
|
|
359
|
-
options2["ref"] = optionValue.value;
|
|
360
|
-
break;
|
|
361
|
-
}
|
|
362
|
-
objectAttributes.push({ ...optionValue, key, attribute: optionFinal });
|
|
363
|
-
};
|
|
364
|
-
var processPageElements = async (element, objectAttributes, parent) => {
|
|
365
|
-
if (typeof element === "boolean" || typeof element === "number" || Array.isArray(element)) return element;
|
|
366
|
-
if (typeof element === "string") {
|
|
367
|
-
return element;
|
|
368
|
-
}
|
|
369
|
-
const processElementOptionsAsChildAndReturn = async () => {
|
|
370
|
-
const children = element.children;
|
|
371
|
-
element.children = [
|
|
372
|
-
element.options,
|
|
373
|
-
...children
|
|
374
|
-
];
|
|
375
|
-
element.options = {};
|
|
376
|
-
for (let i = 0; i < children.length + 1; i++) {
|
|
377
|
-
const child2 = element.children[i];
|
|
378
|
-
const processedChild = await processPageElements(child2, objectAttributes, element);
|
|
379
|
-
element.children[i] = processedChild;
|
|
380
|
-
}
|
|
381
|
-
return {
|
|
382
|
-
...element,
|
|
383
|
-
options: {}
|
|
384
|
-
};
|
|
385
|
-
};
|
|
386
|
-
if (typeof element.options !== "object") {
|
|
387
|
-
return await processElementOptionsAsChildAndReturn();
|
|
388
|
-
}
|
|
389
|
-
const {
|
|
390
|
-
tag: elementTag,
|
|
391
|
-
options: elementOptions,
|
|
392
|
-
children: elementChildren
|
|
393
|
-
} = element.options;
|
|
394
|
-
if (elementTag && elementOptions && elementChildren) {
|
|
395
|
-
return await processElementOptionsAsChildAndReturn();
|
|
396
|
-
}
|
|
397
|
-
const options2 = element.options;
|
|
398
|
-
for (const [optionName, optionValue] of Object.entries(options2)) {
|
|
399
|
-
const lcOptionName = optionName.toLowerCase();
|
|
400
|
-
if (typeof optionValue !== "object") {
|
|
401
|
-
if (lcOptionName === "innertext") {
|
|
402
|
-
delete options2[optionName];
|
|
403
|
-
if (element.children === null) {
|
|
404
|
-
throw `Cannot use innerText or innerHTML on childrenless elements.`;
|
|
405
|
-
}
|
|
406
|
-
element.children = [optionValue, ...element.children];
|
|
407
|
-
continue;
|
|
408
|
-
} else if (lcOptionName === "innerhtml") {
|
|
409
|
-
if (element.children === null) {
|
|
410
|
-
throw `Cannot use innerText or innerHTML on childrenless elements.`;
|
|
411
|
-
}
|
|
412
|
-
delete options2[optionName];
|
|
413
|
-
element.children = [optionValue];
|
|
414
|
-
continue;
|
|
415
|
-
}
|
|
416
|
-
continue;
|
|
417
|
-
}
|
|
418
|
-
;
|
|
419
|
-
processOptionAsObjectAttribute(element, optionName, optionValue, objectAttributes);
|
|
420
|
-
}
|
|
421
|
-
if (element.children) {
|
|
422
|
-
for (let i = 0; i < element.children.length; i++) {
|
|
423
|
-
const child2 = element.children[i];
|
|
424
|
-
const processedChild = await processPageElements(child2, objectAttributes, element);
|
|
425
|
-
element.children[i] = processedChild;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
return element;
|
|
429
|
-
};
|
|
430
|
-
var generateSuitablePageElements = async (pageLocation, pageElements, metadata, DIST_DIR, pageName, requiredClientModules) => {
|
|
431
|
-
if (typeof pageElements === "string" || typeof pageElements === "boolean" || typeof pageElements === "number" || Array.isArray(pageElements)) {
|
|
432
|
-
return [];
|
|
433
|
-
}
|
|
434
|
-
const objectAttributes = [];
|
|
435
|
-
const processedPageElements = await processPageElements(pageElements, objectAttributes, []);
|
|
436
|
-
elementKey = 0;
|
|
437
|
-
const renderedPage = await serverSideRenderPage(
|
|
438
|
-
processedPageElements,
|
|
439
|
-
pageLocation
|
|
440
|
-
);
|
|
441
|
-
const template = await generateHTMLTemplate({
|
|
442
|
-
pageURL: path.relative(DIST_DIR, pageLocation),
|
|
443
|
-
head: metadata,
|
|
444
|
-
addPageScriptTag: true,
|
|
445
|
-
name: pageName,
|
|
446
|
-
requiredClientModules,
|
|
447
|
-
environment: "production"
|
|
448
|
-
});
|
|
449
|
-
const resultHTML = `<!DOCTYPE html>${template}${renderedPage.bodyHTML}`;
|
|
450
|
-
return {
|
|
451
|
-
objectAttributes,
|
|
452
|
-
resultHTML
|
|
453
|
-
};
|
|
454
|
-
};
|
|
455
|
-
var generateClientPageData = async (pageLocation, state, objectAttributes, pageLoadHooks, DIST_DIR, pageName) => {
|
|
456
|
-
const pageDiff = path.relative(DIST_DIR, pageLocation);
|
|
457
|
-
let clientPageJSText = `${globalThis.__SERVER_PAGE_DATA_BANNER__}
|
|
458
|
-
/*ELEGANCE_JS*/
|
|
459
|
-
let url="${pageDiff === "" ? "/" : `/${pageDiff}`}";`;
|
|
460
|
-
{
|
|
461
|
-
clientPageJSText += `export const data = {`;
|
|
462
|
-
if (state) {
|
|
463
|
-
const nonBoundState = state.filter((subj) => subj.bind === void 0);
|
|
464
|
-
clientPageJSText += `state:[`;
|
|
465
|
-
for (const subject of nonBoundState) {
|
|
466
|
-
if (typeof subject.value === "string") {
|
|
467
|
-
const stringified = JSON.stringify(subject.value);
|
|
468
|
-
clientPageJSText += `{id:${subject.id},value:${stringified}},`;
|
|
469
|
-
} else if (typeof subject.value === "function") {
|
|
470
|
-
clientPageJSText += `{id:${subject.id},value:${subject.value.toString()}},`;
|
|
471
|
-
} else {
|
|
472
|
-
clientPageJSText += `{id:${subject.id},value:${JSON.stringify(subject.value)}},`;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
clientPageJSText += `],`;
|
|
476
|
-
const formattedBoundState = {};
|
|
477
|
-
const stateBinds = state.map((subj) => subj.bind).filter((bind) => bind !== void 0);
|
|
478
|
-
for (const bind of stateBinds) {
|
|
479
|
-
formattedBoundState[bind] = [];
|
|
480
|
-
}
|
|
481
|
-
;
|
|
482
|
-
const boundState = state.filter((subj) => subj.bind !== void 0);
|
|
483
|
-
for (const subject of boundState) {
|
|
484
|
-
const bindingState = formattedBoundState[subject.bind];
|
|
485
|
-
delete subject.bind;
|
|
486
|
-
bindingState.push(subject);
|
|
487
|
-
}
|
|
488
|
-
const bindSubjectPairing = Object.entries(formattedBoundState);
|
|
489
|
-
if (bindSubjectPairing.length > 0) {
|
|
490
|
-
clientPageJSText += "binds:{";
|
|
491
|
-
for (const [bind, subjects] of bindSubjectPairing) {
|
|
492
|
-
clientPageJSText += `${bind}:[`;
|
|
493
|
-
for (const subject of subjects) {
|
|
494
|
-
if (typeof subject.value === "string") {
|
|
495
|
-
clientPageJSText += `{id:${subject.id},value:${JSON.stringify(subject.value)}},`;
|
|
496
|
-
} else {
|
|
497
|
-
clientPageJSText += `{id:${subject.id},value:${JSON.stringify(subject.value)}},`;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
clientPageJSText += "]";
|
|
501
|
-
}
|
|
502
|
-
clientPageJSText += "},";
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
const stateObjectAttributes = objectAttributes.filter((oa) => oa.type === 1 /* STATE */);
|
|
506
|
-
if (stateObjectAttributes.length > 0) {
|
|
507
|
-
const processed = [...stateObjectAttributes].map((soa) => {
|
|
508
|
-
delete soa.type;
|
|
509
|
-
return soa;
|
|
510
|
-
});
|
|
511
|
-
clientPageJSText += `soa:${JSON.stringify(processed)},`;
|
|
512
|
-
}
|
|
513
|
-
const observerObjectAttributes = objectAttributes.filter((oa) => oa.type === 2 /* OBSERVER */);
|
|
514
|
-
if (observerObjectAttributes.length > 0) {
|
|
515
|
-
let observerObjectAttributeString = "ooa:[";
|
|
516
|
-
for (const observerObjectAttribute of observerObjectAttributes) {
|
|
517
|
-
const ooa = observerObjectAttribute;
|
|
518
|
-
observerObjectAttributeString += `{key:${ooa.key},attribute:"${ooa.attribute}",update:${ooa.update.toString()},`;
|
|
519
|
-
observerObjectAttributeString += `refs:[`;
|
|
520
|
-
for (const ref of ooa.refs) {
|
|
521
|
-
observerObjectAttributeString += `{id:${ref.id}`;
|
|
522
|
-
if (ref.bind !== void 0) observerObjectAttributeString += `,bind:${ref.bind}`;
|
|
523
|
-
observerObjectAttributeString += "},";
|
|
524
|
-
}
|
|
525
|
-
observerObjectAttributeString += "]},";
|
|
526
|
-
}
|
|
527
|
-
observerObjectAttributeString += "],";
|
|
528
|
-
clientPageJSText += observerObjectAttributeString;
|
|
529
|
-
}
|
|
530
|
-
if (pageLoadHooks.length > 0) {
|
|
531
|
-
clientPageJSText += "lh:[";
|
|
532
|
-
for (const loadHook of pageLoadHooks) {
|
|
533
|
-
const key = loadHook.bind;
|
|
534
|
-
clientPageJSText += `{fn:${loadHook.fn},bind:"${key || ""}"},`;
|
|
535
|
-
}
|
|
536
|
-
clientPageJSText += "],";
|
|
537
|
-
}
|
|
538
|
-
clientPageJSText += `};`;
|
|
539
|
-
}
|
|
540
|
-
clientPageJSText += "if(!globalThis.pd) { globalThis.pd = {}; globalThis.pd[url] = data}";
|
|
541
|
-
const pageDataPath = path.join(pageLocation, `${pageName}_data.js`);
|
|
542
|
-
let sendHardReloadInstruction = false;
|
|
543
|
-
const transformedResult = await esbuild.transform(clientPageJSText, { minify: true }).catch((error) => {
|
|
544
|
-
console.error("Failed to transform client page js!", error);
|
|
545
|
-
});
|
|
546
|
-
if (!transformedResult) return { sendHardReloadInstruction };
|
|
547
|
-
fs.writeFileSync(pageDataPath, transformedResult.code, "utf-8");
|
|
548
|
-
return { sendHardReloadInstruction };
|
|
549
|
-
};
|
|
550
|
-
var buildDynamicPage = async (filePath, DIST_DIR, req, res) => {
|
|
551
|
-
let pageElements;
|
|
552
|
-
let metadata;
|
|
553
|
-
initializeState();
|
|
554
|
-
initializeObjectAttributes();
|
|
555
|
-
resetLoadHooks();
|
|
556
|
-
globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
|
|
557
|
-
globalThis.__SERVER_CURRENT_STATE_ID__ = 1;
|
|
558
|
-
let modules = [];
|
|
559
|
-
try {
|
|
560
|
-
const {
|
|
561
|
-
construct
|
|
562
|
-
} = await import("file://" + filePath);
|
|
563
|
-
const {
|
|
564
|
-
page,
|
|
565
|
-
metadata: pageMetadata,
|
|
566
|
-
isDynamicPage,
|
|
567
|
-
requestHook,
|
|
568
|
-
requiredClientModules
|
|
569
|
-
} = construct();
|
|
570
|
-
if (requiredClientModules !== void 0) {
|
|
571
|
-
modules = requiredClientModules;
|
|
572
|
-
}
|
|
573
|
-
if (typeof requestHook === "function") {
|
|
574
|
-
if (requestHook.constructor.name === "AsyncFunction") {
|
|
575
|
-
const doProcessRequest = await requestHook(req, res);
|
|
576
|
-
if (doProcessRequest !== void 0 == doProcessRequest === false) {
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
} else {
|
|
580
|
-
const doProcessRequest = requestHook(req, res);
|
|
581
|
-
if (doProcessRequest !== void 0 == doProcessRequest === false) {
|
|
582
|
-
return false;
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
pageElements = page;
|
|
587
|
-
metadata = pageMetadata;
|
|
588
|
-
if (isDynamicPage === false) {
|
|
589
|
-
throw new Error("Cannot dynamically render a non-dynamic page.");
|
|
590
|
-
}
|
|
591
|
-
} catch (e) {
|
|
592
|
-
throw `${filePath} - ${e}
|
|
593
|
-
${e?.stack ?? "No stack."}
|
|
594
|
-
|
|
595
|
-
`;
|
|
596
|
-
}
|
|
597
|
-
if (!metadata || metadata && typeof metadata !== "function") {
|
|
598
|
-
console.warn(`WARNING: Dynamic ${filePath} does not export a metadata function. This is *highly* recommended.`);
|
|
599
|
-
}
|
|
600
|
-
if (!pageElements) {
|
|
601
|
-
console.warn(`WARNING: Dynamic ${filePath} should export a const page, which is of type BuiltElement<"body">.`);
|
|
602
|
-
}
|
|
603
|
-
if (typeof pageElements === "function") {
|
|
604
|
-
if (pageElements.constructor.name === "AsyncFunction") {
|
|
605
|
-
pageElements = await pageElements();
|
|
606
|
-
} else {
|
|
607
|
-
pageElements = pageElements();
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
const state = getState();
|
|
611
|
-
const pageLoadHooks = getLoadHooks();
|
|
612
|
-
const objectAttributes = getObjectAttributes();
|
|
613
|
-
const foundObjectAttributes = await generateSuitablePageElements(
|
|
614
|
-
path.dirname(filePath),
|
|
615
|
-
pageElements || body(),
|
|
616
|
-
metadata ?? (() => head()),
|
|
617
|
-
DIST_DIR,
|
|
618
|
-
"page",
|
|
619
|
-
modules
|
|
620
|
-
);
|
|
621
|
-
await generateClientPageData(
|
|
622
|
-
path.dirname(filePath),
|
|
623
|
-
state || {},
|
|
624
|
-
[...objectAttributes, ...foundObjectAttributes.objectAttributes],
|
|
625
|
-
pageLoadHooks || [],
|
|
626
|
-
DIST_DIR,
|
|
627
|
-
"page"
|
|
628
|
-
);
|
|
629
|
-
return foundObjectAttributes.resultHTML;
|
|
630
|
-
};
|
|
631
|
-
|
|
632
|
-
// src/server/server.ts
|
|
633
|
-
import { createServer as createHttpServer } from "http";
|
|
634
|
-
import { promises as fs2 } from "fs";
|
|
635
|
-
import { join, normalize, extname, dirname, resolve } from "path";
|
|
636
|
-
import { pathToFileURL } from "url";
|
|
637
|
-
import { gzip, deflate } from "zlib";
|
|
638
|
-
import { promisify } from "util";
|
|
639
|
-
var gzipAsync = promisify(gzip);
|
|
640
|
-
var deflateAsync = promisify(deflate);
|
|
641
|
-
var MIME_TYPES = {
|
|
642
|
-
".html": "text/html; charset=utf-8",
|
|
643
|
-
".css": "text/css; charset=utf-8",
|
|
644
|
-
".js": "application/javascript; charset=utf-8",
|
|
645
|
-
".json": "application/json; charset=utf-8",
|
|
646
|
-
".png": "image/png",
|
|
647
|
-
".jpg": "image/jpeg",
|
|
648
|
-
".jpeg": "image/jpeg",
|
|
649
|
-
".gif": "image/gif",
|
|
650
|
-
".svg": "image/svg+xml",
|
|
651
|
-
".ico": "image/x-icon",
|
|
652
|
-
".txt": "text/plain; charset=utf-8"
|
|
653
|
-
};
|
|
654
|
-
function startServer({
|
|
655
|
-
root,
|
|
656
|
-
port = 3e3,
|
|
657
|
-
host = "localhost",
|
|
658
|
-
environment = "production",
|
|
659
|
-
DIST_DIR
|
|
660
|
-
}) {
|
|
661
|
-
if (!root) throw new Error("Root directory must be specified.");
|
|
662
|
-
root = normalize(root).replace(/[\\/]+$/, "");
|
|
663
|
-
const requestHandler = async (req, res) => {
|
|
664
|
-
try {
|
|
665
|
-
if (!req.url) {
|
|
666
|
-
await sendResponse(req, res, 400, { "Content-Type": "text/plain; charset=utf-8" }, "Bad Request");
|
|
667
|
-
return;
|
|
668
|
-
}
|
|
669
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
670
|
-
res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
|
|
671
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
672
|
-
if (req.method === "OPTIONS") {
|
|
673
|
-
res.writeHead(204);
|
|
674
|
-
res.end();
|
|
675
|
-
if (environment === "development") {
|
|
676
|
-
log.info(req.method, "::", req.url, "-", res.statusCode);
|
|
677
|
-
}
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
681
|
-
if (url.pathname.startsWith("/api/")) {
|
|
682
|
-
await handleApiRequest(root, url.pathname, req, res);
|
|
683
|
-
} else {
|
|
684
|
-
await handleStaticRequest(root, url.pathname, req, res, DIST_DIR);
|
|
685
|
-
}
|
|
686
|
-
if (environment === "development") {
|
|
687
|
-
log.info(req.method, "::", req.url, "-", res.statusCode);
|
|
688
|
-
}
|
|
689
|
-
} catch (err) {
|
|
690
|
-
log.error(err);
|
|
691
|
-
await sendResponse(req, res, 500, { "Content-Type": "text/plain; charset=utf-8" }, "Internal Server Error");
|
|
692
|
-
}
|
|
693
|
-
};
|
|
694
|
-
function attemptListen(p) {
|
|
695
|
-
const server = createHttpServer(requestHandler);
|
|
696
|
-
server.on("error", (err) => {
|
|
697
|
-
if (err.code === "EADDRINUSE") {
|
|
698
|
-
attemptListen(p + 1);
|
|
699
|
-
} else {
|
|
700
|
-
console.error(err);
|
|
701
|
-
}
|
|
702
|
-
});
|
|
703
|
-
server.listen(p, host, () => {
|
|
704
|
-
log.info(`Server running at http://${host}:${p}/`);
|
|
705
|
-
});
|
|
706
|
-
return server;
|
|
707
|
-
}
|
|
708
|
-
return attemptListen(port);
|
|
709
|
-
}
|
|
710
|
-
async function handleStaticRequest(root, pathname, req, res, DIST_DIR) {
|
|
711
|
-
const originalPathname = pathname;
|
|
712
|
-
let filePath = normalize(join(root, decodeURIComponent(pathname))).replace(/[\\/]+$/, "");
|
|
713
|
-
if (!filePath.startsWith(root)) {
|
|
714
|
-
await sendResponse(req, res, 403, { "Content-Type": "text/plain; charset=utf-8" }, "Forbidden");
|
|
715
|
-
return;
|
|
716
|
-
}
|
|
717
|
-
let stats;
|
|
718
|
-
try {
|
|
719
|
-
stats = await fs2.stat(filePath);
|
|
720
|
-
} catch {
|
|
721
|
-
}
|
|
722
|
-
let pageDir;
|
|
723
|
-
if (stats) {
|
|
724
|
-
if (stats.isDirectory()) {
|
|
725
|
-
pageDir = filePath;
|
|
726
|
-
} else {
|
|
727
|
-
pageDir = dirname(filePath);
|
|
728
|
-
}
|
|
729
|
-
} else {
|
|
730
|
-
if (originalPathname.endsWith("/")) {
|
|
731
|
-
pageDir = filePath;
|
|
732
|
-
} else {
|
|
733
|
-
pageDir = dirname(filePath);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
const relDir = pageDir.slice(root.length).replace(/^[\/\\]+/, "");
|
|
737
|
-
const parts = relDir.split(/[\\/]/).filter(Boolean);
|
|
738
|
-
const middlewareDirs = [];
|
|
739
|
-
let current = root;
|
|
740
|
-
middlewareDirs.push(current);
|
|
741
|
-
for (const part of parts) {
|
|
742
|
-
current = join(current, part);
|
|
743
|
-
middlewareDirs.push(current);
|
|
744
|
-
}
|
|
745
|
-
const middlewares = [];
|
|
746
|
-
for (const dir of middlewareDirs) {
|
|
747
|
-
const mwPath = join(dir, "middleware.mjs");
|
|
748
|
-
let mwModule;
|
|
749
|
-
try {
|
|
750
|
-
await fs2.access(mwPath);
|
|
751
|
-
const url = pathToFileURL(mwPath).href;
|
|
752
|
-
mwModule = await import(url);
|
|
753
|
-
} catch {
|
|
754
|
-
continue;
|
|
755
|
-
}
|
|
756
|
-
const mwKeys = Object.keys(mwModule).sort();
|
|
757
|
-
for (const key of mwKeys) {
|
|
758
|
-
const f = mwModule[key];
|
|
759
|
-
if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
|
|
760
|
-
middlewares.push(f);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
let isDynamic = false;
|
|
765
|
-
let handlerPath = filePath;
|
|
766
|
-
if (stats && stats.isDirectory()) {
|
|
767
|
-
const pageMjsPath = join(filePath, "page.mjs");
|
|
768
|
-
try {
|
|
769
|
-
await fs2.access(pageMjsPath);
|
|
770
|
-
handlerPath = pageMjsPath;
|
|
771
|
-
isDynamic = true;
|
|
772
|
-
} catch {
|
|
773
|
-
handlerPath = join(filePath, "index.html");
|
|
774
|
-
isDynamic = false;
|
|
775
|
-
}
|
|
776
|
-
} else {
|
|
777
|
-
handlerPath = filePath;
|
|
778
|
-
isDynamic = false;
|
|
779
|
-
}
|
|
780
|
-
let hasHandler = false;
|
|
781
|
-
try {
|
|
782
|
-
await fs2.access(handlerPath);
|
|
783
|
-
hasHandler = true;
|
|
784
|
-
} catch {
|
|
785
|
-
}
|
|
786
|
-
const finalHandler = async (req2, res2) => {
|
|
787
|
-
if (!hasHandler) {
|
|
788
|
-
await respondWithErrorPage(root, pathname, 404, req2, res2);
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
if (isDynamic) {
|
|
792
|
-
try {
|
|
793
|
-
const resultHTML = await buildDynamicPage(resolve(handlerPath), DIST_DIR, req2, res2);
|
|
794
|
-
if (resultHTML === false) {
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
797
|
-
await sendResponse(req2, res2, 200, { "Content-Type": MIME_TYPES[".html"] }, resultHTML);
|
|
798
|
-
} catch (err) {
|
|
799
|
-
log.error("Error building dynamic page -", err);
|
|
800
|
-
}
|
|
801
|
-
} else {
|
|
802
|
-
const ext = extname(handlerPath).toLowerCase();
|
|
803
|
-
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
804
|
-
const data = await fs2.readFile(handlerPath);
|
|
805
|
-
await sendResponse(req2, res2, 200, { "Content-Type": contentType }, data);
|
|
806
|
-
}
|
|
807
|
-
};
|
|
808
|
-
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: false, root, pathname });
|
|
809
|
-
await composed(req, res);
|
|
810
|
-
}
|
|
811
|
-
async function handleApiRequest(root, pathname, req, res) {
|
|
812
|
-
const apiSubPath = pathname.slice("/api/".length);
|
|
813
|
-
const parts = apiSubPath.split("/").filter(Boolean);
|
|
814
|
-
const routeDir = join(root, pathname);
|
|
815
|
-
const routePath = join(routeDir, "route.mjs");
|
|
816
|
-
let hasRoute = false;
|
|
817
|
-
try {
|
|
818
|
-
await fs2.access(routePath);
|
|
819
|
-
hasRoute = true;
|
|
820
|
-
} catch {
|
|
821
|
-
}
|
|
822
|
-
let fn = null;
|
|
823
|
-
let module = null;
|
|
824
|
-
if (hasRoute) {
|
|
825
|
-
try {
|
|
826
|
-
const moduleUrl = pathToFileURL(routePath).href;
|
|
827
|
-
module = await import(moduleUrl);
|
|
828
|
-
fn = module[req.method];
|
|
829
|
-
} catch (err) {
|
|
830
|
-
console.error(err);
|
|
831
|
-
return respondWithJsonError(req, res, 500, "Internal Server Error");
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
const middlewareDirs = [];
|
|
835
|
-
let current = join(root, "api");
|
|
836
|
-
middlewareDirs.push(current);
|
|
837
|
-
for (const part of parts) {
|
|
838
|
-
current = join(current, part);
|
|
839
|
-
middlewareDirs.push(current);
|
|
840
|
-
}
|
|
841
|
-
const middlewares = [];
|
|
842
|
-
for (const dir of middlewareDirs) {
|
|
843
|
-
const mwPath = join(dir, "middleware.mjs");
|
|
844
|
-
let mwModule;
|
|
845
|
-
try {
|
|
846
|
-
await fs2.access(mwPath);
|
|
847
|
-
const url = pathToFileURL(mwPath).href;
|
|
848
|
-
mwModule = await import(url);
|
|
849
|
-
} catch {
|
|
850
|
-
continue;
|
|
851
|
-
}
|
|
852
|
-
const mwKeys = Object.keys(mwModule).sort();
|
|
853
|
-
for (const key of mwKeys) {
|
|
854
|
-
const f = mwModule[key];
|
|
855
|
-
if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
|
|
856
|
-
middlewares.push(f);
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
const finalHandler = async (req2, res2) => {
|
|
861
|
-
if (!hasRoute) {
|
|
862
|
-
return respondWithJsonError(req2, res2, 404, "Not Found");
|
|
863
|
-
}
|
|
864
|
-
if (typeof fn !== "function") {
|
|
865
|
-
return respondWithJsonError(req2, res2, 405, "Method Not Allowed");
|
|
866
|
-
}
|
|
867
|
-
await fn(req2, res2);
|
|
868
|
-
};
|
|
869
|
-
const composed = composeMiddlewares(middlewares, finalHandler, { isApi: true });
|
|
870
|
-
await composed(req, res);
|
|
871
|
-
}
|
|
872
|
-
function composeMiddlewares(mws, final, options2) {
|
|
873
|
-
return async function(req, res) {
|
|
874
|
-
let index = 0;
|
|
875
|
-
async function dispatch(err) {
|
|
876
|
-
if (err) {
|
|
877
|
-
if (options2.isApi) {
|
|
878
|
-
return respondWithJsonError(req, res, 500, err.message || "Internal Server Error");
|
|
879
|
-
} else {
|
|
880
|
-
return await respondWithErrorPage(options2.root, options2.pathname, 500, req, res);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
if (index >= mws.length) {
|
|
884
|
-
return await final(req, res);
|
|
885
|
-
}
|
|
886
|
-
const thisMw = mws[index++];
|
|
887
|
-
const next = (e) => dispatch(e);
|
|
888
|
-
const onceNext = (nextFn) => {
|
|
889
|
-
let called = false;
|
|
890
|
-
return async (e) => {
|
|
891
|
-
if (called) {
|
|
892
|
-
log.warn("next() was called in a middleware more than once.");
|
|
893
|
-
return;
|
|
894
|
-
}
|
|
895
|
-
called = true;
|
|
896
|
-
await nextFn(e);
|
|
897
|
-
};
|
|
898
|
-
};
|
|
899
|
-
try {
|
|
900
|
-
await thisMw(req, res, onceNext(next));
|
|
901
|
-
} catch (error) {
|
|
902
|
-
await dispatch(error);
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
await dispatch();
|
|
906
|
-
};
|
|
907
|
-
}
|
|
908
|
-
async function respondWithJsonError(req, res, code, message) {
|
|
909
|
-
const body2 = JSON.stringify({ error: message });
|
|
910
|
-
await sendResponse(req, res, code, { "Content-Type": "application/json; charset=utf-8" }, body2);
|
|
911
|
-
}
|
|
912
|
-
async function respondWithErrorPage(root, pathname, code, req, res) {
|
|
913
|
-
let currentPath = normalize(join(root, decodeURIComponent(pathname)));
|
|
914
|
-
let tried = /* @__PURE__ */ new Set();
|
|
915
|
-
let errorFilePath = null;
|
|
916
|
-
while (currentPath.startsWith(root)) {
|
|
917
|
-
const candidate = join(currentPath, `${code}.html`);
|
|
918
|
-
if (!tried.has(candidate)) {
|
|
919
|
-
try {
|
|
920
|
-
await fs2.access(candidate);
|
|
921
|
-
errorFilePath = candidate;
|
|
922
|
-
break;
|
|
923
|
-
} catch {
|
|
924
|
-
}
|
|
925
|
-
tried.add(candidate);
|
|
926
|
-
}
|
|
927
|
-
const parent = dirname(currentPath);
|
|
928
|
-
if (parent === currentPath) break;
|
|
929
|
-
currentPath = parent;
|
|
930
|
-
}
|
|
931
|
-
if (!errorFilePath) {
|
|
932
|
-
const fallback = join(root, `${code}.html`);
|
|
933
|
-
try {
|
|
934
|
-
await fs2.access(fallback);
|
|
935
|
-
errorFilePath = fallback;
|
|
936
|
-
} catch {
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
if (errorFilePath) {
|
|
940
|
-
try {
|
|
941
|
-
const html = await fs2.readFile(errorFilePath, "utf8");
|
|
942
|
-
await sendResponse(req, res, code, { "Content-Type": "text/html; charset=utf-8" }, html);
|
|
943
|
-
return;
|
|
944
|
-
} catch {
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
await sendResponse(req, res, code, { "Content-Type": "text/plain; charset=utf-8" }, `${code} Error`);
|
|
948
|
-
}
|
|
949
|
-
function isCompressible(contentType) {
|
|
950
|
-
if (!contentType) return false;
|
|
951
|
-
return /text\/|javascript|json|xml|svg/.test(contentType);
|
|
952
|
-
}
|
|
953
|
-
async function sendResponse(req, res, status, headers, body2) {
|
|
954
|
-
if (typeof body2 === "string") {
|
|
955
|
-
body2 = Buffer.from(body2);
|
|
956
|
-
}
|
|
957
|
-
const accept = req.headers["accept-encoding"] || "";
|
|
958
|
-
let encoding = null;
|
|
959
|
-
if (accept.match(/\bgzip\b/)) {
|
|
960
|
-
encoding = "gzip";
|
|
961
|
-
} else if (accept.match(/\bdeflate\b/)) {
|
|
962
|
-
encoding = "deflate";
|
|
963
|
-
}
|
|
964
|
-
if (!encoding || !isCompressible(headers["Content-Type"] || "")) {
|
|
965
|
-
res.writeHead(status, headers);
|
|
966
|
-
res.end(body2);
|
|
967
|
-
return;
|
|
968
|
-
}
|
|
969
|
-
const compressor = encoding === "gzip" ? gzipAsync : deflateAsync;
|
|
970
|
-
try {
|
|
971
|
-
const compressed = await compressor(body2);
|
|
972
|
-
headers["Content-Encoding"] = encoding;
|
|
973
|
-
headers["Vary"] = "Accept-Encoding";
|
|
974
|
-
res.writeHead(status, headers);
|
|
975
|
-
res.end(compressed);
|
|
976
|
-
} catch (err) {
|
|
977
|
-
log.error("Compression error:", err);
|
|
978
|
-
res.writeHead(status, headers);
|
|
979
|
-
res.end(body2);
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
|
|
983
44
|
// src/build.ts
|
|
984
|
-
var __filename =
|
|
985
|
-
var __dirname =
|
|
986
|
-
var
|
|
987
|
-
var builderPath =
|
|
45
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
46
|
+
var __dirname = path.dirname(__filename);
|
|
47
|
+
var packageDir = path.resolve(__dirname, "..");
|
|
48
|
+
var builderPath = path.resolve(packageDir, "./dist/page_compiler.mjs");
|
|
988
49
|
var yellow = (text) => {
|
|
989
50
|
return `\x1B[38;2;238;184;68m${text}`;
|
|
990
51
|
};
|
|
@@ -1003,11 +64,11 @@ var finishLog = (...text) => {
|
|
|
1003
64
|
var options = process.env.OPTIONS;
|
|
1004
65
|
var getAllSubdirectories = (dir, baseDir = dir) => {
|
|
1005
66
|
let directories = [];
|
|
1006
|
-
const items =
|
|
67
|
+
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
1007
68
|
for (const item of items) {
|
|
1008
69
|
if (item.isDirectory()) {
|
|
1009
|
-
const fullPath =
|
|
1010
|
-
const relativePath =
|
|
70
|
+
const fullPath = path.join(dir, item.name);
|
|
71
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
1011
72
|
directories.push(relativePath);
|
|
1012
73
|
directories = directories.concat(getAllSubdirectories(fullPath, baseDir));
|
|
1013
74
|
}
|
|
@@ -1027,7 +88,7 @@ var runBuild = (filepath, DIST_DIR) => {
|
|
|
1027
88
|
}
|
|
1028
89
|
child = child_process.spawn("node", [filepath], {
|
|
1029
90
|
stdio: ["inherit", "inherit", "inherit", "ipc"],
|
|
1030
|
-
env: { ...process.env, DIST_DIR, OPTIONS: optionsString, PACKAGE_PATH:
|
|
91
|
+
env: { ...process.env, DIST_DIR, OPTIONS: optionsString, PACKAGE_PATH: packageDir }
|
|
1031
92
|
});
|
|
1032
93
|
child.on("error", () => {
|
|
1033
94
|
log.error("Failed to start child process.");
|
|
@@ -1054,9 +115,6 @@ var runBuild = (filepath, DIST_DIR) => {
|
|
|
1054
115
|
);
|
|
1055
116
|
options.postCompile();
|
|
1056
117
|
}
|
|
1057
|
-
} else if (data === "set-layouts") {
|
|
1058
|
-
globalThis.__SERVER_CURRENT_LAYOUTS__ = new Map(JSON.parse(message.layouts));
|
|
1059
|
-
globalThis.__SERVER_CURRENT_LAYOUT_ID__ = parseInt(message.currentLayoutId);
|
|
1060
118
|
}
|
|
1061
119
|
});
|
|
1062
120
|
};
|
|
@@ -1098,31 +156,22 @@ var compile = async (props) => {
|
|
|
1098
156
|
options = props;
|
|
1099
157
|
setQuiet(options.quiet ?? false);
|
|
1100
158
|
const watch = options.hotReload !== void 0;
|
|
1101
|
-
const BUILD_FLAG =
|
|
1102
|
-
if (!
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
159
|
+
const BUILD_FLAG = path.join(options.outputDirectory, "ELEGANCE_BUILD_FLAG");
|
|
160
|
+
if (!fs.existsSync(options.outputDirectory)) {
|
|
161
|
+
fs.mkdirSync(options.outputDirectory, { recursive: true });
|
|
162
|
+
fs.writeFileSync(
|
|
163
|
+
path.join(BUILD_FLAG),
|
|
1106
164
|
"This file just marks this directory as one containing an Elegance Build.",
|
|
1107
165
|
"utf-8"
|
|
1108
166
|
);
|
|
1109
167
|
} else {
|
|
1110
|
-
if (!
|
|
168
|
+
if (!fs.existsSync(BUILD_FLAG)) {
|
|
1111
169
|
throw `The output directory already exists, but is not an Elegance Build directory.`;
|
|
1112
170
|
}
|
|
1113
171
|
}
|
|
1114
|
-
const DIST_DIR =
|
|
1115
|
-
if (!
|
|
1116
|
-
|
|
1117
|
-
}
|
|
1118
|
-
if (props.server != void 0 && props.server.runServer == true) {
|
|
1119
|
-
startServer({
|
|
1120
|
-
root: props.server.root ?? DIST_DIR,
|
|
1121
|
-
environment: props.environment,
|
|
1122
|
-
port: props.server.port ?? 3e3,
|
|
1123
|
-
host: props.server.host ?? "localhost",
|
|
1124
|
-
DIST_DIR
|
|
1125
|
-
});
|
|
172
|
+
const DIST_DIR = path.join(props.outputDirectory, "dist");
|
|
173
|
+
if (!fs.existsSync(DIST_DIR)) {
|
|
174
|
+
fs.mkdirSync(DIST_DIR, { recursive: true });
|
|
1126
175
|
}
|
|
1127
176
|
if (watch) {
|
|
1128
177
|
await registerListener();
|
|
@@ -1134,12 +183,12 @@ var compile = async (props) => {
|
|
|
1134
183
|
const dirs = options.hotReload?.extraWatchDirectories ?? [];
|
|
1135
184
|
if (dirs.length !== 0) {
|
|
1136
185
|
for (const dir of dirs) {
|
|
1137
|
-
const subdirs = getAllSubdirectories(dir).map((f) =>
|
|
186
|
+
const subdirs = getAllSubdirectories(dir).map((f) => path.join(dir, f));
|
|
1138
187
|
extra.push(...subdirs);
|
|
1139
188
|
}
|
|
1140
189
|
}
|
|
1141
190
|
}
|
|
1142
|
-
const pagesSubDirs = getAllSubdirectories(options.pagesDirectory).map((f) =>
|
|
191
|
+
const pagesSubDirs = getAllSubdirectories(options.pagesDirectory).map((f) => path.join(options.pagesDirectory, f));
|
|
1143
192
|
const subdirectories = [...pagesSubDirs, options.pagesDirectory, ...extra];
|
|
1144
193
|
finishLog(yellow("Hot-Reload Watching Subdirectories: "), ...subdirectories.join(", "));
|
|
1145
194
|
const watcherFn = async () => {
|
|
@@ -1152,7 +201,7 @@ var compile = async (props) => {
|
|
|
1152
201
|
}, 100);
|
|
1153
202
|
};
|
|
1154
203
|
for (const directory of subdirectories) {
|
|
1155
|
-
const watcher =
|
|
204
|
+
const watcher = fs.watch(
|
|
1156
205
|
directory,
|
|
1157
206
|
{},
|
|
1158
207
|
watcherFn
|