~repos /edge-city
git clone https://pyrossh.dev/repos/edge-city.git
edge-city is a next level meta-framework for react that runs only on edge runtimes
072de503
—
pyrossh 2 years ago
use fse
- cli.js +25 -25
- example/package.json +1 -1
- example/pages/_404/page.css +0 -1
- example/pages/_404/page.jsx +11 -8
- example/pages/_500/page.jsx +11 -8
- index.js +10 -2
- package.json +1 -0
- pnpm-lock.yaml +67 -0
- pnpm-workspace.yaml +1 -0
cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import { hideBin } from 'yargs/helpers'
|
|
|
4
4
|
import esbuild from 'esbuild';
|
|
5
5
|
import resolve from 'esbuild-plugin-resolve';
|
|
6
6
|
import fs from "fs";
|
|
7
|
+
import fse from "fs-extra";
|
|
7
8
|
import path from 'path';
|
|
8
9
|
import walkdir from 'walkdir';
|
|
9
10
|
import postcss from "postcss"
|
|
@@ -14,7 +15,8 @@ import bytes from 'bytes';
|
|
|
14
15
|
import pc from 'picocolors';
|
|
15
16
|
import ms from 'ms';
|
|
16
17
|
|
|
18
|
+
let isProd = false;
|
|
17
|
-
const
|
|
19
|
+
const inputStaticDir = path.join(process.cwd(), "static");
|
|
18
20
|
const buildDir = path.join(process.cwd(), "build");
|
|
19
21
|
const staticDir = path.join(buildDir, "static");
|
|
20
22
|
|
|
@@ -50,6 +52,8 @@ const bundleJs = async ({ entryPoints, outfile, ...options }, plg) => {
|
|
|
50
52
|
plugins: [
|
|
51
53
|
resolve({
|
|
52
54
|
"/routemap.json": `${staticDir}/routemap.json`,
|
|
55
|
+
"@/_404/page": `${process.cwd()}/pages/_404/page.jsx`,
|
|
56
|
+
"@/_500/page": `${process.cwd()}/pages/_500/page.jsx`,
|
|
53
57
|
}),
|
|
54
58
|
plg,
|
|
55
59
|
]
|
|
@@ -87,6 +91,9 @@ const bundlePages = async () => {
|
|
|
87
91
|
const data = fs.readFileSync(args.path);
|
|
88
92
|
const newSrc = `
|
|
89
93
|
import { renderPage } from "edge-city";
|
|
94
|
+
import NotFoundPage from "@/_404/page";
|
|
95
|
+
import ErrorPage from "@/_500/page";
|
|
96
|
+
|
|
90
97
|
${data.toString()}
|
|
91
98
|
|
|
92
99
|
export function onRequest(context) {
|
|
@@ -159,7 +166,7 @@ const bundleServices = async () => {
|
|
|
159
166
|
const services = walkdir.sync(path.join(process.cwd(), "services"))
|
|
160
167
|
.filter((s) => s.includes(".service.js"));
|
|
161
168
|
for (const s of services) {
|
|
162
|
-
const dest = s.replace(process.cwd(), "").replace("/services", "").replace(".service.js", "")
|
|
169
|
+
const dest = s.replace(process.cwd(), "").replace("/services", "").replace(".service.js", "");
|
|
163
170
|
const pkg = await import(s);
|
|
164
171
|
for (const p of Object.keys(pkg)) {
|
|
165
172
|
const buildStart = Date.now();
|
|
@@ -200,7 +207,7 @@ const bundleServices = async () => {
|
|
|
200
207
|
});
|
|
201
208
|
}
|
|
202
209
|
})
|
|
203
|
-
|
|
210
|
+
fse.ensureDirSync(`build/functions/_rpc${dest}`)
|
|
204
211
|
const outfile = `build/functions/_rpc${dest}/${p}.js`;
|
|
205
212
|
fs.writeFileSync(outfile, result.outputFiles[0].contents);
|
|
206
213
|
recordSize(buildStart, outfile);
|
|
@@ -214,32 +221,25 @@ const bundleCss = async () => {
|
|
|
214
221
|
postcssCustomMedia(),
|
|
215
222
|
postcssNesting,
|
|
216
223
|
]).process(generatedCss, { from: "app.css", to: "app.css" });
|
|
217
|
-
|
|
224
|
+
fse.ensureDirSync(`build/static/css`)
|
|
218
225
|
fs.writeFileSync(`${process.cwd()}/build/static/css/app.css`, result.toString());
|
|
219
226
|
}
|
|
220
227
|
|
|
228
|
+
const build = async (platform, setProd) => {
|
|
229
|
+
fse.removeSync(buildDir);
|
|
221
|
-
|
|
230
|
+
fse.ensureDirSync(buildDir);
|
|
222
|
-
|
|
231
|
+
fse.ensureDirSync(staticDir);
|
|
223
|
-
|
|
232
|
+
fse.copySync(inputStaticDir, staticDir);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const cleanDir = (d) => {
|
|
228
|
-
if (
|
|
233
|
+
if (setProd) {
|
|
229
|
-
|
|
234
|
+
process.env.NODE_ENV = "production";
|
|
235
|
+
isProd = true;
|
|
230
236
|
}
|
|
231
|
-
}
|
|
232
|
-
const createDirs = () => {
|
|
233
|
-
cleanDir(buildDir);
|
|
234
|
-
ensureDir(buildDir);
|
|
235
|
-
ensureDir(staticDir);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const build = async () => {
|
|
239
|
-
createDirs();
|
|
240
237
|
await bundlePages();
|
|
241
|
-
|
|
238
|
+
await bundleServices();
|
|
242
239
|
await bundleCss();
|
|
240
|
+
if (platform === "cloudflare") {
|
|
241
|
+
// create _routes.json for cloudflare which only includes the pages and services
|
|
242
|
+
}
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
yargs(hideBin(process.argv))
|
|
@@ -253,7 +253,7 @@ yargs(hideBin(process.argv))
|
|
|
253
253
|
})
|
|
254
254
|
.demandOption("p")
|
|
255
255
|
}, ({ platform }) => {
|
|
256
|
-
build(platform);
|
|
256
|
+
build(platform, true);
|
|
257
257
|
})
|
|
258
258
|
.command('dev', 'run the dev server', (y) => {
|
|
259
259
|
y.option('platform', {
|
|
@@ -263,7 +263,7 @@ yargs(hideBin(process.argv))
|
|
|
263
263
|
choices: ['cloudflare', 'vercel']
|
|
264
264
|
})
|
|
265
265
|
}, ({ platform }) => {
|
|
266
|
-
build(platform);
|
|
266
|
+
build(platform, false);
|
|
267
267
|
})
|
|
268
268
|
.demandCommand(1)
|
|
269
269
|
.parse()
|
example/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"type": "module",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "edge-city dev -p cloudflare",
|
|
6
|
-
"build
|
|
6
|
+
"build": " edge-city build -p cloudflare",
|
|
7
7
|
"test": "jest",
|
|
8
8
|
"test-e2e": "playwright test"
|
|
9
9
|
},
|
example/pages/_404/page.css
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
color: #000;
|
|
7
7
|
background: #fff;
|
|
8
8
|
font-family: -apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif;
|
|
9
|
-
height: 100vh;
|
|
10
9
|
text-align: center;
|
|
11
10
|
|
|
12
11
|
& h1 {
|
example/pages/_404/page.jsx
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Helmet } from 'react-helmet-async';
|
|
3
|
+
import Layout from '@/components/Layout/Layout';
|
|
3
4
|
import "./page.css";
|
|
4
5
|
|
|
5
6
|
const Page = () => {
|
|
6
7
|
return (
|
|
8
|
+
<Layout>
|
|
7
|
-
|
|
9
|
+
<div className="notfound-page">
|
|
8
|
-
|
|
10
|
+
<Helmet>
|
|
9
|
-
|
|
11
|
+
<title>Page not found</title>
|
|
10
|
-
|
|
12
|
+
</Helmet>
|
|
11
|
-
|
|
13
|
+
<h1>404 - Page not found</h1>
|
|
12
|
-
|
|
14
|
+
<div className="content">
|
|
13
|
-
|
|
15
|
+
<h2>This page could not be found</h2>
|
|
16
|
+
</div>
|
|
14
17
|
</div>
|
|
15
|
-
</
|
|
18
|
+
</Layout>
|
|
16
19
|
)
|
|
17
20
|
}
|
|
18
21
|
|
example/pages/_500/page.jsx
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Helmet } from 'react-helmet-async';
|
|
3
|
+
import Layout from '@/components/Layout/Layout';
|
|
3
4
|
import "./page.css";
|
|
4
5
|
|
|
5
6
|
const Page = () => {
|
|
6
7
|
return (
|
|
8
|
+
<Layout>
|
|
7
|
-
|
|
9
|
+
<div className="err-page">
|
|
8
|
-
|
|
10
|
+
<Helmet>
|
|
9
|
-
|
|
11
|
+
<title>Oop's Something went wrong</title>
|
|
10
|
-
|
|
12
|
+
</Helmet>
|
|
11
|
-
|
|
13
|
+
<h1>Oop's Something went wrong</h1>
|
|
12
|
-
|
|
14
|
+
<div className="content">
|
|
13
|
-
|
|
15
|
+
<h2>Internal Server Error</h2>
|
|
16
|
+
</div>
|
|
14
17
|
</div>
|
|
15
|
-
</
|
|
18
|
+
</Layout>
|
|
16
19
|
)
|
|
17
20
|
}
|
|
18
21
|
|
index.js
CHANGED
|
@@ -125,7 +125,7 @@ export const RouterContext = createContext(undefined);
|
|
|
125
125
|
const getMatch = (router, pathname) => {
|
|
126
126
|
const matchedPage = router.lookup(pathname);
|
|
127
127
|
if (!matchedPage) {
|
|
128
|
-
return router.lookup("/
|
|
128
|
+
return router.lookup("/_404")
|
|
129
129
|
}
|
|
130
130
|
return matchedPage;
|
|
131
131
|
}
|
|
@@ -250,6 +250,14 @@ export const renderPage = async (PageComponent, req) => {
|
|
|
250
250
|
const history = createMemoryHistory({
|
|
251
251
|
initialEntries: [url.pathname + url.search],
|
|
252
252
|
});
|
|
253
|
+
const router = createRouter({
|
|
254
|
+
strictTrailingSlash: true,
|
|
255
|
+
routes: Object.keys(routemap).reduce((acc, r) => {
|
|
256
|
+
acc[r] = r;
|
|
257
|
+
return acc;
|
|
258
|
+
}, {}),
|
|
259
|
+
});
|
|
260
|
+
const AppPage = router.lookup(url.pathname) ? PageComponent : NotFoundPage;
|
|
253
261
|
const jsScript = url.pathname === "/" ? "index" : url.pathname;
|
|
254
262
|
const helmetContext = {}
|
|
255
263
|
const stream = await renderToReadableStream(
|
|
@@ -271,7 +279,7 @@ export const renderPage = async (PageComponent, req) => {
|
|
|
271
279
|
router: null,
|
|
272
280
|
rpcCache: {},
|
|
273
281
|
helmetContext,
|
|
274
|
-
PageComponent,
|
|
282
|
+
PageComponent: AppPage,
|
|
275
283
|
}), _jsx(_Fragment, {
|
|
276
284
|
children: _jsx("script", {
|
|
277
285
|
type: "module",
|
package.json
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"esbuild": "0.17.19",
|
|
21
21
|
"yargs": "17.7.2",
|
|
22
22
|
"mime-types": "2.1.35",
|
|
23
|
+
"fs-extra": "11.1.1",
|
|
23
24
|
"ms": "2.1.3",
|
|
24
25
|
"picocolors": "1.0.0",
|
|
25
26
|
"postcss": "^8.4.21",
|
pnpm-lock.yaml
CHANGED
|
@@ -41,6 +41,9 @@ importers:
|
|
|
41
41
|
esbuild-plugin-resolve:
|
|
42
42
|
specifier: 2.0.0
|
|
43
43
|
version: 2.0.0
|
|
44
|
+
fs-extra:
|
|
45
|
+
specifier: 11.1.1
|
|
46
|
+
version: 11.1.1
|
|
44
47
|
jest:
|
|
45
48
|
specifier: 29.5.0
|
|
46
49
|
version: 29.5.0
|
|
@@ -69,6 +72,12 @@ importers:
|
|
|
69
72
|
specifier: 17.7.2
|
|
70
73
|
version: 17.7.2
|
|
71
74
|
|
|
75
|
+
docs:
|
|
76
|
+
dependencies:
|
|
77
|
+
'@markdoc/markdoc':
|
|
78
|
+
specifier: 0.2.2
|
|
79
|
+
version: 0.2.2(react@18.2.0)
|
|
80
|
+
|
|
72
81
|
example:
|
|
73
82
|
dependencies:
|
|
74
83
|
'@neondatabase/serverless':
|
|
@@ -2107,6 +2116,23 @@ packages:
|
|
|
2107
2116
|
'@jridgewell/sourcemap-codec': 1.4.14
|
|
2108
2117
|
dev: true
|
|
2109
2118
|
|
|
2119
|
+
/@markdoc/markdoc@0.2.2(react@18.2.0):
|
|
2120
|
+
resolution: {integrity: sha512-0TiD9jmA5h5znN4lxo7HECAu3WieU5g5vUsfByeucrdR/x88hEilpt16EydFyJwJddQ/3w5HQgW7Ovy62r4cyw==}
|
|
2121
|
+
engines: {node: '>=14.7.0'}
|
|
2122
|
+
peerDependencies:
|
|
2123
|
+
'@types/react': '*'
|
|
2124
|
+
react: '*'
|
|
2125
|
+
peerDependenciesMeta:
|
|
2126
|
+
'@types/react':
|
|
2127
|
+
optional: true
|
|
2128
|
+
react:
|
|
2129
|
+
optional: true
|
|
2130
|
+
dependencies:
|
|
2131
|
+
react: 18.2.0
|
|
2132
|
+
optionalDependencies:
|
|
2133
|
+
'@types/markdown-it': 12.2.3
|
|
2134
|
+
dev: false
|
|
2135
|
+
|
|
2110
2136
|
/@neondatabase/serverless@0.2.9:
|
|
2111
2137
|
resolution: {integrity: sha512-fp7gXG8rt+uP+UT2ReGoCrf8GYb25Tv6xklDtZEoe8XKkBtVyZO+sii5oLNRwhvTLkqt7FX49MBCh3Est9b2KQ==}
|
|
2112
2138
|
dev: false
|
|
@@ -3434,6 +3460,25 @@ packages:
|
|
|
3434
3460
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
|
3435
3461
|
dev: true
|
|
3436
3462
|
|
|
3463
|
+
/@types/linkify-it@3.0.2:
|
|
3464
|
+
resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==}
|
|
3465
|
+
dev: false
|
|
3466
|
+
optional: true
|
|
3467
|
+
|
|
3468
|
+
/@types/markdown-it@12.2.3:
|
|
3469
|
+
resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
|
|
3470
|
+
requiresBuild: true
|
|
3471
|
+
dependencies:
|
|
3472
|
+
'@types/linkify-it': 3.0.2
|
|
3473
|
+
'@types/mdurl': 1.0.2
|
|
3474
|
+
dev: false
|
|
3475
|
+
optional: true
|
|
3476
|
+
|
|
3477
|
+
/@types/mdurl@1.0.2:
|
|
3478
|
+
resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==}
|
|
3479
|
+
dev: false
|
|
3480
|
+
optional: true
|
|
3481
|
+
|
|
3437
3482
|
/@types/node@20.2.1:
|
|
3438
3483
|
resolution: {integrity: sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==}
|
|
3439
3484
|
dev: true
|
|
@@ -4893,6 +4938,15 @@ packages:
|
|
|
4893
4938
|
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
|
|
4894
4939
|
dev: true
|
|
4895
4940
|
|
|
4941
|
+
/fs-extra@11.1.1:
|
|
4942
|
+
resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
|
|
4943
|
+
engines: {node: '>=14.14'}
|
|
4944
|
+
dependencies:
|
|
4945
|
+
graceful-fs: 4.2.11
|
|
4946
|
+
jsonfile: 6.1.0
|
|
4947
|
+
universalify: 2.0.0
|
|
4948
|
+
dev: true
|
|
4949
|
+
|
|
4896
4950
|
/fs.realpath@1.0.0:
|
|
4897
4951
|
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
|
4898
4952
|
dev: true
|
|
@@ -5842,6 +5896,14 @@ packages:
|
|
|
5842
5896
|
hasBin: true
|
|
5843
5897
|
dev: true
|
|
5844
5898
|
|
|
5899
|
+
/jsonfile@6.1.0:
|
|
5900
|
+
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
|
5901
|
+
dependencies:
|
|
5902
|
+
universalify: 2.0.0
|
|
5903
|
+
optionalDependencies:
|
|
5904
|
+
graceful-fs: 4.2.11
|
|
5905
|
+
dev: true
|
|
5906
|
+
|
|
5845
5907
|
/jsx-ast-utils@3.3.3:
|
|
5846
5908
|
resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==}
|
|
5847
5909
|
engines: {node: '>=4.0'}
|
|
@@ -6939,6 +7001,11 @@ packages:
|
|
|
6939
7001
|
engines: {node: '>=4'}
|
|
6940
7002
|
dev: true
|
|
6941
7003
|
|
|
7004
|
+
/universalify@2.0.0:
|
|
7005
|
+
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
|
|
7006
|
+
engines: {node: '>= 10.0.0'}
|
|
7007
|
+
dev: true
|
|
7008
|
+
|
|
6942
7009
|
/update-browserslist-db@1.0.11(browserslist@4.21.5):
|
|
6943
7010
|
resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
|
|
6944
7011
|
hasBin: true
|
pnpm-workspace.yaml
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
packages:
|
|
2
2
|
- "./"
|
|
3
3
|
- "example"
|
|
4
|
+
- "docs"
|