edge-city

#react#js#ssr

git clone https://git.pyrossh.dev/edge-city

edge-city is a next level meta-framework for react that runs only on edge runtimes


54eb6f5 — pyrossh 2023-05-24T00:38:19+05:30
fix services

Generated files not shown: pnpm-lock.yaml

Files changed (35) hide show
  1. cli.js +66 -33
  2. example/jsconfig.json +1 -1
  3. example/main.js +4 -0
  4. example/package.json +1 -1
  5. example/{components → src/components}/Counter/Counter.jsx +0 -0
  6. example/{components → src/components}/Layout/Layout.css +0 -0
  7. example/{components → src/components}/Layout/Layout.jsx +0 -0
  8. example/{components → src/components}/Timer/Timer.jsx +0 -0
  9. example/{components → src/components}/Todo/Todo.css +0 -0
  10. example/{components → src/components}/Todo/Todo.jsx +0 -0
  11. example/{db → src/db}/index.js +1 -1
  12. example/{db → src/db}/migrations/0000_empty_shatterstar.sql +0 -0
  13. example/{db → src/db}/migrations/meta/0000_snapshot.json +0 -0
  14. example/{db → src/db}/migrations/meta/_journal.json +0 -0
  15. example/{pages → src/pages}/_404/page.css +0 -0
  16. example/{pages → src/pages}/_404/page.jsx +0 -0
  17. example/{pages → src/pages}/_500/page.css +0 -0
  18. example/{pages → src/pages}/_500/page.jsx +0 -0
  19. example/{pages → src/pages}/about/page.css +0 -0
  20. example/{pages → src/pages}/about/page.jsx +0 -0
  21. example/{pages → src/pages}/page.css +0 -0
  22. example/{pages → src/pages}/page.jsx +1 -1
  23. example/{pages → src/pages}/page.spec.js +0 -0
  24. example/{services → src/services}/auth.service.js +0 -0
  25. example/{services → src/services}/todos.service.js +0 -0
  26. example/{services → src/services}/todos.service.test.js +0 -0
  27. example/{static → src/static}/favicon.ico +0 -0
  28. example/{static → src/static}/logo192.png +0 -0
  29. example/{static → src/static}/logo512.png +0 -0
  30. example/{static → src/static}/manifest.json +0 -0
  31. example/{static → src/static}/robots.txt +0 -0
  32. example/{static → src/static}/todos/page.css +0 -0
  33. example/{static → src/static}/todos/page.jsx +0 -0
  34. package.json +3 -0
  35. renderApi.js +4 -2
cli.js CHANGED
@@ -14,9 +14,14 @@ import postcssNesting from "postcss-nesting";
14
14
  import bytes from 'bytes';
15
15
  import pc from 'picocolors';
16
16
  import ms from 'ms';
17
+ import watch from 'node-watch';
18
+ import dotenv from 'dotenv';
19
+
20
+ dotenv.config();
17
21
 
18
22
  let isProd = false;
23
+ const srcDir = path.join(process.cwd(), "src");
19
- const inputStaticDir = path.join(process.cwd(), "static");
24
+ const inputStaticDir = path.join(srcDir, "static");
20
25
  const buildDir = path.join(process.cwd(), "build");
21
26
  const staticDir = path.join(buildDir, "static");
22
27
 
@@ -30,7 +35,20 @@ const recordSize = (buildStart, dest) => {
30
35
 
31
36
  let generatedCss = ``;
32
37
  const cssCache = [];
38
+ const serverEnvs = Object.keys(process.env)
39
+ .filter((k) => k.startsWith("EC_") || k === "NODE_ENV")
40
+ .reduce((acc, k) => {
41
+ acc[`process.env.${k}`] = JSON.stringify(process.env[k]);
42
+ return acc
43
+ }, {});
44
+ const clientEnvs = Object.keys(process.env)
45
+ .filter((k) => k.startsWith("EC_PUBLIC") || k === "NODE_ENV")
46
+ .reduce((acc, k) => {
47
+ acc[`process.env.${k}`] = JSON.stringify(process.env[k]);
48
+ return acc
49
+ }, {});
50
+
33
- const bundleJs = async ({ entryPoints, outfile, ...options }, plg) => {
51
+ const bundleJs = async ({ entryPoints, isServer, outfile, ...options }, plg) => {
34
52
  const result = await esbuild.build({
35
53
  bundle: true,
36
54
  target: ['es2022'],
@@ -45,10 +63,7 @@ const bundleJs = async ({ entryPoints, outfile, ...options }, plg) => {
45
63
  jsxDev: !isProd,
46
64
  jsx: 'automatic',
47
65
  ...options,
48
- define: {
49
- 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || "development"),
66
+ define: isServer ? serverEnvs : clientEnvs,
50
- 'process.env.PG_CONN_URL': JSON.stringify(process.env.PG_CONN_URL || ""),
51
- },
52
67
  plugins: [
53
68
  resolve({
54
69
  "/routemap.json": `${staticDir}/routemap.json`,
@@ -72,17 +87,17 @@ const buildRouteMap = (routes) => {
72
87
  }
73
88
 
74
89
  const bundlePages = async () => {
75
- const routes = walkdir.sync(path.join(process.cwd(), "pages"))
90
+ const routes = walkdir.sync(path.join(srcDir, "pages"))
76
91
  .filter((p) => p.includes("page.jsx"))
77
92
  .map((r) => ({
78
93
  in: r,
79
- out: (r.replace(process.cwd(), "").replace("/pages", "").replace("/page.jsx", "") || "/index") + ".js",
94
+ out: (r.replace(srcDir, "").replace("/pages", "").replace("/page.jsx", "") || "/index") + ".js",
80
95
  }));
81
96
  buildRouteMap(routes);
82
97
  for (const r of routes) {
83
98
  const buildStart = Date.now();
84
99
  const outfile = `build/functions${r.out}`;
85
- await bundleJs({ entryPoints: [r.in], outfile }, {
100
+ await bundleJs({ isServer: true, entryPoints: [r.in], outfile }, {
86
101
  name: "page-plugin",
87
102
  setup(build) {
88
103
  build.onLoad({ filter: /\\*.page.jsx/, namespace: undefined }, (args) => {
@@ -117,6 +132,7 @@ const bundlePages = async () => {
117
132
  recordSize(buildStart, outfile);
118
133
  }
119
134
  await bundleJs({
135
+ isServer: false,
120
136
  entryPoints: routes.map((r) => ({
121
137
  in: r.in,
122
138
  out: "." + r.out.replace(".js", ""),
@@ -159,33 +175,42 @@ const bundlePages = async () => {
159
175
  }
160
176
 
161
177
  const bundleServices = async () => {
162
- const services = walkdir.sync(path.join(process.cwd(), "services"))
178
+ const services = walkdir.sync(path.join(srcDir, "services"))
163
179
  .filter((s) => s.includes(".service.js"));
164
180
  for (const s of services) {
165
- const dest = s.replace(process.cwd(), "").replace("/services", "").replace(".service.js", "");
181
+ const dest = s.replace(srcDir, "").replace("/services", "").replace(".service.js", "");
166
- const pkg = await import(s);
182
+ const src = fs.readFileSync(s, 'utf8');
183
+ const funcs = src.split("\n").filter((l) => l.includes("export const") && l.includes("=>"))
184
+ .map((l) => /export const (.*) = async/g.exec(l))
185
+ .filter((n) => n && n[1])
186
+ .map((n) => n[1]);
167
- for (const p of Object.keys(pkg)) {
187
+ for (const p of funcs) {
168
188
  const buildStart = Date.now();
189
+ const result = await bundleJs({
190
+ isServer: true,
191
+ write: false,
192
+ entryPoints: [s],
169
- const result = await bundleJs({ write: false }, s, `build/functions/_rpc${dest}.js`, {
193
+ // outfile: `build/functions/_rpc${dest}.js`,
194
+ },
195
+ {
170
- name: "service-plugin",
196
+ name: "service-plugin",
171
- setup(build) {
197
+ setup(build) {
172
- build.onLoad({ filter: /\\*.service.js/, namespace: undefined }, async (args) => {
198
+ build.onLoad({ filter: /\\*.service.js/, namespace: undefined }, async (args) => {
173
- const src = fs.readFileSync(args.path);
174
- const newSrc = `
199
+ const newSrc = `
175
- import renderApi from "edge-city/renderApi";
200
+ import renderApi from "edge-city/renderApi";
176
- ${src.toString()}
201
+ ${src.toString()}
177
202
 
178
- export function onRequest(context) {
203
+ export function onRequest(context) {
179
- return renderApi(${p}, context.request);
204
+ return renderApi(${p}, context.request);
180
- }
205
+ }
181
- `
206
+ `
182
- return {
207
+ return {
183
- contents: newSrc,
208
+ contents: newSrc,
184
- loader: "js",
209
+ loader: "js",
185
- };
210
+ };
186
- });
211
+ });
187
- }
212
+ }
188
- })
213
+ })
189
214
  fse.ensureDirSync(`build/functions/_rpc${dest}`)
190
215
  const outfile = `build/functions/_rpc${dest}/${p}.js`;
191
216
  fs.writeFileSync(outfile, result.outputFiles[0].contents);
@@ -214,8 +239,16 @@ const build = async (platform, setProd) => {
214
239
  isProd = true;
215
240
  }
216
241
  await bundlePages();
217
- // await bundleServices();
242
+ await bundleServices();
218
243
  await bundleCss();
244
+ if (!setProd) {
245
+ // watch src files, imports and dotenv
246
+ watch(srcDir, { recursive: true }, async (evt, name) => {
247
+ await bundlePages();
248
+ await bundleServices();
249
+ await bundleCss();
250
+ });
251
+ }
219
252
  if (platform === "cloudflare") {
220
253
  // create _routes.json for cloudflare which only includes the pages and services
221
254
  }
example/jsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "compilerOptions": {
3
3
  "paths": {
4
4
  "@/*": [
5
- "./*"
5
+ "./src/*"
6
6
  ]
7
7
  }
8
8
  }
example/main.js ADDED
@@ -0,0 +1,4 @@
1
+ import { getTodos } from "@/services/todos.service";
2
+
3
+ const todos = await getTodos();
4
+ console.log(todos);
example/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "test-e2e": "playwright test"
9
9
  },
10
10
  "dependencies": {
11
- "@neondatabase/serverless": "^0.2.9",
11
+ "@neondatabase/serverless": "0.4.5",
12
12
  "drizzle-orm": "0.26.0",
13
13
  "modern-normalize": "^2.0.0",
14
14
  "normalize.css": "^8.0.1",
example/{components → src/components}/Counter/Counter.jsx RENAMED
File without changes
example/{components → src/components}/Layout/Layout.css RENAMED
File without changes
example/{components → src/components}/Layout/Layout.jsx RENAMED
File without changes
example/{components → src/components}/Timer/Timer.jsx RENAMED
File without changes
example/{components → src/components}/Todo/Todo.css RENAMED
File without changes
example/{components → src/components}/Todo/Todo.jsx RENAMED
File without changes
example/{db → src/db}/index.js RENAMED
@@ -2,7 +2,7 @@ import { drizzle } from 'drizzle-orm/neon-serverless';
2
2
  import { Pool } from '@neondatabase/serverless';
3
3
  import { highlight } from 'sql-highlight';
4
4
 
5
- export const pool = new Pool({ connectionString: process.env.PG_CONN_URL });
5
+ export const pool = new Pool({ connectionString: process.env.EC_PG_CONN_URL });
6
6
  const db = drizzle(pool, {
7
7
  logger: {
8
8
  logQuery: (query, params) => {
example/{db → src/db}/migrations/0000_empty_shatterstar.sql RENAMED
File without changes
example/{db → src/db}/migrations/meta/0000_snapshot.json RENAMED
File without changes
example/{db → src/db}/migrations/meta/_journal.json RENAMED
File without changes
example/{pages → src/pages}/_404/page.css RENAMED
File without changes
example/{pages → src/pages}/_404/page.jsx RENAMED
File without changes
example/{pages → src/pages}/_500/page.css RENAMED
File without changes
example/{pages → src/pages}/_500/page.jsx RENAMED
File without changes
example/{pages → src/pages}/about/page.css RENAMED
File without changes
example/{pages → src/pages}/about/page.jsx RENAMED
File without changes
example/{pages → src/pages}/page.css RENAMED
File without changes
example/{pages → src/pages}/page.jsx RENAMED
@@ -16,7 +16,7 @@ const Page = () => {
16
16
  <title>Edge City</title>
17
17
  </Helmet>
18
18
  <div className="home-page">
19
- <h1>Home Page</h1>
19
+ <h1>Home Page 123 444</h1>
20
20
  <p>
21
21
  Path: {router.pathname}
22
22
  </p>
example/{pages → src/pages}/page.spec.js RENAMED
File without changes
example/{services → src/services}/auth.service.js RENAMED
File without changes
example/{services → src/services}/todos.service.js RENAMED
File without changes
example/{services → src/services}/todos.service.test.js RENAMED
File without changes
example/{static → src/static}/favicon.ico RENAMED
File without changes
example/{static → src/static}/logo192.png RENAMED
File without changes
example/{static → src/static}/logo512.png RENAMED
File without changes
example/{static → src/static}/manifest.json RENAMED
File without changes
example/{static → src/static}/robots.txt RENAMED
File without changes
example/{static → src/static}/todos/page.css RENAMED
File without changes
example/{static → src/static}/todos/page.jsx RENAMED
File without changes
package.json CHANGED
@@ -28,6 +28,9 @@
28
28
  "postcss-nesting": "^11.2.1",
29
29
  "walkdir": "0.4.1",
30
30
  "esbuild-plugin-resolve": "2.0.0",
31
+ "wrangler": "3.0.1",
32
+ "node-watch": "0.7.3",
33
+ "dotenv": "16.0.3",
31
34
  "jest": "29.5.0"
32
35
  },
33
36
  "peerDependencies": {
renderApi.js CHANGED
@@ -8,8 +8,10 @@ export const renderApi = async (fn, req) => {
8
8
  status: 200,
9
9
  });
10
10
  } catch (err) {
11
+ console.log("err: renderApi", err);
11
- const message = err.format ? err.format() : err;
12
+ const message = err.format ? err.format() : err.message;
13
+ const data = process.env.NODE_ENV === "development" ? { message, stack: err.stack } : { message };
12
- return new Response(JSON.stringify(message), {
14
+ return new Response(JSON.stringify(data), {
13
15
  headers: { 'Content-Type': 'application/json' },
14
16
  status: 400,
15
17
  });