satto 1.0.8 → 1.0.9

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/lib/index.js +78 -44
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "satto",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "A minimal server-rendered web framework for Node.js",
5
5
  "main": "src/lib/index.js",
6
6
  "bin": {
package/src/lib/index.js CHANGED
@@ -18,41 +18,67 @@ function applyParams(template, params) {
18
18
  }
19
19
 
20
20
  async function renderPage(html, params) {
21
- const match = html.match(/<ssr\s+url="([^"]+)"\s+.*response="([^"]+)"[^>]*>/);
21
+ try {
22
+ const match = html.match(/<ssr\s+url="([^"]+)"\s+.*response="([^"]+)"[^>]*>/);
22
23
 
23
- if(match) {
24
- const url = applyParams(match?.[1], params);
25
- const resVar = match?.[2];
26
- let data = {};
24
+ if (match) {
25
+ const url = applyParams(match?.[1], params);
26
+ const resVar = match?.[2];
27
+ let data = {};
27
28
 
28
- if (url) {
29
- const res = await fetch(url);
30
- data = await res.json();
31
- }
29
+ if (url) {
30
+ const res = await fetch(url);
31
+ data = await res.json();
32
+ }
32
33
 
33
- html = html.replace(/<ssr[^>]*>([\s\S]*?)<\/ssr>/g, (_, content) => {
34
- return content.replace(
35
- /<ssr[^>]*>|<\/ssr>|\{\{(.*?)\}\}|<for\s+condition="let\s+(.+?)\s+in\s+(.+?)"\s*>|<\/for>|<if\s+condition="(.*?)"\s*>|<\/if>|\[(.+?)\]="(.+?)"/g,
36
- (match, expr, item, arr, cond, attr, val) => {
37
- if (match.startsWith("<ssr")) return "";
38
- if (match === "</ssr>") return "";
39
- if (expr) return `<%= ${expr.trim()} %>`;
40
- if (item && arr) return `<% ${arr}.forEach(${item} => { %>`;
41
- if (match === "</for>") return "<% }) %>";
42
- if (cond) return `<% if (${cond}) { %>`;
43
- if (match === "</if>") return "<% } %>";
44
- if (attr && val) return `${attr}="<%= ${val} %>"`;
45
- return match;
46
- }
47
- );
48
- });
34
+ html = html.replace(/<ssr[^>]*>([\s\S]*?)<\/ssr>/g, (_, content) => {
35
+ return content.replace(
36
+ /<ssr[^>]*>|<\/ssr>|\{\{(.*?)\}\}|<for\s+condition="let\s+(.+?)\s+in\s+(.+?)"\s*>|<\/for>|<if\s+condition="(.*?)"\s*>|<\/if>|\[(.+?)\]="(.+?)"/g,
37
+ (match, expr, item, arr, cond, attr, val) => {
38
+ if (match.startsWith("<ssr")) return "";
39
+ if (match === "</ssr>") return "";
40
+ if (expr) return `<%= ${expr.trim()} %>`;
41
+ if (item && arr) return `<% ${arr}.forEach(${item} => { %>`;
42
+ if (match === "</for>") return "<% }) %>";
43
+ if (cond) return `<% if (${cond}) { %>`;
44
+ if (match === "</if>") return "<% } %>";
45
+ if (attr && val) return `${attr}="<%= ${val} %>"`;
46
+ return match;
47
+ }
48
+ );
49
+ });
49
50
 
50
- return ejs.render(html, {params, [resVar]: data});
51
- } else {
52
- return html;
51
+ return ejs.render(html, { params, [resVar]: data });
52
+ } else {
53
+ return html;
54
+ }
55
+ } catch (err) {
56
+ throw err;
53
57
  }
54
58
  }
55
59
 
60
+ function renderErrorPage(code, message) {
61
+ return `
62
+ <style>
63
+ body {
64
+ margin: 0;
65
+ height: 100vh;
66
+ display: flex;
67
+ justify-content: center;
68
+ align-items: center;
69
+ background: black;
70
+ color: white;
71
+ font-family: system-ui, sans-serif;
72
+ }
73
+ h1 {
74
+ font-size: 2rem;
75
+ font-weight: 400;
76
+ }
77
+ </style>
78
+ <h1>${code} — ${message}</h1>
79
+ `;
80
+ }
81
+
56
82
  function createServer(__dirname, routes = [], port = 3000) {
57
83
  const versionApp = Date.now();
58
84
  const app = express();
@@ -65,15 +91,15 @@ function createServer(__dirname, routes = [], port = 3000) {
65
91
  app.use(express.static(path.join(__dirname, "static")));
66
92
 
67
93
  routes.forEach((route) => {
68
- app.get(route.path, async (req, res) => {
69
- try {
70
- const page = route.page;
71
- const htmlPath = path.join(__dirname, "app", page, page + ".html");
72
- app.use(express.static(path.join(__dirname, "app", page)));
94
+ app.get(route.path, (req, res, next) => {
95
+ const page = route.page;
96
+ const htmlPath = path.join(__dirname, "app", page, page + ".html");
97
+ app.use(express.static(path.join(__dirname, "app", page)));
73
98
 
74
- fs.readFile(htmlPath, "utf8", async (err, html) => {
99
+ fs.readFile(htmlPath, "utf8", async (err, html) => {
100
+ try {
75
101
  if (err) {
76
- return res.status(404).send();
102
+ return next();
77
103
  }
78
104
 
79
105
  const params = { ...req.params };
@@ -82,30 +108,38 @@ function createServer(__dirname, routes = [], port = 3000) {
82
108
  const CssPath = path.join(__dirname, "app", page, page + ".css");
83
109
  const JsPath = path.join(__dirname, "app", page, page + ".js");
84
110
 
85
- if(hasContent(JsPath)) {
111
+ if (hasContent(JsPath)) {
86
112
  html += `\n<script src="./${page}.js?v=${versionApp}"></script>`;
87
113
  }
88
114
 
89
115
  html = index.replace("<routes></routes>", html);
90
116
  html = html.replace(`<link rel="stylesheet" href="/styles.css">`, `<link rel="stylesheet" href="/styles.css?v=${versionApp}">`);
91
117
 
92
- if(hasContent(CssPath)) {
118
+ if (hasContent(CssPath)) {
93
119
  html = html.replace(
94
- "</head>",
120
+ "</head>",
95
121
  `<link rel="stylesheet" href="./${page}.css?v=${versionApp}">
96
- </head>`
122
+ </head>`
97
123
  );
98
124
  }
99
125
 
100
126
  res.send(await renderPage(html, params));
101
- });
102
- } catch (err) {
103
- console.error(err);
104
- res.status(500).send();
105
- }
127
+ } catch (err) {
128
+ next(err);
129
+ }
130
+ });
106
131
  });
107
132
  });
108
133
 
134
+ app.use((req, res) => {
135
+ res.status(404).send(renderErrorPage(404, "Page Not Found"));
136
+ });
137
+
138
+ app.use((err, req, res, next) => {
139
+ console.error(err);
140
+ res.status(500).send(renderErrorPage(500, "Internal Server Error"));
141
+ });
142
+
109
143
  app.listen(port, () => {
110
144
  const banner = [
111
145
  " ____ _ _ ",