~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
ede7ce4b
—
pyrossh 2 years ago
improve code
- cli.js +2 -6
- docs/package.json +7 -0
- example/components/Layout/Layout.jsx +0 -1
- example/package.json +0 -1
- index.js +53 -66
- package.json +0 -1
- pnpm-lock.yaml +0 -10
cli.js
CHANGED
|
@@ -52,8 +52,6 @@ const bundleJs = async ({ entryPoints, outfile, ...options }, plg) => {
|
|
|
52
52
|
plugins: [
|
|
53
53
|
resolve({
|
|
54
54
|
"/routemap.json": `${staticDir}/routemap.json`,
|
|
55
|
-
"@/_404/page": `${process.cwd()}/pages/_404/page.jsx`,
|
|
56
|
-
"@/_500/page": `${process.cwd()}/pages/_500/page.jsx`,
|
|
57
55
|
}),
|
|
58
56
|
plg,
|
|
59
57
|
]
|
|
@@ -91,8 +89,6 @@ const bundlePages = async () => {
|
|
|
91
89
|
const data = fs.readFileSync(args.path);
|
|
92
90
|
const newSrc = `
|
|
93
91
|
import { renderPage } from "edge-city";
|
|
94
|
-
import NotFoundPage from "@/_404/page";
|
|
95
|
-
import ErrorPage from "@/_500/page";
|
|
96
92
|
|
|
97
93
|
${data.toString()}
|
|
98
94
|
|
|
@@ -140,7 +136,7 @@ const bundlePages = async () => {
|
|
|
140
136
|
|
|
141
137
|
const searchParams = new URL(import.meta.url).searchParams;
|
|
142
138
|
if (searchParams.get("hydrate") === "true") {
|
|
143
|
-
hydrateApp(
|
|
139
|
+
hydrateApp()
|
|
144
140
|
}
|
|
145
141
|
`
|
|
146
142
|
return {
|
|
@@ -235,7 +231,7 @@ const build = async (platform, setProd) => {
|
|
|
235
231
|
isProd = true;
|
|
236
232
|
}
|
|
237
233
|
await bundlePages();
|
|
238
|
-
await bundleServices();
|
|
234
|
+
// await bundleServices();
|
|
239
235
|
await bundleCss();
|
|
240
236
|
if (platform === "cloudflare") {
|
|
241
237
|
// create _routes.json for cloudflare which only includes the pages and services
|
docs/package.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "edge-city-docs",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"@markdoc/markdoc": "0.2.2"
|
|
6
|
+
}
|
|
7
|
+
}
|
example/components/Layout/Layout.jsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Link } from "edge-city";
|
|
3
3
|
import "modern-normalize";
|
|
4
|
-
import "nprogress";
|
|
5
4
|
import "./Layout.css";
|
|
6
5
|
|
|
7
6
|
const Layout = ({ children }) => {
|
example/package.json
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"drizzle-orm": "0.26.0",
|
|
13
13
|
"modern-normalize": "^2.0.0",
|
|
14
14
|
"normalize.css": "^8.0.1",
|
|
15
|
-
"nprogress": "0.2.0",
|
|
16
15
|
"edge-city": "workspace:*",
|
|
17
16
|
"react": "18.2.0",
|
|
18
17
|
"react-aria-components": "1.0.0-alpha.3",
|
index.js
CHANGED
|
@@ -8,7 +8,6 @@ import { HelmetProvider } from 'react-helmet-async';
|
|
|
8
8
|
import { ErrorBoundary } from "react-error-boundary";
|
|
9
9
|
import { createMemoryHistory, createBrowserHistory } from "history";
|
|
10
10
|
import { createRouter } from "radix3";
|
|
11
|
-
import nProgress from "nprogress";
|
|
12
11
|
import routemap from '/routemap.json' assert {type: 'json'};
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -122,59 +121,17 @@ export const useMutation = (fn) => {
|
|
|
122
121
|
|
|
123
122
|
export const RouterContext = createContext(undefined);
|
|
124
123
|
|
|
125
|
-
const getMatch = (router, pathname) => {
|
|
126
|
-
const matchedPage = router.lookup(pathname);
|
|
127
|
-
if (!matchedPage) {
|
|
128
|
-
return router.lookup("/_404")
|
|
129
|
-
}
|
|
130
|
-
return matchedPage;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const getCssUrl = (pathname) => `/pages${pathname === "/" ? "" : pathname}/page.css`;
|
|
134
|
-
|
|
135
|
-
export const App = ({
|
|
124
|
+
export const App = ({ history, router, rpcCache, helmetContext }) => {
|
|
136
|
-
const [
|
|
125
|
+
const [_, startTransition] = useTransition();
|
|
137
|
-
const [match, setMatch] = useState(() => {
|
|
138
|
-
if (PageComponent) {
|
|
139
|
-
return PageComponent;
|
|
140
|
-
}
|
|
141
|
-
|
|
126
|
+
const [pathname, setPathname] = useState(history.location.pathname);
|
|
142
|
-
|
|
127
|
+
const match = router.lookup(pathname) || router.lookup("/_404");
|
|
143
128
|
useEffect(() => {
|
|
144
129
|
return history.listen(({ location }) => {
|
|
145
|
-
// const href = getCssUrl(location.pathname);
|
|
146
|
-
//
|
|
130
|
+
startTransition(() => { // this causes 2 renders to happen but stops jitter or layout reflow due to React.lazy
|
|
147
|
-
// .map((link) => link.href.replace(window.origin, "")).includes(href);
|
|
148
|
-
// if (!isLoaded) {
|
|
149
|
-
// const link = document.createElement('link');
|
|
150
|
-
// link.setAttribute("rel", "stylesheet");
|
|
151
|
-
// link.setAttribute("type", "text/css");
|
|
152
|
-
// link.onload = () => {
|
|
153
|
-
// nProgress.start();
|
|
154
|
-
// startTransition(() => {
|
|
155
|
-
// setMatch(getMatch(router, location.pathname));
|
|
156
|
-
// })
|
|
157
|
-
// };
|
|
158
|
-
// link.setAttribute("href", href);
|
|
159
|
-
// document.getElementsByTagName("head")[0].appendChild(link);
|
|
160
|
-
// } else {
|
|
161
|
-
// const link = document.createElement('link');
|
|
162
|
-
// link.setAttribute("rel", "stylesheet");
|
|
163
|
-
// link.setAttribute("type", "text/css");
|
|
164
|
-
// link.setAttribute("href", href);
|
|
165
|
-
// document.getElementsByTagName("head")[0].appendChild(link);
|
|
166
|
-
nProgress.start();
|
|
167
|
-
startTransition(() => {
|
|
168
|
-
|
|
131
|
+
setPathname(location.pathname);
|
|
169
132
|
})
|
|
170
|
-
// }
|
|
171
133
|
});
|
|
172
134
|
}, []);
|
|
173
|
-
useEffect(() => {
|
|
174
|
-
if (!isPending) {
|
|
175
|
-
nProgress.done();
|
|
176
|
-
}
|
|
177
|
-
}, [isPending]);
|
|
178
135
|
return _jsx(HelmetProvider, {
|
|
179
136
|
context: helmetContext,
|
|
180
137
|
children: _jsx(RpcContext.Provider, {
|
|
@@ -243,7 +200,7 @@ export const NavLink = ({ children, className, activeClassName, ...props }) => {
|
|
|
243
200
|
/**
|
|
244
201
|
* SSR related functions
|
|
245
202
|
*/
|
|
246
|
-
export const renderPage = async (
|
|
203
|
+
export const renderPage = async (Page, req) => {
|
|
247
204
|
const { renderToReadableStream } = await import("react-dom/server");
|
|
248
205
|
const { default: isbot } = await import("isbot");
|
|
249
206
|
const url = new URL(req.url);
|
|
@@ -253,13 +210,53 @@ export const renderPage = async (PageComponent, req) => {
|
|
|
253
210
|
const router = createRouter({
|
|
254
211
|
strictTrailingSlash: true,
|
|
255
212
|
routes: Object.keys(routemap).reduce((acc, r) => {
|
|
256
|
-
acc[r] =
|
|
213
|
+
acc[r] = React.lazy(() => Promise.resolve({ default: Page }));
|
|
257
214
|
return acc;
|
|
258
215
|
}, {}),
|
|
259
216
|
});
|
|
260
|
-
const AppPage = router.lookup(url.pathname) ? PageComponent : NotFoundPage;
|
|
261
|
-
const jsScript = url.pathname === "/" ? "index" : url.pathname;
|
|
217
|
+
const jsScript = url.pathname === "/" ? "/index" : url.pathname;
|
|
262
218
|
const helmetContext = {}
|
|
219
|
+
if (isbot(req.headers.get('User-Agent'))) {
|
|
220
|
+
const stream = await renderToReadableStream(_jsx("body", {
|
|
221
|
+
children: _jsxs("div", {
|
|
222
|
+
id: "root",
|
|
223
|
+
children: [_jsx(App, {
|
|
224
|
+
history,
|
|
225
|
+
router,
|
|
226
|
+
rpcCache: {},
|
|
227
|
+
helmetContext,
|
|
228
|
+
}), _jsx(_Fragment, {
|
|
229
|
+
children: _jsx("script", {
|
|
230
|
+
type: "module",
|
|
231
|
+
defer: true,
|
|
232
|
+
src: `/js${jsScript}.js?hydrate=true`,
|
|
233
|
+
})
|
|
234
|
+
})]
|
|
235
|
+
})
|
|
236
|
+
}))
|
|
237
|
+
await stream.allReady;
|
|
238
|
+
// const data = [];
|
|
239
|
+
// const reader = stream.getReader();
|
|
240
|
+
// await reader.read().then(function pump({ done, value }) {
|
|
241
|
+
// if (done) {
|
|
242
|
+
// return;
|
|
243
|
+
// }
|
|
244
|
+
// data.push(value);
|
|
245
|
+
// return reader.read().then(pump);
|
|
246
|
+
// });
|
|
247
|
+
// return new Response(`
|
|
248
|
+
// <!DOCTYPE html>
|
|
249
|
+
// <html lang="en">
|
|
250
|
+
// <head>
|
|
251
|
+
// ${helmetContext.helmet.title.toString()}
|
|
252
|
+
// </head>
|
|
253
|
+
// ${res}
|
|
254
|
+
// </html>
|
|
255
|
+
// `, {
|
|
256
|
+
// headers: { 'Content-Type': 'text/html' },
|
|
257
|
+
// status: 200,
|
|
258
|
+
// });
|
|
259
|
+
}
|
|
263
260
|
const stream = await renderToReadableStream(
|
|
264
261
|
_jsxs("html", {
|
|
265
262
|
lang: "en",
|
|
@@ -274,35 +271,27 @@ export const renderPage = async (PageComponent, req) => {
|
|
|
274
271
|
children: _jsxs("div", {
|
|
275
272
|
id: "root",
|
|
276
273
|
children: [_jsx(App, {
|
|
277
|
-
nProgress,
|
|
278
274
|
history,
|
|
279
|
-
router
|
|
275
|
+
router,
|
|
280
276
|
rpcCache: {},
|
|
281
277
|
helmetContext,
|
|
282
|
-
PageComponent: AppPage,
|
|
283
278
|
}), _jsx(_Fragment, {
|
|
284
279
|
children: _jsx("script", {
|
|
285
280
|
type: "module",
|
|
286
281
|
defer: true,
|
|
287
|
-
src: `/js
|
|
282
|
+
src: `/js${jsScript}.js?hydrate=true`,
|
|
288
283
|
})
|
|
289
284
|
})]
|
|
290
285
|
})
|
|
291
286
|
})]
|
|
292
287
|
}));
|
|
293
|
-
|
|
294
|
-
if (isbot(req.headers.get('User-Agent'))) {
|
|
295
|
-
await stream.allReady
|
|
296
|
-
// TODO:
|
|
297
|
-
// add helmetContext to head
|
|
298
|
-
}
|
|
299
288
|
return new Response(stream, {
|
|
300
289
|
headers: { 'Content-Type': 'text/html' },
|
|
301
290
|
status: 200,
|
|
302
291
|
});
|
|
303
292
|
}
|
|
304
293
|
|
|
305
|
-
export const hydrateApp = async (
|
|
294
|
+
export const hydrateApp = async () => {
|
|
306
295
|
const module = await import("react-dom/client");
|
|
307
296
|
const history = createBrowserHistory();
|
|
308
297
|
const router = createRouter({
|
|
@@ -314,11 +303,9 @@ export const hydrateApp = async (Page) => {
|
|
|
314
303
|
});
|
|
315
304
|
const root = document.getElementById("root");
|
|
316
305
|
module.default.hydrateRoot(root, React.createElement(App, {
|
|
317
|
-
nProgress,
|
|
318
306
|
history,
|
|
319
307
|
router,
|
|
320
308
|
rpcCache: {},
|
|
321
309
|
helmetContext: {},
|
|
322
|
-
PageComponent: Page,
|
|
323
310
|
}));
|
|
324
311
|
}
|
package.json
CHANGED
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": "*",
|
|
35
35
|
"react-dom": "*",
|
|
36
|
-
"nprogress": "*",
|
|
37
36
|
"react-error-boundary": "*",
|
|
38
37
|
"react-helmet-async": "*"
|
|
39
38
|
},
|
pnpm-lock.yaml
CHANGED
|
@@ -10,9 +10,6 @@ importers:
|
|
|
10
10
|
isbot:
|
|
11
11
|
specifier: 3.6.10
|
|
12
12
|
version: 3.6.10
|
|
13
|
-
nprogress:
|
|
14
|
-
specifier: '*'
|
|
15
|
-
version: 0.2.0
|
|
16
13
|
radix3:
|
|
17
14
|
specifier: ^1.0.0
|
|
18
15
|
version: 1.0.0
|
|
@@ -95,9 +92,6 @@ importers:
|
|
|
95
92
|
normalize.css:
|
|
96
93
|
specifier: ^8.0.1
|
|
97
94
|
version: 8.0.1
|
|
98
|
-
nprogress:
|
|
99
|
-
specifier: 0.2.0
|
|
100
|
-
version: 0.2.0
|
|
101
95
|
react:
|
|
102
96
|
specifier: 18.2.0
|
|
103
97
|
version: 18.2.0
|
|
@@ -6102,10 +6096,6 @@ packages:
|
|
|
6102
6096
|
path-key: 3.1.1
|
|
6103
6097
|
dev: true
|
|
6104
6098
|
|
|
6105
|
-
/nprogress@0.2.0:
|
|
6106
|
-
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
|
|
6107
|
-
dev: false
|
|
6108
|
-
|
|
6109
6099
|
/object-assign@4.1.1:
|
|
6110
6100
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
|
6111
6101
|
engines: {node: '>=0.10.0'}
|