~repos /edge-city

#react#js#ssr

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 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(Page)
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 = ({ nProgress, history, router, rpcCache, helmetContext, PageComponent }) => {
124
+ export const App = ({ history, router, rpcCache, helmetContext }) => {
136
- const [isPending, startTransition] = useTransition();
125
+ const [_, startTransition] = useTransition();
137
- const [match, setMatch] = useState(() => {
138
- if (PageComponent) {
139
- return PageComponent;
140
- }
141
- return getMatch(router, history.location.pathname)
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
- // const isLoaded = Array.from(document.getElementsByTagName("link"))
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
- setMatch(getMatch(router, location.pathname));
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 (PageComponent, req) => {
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] = 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: null,
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/${jsScript}.js?hydrate=true`,
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 (Page) => {
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'}