~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
9e6ce31c
—
Peter John 2 years ago
improve dir structure
- .gitignore +2 -1
- api/health.js +6 -1
- api/todos/[id]/index.js +6 -1
- astroPlugin.js +24 -6
- bun.lockb +0 -0
- components/Todo.astro +15 -0
- containers/TodoList.astro +10 -0
- index.css +0 -3
- index.js +101 -51
- package-lock.json +150 -0
- package.json +4 -0
- public/index.html +0 -44
- routes/about/index.jsx +0 -12
- routes/index.astro +14 -17
- routes/layout.astro +0 -0
- routes/page.jsx +21 -0
- {public → static}/favicon.ico +0 -0
- {public → static}/logo192.png +0 -0
- {public → static}/logo512.png +0 -0
- {public → static}/manifest.json +0 -0
- {public → static}/robots.txt +0 -0
- utils.js +0 -13
.gitignore
CHANGED
|
@@ -168,4 +168,5 @@ dist
|
|
|
168
168
|
.yarn/install-state.gz
|
|
169
169
|
.pnp.\*
|
|
170
170
|
.cache
|
|
171
|
-
dist
|
|
171
|
+
dist
|
|
172
|
+
.vercel
|
api/health.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
export const onGet = (req) => {
|
|
2
|
-
return new Response("ok"
|
|
2
|
+
return new Response("ok", {
|
|
3
|
+
headers: {
|
|
4
|
+
"Content-Type": "application/json",
|
|
5
|
+
},
|
|
6
|
+
status: 200,
|
|
7
|
+
});
|
|
3
8
|
}
|
api/todos/[id]/index.js
CHANGED
|
@@ -8,7 +8,12 @@ export const onGet = async (req) => {
|
|
|
8
8
|
filter: { id },
|
|
9
9
|
});
|
|
10
10
|
const data = JSON.stringify(item);
|
|
11
|
-
return new Response(data
|
|
11
|
+
return new Response(data, {
|
|
12
|
+
headers: {
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
},
|
|
15
|
+
status: 200,
|
|
16
|
+
});
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
export const onPut = async (req) => {
|
astroPlugin.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { plugin } from "bun";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
4
|
+
import postcss from "postcss"
|
|
5
|
+
import autoprefixer from "autoprefixer";
|
|
6
|
+
import postcssNested from "postcss-nested";
|
|
2
7
|
|
|
3
8
|
const transpiler = new Bun.Transpiler({
|
|
4
9
|
loader: "jsx",
|
|
@@ -9,13 +14,16 @@ const transpiler = new Bun.Transpiler({
|
|
|
9
14
|
plugin({
|
|
10
15
|
name: "Astro",
|
|
11
16
|
async setup(build) {
|
|
12
|
-
const { readFileSync, writeFileSync } = await import("fs");
|
|
13
17
|
build.onLoad({ filter: /\.astro$/ }, async (args) => {
|
|
18
|
+
const folder = path.dirname(args.path).replace(process.cwd(), "");
|
|
19
|
+
const filename = path.basename(args.path).replace("astro", "js");
|
|
20
|
+
const outputFolder = path.join(process.cwd(), ".cache", folder);
|
|
21
|
+
const outputFile = path.join(outputFolder, filename);
|
|
14
22
|
const text = readFileSync(args.path, "utf8");
|
|
15
|
-
const [_, js, html] = text.split("---");
|
|
23
|
+
const [_, js, html, css] = text.split("---");
|
|
16
24
|
const imports = js.split("\n").filter((line) => line.startsWith("import")).join("\n");
|
|
17
25
|
const body = js.split("\n").filter((line) => !line.startsWith("import")).join("\n");
|
|
18
|
-
const
|
|
26
|
+
const tpl = `
|
|
19
27
|
${imports}
|
|
20
28
|
|
|
21
29
|
export default () => {
|
|
@@ -25,10 +33,20 @@ plugin({
|
|
|
25
33
|
${html}
|
|
26
34
|
);
|
|
27
35
|
}
|
|
28
|
-
`
|
|
36
|
+
`;
|
|
37
|
+
// console.log('tpl', tpl);
|
|
38
|
+
const code = await transpiler.transform(tpl);
|
|
29
39
|
// console.log('code', code);
|
|
40
|
+
if (!existsSync(outputFolder)) {
|
|
41
|
+
mkdirSync(outputFolder);
|
|
42
|
+
}
|
|
30
|
-
writeFileSync(
|
|
43
|
+
writeFileSync(outputFile, code);
|
|
44
|
+
if (css) {
|
|
45
|
+
const result = postcss([autoprefixer, postcssNested])
|
|
46
|
+
.process(css, { from: 'src/app.css', to: 'dest/app.css' });
|
|
47
|
+
writeFileSync(path.join(outputFolder, filename.replace("js", "css")), result.css);
|
|
48
|
+
}
|
|
31
|
-
const src = await import(
|
|
49
|
+
const src = await import(outputFile);
|
|
32
50
|
return {
|
|
33
51
|
exports: {
|
|
34
52
|
default: src.default,
|
bun.lockb
CHANGED
|
Binary file
|
components/Todo.astro
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
const { id, text } = Astro.props;
|
|
3
|
+
const todos = [{ text: "123" }];
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<div>
|
|
7
|
+
<p>
|
|
8
|
+
{item.text}
|
|
9
|
+
</p>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
div {
|
|
14
|
+
font-size: 20px;
|
|
15
|
+
}
|
containers/TodoList.astro
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
const todos = [{ text: "123" }];
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<div className="todo-list">
|
|
6
|
+
<h1>Todos</h1>
|
|
7
|
+
<ul>
|
|
8
|
+
{todos.map((item) => <li key={item.text}>{item.text}</li>)}
|
|
9
|
+
</ul>
|
|
10
|
+
</div>
|
index.css
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
.ccs {
|
|
2
|
-
display: flex;
|
|
3
|
-
}
|
index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import './astroPlugin.js';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { SWRConfig } from 'swr';
|
|
2
|
-
import {
|
|
4
|
+
import { renderToReadableStream } from 'react-dom/server';
|
|
3
5
|
import { RouterProvider } from './router.js';
|
|
6
|
+
import packageJson from "./package.json";
|
|
4
7
|
|
|
5
8
|
const router = new Bun.FileSystemRouter({
|
|
6
9
|
style: "nextjs",
|
|
@@ -20,7 +23,13 @@ const renderApi = async (route, req) => {
|
|
|
20
23
|
console.log('routeImport', routeImport);
|
|
21
24
|
}
|
|
22
25
|
|
|
26
|
+
const deps = Object.keys(packageJson.dependencies).reduce((acc, dep) => {
|
|
27
|
+
acc[dep] = `https://esm.sh/${dep}@${packageJson.dependencies[dep]}?dev`;
|
|
28
|
+
return acc;
|
|
29
|
+
}, {})
|
|
30
|
+
|
|
23
31
|
const renderPage = async (filePath, url, params) => {
|
|
32
|
+
const file = path.basename(url.pathname).replace("astro", "js") + "index.js";
|
|
24
33
|
const query = {};
|
|
25
34
|
for (const key of url.searchParams.keys()) {
|
|
26
35
|
query[key] = url.searchParams.get(key);
|
|
@@ -36,6 +45,7 @@ const renderPage = async (filePath, url, params) => {
|
|
|
36
45
|
<html lang="en">
|
|
37
46
|
<head>
|
|
38
47
|
{/* {routeImport.head()} */}
|
|
48
|
+
<link rel="stylesheet" href="/routes/index.css" />
|
|
39
49
|
<script id="initial_route_context" type='application/json' dangerouslySetInnerHTML={{
|
|
40
50
|
__html: JSON.stringify(initialRouteValue)
|
|
41
51
|
}} />
|
|
@@ -43,25 +53,44 @@ const renderPage = async (filePath, url, params) => {
|
|
|
43
53
|
__html: JSON.stringify(
|
|
44
54
|
{
|
|
45
55
|
"imports": {
|
|
46
|
-
|
|
56
|
+
...deps,
|
|
47
|
-
"react-dom": "https://esm.sh/react-dom@18.2.0?dev",
|
|
48
57
|
"react-dom/client": "https://esm.sh/react-dom@18.2.0/client?dev",
|
|
49
58
|
"react/jsx-dev-runtime": "https://esm.sh/react@18.2.0/jsx-dev-runtime?dev",
|
|
50
|
-
"@/utils": "/assets/js/src/utils.js",
|
|
51
59
|
"@/router.js": "/assets/js/src/router.js",
|
|
60
|
+
"@/routes/index.js": "/routes/index.js",
|
|
61
|
+
"@/components/Todo.astro": "/components/Todo.js",
|
|
62
|
+
"@/containers/TodoList.astro": "/containers/TodoList.js"
|
|
52
63
|
}
|
|
53
64
|
}
|
|
54
65
|
)
|
|
55
66
|
}}>
|
|
56
67
|
</script>
|
|
57
|
-
|
|
68
|
+
<script type="module" defer dangerouslySetInnerHTML={{
|
|
69
|
+
__html: `
|
|
70
|
+
import* as JSX from "react/jsx-dev-runtime";
|
|
71
|
+
var $jsx = JSX.jsxDEV;
|
|
72
|
+
import { hydrateRoot } from 'react-dom/client';
|
|
73
|
+
import { SWRConfig } from 'swr';
|
|
74
|
+
import {RouterProvider} from "@/router.js";
|
|
75
|
+
import Page from "@/routes/${file}";
|
|
76
|
+
|
|
58
|
-
|
|
77
|
+
const initialRouteValue = JSON.parse(document.getElementById('initial_route_context').textContent);
|
|
78
|
+
const root = hydrateRoot(document.getElementById("root"), $jsx(SWRConfig, {
|
|
79
|
+
value: { suspense: true },
|
|
80
|
+
children: $jsx(RouterProvider, {
|
|
81
|
+
value: initialRouteValue,
|
|
82
|
+
children: $jsx(Page, {}, undefined, false, undefined, this)
|
|
83
|
+
}, undefined, false, undefined, this)
|
|
84
|
+
}, undefined, false, undefined, this));
|
|
85
|
+
`}}></script>
|
|
59
86
|
</head>
|
|
60
87
|
<body>
|
|
61
88
|
<div id="root">
|
|
89
|
+
<SWRConfig value={{ suspense: true }}>
|
|
62
|
-
|
|
90
|
+
<RouterProvider value={initialRouteValue}>
|
|
63
|
-
|
|
91
|
+
<Page />
|
|
64
|
-
|
|
92
|
+
</RouterProvider>
|
|
93
|
+
</SWRConfig>
|
|
65
94
|
</div>
|
|
66
95
|
</body>
|
|
67
96
|
</html >
|
|
@@ -74,59 +103,80 @@ const renderPage = async (filePath, url, params) => {
|
|
|
74
103
|
});
|
|
75
104
|
}
|
|
76
105
|
|
|
106
|
+
// const renderBootstrap = async (url) => {
|
|
107
|
+
// const folder = path.dirname(url.pathname);
|
|
108
|
+
// const file = path.basename(url.pathname).replace("astro", "js");
|
|
109
|
+
// const result = await transpiler.transform(`
|
|
110
|
+
// import { hydrateRoot } from 'react-dom/client';
|
|
111
|
+
// import {RouterProvider} from "@/router.js";
|
|
112
|
+
// import Page from "@/routes/${file}";
|
|
113
|
+
|
|
114
|
+
// const initialRouteValue = JSON.parse(document.getElementById('initial_route_context').textContent);
|
|
115
|
+
// const root = hydrateRoot(document.getElementById('root'), (
|
|
116
|
+
// <RouterProvider value={initialRouteValue}>
|
|
117
|
+
// <Page />
|
|
118
|
+
// </RouterProvider>
|
|
119
|
+
// ));
|
|
120
|
+
// `);
|
|
121
|
+
// return new Response(result, {
|
|
122
|
+
// headers: {
|
|
123
|
+
// 'Content-Type': 'application/javascript',
|
|
124
|
+
// },
|
|
125
|
+
// status: 200,
|
|
126
|
+
// });
|
|
127
|
+
// }
|
|
128
|
+
|
|
129
|
+
const renderJs = async (url) => {
|
|
130
|
+
const localFile = url.pathname.replace("/assets/js/", "").replace("src/", "");
|
|
131
|
+
const src = await Bun.file(localFile).text();
|
|
132
|
+
const result = await transpiler.transform(src);
|
|
133
|
+
return new Response(result, {
|
|
134
|
+
headers: {
|
|
135
|
+
'Content-Type': 'application/javascript',
|
|
136
|
+
},
|
|
137
|
+
status: 200,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const sendFile = async (url) => {
|
|
142
|
+
const localFile = url.pathname.replace("/assets/js/", "").replace("src/", "");
|
|
143
|
+
const result = await Bun.file(path.join(".cache", localFile)).text();
|
|
144
|
+
let contentType = "application/javascript";
|
|
145
|
+
if (url.pathname.endsWith(".css")) {
|
|
146
|
+
contentType = 'text/css';
|
|
147
|
+
}
|
|
148
|
+
return new Response(result, {
|
|
149
|
+
headers: {
|
|
150
|
+
'Content-Type': contentType,
|
|
151
|
+
},
|
|
152
|
+
status: 200,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
77
156
|
export default {
|
|
78
157
|
port: 3000,
|
|
79
158
|
async fetch(req) {
|
|
80
159
|
const url = new URL(req.url);
|
|
160
|
+
console.log(req.method, url.pathname)
|
|
81
|
-
if (url.pathname.
|
|
161
|
+
if (url.pathname.includes("/components/") || url.pathname.includes("/containers/") || url.pathname.includes("/routes/")) {
|
|
82
|
-
const src = await Bun.file("./dist/index.js").text();
|
|
83
|
-
return
|
|
162
|
+
return sendFile(url);
|
|
84
|
-
headers: {
|
|
85
|
-
'Content-Type': 'application/javascript',
|
|
86
|
-
},
|
|
87
|
-
status: 200,
|
|
88
|
-
});
|
|
89
163
|
}
|
|
90
|
-
if (url.pathname.
|
|
164
|
+
if (url.pathname.includes("/assets/js")) {
|
|
91
|
-
const lib = url.pathname.replace("/assets/js/", "");
|
|
92
|
-
const localFile = lib.replace("src/", "");
|
|
93
|
-
let result;
|
|
94
|
-
if (localFile.includes("routes")) {
|
|
95
|
-
result = await transpiler.transform(`
|
|
96
|
-
import { hydrateRoot } from 'react-dom/client';
|
|
97
|
-
import {RouterProvider} from "@/router.js";
|
|
98
|
-
import Page from "/dist/js/index.js";
|
|
99
|
-
|
|
100
|
-
const initialRouteValue = JSON.parse(document.getElementById('initial_route_context').textContent);
|
|
101
|
-
const root = hydrateRoot(document.getElementById('root'), (
|
|
102
|
-
<RouterProvider value={initialRouteValue}>
|
|
103
|
-
<Page />
|
|
104
|
-
</RouterProvider>
|
|
105
|
-
));
|
|
106
|
-
`);
|
|
107
|
-
} else {
|
|
108
|
-
const src = await Bun.file(localFile).text();
|
|
109
|
-
result = await transpiler.transform(src);
|
|
110
|
-
}
|
|
111
|
-
return
|
|
165
|
+
return renderJs(url);
|
|
112
|
-
headers: {
|
|
113
|
-
'Content-Type': 'application/javascript',
|
|
114
|
-
},
|
|
115
|
-
status: 200,
|
|
116
|
-
});
|
|
117
166
|
}
|
|
118
|
-
if (url.pathname.
|
|
167
|
+
if (url.pathname.includes("/api")) {
|
|
119
|
-
console.log('api', url.pathname);
|
|
120
|
-
|
|
168
|
+
return renderApi(url, req);
|
|
169
|
+
}
|
|
170
|
+
if (url.pathname.includes("/favicon")) {
|
|
171
|
+
return new Response(`Not Found`, {
|
|
172
|
+
headers: { 'Content-Type': 'text/html' },
|
|
173
|
+
status: 404,
|
|
174
|
+
});
|
|
121
175
|
}
|
|
122
176
|
return renderPage("./routes/index.astro", url, {});
|
|
123
177
|
// const route = router.match(url.pathname);
|
|
124
178
|
// if (route) {
|
|
125
179
|
// return renderPage(route, url);
|
|
126
180
|
// }
|
|
127
|
-
return new Response(`Not Found`, {
|
|
128
|
-
headers: { 'Content-Type': 'text/html' },
|
|
129
|
-
status: 404,
|
|
130
|
-
});
|
|
131
181
|
},
|
|
132
182
|
};
|
package-lock.json
CHANGED
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
"": {
|
|
7
7
|
"name": "quickstart",
|
|
8
8
|
"dependencies": {
|
|
9
|
+
"postcss": "^8.4.21",
|
|
10
|
+
"postcss-js": "^4.0.1",
|
|
9
11
|
"react": "18.2.0",
|
|
10
12
|
"react-dom": "^18.2.0",
|
|
13
|
+
"swr": "^2.1.0",
|
|
11
14
|
"zod": "^3.21.0"
|
|
12
15
|
},
|
|
13
16
|
"devDependencies": {
|
|
@@ -18,6 +21,14 @@
|
|
|
18
21
|
"version": "0.5.7",
|
|
19
22
|
"dev": true
|
|
20
23
|
},
|
|
24
|
+
"node_modules/camelcase-css": {
|
|
25
|
+
"version": "2.0.1",
|
|
26
|
+
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
|
27
|
+
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">= 6"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
21
32
|
"node_modules/js-tokens": {
|
|
22
33
|
"version": "4.0.0",
|
|
23
34
|
"license": "MIT"
|
|
@@ -32,6 +43,63 @@
|
|
|
32
43
|
"loose-envify": "cli.js"
|
|
33
44
|
}
|
|
34
45
|
},
|
|
46
|
+
"node_modules/nanoid": {
|
|
47
|
+
"version": "3.3.4",
|
|
48
|
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
|
49
|
+
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
|
50
|
+
"bin": {
|
|
51
|
+
"nanoid": "bin/nanoid.cjs"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"node_modules/picocolors": {
|
|
58
|
+
"version": "1.0.0",
|
|
59
|
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
|
60
|
+
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
|
61
|
+
},
|
|
62
|
+
"node_modules/postcss": {
|
|
63
|
+
"version": "8.4.21",
|
|
64
|
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
|
|
65
|
+
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
|
|
66
|
+
"funding": [
|
|
67
|
+
{
|
|
68
|
+
"type": "opencollective",
|
|
69
|
+
"url": "https://opencollective.com/postcss/"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "tidelift",
|
|
73
|
+
"url": "https://tidelift.com/funding/github/npm/postcss"
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"nanoid": "^3.3.4",
|
|
78
|
+
"picocolors": "^1.0.0",
|
|
79
|
+
"source-map-js": "^1.0.2"
|
|
80
|
+
},
|
|
81
|
+
"engines": {
|
|
82
|
+
"node": "^10 || ^12 || >=14"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"node_modules/postcss-js": {
|
|
86
|
+
"version": "4.0.1",
|
|
87
|
+
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
|
88
|
+
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"camelcase-css": "^2.0.1"
|
|
91
|
+
},
|
|
92
|
+
"engines": {
|
|
93
|
+
"node": "^12 || ^14 || >= 16"
|
|
94
|
+
},
|
|
95
|
+
"funding": {
|
|
96
|
+
"type": "opencollective",
|
|
97
|
+
"url": "https://opencollective.com/postcss/"
|
|
98
|
+
},
|
|
99
|
+
"peerDependencies": {
|
|
100
|
+
"postcss": "^8.4.21"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
35
103
|
"node_modules/react": {
|
|
36
104
|
"version": "18.2.0",
|
|
37
105
|
"license": "MIT",
|
|
@@ -61,6 +129,36 @@
|
|
|
61
129
|
"loose-envify": "^1.1.0"
|
|
62
130
|
}
|
|
63
131
|
},
|
|
132
|
+
"node_modules/source-map-js": {
|
|
133
|
+
"version": "1.0.2",
|
|
134
|
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
|
135
|
+
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
|
136
|
+
"engines": {
|
|
137
|
+
"node": ">=0.10.0"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"node_modules/swr": {
|
|
141
|
+
"version": "2.1.0",
|
|
142
|
+
"resolved": "https://registry.npmjs.org/swr/-/swr-2.1.0.tgz",
|
|
143
|
+
"integrity": "sha512-4hYl5p3/KalQ1MORealM79g/DtLohmud6yyfXw5l4wjtFksYUnocRFudvyaoUtgj3FrVNK9lS25Av9dsZYvz0g==",
|
|
144
|
+
"dependencies": {
|
|
145
|
+
"use-sync-external-store": "^1.2.0"
|
|
146
|
+
},
|
|
147
|
+
"engines": {
|
|
148
|
+
"pnpm": "7"
|
|
149
|
+
},
|
|
150
|
+
"peerDependencies": {
|
|
151
|
+
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"node_modules/use-sync-external-store": {
|
|
155
|
+
"version": "1.2.0",
|
|
156
|
+
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
|
157
|
+
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
|
158
|
+
"peerDependencies": {
|
|
159
|
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
|
160
|
+
}
|
|
161
|
+
},
|
|
64
162
|
"node_modules/zod": {
|
|
65
163
|
"version": "3.21.0",
|
|
66
164
|
"license": "MIT",
|
|
@@ -74,6 +172,11 @@
|
|
|
74
172
|
"version": "0.5.7",
|
|
75
173
|
"dev": true
|
|
76
174
|
},
|
|
175
|
+
"camelcase-css": {
|
|
176
|
+
"version": "2.0.1",
|
|
177
|
+
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
|
178
|
+
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
|
|
179
|
+
},
|
|
77
180
|
"js-tokens": {
|
|
78
181
|
"version": "4.0.0"
|
|
79
182
|
},
|
|
@@ -83,6 +186,34 @@
|
|
|
83
186
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
|
84
187
|
}
|
|
85
188
|
},
|
|
189
|
+
"nanoid": {
|
|
190
|
+
"version": "3.3.4",
|
|
191
|
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
|
192
|
+
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
|
|
193
|
+
},
|
|
194
|
+
"picocolors": {
|
|
195
|
+
"version": "1.0.0",
|
|
196
|
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
|
197
|
+
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
|
198
|
+
},
|
|
199
|
+
"postcss": {
|
|
200
|
+
"version": "8.4.21",
|
|
201
|
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
|
|
202
|
+
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
|
|
203
|
+
"requires": {
|
|
204
|
+
"nanoid": "^3.3.4",
|
|
205
|
+
"picocolors": "^1.0.0",
|
|
206
|
+
"source-map-js": "^1.0.2"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
"postcss-js": {
|
|
210
|
+
"version": "4.0.1",
|
|
211
|
+
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
|
212
|
+
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
|
213
|
+
"requires": {
|
|
214
|
+
"camelcase-css": "^2.0.1"
|
|
215
|
+
}
|
|
216
|
+
},
|
|
86
217
|
"react": {
|
|
87
218
|
"version": "18.2.0",
|
|
88
219
|
"requires": {
|
|
@@ -104,6 +235,25 @@
|
|
|
104
235
|
"loose-envify": "^1.1.0"
|
|
105
236
|
}
|
|
106
237
|
},
|
|
238
|
+
"source-map-js": {
|
|
239
|
+
"version": "1.0.2",
|
|
240
|
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
|
241
|
+
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
|
|
242
|
+
},
|
|
243
|
+
"swr": {
|
|
244
|
+
"version": "2.1.0",
|
|
245
|
+
"resolved": "https://registry.npmjs.org/swr/-/swr-2.1.0.tgz",
|
|
246
|
+
"integrity": "sha512-4hYl5p3/KalQ1MORealM79g/DtLohmud6yyfXw5l4wjtFksYUnocRFudvyaoUtgj3FrVNK9lS25Av9dsZYvz0g==",
|
|
247
|
+
"requires": {
|
|
248
|
+
"use-sync-external-store": "^1.2.0"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"use-sync-external-store": {
|
|
252
|
+
"version": "1.2.0",
|
|
253
|
+
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
|
254
|
+
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
|
255
|
+
"requires": {}
|
|
256
|
+
},
|
|
107
257
|
"zod": {
|
|
108
258
|
"version": "3.21.0"
|
|
109
259
|
}
|
package.json
CHANGED
|
@@ -10,8 +10,12 @@
|
|
|
10
10
|
"bun-types": "^0.5.0"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"autoprefixer": "^10.4.14",
|
|
14
|
+
"postcss": "^8.4.21",
|
|
15
|
+
"postcss-nested": "^6.0.1",
|
|
13
16
|
"react": "18.2.0",
|
|
14
17
|
"react-dom": "^18.2.0",
|
|
18
|
+
"swr": "^2.1.0",
|
|
15
19
|
"zod": "^3.21.0"
|
|
16
20
|
}
|
|
17
21
|
}
|
public/index.html
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<link rel="icon" href="favicon.ico" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
-
<meta name="theme-color" content="#000000" />
|
|
8
|
-
<meta
|
|
9
|
-
name="description"
|
|
10
|
-
content="Web site created using create-react-app"
|
|
11
|
-
/>
|
|
12
|
-
<link rel="apple-touch-icon" href="/logo192.png" />
|
|
13
|
-
<!--
|
|
14
|
-
manifest.json provides metadata used when your web app is installed on a
|
|
15
|
-
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
16
|
-
-->
|
|
17
|
-
<link rel="manifest" href="/manifest.json" />
|
|
18
|
-
<!--
|
|
19
|
-
Notice the use of %PUBLIC_URL% in the tags above.
|
|
20
|
-
It will be replaced with the URL of the `public` folder during the build.
|
|
21
|
-
Only files inside the `public` folder can be referenced from the HTML.
|
|
22
|
-
|
|
23
|
-
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
24
|
-
work correctly both with client-side routing and a non-root public URL.
|
|
25
|
-
Learn how to configure a non-root public URL by running `npm run build`.
|
|
26
|
-
-->
|
|
27
|
-
<title>React App</title>
|
|
28
|
-
</head>
|
|
29
|
-
<body>
|
|
30
|
-
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
31
|
-
<div id="root"></div>
|
|
32
|
-
<!--
|
|
33
|
-
This HTML file is a template.
|
|
34
|
-
If you open it directly in the browser, you will see an empty page.
|
|
35
|
-
|
|
36
|
-
You can add webfonts, meta tags, or analytics to this file.
|
|
37
|
-
The build step will place the bundled scripts into the <body> tag.
|
|
38
|
-
|
|
39
|
-
To begin the development, run `npm start` or `yarn start`.
|
|
40
|
-
To create a production bundle, use `npm run build` or `yarn build`.
|
|
41
|
-
-->
|
|
42
|
-
<script src="/src/index.jsx" async type="module"></script>
|
|
43
|
-
</body>
|
|
44
|
-
</html>
|
routes/about/index.jsx
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { page, useRouter } from "@/utils";
|
|
2
|
-
|
|
3
|
-
export default page(() => {
|
|
4
|
-
const router = useRouter();
|
|
5
|
-
return (
|
|
6
|
-
<div>
|
|
7
|
-
<p>
|
|
8
|
-
Hello from server
|
|
9
|
-
</p>
|
|
10
|
-
</div>
|
|
11
|
-
);
|
|
12
|
-
});
|
routes/index.astro
CHANGED
|
@@ -1,34 +1,31 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { useState } from
|
|
2
|
+
import { useState } from "react";
|
|
3
|
-
import { useRouter } from
|
|
3
|
+
import { useRouter } from "@/router.js";
|
|
4
|
-
|
|
5
|
-
const head = {
|
|
6
|
-
title: "pyros.sh",
|
|
7
|
-
description:
|
|
8
|
-
|
|
4
|
+
import TodoList from "@/containers/TodoList.astro";
|
|
9
|
-
image: "/favicon.png",
|
|
10
|
-
keywords: "pyros.sh,pyrossh",
|
|
11
|
-
};
|
|
12
5
|
|
|
13
6
|
const router = useRouter();
|
|
14
7
|
const [count, setCount] = useState(5);
|
|
8
|
+
// const { data: todos, isLoading, isRevalidating } = usePromise("/todos");
|
|
15
9
|
---
|
|
16
10
|
|
|
17
|
-
<div
|
|
11
|
+
<div>
|
|
18
12
|
<div>
|
|
19
13
|
<p>
|
|
20
14
|
Hello from server path 123: {router.pathname}
|
|
21
15
|
</p>
|
|
16
|
+
<TodoList />
|
|
22
17
|
<div>
|
|
23
|
-
<button onClick={() => setCount(count - 1)}>
|
|
18
|
+
<button onClick={() => setCount(count - 1)}>-</button>
|
|
24
|
-
-
|
|
25
|
-
</button>
|
|
26
19
|
<div>
|
|
27
20
|
{count}
|
|
28
21
|
</div>
|
|
29
|
-
<button onClick={() => setCount(count + 1)}>
|
|
22
|
+
<button onClick={() => setCount(count + 1)}>+</button>
|
|
30
|
-
+
|
|
31
|
-
</button>
|
|
32
23
|
</div>
|
|
33
24
|
</div>
|
|
34
25
|
</div>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
div {
|
|
29
|
+
padding: 10px;
|
|
30
|
+
background-color: yellow;
|
|
31
|
+
}
|
routes/layout.astro
ADDED
|
File without changes
|
routes/page.jsx
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default () => {
|
|
2
|
+
return (
|
|
3
|
+
<div className="home-page">
|
|
4
|
+
<div>
|
|
5
|
+
<p>
|
|
6
|
+
Hello from server path 123: {router.pathname}
|
|
7
|
+
</p>
|
|
8
|
+
<Suspense fallback={"Loading..."}>
|
|
9
|
+
<TodoList />
|
|
10
|
+
</Suspense>
|
|
11
|
+
<div>
|
|
12
|
+
<button onClick={() => setCount(count - 1)}> -</button>
|
|
13
|
+
<div>
|
|
14
|
+
{count}
|
|
15
|
+
</div>
|
|
16
|
+
<button onClick={() => setCount(count + 1)}> +</button>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
}
|
{public → static}/favicon.ico
RENAMED
|
File without changes
|
{public → static}/logo192.png
RENAMED
|
File without changes
|
{public → static}/logo512.png
RENAMED
|
File without changes
|
{public → static}/manifest.json
RENAMED
|
File without changes
|
{public → static}/robots.txt
RENAMED
|
File without changes
|
utils.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export const json = async (body, status = 200, headers = {}) => {
|
|
2
|
-
return new Response(body, {
|
|
3
|
-
headers: {
|
|
4
|
-
'Content-Type': 'application/json',
|
|
5
|
-
...headers,
|
|
6
|
-
},
|
|
7
|
-
status
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// const ErrorBoundary = () => {
|
|
12
|
-
|
|
13
|
-
// }
|