elegance-js 2.1.12 → 2.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/build.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- export declare let PAGE_MAP: Map<any, any>;
2
- export declare let LAYOUT_MAP: Map<any, any>;
3
1
  type CompilationOptions = {
4
2
  postCompile?: () => any;
5
3
  preCompile?: () => any;
package/dist/build.mjs CHANGED
@@ -5,10 +5,11 @@ import child_process from "node:child_process";
5
5
  import http from "http";
6
6
  import { startServer } from "./server/server";
7
7
  import { log, setQuiet } from "./log";
8
+ import { populateServerMaps } from "./compilation/dynamic_compiler";
8
9
  const __filename = fileURLToPath(import.meta.url);
9
10
  const __dirname = path.dirname(__filename);
10
11
  const packageDir = path.resolve(__dirname, "..");
11
- const builderPath = path.resolve(packageDir, "./dist/page_compiler.mjs");
12
+ const builderPath = path.resolve(packageDir, "dist", "compilation", "compiler_process.mjs");
12
13
  const yellow = (text) => {
13
14
  return `\x1B[38;2;238;184;68m${text}`;
14
15
  };
@@ -24,8 +25,6 @@ const green = (text) => {
24
25
  const finishLog = (...text) => {
25
26
  log.info(text.map((text2) => `${text2}\x1B[0m`).join(""));
26
27
  };
27
- let PAGE_MAP = /* @__PURE__ */ new Map();
28
- let LAYOUT_MAP = /* @__PURE__ */ new Map();
29
28
  let options = process.env.OPTIONS;
30
29
  const getAllSubdirectories = (dir, baseDir = dir) => {
31
30
  let directories = [];
@@ -90,8 +89,7 @@ const runBuild = (filepath, DIST_DIR) => {
90
89
  }
91
90
  } else if (data === "set-pages-and-layouts") {
92
91
  const { pageMap, layoutMap } = JSON.parse(message.content);
93
- PAGE_MAP = new Map(pageMap);
94
- LAYOUT_MAP = new Map(layoutMap);
92
+ populateServerMaps(pageMap, layoutMap);
95
93
  }
96
94
  });
97
95
  };
@@ -138,7 +136,7 @@ const compile = async (props) => {
138
136
  fs.mkdirSync(options.outputDirectory, { recursive: true });
139
137
  fs.writeFileSync(
140
138
  path.join(BUILD_FLAG),
141
- "This file just marks this directory as one containing an Elegance Build.",
139
+ "This file marks this directory as one containing an Elegance Build.",
142
140
  "utf-8"
143
141
  );
144
142
  } else {
@@ -150,6 +148,7 @@ const compile = async (props) => {
150
148
  if (!fs.existsSync(DIST_DIR)) {
151
149
  fs.mkdirSync(DIST_DIR, { recursive: true });
152
150
  }
151
+ build(DIST_DIR);
153
152
  if (options.server != void 0 && options.server.runServer == true) {
154
153
  startServer({
155
154
  root: options.server.root ?? DIST_DIR,
@@ -196,10 +195,7 @@ const compile = async (props) => {
196
195
  currentWatchers.push(watcher);
197
196
  }
198
197
  }
199
- build(DIST_DIR);
200
198
  };
201
199
  export {
202
- LAYOUT_MAP,
203
- PAGE_MAP,
204
200
  compile
205
201
  };
@@ -0,0 +1,134 @@
1
+ import { ObjectAttributeType } from "../helpers/ObjectAttributeType";
2
+ import { LoadHook } from "../server/loadHook";
3
+ type CompilationOptions = {
4
+ postCompile?: () => any;
5
+ preCompile?: () => any;
6
+ environment: "production" | "development";
7
+ pagesDirectory: string;
8
+ outputDirectory: string;
9
+ publicDirectory?: {
10
+ path: string;
11
+ };
12
+ server?: {
13
+ runServer: boolean;
14
+ root?: string;
15
+ port?: number;
16
+ host?: string;
17
+ };
18
+ hotReload?: {
19
+ port: number;
20
+ hostname: string;
21
+ };
22
+ quiet: boolean;
23
+ };
24
+ declare const PAGE_MAP: Map<string, PageInformation>;
25
+ declare const LAYOUT_MAP: Map<string, LayoutInformation>;
26
+ /** A list of modules that are yet to be built. */
27
+ declare let modulesToShip: Array<{
28
+ path: string;
29
+ globalName: string;
30
+ }>;
31
+ declare function setCompilationOptions(newOptions: CompilationOptions, distDir: string): void;
32
+ declare function getAllSubdirectories(dir: string, baseDir?: string): string[];
33
+ declare function buildClient(DIST_DIR: string): Promise<void>;
34
+ /**
35
+ * Recursively iterate through the elements of a given page, and "process them".
36
+ * This involves separating all non-serializable data into an object attributes array,
37
+ * and mutating `element` into something that can be serialized into HTML.
38
+ */
39
+ declare function processPageElements(element: Child, objectAttributes: Array<any>, recursionLevel: number, stack?: any[]): Child;
40
+ /**
41
+ * Takes in a page, and turns it into HTML.
42
+ * If doWrite is false, the page's HTML will be returned.
43
+ */
44
+ declare function pageToHTML(pageLocation: string, pageElements: Child, metadata: () => BuiltElement<"html">, DIST_DIR: string, pageName: string, doWrite: boolean | undefined, requiredClientModules: ShippedModules | undefined, layout: BuiltLayout, pathname?: string): Promise<string | ({
45
+ type: ObjectAttributeType;
46
+ id: string | number;
47
+ value: any;
48
+ bind?: string;
49
+ } | {
50
+ type: ObjectAttributeType;
51
+ refs: {
52
+ id: number;
53
+ bind?: string;
54
+ }[];
55
+ initialValues: any[];
56
+ update: (...value: any) => any;
57
+ } | {
58
+ type: ObjectAttributeType;
59
+ })[]>;
60
+ /**
61
+ * This uses string interpolation to generate the:
62
+ * page_data.js file that the browser receives.
63
+ *
64
+ * It's *very* error-prone, so be careful if you edit this!
65
+ */
66
+ declare function generateClientPageData(pageLocation: string, state: typeof globalThis.__SERVER_CURRENT_STATE__, objectAttributes: Array<ObjectAttribute<any>>, pageLoadHooks: Array<LoadHook>, DIST_DIR: string, pageName: string, globalVariableName?: string, write?: boolean): Promise<{
67
+ sendHardReloadInstruction: boolean;
68
+ result?: undefined;
69
+ } | {
70
+ sendHardReloadInstruction: boolean;
71
+ result: string;
72
+ }>;
73
+ declare function generateLayout(DIST_DIR: string,
74
+ /** The absolute path of the layout.ts file. */
75
+ filePath: string,
76
+ /** Path relative to pagesDirectory. */
77
+ directory: string,
78
+ /** What to squish between the start and end HTML (aka the split point). */
79
+ childIndicator: Child,
80
+ /** Whether or not to generate the layout if it is dynamic */
81
+ generateDynamic?: boolean): Promise<false | {
82
+ pageContentHTML: string;
83
+ metadataHTML: string;
84
+ }>;
85
+ type BuiltLayout = {
86
+ pageContent: {
87
+ startHTML: string;
88
+ endHTML: string;
89
+ };
90
+ metadata: {
91
+ startHTML: string;
92
+ endHTML: string;
93
+ };
94
+ scriptTag: string;
95
+ };
96
+ declare function buildLayouts(): Promise<{
97
+ shouldClientHardReload: boolean;
98
+ }>;
99
+ declare function buildLayout(filePath: string, directory: string, generateDynamic?: boolean): Promise<false | {
100
+ pageContent: {
101
+ startHTML: string;
102
+ endHTML: string;
103
+ };
104
+ metadata: {
105
+ startHTML: string;
106
+ endHTML: string;
107
+ };
108
+ scriptTag: string;
109
+ }>;
110
+ /**
111
+ * Iterate through the found layouts, and construct the necessary wrapper HTML for a given page.
112
+ */
113
+ declare function fetchPageLayoutHTML(dirname: string): Promise<{
114
+ pageContent: {
115
+ startHTML: string;
116
+ endHTML: string;
117
+ };
118
+ metadata: {
119
+ startHTML: string;
120
+ endHTML: string;
121
+ };
122
+ scriptTag: string;
123
+ }>;
124
+ declare function buildPages(DIST_DIR: string): Promise<{
125
+ shouldClientHardReload: boolean;
126
+ }>;
127
+ declare function buildPage(DIST_DIR: string, directory: string, filePath: string, name: string): Promise<boolean>;
128
+ declare function shipModules(): Promise<void>;
129
+ /** Retrieve a list of the pages and layouts that were found during the original compilation process. */
130
+ declare function retrievePageAndLayoutMaps(): {
131
+ LAYOUT_MAP: Map<string, LayoutInformation>;
132
+ PAGE_MAP: Map<string, PageInformation>;
133
+ };
134
+ export { CompilationOptions, setCompilationOptions, getAllSubdirectories, retrievePageAndLayoutMaps, buildClient, processPageElements, pageToHTML, generateClientPageData, generateLayout, buildLayouts, buildLayout, fetchPageLayoutHTML, buildPages, buildPage, shipModules, PAGE_MAP, LAYOUT_MAP, modulesToShip, };
@@ -4,48 +4,31 @@ const __filename = fileURLToPath(import.meta.url);
4
4
  const __dirname = path.dirname(__filename);
5
5
  import esbuild from "esbuild";
6
6
  import { fileURLToPath } from "url";
7
- import { generateHTMLTemplate } from "./server/generateHTMLTemplate";
8
- import { ObjectAttributeType } from "./helpers/ObjectAttributeType";
9
- import { serverSideRenderPage } from "./server/render";
10
- import { getState, initializeState, initializeObjectAttributes, getObjectAttributes } from "./server/state";
11
- import { getLoadHooks, resetLoadHooks } from "./server/loadHook";
12
- import { resetLayouts } from "./server/layout";
13
- import { renderRecursively } from "./server/render";
7
+ import { generateHTMLTemplate } from "../server/generateHTMLTemplate";
8
+ import { ObjectAttributeType } from "../helpers/ObjectAttributeType";
9
+ import { serverSideRenderPage } from "../server/render";
10
+ import { getState, initializeState, initializeObjectAttributes, getObjectAttributes } from "../server/state";
11
+ import { getLoadHooks, resetLoadHooks } from "../server/loadHook";
12
+ import { resetLayouts } from "../server/layout";
13
+ import { renderRecursively } from "../server/render";
14
+ const PAGE_MAP = /* @__PURE__ */ new Map();
15
+ const LAYOUT_MAP = /* @__PURE__ */ new Map();
16
+ let options;
17
+ let DIST_DIR;
18
+ let elementKey = 0;
19
+ const shippedModules = /* @__PURE__ */ new Map();
20
+ let modulesToShip = [];
14
21
  let packageDir = process.env.PACKAGE_PATH;
15
22
  if (packageDir === void 0) {
16
23
  packageDir = path.resolve(__dirname, "..");
17
24
  }
18
25
  const clientPath = path.resolve(packageDir, "./dist/client/client.mjs");
19
26
  const watcherPath = path.resolve(packageDir, "./dist/client/watcher.mjs");
20
- const shippedModules = /* @__PURE__ */ new Map();
21
- let modulesToShip = [];
22
- const yellow = (text) => {
23
- return `\x1B[38;2;238;184;68m${text}`;
24
- };
25
- const black = (text) => {
26
- return `\x1B[38;2;0;0;0m${text}`;
27
- };
28
- const bgYellow = (text) => {
29
- return `\x1B[48;2;238;184;68m${text}`;
30
- };
31
- const bold = (text) => {
32
- return `\x1B[1m${text}`;
33
- };
34
- const underline = (text) => {
35
- return `\x1B[4m${text}`;
36
- };
37
- const white = (text) => {
38
- return `\x1B[38;2;255;247;229m${text}`;
39
- };
40
- const log = (...text) => {
41
- if (options.quiet) return;
42
- return console.log(text.map((text2) => `${text2}\x1B[0m`).join(""));
43
- };
44
- let options = JSON.parse(process.env.OPTIONS || "{}");
45
- const DIST_DIR = process.env.DIST_DIR;
46
- const PAGE_MAP = /* @__PURE__ */ new Map();
47
- const LAYOUT_MAP = /* @__PURE__ */ new Map();
48
- const getAllSubdirectories = (dir, baseDir = dir) => {
27
+ function setCompilationOptions(newOptions, distDir) {
28
+ options = newOptions;
29
+ DIST_DIR = distDir;
30
+ }
31
+ function getAllSubdirectories(dir, baseDir = dir) {
49
32
  let directories = [];
50
33
  const items = fs.readdirSync(dir, { withFileTypes: true });
51
34
  for (const item of items) {
@@ -57,8 +40,9 @@ const getAllSubdirectories = (dir, baseDir = dir) => {
57
40
  }
58
41
  }
59
42
  return directories;
60
- };
61
- const buildClient = async (DIST_DIR2) => {
43
+ }
44
+ ;
45
+ async function buildClient(DIST_DIR2) {
62
46
  let clientString = "window.__name = (func) => func; ";
63
47
  clientString += fs.readFileSync(clientPath, "utf-8");
64
48
  if (options.hotReload !== void 0) {
@@ -77,9 +61,9 @@ const buildClient = async (DIST_DIR2) => {
77
61
  path.join(DIST_DIR2, "/client.js"),
78
62
  transformedClient.code
79
63
  );
80
- };
81
- let elementKey = 0;
82
- const processOptionAsObjectAttribute = (element, optionName, optionValue, objectAttributes) => {
64
+ }
65
+ ;
66
+ function processOptionAsObjectAttribute(element, optionName, optionValue, objectAttributes) {
83
67
  const lcOptionName = optionName.toLowerCase();
84
68
  const options2 = element.options;
85
69
  let key = options2.key;
@@ -123,7 +107,8 @@ const processOptionAsObjectAttribute = (element, optionName, optionValue, object
123
107
  break;
124
108
  }
125
109
  objectAttributes.push({ ...optionValue, key, attribute: optionFinal });
126
- };
110
+ }
111
+ ;
127
112
  function buildTrace(stack, indent = 4) {
128
113
  try {
129
114
  if (!stack || stack.length === 0) return "[]";
@@ -159,7 +144,7 @@ function buildTrace(stack, indent = 4) {
159
144
  return "Could not build stack-trace.";
160
145
  }
161
146
  }
162
- const processPageElements = (element, objectAttributes, recursionLevel, stack = []) => {
147
+ function processPageElements(element, objectAttributes, recursionLevel, stack = []) {
163
148
  stack.push(element);
164
149
  try {
165
150
  if (typeof element === "boolean" || typeof element === "number" || Array.isArray(element)) {
@@ -251,8 +236,9 @@ ${trace}`);
251
236
  throw e;
252
237
  }
253
238
  }
254
- };
255
- const pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageName, doWrite = true, requiredClientModules = {}, layout, pathname = "") => {
239
+ }
240
+ ;
241
+ async function pageToHTML(pageLocation, pageElements, metadata, DIST_DIR2, pageName, doWrite = true, requiredClientModules = {}, layout, pathname = "") {
256
242
  if (typeof pageElements === "string" || typeof pageElements === "boolean" || typeof pageElements === "number" || Array.isArray(pageElements)) {
257
243
  throw new Error(`The root element of a page / layout must be a built element, not just a Child. Received: ${typeof pageElements}.`);
258
244
  }
@@ -327,8 +313,9 @@ const pageToHTML = async (pageLocation, pageElements, metadata, DIST_DIR2, pageN
327
313
  return objectAttributes;
328
314
  }
329
315
  return resultHTML;
330
- };
331
- const generateClientPageData = async (pageLocation, state, objectAttributes, pageLoadHooks, DIST_DIR2, pageName, globalVariableName = "pd", write = true) => {
316
+ }
317
+ ;
318
+ async function generateClientPageData(pageLocation, state, objectAttributes, pageLoadHooks, DIST_DIR2, pageName, globalVariableName = "pd", write = true) {
332
319
  let clientPageJSText = "";
333
320
  {
334
321
  clientPageJSText += `${globalThis.__SERVER_PAGE_DATA_BANNER__}`;
@@ -395,8 +382,9 @@ const generateClientPageData = async (pageLocation, state, objectAttributes, pag
395
382
  }
396
383
  if (write) fs.writeFileSync(pageDataPath, transformedResult.code, "utf-8");
397
384
  return { sendHardReloadInstruction, result: transformedResult.code };
398
- };
399
- const generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, generateDynamic = false) => {
385
+ }
386
+ ;
387
+ async function generateLayout(DIST_DIR2, filePath, directory, childIndicator, generateDynamic = false) {
400
388
  initializeState();
401
389
  initializeObjectAttributes();
402
390
  resetLoadHooks();
@@ -476,9 +464,10 @@ const generateLayout = async (DIST_DIR2, filePath, directory, childIndicator, ge
476
464
  "ld"
477
465
  );
478
466
  return { pageContentHTML: renderedPage.bodyHTML, metadataHTML };
479
- };
467
+ }
468
+ ;
480
469
  const builtLayouts = /* @__PURE__ */ new Map();
481
- const buildLayouts = async () => {
470
+ async function buildLayouts() {
482
471
  const pagesDirectory = path.resolve(options.pagesDirectory);
483
472
  const subdirectories = [...getAllSubdirectories(pagesDirectory), ""];
484
473
  let shouldClientHardReload = false;
@@ -503,8 +492,8 @@ const buildLayouts = async () => {
503
492
  }
504
493
  }
505
494
  return { shouldClientHardReload };
506
- };
507
- const buildLayout = async (filePath, directory, generateDynamic = false) => {
495
+ }
496
+ async function buildLayout(filePath, directory, generateDynamic = false) {
508
497
  const id = globalThis.__SERVER_CURRENT_STATE_ID__ += 1;
509
498
  const childIndicator = `<template layout-id="${id}"></template>`;
510
499
  const result = await generateLayout(
@@ -516,40 +505,49 @@ const buildLayout = async (filePath, directory, generateDynamic = false) => {
516
505
  );
517
506
  if (result === false) return false;
518
507
  const { pageContentHTML, metadataHTML } = result;
519
- const splitAround = (str, sub) => {
508
+ function splitAround(str, sub) {
520
509
  const i = str.indexOf(sub);
521
510
  if (i === -1) throw new Error("substring does not exist in parent string");
522
511
  return {
523
512
  startHTML: str.substring(0, i),
524
513
  endHTML: str.substring(i + sub.length)
525
514
  };
526
- };
527
- const splitAt = (str, sub) => {
515
+ }
516
+ function splitAt(str, sub) {
528
517
  const i = str.indexOf(sub) + sub.length;
529
518
  if (i === -1) throw new Error("substring does not exist in parent string");
530
519
  return {
531
520
  startHTML: str.substring(0, i),
532
521
  endHTML: str.substring(i)
533
522
  };
534
- };
523
+ }
535
524
  const pathname = directory === "" ? "/" : directory;
536
525
  return {
537
526
  pageContent: splitAt(pageContentHTML, childIndicator),
538
527
  metadata: splitAround(metadataHTML, childIndicator),
539
528
  scriptTag: `<script data-layout="true" type="module" src="${pathname}layout_data.js" data-pathname="${pathname}" defer="true"></script>`
540
529
  };
541
- };
542
- const fetchPageLayoutHTML = async (dirname) => {
530
+ }
531
+ ;
532
+ async function fetchPageLayoutHTML(dirname) {
543
533
  const relative = path.relative(options.pagesDirectory, dirname);
544
534
  let split = relative.split(path.sep).filter(Boolean);
545
535
  split.push("/");
546
536
  split.reverse();
547
537
  let layouts = [];
548
538
  for (const dir of split) {
549
- if (LAYOUT_MAP.has(dir)) {
550
- const filePath = path.join(path.resolve(options.pagesDirectory), dir, "layout.ts");
551
- const layout = LAYOUT_MAP.get(dir);
552
- if (layout.isDynamic) {
539
+ if (!LAYOUT_MAP.has(dir)) {
540
+ console.warn("A layout was not found within the layout map for a path:", dir, "This is normally not meant to be possible, so you might have royally screwed up.");
541
+ continue;
542
+ }
543
+ const filePath = path.join(path.resolve(options.pagesDirectory), dir, "layout.ts");
544
+ const layout = LAYOUT_MAP.get(dir);
545
+ if (layout.isDynamic) {
546
+ const builtLayout = await buildLayout(layout.filePath, dir, true);
547
+ if (!builtLayout) continue;
548
+ layouts.push(builtLayout);
549
+ } else {
550
+ if (!builtLayouts.has(filePath)) {
553
551
  const builtLayout = await buildLayout(layout.filePath, dir, true);
554
552
  if (!builtLayout) continue;
555
553
  layouts.push(builtLayout);
@@ -575,8 +573,9 @@ const fetchPageLayoutHTML = async (dirname) => {
575
573
  metadata.endHTML += layout.metadata.endHTML;
576
574
  }
577
575
  return { pageContent, metadata, scriptTag: scriptTags };
578
- };
579
- const buildPages = async (DIST_DIR2) => {
576
+ }
577
+ ;
578
+ async function buildPages(DIST_DIR2) {
580
579
  resetLayouts();
581
580
  const pagesDirectory = path.resolve(options.pagesDirectory);
582
581
  const subdirectories = [...getAllSubdirectories(pagesDirectory), ""];
@@ -605,8 +604,9 @@ const buildPages = async (DIST_DIR2) => {
605
604
  return {
606
605
  shouldClientHardReload
607
606
  };
608
- };
609
- const buildPage = async (DIST_DIR2, directory, filePath, name) => {
607
+ }
608
+ ;
609
+ async function buildPage(DIST_DIR2, directory, filePath, name) {
610
610
  initializeState();
611
611
  initializeObjectAttributes();
612
612
  resetLoadHooks();
@@ -691,82 +691,9 @@ const buildPage = async (DIST_DIR2, directory, filePath, name) => {
691
691
  name
692
692
  );
693
693
  return sendHardReloadInstruction === true;
694
- };
695
- const buildDynamicPage = async (DIST_DIR2, directory, pageInfo, req, res, middlewareData) => {
696
- directory = directory === "/" ? "" : directory;
697
- const filePath = pageInfo.filePath;
698
- initializeState();
699
- initializeObjectAttributes();
700
- resetLoadHooks();
701
- globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
702
- let pageElements = async (props) => body();
703
- let metadata = async (props) => html();
704
- let modules = {};
705
- let pageIgnoresLayout = false;
706
- try {
707
- const {
708
- page,
709
- metadata: pageMetadata,
710
- shippedModules: shippedModules2,
711
- ignoreLayout,
712
- requestHook
713
- } = await import("file://" + filePath);
714
- if (requestHook) {
715
- const hook = requestHook;
716
- const doContinue = await hook(req, res);
717
- if (!doContinue) {
718
- return false;
719
- }
720
- }
721
- if (shippedModules2 !== void 0) {
722
- modules = shippedModules2;
723
- }
724
- if (ignoreLayout) {
725
- pageIgnoresLayout = true;
726
- }
727
- pageElements = page;
728
- metadata = pageMetadata;
729
- } catch (e) {
730
- throw new Error(`Error in Page: ${directory}/page.ts - ${e}`);
731
- }
732
- if (modules !== void 0) {
733
- for (const [globalName, path2] of Object.entries(modules)) {
734
- modulesToShip.push({ globalName, path: path2 });
735
- }
736
- }
737
- if (!metadata || metadata && typeof metadata !== "function") {
738
- console.warn(`WARNING: ${filePath} does not export a metadata function.`);
739
- }
740
- if (!pageElements) {
741
- console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
742
- }
743
- const pageProps = {
744
- pageName: directory,
745
- middlewareData
746
- };
747
- if (typeof pageElements === "function") {
748
- if (pageElements.constructor.name === "AsyncFunction") {
749
- pageElements = await pageElements(pageProps);
750
- } else {
751
- pageElements = pageElements(pageProps);
752
- }
753
- }
754
- const layout = await fetchPageLayoutHTML(path.dirname(filePath));
755
- const resultHTML = await pageToHTML(
756
- path.join(DIST_DIR2, directory),
757
- pageElements,
758
- metadata,
759
- DIST_DIR2,
760
- "page",
761
- false,
762
- modules,
763
- layout,
764
- directory
765
- );
766
- await shipModules();
767
- return { resultHTML };
768
- };
769
- const shipModules = async () => {
694
+ }
695
+ ;
696
+ async function shipModules() {
770
697
  for (const plugin of modulesToShip) {
771
698
  {
772
699
  if (shippedModules.has(plugin.globalName)) continue;
@@ -784,71 +711,27 @@ const shipModules = async () => {
784
711
  });
785
712
  }
786
713
  modulesToShip = [];
787
- };
788
- const build = async () => {
789
- try {
790
- {
791
- log(bold(yellow(" -- Elegance.JS -- ")));
792
- if (options.environment === "production") {
793
- log(
794
- " - ",
795
- bgYellow(bold(black(" NOTE "))),
796
- " : ",
797
- white("In production mode, no "),
798
- underline("console.log() "),
799
- white("statements will be shown on the client, and all code will be minified.")
800
- );
801
- log("");
802
- }
803
- }
804
- if (options.preCompile) {
805
- options.preCompile();
806
- }
807
- const start = performance.now();
808
- let shouldClientHardReload;
809
- {
810
- const { shouldClientHardReload: doReload } = await buildLayouts();
811
- if (doReload) shouldClientHardReload = true;
812
- }
813
- {
814
- const { shouldClientHardReload: doReload } = await buildPages(path.resolve(DIST_DIR));
815
- if (doReload) shouldClientHardReload = true;
816
- }
817
- await shipModules();
818
- const pagesBuilt = performance.now();
819
- await buildClient(DIST_DIR);
820
- const end = performance.now();
821
- if (options.publicDirectory) {
822
- log("Recursively copying public directory.. this may take a while.");
823
- const src = path.relative(process.cwd(), options.publicDirectory.path);
824
- if (fs.existsSync(src) === false) {
825
- console.warn("WARNING: Public directory not found, an attempt will be made create it..");
826
- fs.mkdirSync(src, { recursive: true });
827
- }
828
- await fs.promises.cp(src, path.join(DIST_DIR), { recursive: true });
829
- }
830
- {
831
- log(`Took ${Math.round(pagesBuilt - start)}ms to Build Pages.`);
832
- log(`Took ${Math.round(end - pagesBuilt)}ms to Build Client.`);
833
- }
834
- process.send?.({ event: "message", data: "set-pages-and-layouts", content: JSON.stringify({ pageMap: Array.from(PAGE_MAP), layoutMap: Array.from(LAYOUT_MAP) }) });
835
- process.send?.({ event: "message", data: "compile-finish" });
836
- if (shouldClientHardReload) {
837
- process.send({ event: "message", data: "hard-reload" });
838
- } else {
839
- process.send({ event: "message", data: "soft-reload" });
840
- }
841
- } catch (e) {
842
- console.error("Build Failed! Received Error:");
843
- console.error(e);
844
- return false;
845
- }
846
- return true;
847
- };
848
- (async () => {
849
- if (process.env.DO_BUILD === "true") await build();
850
- })();
714
+ }
715
+ ;
716
+ function retrievePageAndLayoutMaps() {
717
+ return { LAYOUT_MAP, PAGE_MAP };
718
+ }
851
719
  export {
852
- buildDynamicPage,
853
- processPageElements
720
+ LAYOUT_MAP,
721
+ PAGE_MAP,
722
+ buildClient,
723
+ buildLayout,
724
+ buildLayouts,
725
+ buildPage,
726
+ buildPages,
727
+ fetchPageLayoutHTML,
728
+ generateClientPageData,
729
+ generateLayout,
730
+ getAllSubdirectories,
731
+ modulesToShip,
732
+ pageToHTML,
733
+ processPageElements,
734
+ retrievePageAndLayoutMaps,
735
+ setCompilationOptions,
736
+ shipModules
854
737
  };
@@ -0,0 +1,3 @@
1
+ /** This file is essentially script, that is spawned by compile(), which uses tools from ./compilation to build the project of the user. */
2
+ /** It's a separate process, so that we can avoid memory leaks due to us using cache-busting for importing the page files (you cannot un-import things in esm) */
3
+ export {};
@@ -0,0 +1,95 @@
1
+ const __filename = fileURLToPath(import.meta.url);
2
+ const __dirname = path.dirname(__filename);
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ import { buildClient, buildLayouts, buildPages, retrievePageAndLayoutMaps, setCompilationOptions, shipModules } from "./compilation";
7
+ let options = JSON.parse(process.env.OPTIONS || "{}");
8
+ const DIST_DIR = process.env.DIST_DIR;
9
+ const yellow = (text) => {
10
+ return `\x1B[38;2;238;184;68m${text}`;
11
+ };
12
+ const black = (text) => {
13
+ return `\x1B[38;2;0;0;0m${text}`;
14
+ };
15
+ const bgYellow = (text) => {
16
+ return `\x1B[48;2;238;184;68m${text}`;
17
+ };
18
+ const bold = (text) => {
19
+ return `\x1B[1m${text}`;
20
+ };
21
+ const underline = (text) => {
22
+ return `\x1B[4m${text}`;
23
+ };
24
+ const white = (text) => {
25
+ return `\x1B[38;2;255;247;229m${text}`;
26
+ };
27
+ const log = (...text) => {
28
+ if (options.quiet) return;
29
+ return console.log(text.map((text2) => `${text2}\x1B[0m`).join(""));
30
+ };
31
+ const build = async () => {
32
+ setCompilationOptions(options, DIST_DIR);
33
+ try {
34
+ {
35
+ log(bold(yellow(" -- Elegance.JS -- ")));
36
+ if (options.environment === "production") {
37
+ log(
38
+ " - ",
39
+ bgYellow(bold(black(" NOTE "))),
40
+ " : ",
41
+ white("In production mode, no "),
42
+ underline("console.log() "),
43
+ white("statements will be shown on the client, and all code will be minified.")
44
+ );
45
+ log("");
46
+ }
47
+ }
48
+ if (options.preCompile) {
49
+ options.preCompile();
50
+ }
51
+ const start = performance.now();
52
+ let shouldClientHardReload;
53
+ {
54
+ const { shouldClientHardReload: doReload } = await buildLayouts();
55
+ if (doReload) shouldClientHardReload = true;
56
+ }
57
+ {
58
+ const { shouldClientHardReload: doReload } = await buildPages(path.resolve(DIST_DIR));
59
+ if (doReload) shouldClientHardReload = true;
60
+ }
61
+ await shipModules();
62
+ const pagesBuilt = performance.now();
63
+ await buildClient(DIST_DIR);
64
+ const end = performance.now();
65
+ {
66
+ log(`Took ${Math.round(pagesBuilt - start)}ms to Build Pages.`);
67
+ log(`Took ${Math.round(end - pagesBuilt)}ms to Build Client.`);
68
+ }
69
+ if (options.publicDirectory) {
70
+ log("Recursively copying public directory.. this may take a while.");
71
+ const src = path.relative(process.cwd(), options.publicDirectory.path);
72
+ if (fs.existsSync(src) === false) {
73
+ console.warn("WARNING: Public directory not found, an attempt will be made create it..");
74
+ fs.mkdirSync(src, { recursive: true });
75
+ }
76
+ await fs.promises.cp(src, path.join(DIST_DIR), { recursive: true });
77
+ }
78
+ {
79
+ process.send?.({ event: "message", data: "compile-finish" });
80
+ const { PAGE_MAP, LAYOUT_MAP } = retrievePageAndLayoutMaps();
81
+ process.send?.({ event: "message", data: "set-pages-and-layouts", content: JSON.stringify({ pageMap: Array.from(PAGE_MAP), layoutMap: Array.from(LAYOUT_MAP) }) });
82
+ if (shouldClientHardReload) {
83
+ process.send({ event: "message", data: "hard-reload" });
84
+ } else {
85
+ process.send({ event: "message", data: "soft-reload" });
86
+ }
87
+ }
88
+ } catch (e) {
89
+ console.error("Build Failed! Received Error:");
90
+ console.error(e);
91
+ return false;
92
+ }
93
+ return true;
94
+ };
95
+ build();
@@ -0,0 +1,12 @@
1
+ import { IncomingMessage, ServerResponse } from "http";
2
+ /** Populate layout and page map for the server, so it knows what pages exist within the project. */
3
+ declare function populateServerMaps(pageMap: Map<any, any>, layoutMap: Map<any, any>): void;
4
+ /** Render a page that has been deemed dynamic. */
5
+ declare function buildDynamicPage(DIST_DIR: string, directory: string, pageInfo: PageInformation, req: IncomingMessage, res: ServerResponse, middlewareData: MiddlewareData): Promise<false | {
6
+ resultHTML: any;
7
+ }>;
8
+ /** Check if a given pathname was found during the original compilation process. */
9
+ declare function doesPageExist(pathname: string): boolean;
10
+ /** Retrieve a given pathname from the page map. */
11
+ declare function getPage(pathname: string): any;
12
+ export { populateServerMaps, doesPageExist, getPage, buildDynamicPage, };
@@ -0,0 +1,101 @@
1
+ import { initializeObjectAttributes, initializeState } from "../server/state";
2
+ import { resetLoadHooks } from "../server/loadHook";
3
+ import { fetchPageLayoutHTML, pageToHTML, shipModules, modulesToShip } from "./compilation";
4
+ import path from "path";
5
+ let LAYOUT_MAP = /* @__PURE__ */ new Map();
6
+ let PAGE_MAP = /* @__PURE__ */ new Map();
7
+ function populateServerMaps(pageMap, layoutMap) {
8
+ LAYOUT_MAP = layoutMap;
9
+ PAGE_MAP = pageMap;
10
+ }
11
+ async function buildDynamicPage(DIST_DIR, directory, pageInfo, req, res, middlewareData) {
12
+ directory = directory === "/" ? "" : directory;
13
+ const filePath = pageInfo.filePath;
14
+ initializeState();
15
+ initializeObjectAttributes();
16
+ resetLoadHooks();
17
+ globalThis.__SERVER_PAGE_DATA_BANNER__ = "";
18
+ let pageElements = async function(props) {
19
+ return body();
20
+ };
21
+ let metadata = async function(props) {
22
+ return html();
23
+ };
24
+ let modules = {};
25
+ let pageIgnoresLayout = false;
26
+ try {
27
+ const {
28
+ page,
29
+ metadata: pageMetadata,
30
+ shippedModules,
31
+ ignoreLayout,
32
+ requestHook
33
+ } = await import("file://" + filePath);
34
+ if (requestHook) {
35
+ const hook = requestHook;
36
+ const doContinue = await hook(req, res);
37
+ if (!doContinue) {
38
+ return false;
39
+ }
40
+ }
41
+ if (shippedModules !== void 0) {
42
+ modules = shippedModules;
43
+ }
44
+ if (ignoreLayout) {
45
+ pageIgnoresLayout = true;
46
+ }
47
+ pageElements = page;
48
+ metadata = pageMetadata;
49
+ } catch (e) {
50
+ throw new Error(`Error in Page: ${directory}/page.ts - ${e}`);
51
+ }
52
+ if (modules !== void 0) {
53
+ for (const [globalName, path2] of Object.entries(modules)) {
54
+ modulesToShip.push({ globalName, path: path2 });
55
+ }
56
+ }
57
+ if (!metadata || metadata && typeof metadata !== "function") {
58
+ console.warn(`WARNING: ${filePath} does not export a metadata function.`);
59
+ }
60
+ if (!pageElements) {
61
+ console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
62
+ }
63
+ const pageProps = {
64
+ pageName: directory,
65
+ middlewareData
66
+ };
67
+ if (typeof pageElements === "function") {
68
+ if (pageElements.constructor.name === "AsyncFunction") {
69
+ pageElements = await pageElements(pageProps);
70
+ } else {
71
+ pageElements = pageElements(pageProps);
72
+ }
73
+ }
74
+ const layout = await fetchPageLayoutHTML(path.dirname(filePath));
75
+ const resultHTML = await pageToHTML(
76
+ path.join(DIST_DIR, directory),
77
+ pageElements,
78
+ metadata,
79
+ DIST_DIR,
80
+ "page",
81
+ false,
82
+ modules,
83
+ layout,
84
+ directory
85
+ );
86
+ await shipModules();
87
+ return { resultHTML };
88
+ }
89
+ ;
90
+ function doesPageExist(pathname) {
91
+ return PAGE_MAP.has(pathname);
92
+ }
93
+ function getPage(pathname) {
94
+ return PAGE_MAP.get(pathname);
95
+ }
96
+ export {
97
+ buildDynamicPage,
98
+ doesPageExist,
99
+ getPage,
100
+ populateServerMaps
101
+ };
@@ -1,31 +1,11 @@
1
- import {
2
- createServer as createHttpServer
3
- } from "http";
4
- import {
5
- promises as fs
6
- } from "fs";
7
- import {
8
- join,
9
- normalize,
10
- extname,
11
- dirname
12
- } from "path";
13
- import {
14
- pathToFileURL
15
- } from "url";
16
- import {
17
- log
18
- } from "../log";
19
- import {
20
- gzip,
21
- deflate
22
- } from "zlib";
23
- import {
24
- promisify
25
- } from "util";
26
- import {
27
- PAGE_MAP
28
- } from "../build";
1
+ import { createServer as createHttpServer } from "http";
2
+ import { promises as fs } from "fs";
3
+ import { join, normalize, extname, dirname } from "path";
4
+ import { pathToFileURL } from "url";
5
+ import { log } from "../log";
6
+ import { gzip, deflate } from "zlib";
7
+ import { promisify } from "util";
8
+ import { doesPageExist, getPage } from "../compilation/dynamic_compiler";
29
9
  const gzipAsync = promisify(gzip);
30
10
  const deflateAsync = promisify(deflate);
31
11
  const MIME_TYPES = {
@@ -75,8 +55,8 @@ function startServer({
75
55
  const url = new URL(req.url, `http://${req.headers.host}`);
76
56
  if (url.pathname.startsWith("/api/")) {
77
57
  await handleApiRequest(pagesDirectory, url.pathname, req, res);
78
- } else if (PAGE_MAP.has(url.pathname)) {
79
- await handlePageRequest(root, pagesDirectory, url.pathname, req, res, DIST_DIR, PAGE_MAP.get(url.pathname));
58
+ } else if (doesPageExist(url.pathname)) {
59
+ await handlePageRequest(root, pagesDirectory, url.pathname, req, res, DIST_DIR, getPage(url.pathname));
80
60
  } else {
81
61
  await handleStaticRequest(root, pagesDirectory, url.pathname, req, res, DIST_DIR);
82
62
  }
@@ -190,7 +170,7 @@ async function handlePageRequest(root, pagesDirectory, pathname, req, res, DIST_
190
170
  try {
191
171
  const {
192
172
  buildDynamicPage
193
- } = await import("../page_compiler");
173
+ } = await import("../compilation/dynamic_compiler");
194
174
  const result = await buildDynamicPage(
195
175
  DIST_DIR,
196
176
  pathname,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elegance-js",
3
- "version": "2.1.12",
3
+ "version": "2.1.14",
4
4
  "description": "Web-Framework",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "license": "MIT",
36
36
  "dependencies": {
37
37
  "esbuild": "^0.25.9",
38
- "ts-arc": "^1.1.27"
38
+ "ts-arc": "^1.1.28"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@tailwindcss/cli": "^4.0.3",
@@ -1,5 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from "http";
2
- export declare const processPageElements: (element: Child, objectAttributes: Array<any>, recursionLevel: number, stack?: any[]) => Child;
3
- export declare const buildDynamicPage: (DIST_DIR: string, directory: string, pageInfo: PageInformation, req: IncomingMessage, res: ServerResponse, middlewareData: MiddlewareData) => Promise<false | {
4
- resultHTML: any;
5
- }>;