elegance-js 1.6.5 → 1.8.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 CHANGED
@@ -47,7 +47,7 @@ function startServer({ root, port = 3e3, host = "localhost", environment = "prod
47
47
  if (url.pathname.startsWith("/api/")) {
48
48
  await handleApiRequest(root, url.pathname, req, res);
49
49
  } else {
50
- await handleStaticRequest(root, url.pathname, res);
50
+ await handleStaticRequest(root, url.pathname, req, res);
51
51
  }
52
52
  if (environment === "development" && quiet === false) {
53
53
  console.log(req.method, "::", req.url, "-", res.statusCode);
@@ -74,7 +74,7 @@ function startServer({ root, port = 3e3, host = "localhost", environment = "prod
74
74
  }
75
75
  return attemptListen(port);
76
76
  }
77
- async function handleStaticRequest(root, pathname, res) {
77
+ async function handleStaticRequest(root, pathname, req, res) {
78
78
  let filePath = normalize(join(root, decodeURIComponent(pathname)));
79
79
  root = normalize(root);
80
80
  if (!filePath.startsWith(root)) {
@@ -82,22 +82,62 @@ async function handleStaticRequest(root, pathname, res) {
82
82
  res.end("Forbidden");
83
83
  return;
84
84
  }
85
+ let stats;
85
86
  try {
86
- const stats = await fs.stat(filePath);
87
+ stats = await fs.stat(filePath);
87
88
  if (stats.isDirectory()) {
88
89
  filePath = join(filePath, "index.html");
89
90
  }
90
91
  } catch {
91
92
  }
93
+ let hasFile = false;
92
94
  try {
95
+ await fs.access(filePath);
96
+ hasFile = true;
97
+ } catch {
98
+ }
99
+ const pageDir = dirname(filePath);
100
+ const relDir = pageDir.slice(root.length).replace(/^[\/\\]+/, "");
101
+ const parts = relDir.split(/[\\/]/).filter(Boolean);
102
+ const middlewareDirs = [];
103
+ let current = root;
104
+ middlewareDirs.push(current);
105
+ for (const part of parts) {
106
+ current = join(current, part);
107
+ middlewareDirs.push(current);
108
+ }
109
+ const middlewares = [];
110
+ for (const dir of middlewareDirs) {
111
+ const mwPath = join(dir, "middleware.mjs");
112
+ let mwModule;
113
+ try {
114
+ await fs.access(mwPath);
115
+ const url = pathToFileURL(mwPath).href;
116
+ mwModule = await import(url);
117
+ } catch {
118
+ continue;
119
+ }
120
+ const mwKeys = Object.keys(mwModule).sort();
121
+ for (const key of mwKeys) {
122
+ const f = mwModule[key];
123
+ if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
124
+ middlewares.push(f);
125
+ }
126
+ }
127
+ }
128
+ const finalHandler = async (req2, res2) => {
129
+ if (!hasFile) {
130
+ await respondWithErrorPage(root, pathname, 404, res2);
131
+ return;
132
+ }
93
133
  const ext = extname(filePath).toLowerCase();
94
134
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
95
135
  const data = await fs.readFile(filePath);
96
- res.writeHead(200, { "Content-Type": contentType });
97
- res.end(data);
98
- } catch {
99
- await respondWithErrorPage(root, pathname, 404, res);
100
- }
136
+ res2.writeHead(200, { "Content-Type": contentType });
137
+ res2.end(data);
138
+ };
139
+ const composed = composeMiddlewares(middlewares, finalHandler);
140
+ await composed(req, res);
101
141
  }
102
142
  async function handleApiRequest(root, pathname, req, res) {
103
143
  const apiSubPath = pathname.slice("/api/".length);
@@ -50,7 +50,7 @@ function startServer({ root, port = 3e3, host = "localhost", environment: enviro
50
50
  if (url.pathname.startsWith("/api/")) {
51
51
  await handleApiRequest(root, url.pathname, req, res);
52
52
  } else {
53
- await handleStaticRequest(root, url.pathname, res);
53
+ await handleStaticRequest(root, url.pathname, req, res);
54
54
  }
55
55
  if (environment2 === "development" && quiet === false) {
56
56
  console.log(req.method, "::", req.url, "-", res.statusCode);
@@ -77,7 +77,7 @@ function startServer({ root, port = 3e3, host = "localhost", environment: enviro
77
77
  }
78
78
  return attemptListen(port);
79
79
  }
80
- async function handleStaticRequest(root, pathname, res) {
80
+ async function handleStaticRequest(root, pathname, req, res) {
81
81
  let filePath = normalize(join(root, decodeURIComponent(pathname)));
82
82
  root = normalize(root);
83
83
  if (!filePath.startsWith(root)) {
@@ -85,22 +85,62 @@ async function handleStaticRequest(root, pathname, res) {
85
85
  res.end("Forbidden");
86
86
  return;
87
87
  }
88
+ let stats;
88
89
  try {
89
- const stats = await fs.stat(filePath);
90
+ stats = await fs.stat(filePath);
90
91
  if (stats.isDirectory()) {
91
92
  filePath = join(filePath, "index.html");
92
93
  }
93
94
  } catch {
94
95
  }
96
+ let hasFile = false;
95
97
  try {
98
+ await fs.access(filePath);
99
+ hasFile = true;
100
+ } catch {
101
+ }
102
+ const pageDir = dirname(filePath);
103
+ const relDir = pageDir.slice(root.length).replace(/^[\/\\]+/, "");
104
+ const parts = relDir.split(/[\\/]/).filter(Boolean);
105
+ const middlewareDirs = [];
106
+ let current = root;
107
+ middlewareDirs.push(current);
108
+ for (const part of parts) {
109
+ current = join(current, part);
110
+ middlewareDirs.push(current);
111
+ }
112
+ const middlewares = [];
113
+ for (const dir of middlewareDirs) {
114
+ const mwPath = join(dir, "middleware.mjs");
115
+ let mwModule;
116
+ try {
117
+ await fs.access(mwPath);
118
+ const url = pathToFileURL(mwPath).href;
119
+ mwModule = await import(url);
120
+ } catch {
121
+ continue;
122
+ }
123
+ const mwKeys = Object.keys(mwModule).sort();
124
+ for (const key of mwKeys) {
125
+ const f = mwModule[key];
126
+ if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
127
+ middlewares.push(f);
128
+ }
129
+ }
130
+ }
131
+ const finalHandler = async (req2, res2) => {
132
+ if (!hasFile) {
133
+ await respondWithErrorPage(root, pathname, 404, res2);
134
+ return;
135
+ }
96
136
  const ext = extname(filePath).toLowerCase();
97
137
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
98
138
  const data = await fs.readFile(filePath);
99
- res.writeHead(200, { "Content-Type": contentType });
100
- res.end(data);
101
- } catch {
102
- await respondWithErrorPage(root, pathname, 404, res);
103
- }
139
+ res2.writeHead(200, { "Content-Type": contentType });
140
+ res2.end(data);
141
+ };
142
+ const composed = composeMiddlewares(middlewares, finalHandler);
143
+ await composed(req, res);
104
144
  }
105
145
  async function handleApiRequest(root, pathname, req, res) {
106
146
  const apiSubPath = pathname.slice("/api/".length);
@@ -306,39 +306,16 @@ var getAllSubdirectories = (dir, baseDir = dir) => {
306
306
  return directories;
307
307
  };
308
308
  var getProjectFiles = (pagesDirectory) => {
309
- const pageFiles = [];
310
- const apiFiles = [];
311
- const middlewareFiles = [];
309
+ const files = [];
312
310
  const subdirectories = [...getAllSubdirectories(pagesDirectory), ""];
313
311
  for (const subdirectory of subdirectories) {
314
312
  const absoluteDirectoryPath = path.join(pagesDirectory, subdirectory);
315
313
  const subdirectoryFiles = fs.readdirSync(absoluteDirectoryPath, { withFileTypes: true }).filter((f) => f.name.endsWith(".ts"));
316
314
  for (const file of subdirectoryFiles) {
317
- if (file.name === "route.ts") {
318
- apiFiles.push(file);
319
- continue;
320
- } else if (file.name === "page.ts") {
321
- pageFiles.push(file);
322
- continue;
323
- } else if (file.name === "middleware.ts") {
324
- middlewareFiles.push(file);
325
- continue;
326
- }
327
- const name = file.name.slice(0, file.name.length - 3);
328
- const numberName = parseInt(name);
329
- if (isNaN(numberName) === false) {
330
- if (numberName >= 400 && numberName <= 599) {
331
- pageFiles.push(file);
332
- continue;
333
- }
334
- }
315
+ files.push(file);
335
316
  }
336
317
  }
337
- return {
338
- pageFiles,
339
- apiFiles,
340
- middlewareFiles
341
- };
318
+ return files;
342
319
  };
343
320
  var buildClient = async (DIST_DIR2) => {
344
321
  let clientString = "window.__name = (func) => func; ";
@@ -600,19 +577,14 @@ var buildPages = async (DIST_DIR2) => {
600
577
  let shouldClientHardReload = false;
601
578
  for (const directory of subdirectories) {
602
579
  const abs = path.resolve(path.join(DIST_DIR2, directory));
603
- const files = fs.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".js"));
580
+ const files = fs.readdirSync(abs, { withFileTypes: true }).filter((f) => f.name.endsWith(".mjs"));
604
581
  for (const file of files) {
605
582
  const filePath = path.join(file.parentPath, file.name);
606
- const name = file.name.slice(0, file.name.length - 3);
607
- const tempPath = file.parentPath + "/" + Date.now().toString() + ".mjs";
608
- await fs.promises.copyFile(filePath, tempPath);
609
- const bytes = fs.readFileSync(tempPath);
610
- const isPage = bytes.toString().startsWith("//__ELEGANCE_JS_PAGE_MARKER__");
583
+ const name = file.name.slice(0, file.name.length - 4);
584
+ const isPage = file.name.includes("page");
611
585
  if (isPage == false) {
612
- fs.rmSync(tempPath, { force: true });
613
586
  continue;
614
587
  }
615
- fs.rmSync(filePath, { force: true });
616
588
  initializeState();
617
589
  initializeObjectAttributes();
618
590
  resetLoadHooks();
@@ -622,14 +594,12 @@ var buildPages = async (DIST_DIR2) => {
622
594
  const {
623
595
  page,
624
596
  metadata: pageMetadata
625
- } = await import("file://" + tempPath);
597
+ } = await import("file://" + filePath);
626
598
  pageElements = page;
627
599
  metadata = pageMetadata;
628
600
  } catch (e) {
629
- fs.rmSync(tempPath, { force: true });
630
601
  throw new Error(`Error in Page: ${directory === "" ? "/" : directory}${file.name} - ${e}`);
631
602
  }
632
- fs.rmSync(tempPath, { force: true });
633
603
  if (!metadata || metadata && typeof metadata !== "function") {
634
604
  console.warn(`WARNING: ${filePath} does not export a metadata function. This is *highly* recommended.`);
635
605
  }
@@ -690,83 +660,24 @@ var build = async () => {
690
660
  );
691
661
  options.preCompile();
692
662
  }
693
- const { pageFiles, apiFiles, middlewareFiles } = getProjectFiles(options.pagesDirectory);
694
- {
695
- const existingCompiledPages = [...getAllSubdirectories(DIST_DIR), ""];
696
- for (const page of existingCompiledPages) {
697
- const pageFile = pageFiles.find((dir) => path.relative(options.pagesDirectory, dir?.parentPath ?? "") === page);
698
- const apiFile = apiFiles.find((dir) => path.relative(options.pagesDirectory, dir?.parentPath ?? "") === page);
699
- const middlewareFile = middlewareFiles.find((dir) => path.relative(options.pagesDirectory, dir?.parentPath ?? "") === page);
700
- if (!pageFile && !apiFile && !middlewareFile) {
701
- const dir = path.join(DIST_DIR, page);
702
- if (fs.existsSync(dir) === false) {
703
- continue;
704
- }
705
- fs.rmdirSync(dir, { recursive: true });
706
- log("Deleted old page directory:", dir);
707
- }
708
- }
709
- }
663
+ const projectFiles = getProjectFiles(options.pagesDirectory);
710
664
  const start = performance.now();
711
665
  {
666
+ const externalBareImportsPlugin = {
667
+ name: "external-bare-imports",
668
+ setup(build2) {
669
+ build2.onResolve({ filter: /^[^./]/ }, (args) => {
670
+ return { path: args.path, external: true };
671
+ });
672
+ }
673
+ };
712
674
  await esbuild.build({
713
- entryPoints: [
714
- ...pageFiles.map((page) => path.join(page.parentPath, page.name))
715
- ],
716
- minify: options.environment === "production",
717
- drop: options.environment === "production" ? ["console", "debugger"] : void 0,
675
+ entryPoints: projectFiles.map((f) => path.join(f.parentPath, f.name)),
718
676
  bundle: true,
719
677
  outdir: DIST_DIR,
720
- loader: {
721
- ".js": "js",
722
- ".ts": "ts"
723
- },
724
- format: "esm",
725
- platform: "node",
726
- keepNames: false,
727
- banner: {
728
- js: "//__ELEGANCE_JS_PAGE_MARKER__"
729
- },
730
- define: {
731
- "DEV": options.environment === "development" ? "true" : "false",
732
- "PROD": options.environment === "development" ? "false" : "true"
733
- },
734
- external: ["fs"]
735
- });
736
- await esbuild.build({
737
- entryPoints: [
738
- ...apiFiles.map((route) => path.join(route.parentPath, route.name))
739
- ],
740
- minify: options.environment === "production",
741
- drop: options.environment === "production" ? ["console", "debugger"] : void 0,
742
- bundle: false,
743
- outbase: path.join(options.pagesDirectory, "/api"),
744
- outdir: path.join(DIST_DIR, "/api"),
745
- outExtension: { ".js": ".mjs" },
746
- loader: {
747
- ".js": "js",
748
- ".ts": "ts"
749
- },
750
- format: "esm",
751
- platform: "node",
752
- keepNames: false,
753
- define: {
754
- "DEV": options.environment === "development" ? "true" : "false",
755
- "PROD": options.environment === "development" ? "false" : "true"
756
- }
757
- });
758
- await esbuild.build({
759
- entryPoints: [
760
- ...middlewareFiles.map((route) => path.join(route.parentPath, route.name))
761
- ],
762
- minify: options.environment === "production",
763
- drop: options.environment === "production" ? ["console", "debugger"] : void 0,
764
- bundle: false,
765
- outbase: path.join(options.pagesDirectory, "/api"),
766
- outdir: path.join(DIST_DIR, "/api"),
767
678
  outExtension: { ".js": ".mjs" },
679
+ plugins: [externalBareImportsPlugin],
768
680
  loader: {
769
- ".js": "js",
770
681
  ".ts": "ts"
771
682
  },
772
683
  format: "esm",
@@ -798,16 +709,7 @@ var build = async () => {
798
709
  log(`${Math.round(pagesTranspiled - start)}ms to Transpile Pages`);
799
710
  log(`${Math.round(pagesBuilt - pagesTranspiled)}ms to Build Pages`);
800
711
  log(`${Math.round(end - pagesBuilt)}ms to Build Client`);
801
- log(green(bold(`Compiled ${pageFiles.length} pages in ${Math.ceil(end - start)}ms!`)));
802
- for (const pageFile of pageFiles) {
803
- log(
804
- "- /" + path.relative(options.pagesDirectory, pageFile.parentPath),
805
- "(Page)"
806
- );
807
- }
808
- for (const apiFile of apiFiles) {
809
- "- /" + path.relative(options.pagesDirectory, apiFile.parentPath), "(API Route)";
810
- }
712
+ log(green(bold(`Compiled ${projectFiles.length} files in ${Math.ceil(end - start)}ms!`)));
811
713
  }
812
714
  process.send({ event: "message", data: "compile-finish" });
813
715
  if (shouldClientHardReload) {
@@ -40,7 +40,7 @@ function startServer({ root, port = 3e3, host = "localhost", environment = "prod
40
40
  if (url.pathname.startsWith("/api/")) {
41
41
  await handleApiRequest(root, url.pathname, req, res);
42
42
  } else {
43
- await handleStaticRequest(root, url.pathname, res);
43
+ await handleStaticRequest(root, url.pathname, req, res);
44
44
  }
45
45
  if (environment === "development" && quiet === false) {
46
46
  console.log(req.method, "::", req.url, "-", res.statusCode);
@@ -67,7 +67,7 @@ function startServer({ root, port = 3e3, host = "localhost", environment = "prod
67
67
  }
68
68
  return attemptListen(port);
69
69
  }
70
- async function handleStaticRequest(root, pathname, res) {
70
+ async function handleStaticRequest(root, pathname, req, res) {
71
71
  let filePath = normalize(join(root, decodeURIComponent(pathname)));
72
72
  root = normalize(root);
73
73
  if (!filePath.startsWith(root)) {
@@ -75,22 +75,62 @@ async function handleStaticRequest(root, pathname, res) {
75
75
  res.end("Forbidden");
76
76
  return;
77
77
  }
78
+ let stats;
78
79
  try {
79
- const stats = await fs.stat(filePath);
80
+ stats = await fs.stat(filePath);
80
81
  if (stats.isDirectory()) {
81
82
  filePath = join(filePath, "index.html");
82
83
  }
83
84
  } catch {
84
85
  }
86
+ let hasFile = false;
85
87
  try {
88
+ await fs.access(filePath);
89
+ hasFile = true;
90
+ } catch {
91
+ }
92
+ const pageDir = dirname(filePath);
93
+ const relDir = pageDir.slice(root.length).replace(/^[\/\\]+/, "");
94
+ const parts = relDir.split(/[\\/]/).filter(Boolean);
95
+ const middlewareDirs = [];
96
+ let current = root;
97
+ middlewareDirs.push(current);
98
+ for (const part of parts) {
99
+ current = join(current, part);
100
+ middlewareDirs.push(current);
101
+ }
102
+ const middlewares = [];
103
+ for (const dir of middlewareDirs) {
104
+ const mwPath = join(dir, "middleware.mjs");
105
+ let mwModule;
106
+ try {
107
+ await fs.access(mwPath);
108
+ const url = pathToFileURL(mwPath).href;
109
+ mwModule = await import(url);
110
+ } catch {
111
+ continue;
112
+ }
113
+ const mwKeys = Object.keys(mwModule).sort();
114
+ for (const key of mwKeys) {
115
+ const f = mwModule[key];
116
+ if (typeof f === "function" && !middlewares.some((existing) => existing === f)) {
117
+ middlewares.push(f);
118
+ }
119
+ }
120
+ }
121
+ const finalHandler = async (req2, res2) => {
122
+ if (!hasFile) {
123
+ await respondWithErrorPage(root, pathname, 404, res2);
124
+ return;
125
+ }
86
126
  const ext = extname(filePath).toLowerCase();
87
127
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
88
128
  const data = await fs.readFile(filePath);
89
- res.writeHead(200, { "Content-Type": contentType });
90
- res.end(data);
91
- } catch {
92
- await respondWithErrorPage(root, pathname, 404, res);
93
- }
129
+ res2.writeHead(200, { "Content-Type": contentType });
130
+ res2.end(data);
131
+ };
132
+ const composed = composeMiddlewares(middlewares, finalHandler);
133
+ await composed(req, res);
94
134
  }
95
135
  async function handleApiRequest(root, pathname, req, res) {
96
136
  const apiSubPath = pathname.slice("/api/".length);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elegance-js",
3
- "version": "1.6.5",
3
+ "version": "1.8.0",
4
4
  "description": "Web-Framework",
5
5
  "type": "module",
6
6
  "bin": {