~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


461357aa Peter John

2 years ago
move fetch
packages/example/routes/page.jsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect } from 'react';
2
- import { Link, useRouter, useFetch } from "parotta/router";
2
+ import { Link, useRouter } from "parotta/router";
3
+ import { useFetch } from "parotta/fetch";
3
4
  import Counter from "@/components/Counter/Counter";
4
5
  import "./page.css";
5
6
 
@@ -14,11 +15,11 @@ export default function Page() {
14
15
  const { data, cache } = useFetch("/todos");
15
16
  console.log('page');
16
17
  console.log('data', data);
17
- // useEffect(() => {
18
+ useEffect(() => {
18
- // setTimeout(() => {
19
+ setTimeout(() => {
19
- // cache.invalidate(/todos/);
20
+ cache.invalidate(/todos/);
20
- // }, 3000)
21
+ }, 3000)
21
- // }, [])
22
+ }, [])
22
23
  const router = useRouter();
23
24
  return (
24
25
  <div className="home-page">
packages/example/routes/todos/:id/page.jsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Suspense } from "react";
2
- import { Link, useRouter, useFetch } from "parotta/router";
2
+ import { Link, useRouter } from "parotta/router";
3
+ import { useFetch } from "parotta/fetch";
3
4
  // import "./index.css";
4
5
 
5
6
  export default function Page() {
packages/parotta/cli.js CHANGED
@@ -77,7 +77,7 @@ const serverRouter = createRouter({
77
77
  routes: serverSideRoutes,
78
78
  });
79
79
 
80
- const clientRoutes = await clientSideRoutes.reduce((acc, r) => {
80
+ const clientRoutes = clientSideRoutes.reduce((acc, r) => {
81
81
  const Head = import(`${process.cwd()}/routes${r === "" ? "" : r}/page.jsx`);
82
82
  const Page = import(`${process.cwd()}/routes${r === "" ? "" : r}/page.jsx`);
83
83
  acc[r === "" ? "/" : r] = {
@@ -142,8 +142,10 @@ const renderPage = async (url) => {
142
142
  "nprogress": "https://esm.sh/nprogress@0.2.0",
143
143
  // "parotta/router": `https://esm.sh/parotta@${version}/router.js`,
144
144
  // "parotta/error": `https://esm.sh/parotta@${version}/error.js`,
145
+ // "parotta/fetch": `https://esm.sh/parotta@${version}/fetch.js`,
145
146
  "parotta/router": `/parotta/router.js`,
146
147
  "parotta/error": `/parotta/error.js`,
148
+ "parotta/fetch": `/parotta/fetch.js`,
147
149
  ...nodeDeps,
148
150
  ...components,
149
151
  ...containers,
packages/parotta/fetch.js ADDED
@@ -0,0 +1,55 @@
1
+ import { useState, useMemo } from "react";
2
+
3
+ export const domain = () => typeof window !== 'undefined' ? window.origin : "http://0.0.0.0:3000";
4
+ export const globalCache = new Map();
5
+
6
+ export const useCache = () => {
7
+ const [_, rerender] = useState(false);
8
+ const cache = useMemo(() => globalCache, []);
9
+ const get = (k) => cache.get(k)
10
+ const set = (k, v) => {
11
+ cache.set(k, v);
12
+ rerender((c) => !c);
13
+ }
14
+ const invalidate = (regex) => {
15
+ Array.from(cache.keys())
16
+ .filter((k) => regex.test(k))
17
+ .forEach((k) => {
18
+ fetchData(k).then((v) => set(k, v));
19
+ });
20
+ }
21
+ return {
22
+ get,
23
+ set,
24
+ invalidate,
25
+ }
26
+ }
27
+
28
+ const fetchData = async (route) => {
29
+ const url = `${domain()}${route}`;
30
+ const res = await fetch(url, {
31
+ headers: {
32
+ "Accept": "application/json",
33
+ },
34
+ });
35
+ if (res.ok) {
36
+ return await res.json();
37
+ } else {
38
+ return new Error(await res.text());
39
+ }
40
+ }
41
+
42
+ export const useFetch = (url) => {
43
+ const cache = useCache();
44
+ const value = cache.get(url);
45
+ if (value) {
46
+ if (value instanceof Promise) {
47
+ throw value;
48
+ } else if (value instanceof Error) {
49
+ throw value;
50
+ }
51
+ return { data: value, cache };
52
+ }
53
+ cache.set(url, fetchData(url).then((v) => cache.set(url, v)));
54
+ throw cache.get(url);
55
+ }
packages/parotta/router.js CHANGED
@@ -1,62 +1,6 @@
1
1
  import React, { createContext, useContext, useState, useEffect, useMemo, useSyncExternalStore } from "react";
2
2
  import nProgress from "nprogress";
3
3
 
4
- export const isClient = () => typeof window !== 'undefined';
5
- export const domain = () => isClient() ? window.origin : "http://0.0.0.0:3000";
6
- export const basePath = () => isClient() ? "" : process.cwd();
7
- export const globalCache = new Map();
8
- export const useFetchCache = () => {
9
- const [_, rerender] = useState(false);
10
- const cache = useMemo(() => globalCache, []);
11
- const get = (k) => cache.get(k)
12
- const set = (k, v) => {
13
- cache.set(k, v);
14
- rerender((c) => !c);
15
- }
16
- const invalidate = (regex) => {
17
- Array.from(cache.keys())
18
- .filter((k) => regex.test(k))
19
- .forEach((k) => {
20
- fetchData(k).then((v) => set(k, v));
21
- });
22
- }
23
- return {
24
- get,
25
- set,
26
- invalidate,
27
- }
28
- }
29
-
30
- const fetchData = async (route) => {
31
- const url = `${domain()}${route}`;
32
- console.log('url', url);
33
- const res = await fetch(url, {
34
- headers: {
35
- "Accept": "application/json",
36
- },
37
- });
38
- if (res.ok) {
39
- return await res.json();
40
- } else {
41
- return new Error(await res.text());
42
- }
43
- }
44
-
45
- export const useFetch = (url) => {
46
- const cache = useFetchCache();
47
- const value = cache.get(url);
48
- if (value) {
49
- if (value instanceof Promise) {
50
- throw value;
51
- } else if (value instanceof Error) {
52
- throw value;
53
- }
54
- return { data: value, cache };
55
- }
56
- cache.set(url, fetchData(url).then((v) => cache.set(url, v)));
57
- throw cache.get(url);
58
- }
59
-
60
4
  export const RouterContext = createContext(undefined);
61
5
 
62
6
  const getMatch = (radixRouter, pathname) => {
@@ -97,18 +41,8 @@ export const Header = ({ history, radixRouter, importMap }) => {
97
41
  });
98
42
  }
99
43
 
100
- // export const PP = ({ children }) => {
101
- // React.useEffect(() => {
102
- // nProgress.done()
103
- // return () => {
104
- // nProgress.start();
105
- // }
106
- // }, []);
107
- // return children
108
- // }
109
-
110
44
  export const Router = ({ App, history, radixRouter }) => {
111
- const [, startTransition] = React.useTransition();
45
+ const [isPending, startTransition] = React.useTransition();
112
46
  const [match, setMatch] = useState(() => getMatch(radixRouter, history.location.pathname));
113
47
  useEffect(() => {
114
48
  return history.listen(({ location }) => {
@@ -134,8 +68,13 @@ export const Router = ({ App, history, radixRouter }) => {
134
68
  })
135
69
  }
136
70
  });
137
- }, [])
71
+ }, []);
72
+ useEffect(() => {
73
+ if (!isPending) {
74
+ nProgress.done();
75
+ }
76
+ }, [isPending])
138
- console.log('Router');
77
+ console.log('Router', isPending);
139
78
  return React.createElement(RouterContext.Provider, {
140
79
  value: {
141
80
  history: history,
@@ -165,10 +104,11 @@ export const Link = (props) => {
165
104
  const router = useRouter();
166
105
  return React.createElement("a", {
167
106
  ...props,
168
- // onMouseOver: (e) => {
107
+ onMouseOver: (e) => {
169
- // fetch(`/routes${pathname === "/" ? "" : pathname}/page.css`);
108
+ // Simple prefetching for now will work only with cache headers
109
+ fetch(getCssUrl(props.href));
170
- // fetch(`/routes${pathname === "/" ? "" : pathname}/page.jsx`);
110
+ fetch(getCssUrl(props.href).replace("css", "jsx"));
171
- // },
111
+ },
172
112
  onClick: (e) => {
173
113
  e.preventDefault();
174
114
  if (props && props.onClick) {
readme.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # parotta
2
2
 
3
- parotta is a next level meta-framework for react that runs only on the bun js runtime.
3
+ parotta is a next level meta-framework for react that runs only on edge runtimes mainly bun.
4
- It uses File system routing with SSR with streaming + CSR as the method to render pages. Basically a MPA + SPA Transitional App.
4
+ It uses File System routing with streaming SSR + CSR as the method to render pages. Basically a MPA + SPA Transitional App.
5
5
  It is very opionated and has set of idiomatic ways of doing things.
6
6
 
7
7
  ### Todo
8
- 1. Prefetching assets
9
- 2. Add build step
8
+ 1. Add build step
10
- 3. Deploy to Docker, Deno deploy, Cloudflare workers, Vercel edge functions, Bun edge (whenever it releases)
9
+ 2. Deploy to Docker, Deno deploy, Vercel edge functions, Cloudflare workers, Bun edge (whenever it releases)
11
- 4. Hydrate fetch cache
10
+ 3. Hydrate fetch cache