edge-city
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
- cli.js +66 -33
- example/jsconfig.json +1 -1
- example/main.js +4 -0
- example/package.json +1 -1
- example/{components → src/components}/Counter/Counter.jsx +0 -0
- example/{components → src/components}/Layout/Layout.css +0 -0
- example/{components → src/components}/Layout/Layout.jsx +0 -0
- example/{components → src/components}/Timer/Timer.jsx +0 -0
- example/{components → src/components}/Todo/Todo.css +0 -0
- example/{components → src/components}/Todo/Todo.jsx +0 -0
- example/{db → src/db}/index.js +1 -1
- example/{db → src/db}/migrations/0000_empty_shatterstar.sql +0 -0
- example/{db → src/db}/migrations/meta/0000_snapshot.json +0 -0
- example/{db → src/db}/migrations/meta/_journal.json +0 -0
- example/{pages → src/pages}/_404/page.css +0 -0
- example/{pages → src/pages}/_404/page.jsx +0 -0
- example/{pages → src/pages}/_500/page.css +0 -0
- example/{pages → src/pages}/_500/page.jsx +0 -0
- example/{pages → src/pages}/about/page.css +0 -0
- example/{pages → src/pages}/about/page.jsx +0 -0
- example/{pages → src/pages}/page.css +0 -0
- example/{pages → src/pages}/page.jsx +1 -1
- example/{pages → src/pages}/page.spec.js +0 -0
- example/{services → src/services}/auth.service.js +0 -0
- example/{services → src/services}/todos.service.js +0 -0
- example/{services → src/services}/todos.service.test.js +0 -0
- example/{static → src/static}/favicon.ico +0 -0
- example/{static → src/static}/logo192.png +0 -0
- example/{static → src/static}/logo512.png +0 -0
- example/{static → src/static}/manifest.json +0 -0
- example/{static → src/static}/robots.txt +0 -0
- example/{static → src/static}/todos/page.css +0 -0
- example/{static → src/static}/todos/page.jsx +0 -0
- package.json +3 -0
- 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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
181
|
+
const dest = s.replace(srcDir, "").replace("/services", "").replace(".service.js", "");
|
|
166
|
-
const
|
|
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
|
|
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
|
-
|
|
193
|
+
// outfile: `build/functions/_rpc${dest}.js`,
|
|
194
|
+
},
|
|
195
|
+
{
|
|
170
|
-
|
|
196
|
+
name: "service-plugin",
|
|
171
|
-
|
|
197
|
+
setup(build) {
|
|
172
|
-
|
|
198
|
+
build.onLoad({ filter: /\\*.service.js/, namespace: undefined }, async (args) => {
|
|
173
|
-
const src = fs.readFileSync(args.path);
|
|
174
|
-
|
|
199
|
+
const newSrc = `
|
|
175
|
-
|
|
200
|
+
import renderApi from "edge-city/renderApi";
|
|
176
|
-
|
|
201
|
+
${src.toString()}
|
|
177
202
|
|
|
178
|
-
|
|
203
|
+
export function onRequest(context) {
|
|
179
|
-
|
|
204
|
+
return renderApi(${p}, context.request);
|
|
180
|
-
|
|
205
|
+
}
|
|
181
|
-
|
|
206
|
+
`
|
|
182
|
-
|
|
207
|
+
return {
|
|
183
|
-
|
|
208
|
+
contents: newSrc,
|
|
184
|
-
|
|
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
|
-
|
|
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": "
|
|
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.
|
|
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(
|
|
14
|
+
return new Response(JSON.stringify(data), {
|
|
13
15
|
headers: { 'Content-Type': 'application/json' },
|
|
14
16
|
status: 400,
|
|
15
17
|
});
|