~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
5a97fa61
—
Peter John 2 years ago
improve stuff
- bun.toml +0 -3
- package-lock.json +44 -25
- packages/example/bun.lockb +0 -0
- packages/example/components/Counter/Counter.jsx +1 -1
- packages/example/components/Todo/Todo.jsx +2 -0
- packages/example/containers/TodoList/TodoList.jsx +1 -0
- packages/example/jsconfig.json +5 -1
- packages/example/package.json +2 -2
- packages/example/routes/about/page.css +3 -0
- packages/example/routes/about/page.jsx +19 -0
- packages/example/routes/app.jsx +26 -0
- packages/example/routes/page.css +4 -0
- packages/example/routes/page.jsx +11 -4
- packages/parotta/cli.js +53 -31
bun.toml
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
[loaders]
|
|
2
|
-
".jsx" = "js"
|
|
3
|
-
".css" = "css"
|
package-lock.json
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "quickstart",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
|
-
"name": "parotta-workspace",
|
|
9
|
-
"version": "1.0.0",
|
|
10
8
|
"workspaces": [
|
|
11
9
|
"packages/example",
|
|
12
10
|
"packages/parotta"
|
|
13
|
-
]
|
|
11
|
+
]
|
|
14
|
-
"bin": {
|
|
15
|
-
"parotta": "package/parotta/cli"
|
|
16
|
-
}
|
|
17
12
|
},
|
|
18
13
|
"node_modules/js-tokens": {
|
|
19
14
|
"version": "4.0.0",
|
|
@@ -65,16 +60,38 @@
|
|
|
65
60
|
"loose-envify": "^1.1.0"
|
|
66
61
|
}
|
|
67
62
|
},
|
|
63
|
+
"node_modules/swr": {
|
|
64
|
+
"version": "2.1.0",
|
|
65
|
+
"resolved": "https://registry.npmjs.org/swr/-/swr-2.1.0.tgz",
|
|
66
|
+
"integrity": "sha512-4hYl5p3/KalQ1MORealM79g/DtLohmud6yyfXw5l4wjtFksYUnocRFudvyaoUtgj3FrVNK9lS25Av9dsZYvz0g==",
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"use-sync-external-store": "^1.2.0"
|
|
69
|
+
},
|
|
70
|
+
"engines": {
|
|
71
|
+
"pnpm": "7"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"node_modules/use-sync-external-store": {
|
|
78
|
+
"version": "1.2.0",
|
|
79
|
+
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
|
80
|
+
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
|
81
|
+
"peerDependencies": {
|
|
82
|
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
68
85
|
"packages/example": {
|
|
69
86
|
"name": "quickstart",
|
|
70
87
|
"dependencies": {
|
|
71
|
-
"parotta": "0.1.0",
|
|
72
88
|
"react": "18.2.0",
|
|
73
|
-
"react-dom": "^18.2.0"
|
|
89
|
+
"react-dom": "^18.2.0",
|
|
90
|
+
"swr": "2.1.0"
|
|
74
91
|
}
|
|
75
92
|
},
|
|
76
93
|
"packages/parotta": {
|
|
77
|
-
"version": "0.
|
|
94
|
+
"version": "0.2.0",
|
|
78
95
|
"dependencies": {
|
|
79
96
|
"autoprefixer": "^10.4.14",
|
|
80
97
|
"mime-types": "2.1.35",
|
|
@@ -86,10 +103,7 @@
|
|
|
86
103
|
"walkdir": "0.4.1"
|
|
87
104
|
},
|
|
88
105
|
"bin": {
|
|
89
|
-
"parotta": "cli"
|
|
106
|
+
"parotta": "cli.js"
|
|
90
|
-
},
|
|
91
|
-
"devDependencies": {
|
|
92
|
-
"bun-types": "^0.5.0"
|
|
93
107
|
}
|
|
94
108
|
},
|
|
95
109
|
"packages/parotta/node_modules/@csstools/cascade-layer-name-parser": {
|
|
@@ -223,10 +237,6 @@
|
|
|
223
237
|
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
|
224
238
|
}
|
|
225
239
|
},
|
|
226
|
-
"packages/parotta/node_modules/bun-types": {
|
|
227
|
-
"version": "0.5.7",
|
|
228
|
-
"dev": true
|
|
229
|
-
},
|
|
230
240
|
"packages/parotta/node_modules/caniuse-lite": {
|
|
231
241
|
"version": "1.0.30001468",
|
|
232
242
|
"funding": [
|
|
@@ -482,7 +492,6 @@
|
|
|
482
492
|
"version": "file:packages/parotta",
|
|
483
493
|
"requires": {
|
|
484
494
|
"autoprefixer": "^10.4.14",
|
|
485
|
-
"bun-types": "^0.5.0",
|
|
486
495
|
"mime-types": "2.1.35",
|
|
487
496
|
"postcss": "^8.4.21",
|
|
488
497
|
"postcss-custom-media": "^9.1.2",
|
|
@@ -534,10 +543,6 @@
|
|
|
534
543
|
"update-browserslist-db": "^1.0.10"
|
|
535
544
|
}
|
|
536
545
|
},
|
|
537
|
-
"bun-types": {
|
|
538
|
-
"version": "0.5.7",
|
|
539
|
-
"dev": true
|
|
540
|
-
},
|
|
541
546
|
"caniuse-lite": {
|
|
542
547
|
"version": "1.0.30001468"
|
|
543
548
|
},
|
|
@@ -647,9 +652,9 @@
|
|
|
647
652
|
"quickstart": {
|
|
648
653
|
"version": "file:packages/example",
|
|
649
654
|
"requires": {
|
|
650
|
-
"parotta": "0.1.0",
|
|
651
655
|
"react": "18.2.0",
|
|
652
|
-
"react-dom": "^18.2.0"
|
|
656
|
+
"react-dom": "^18.2.0",
|
|
657
|
+
"swr": "2.1.0"
|
|
653
658
|
}
|
|
654
659
|
},
|
|
655
660
|
"react": {
|
|
@@ -670,6 +675,20 @@
|
|
|
670
675
|
"requires": {
|
|
671
676
|
"loose-envify": "^1.1.0"
|
|
672
677
|
}
|
|
678
|
+
},
|
|
679
|
+
"swr": {
|
|
680
|
+
"version": "2.1.0",
|
|
681
|
+
"resolved": "https://registry.npmjs.org/swr/-/swr-2.1.0.tgz",
|
|
682
|
+
"integrity": "sha512-4hYl5p3/KalQ1MORealM79g/DtLohmud6yyfXw5l4wjtFksYUnocRFudvyaoUtgj3FrVNK9lS25Av9dsZYvz0g==",
|
|
683
|
+
"requires": {
|
|
684
|
+
"use-sync-external-store": "^1.2.0"
|
|
685
|
+
}
|
|
686
|
+
},
|
|
687
|
+
"use-sync-external-store": {
|
|
688
|
+
"version": "1.2.0",
|
|
689
|
+
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
|
690
|
+
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
|
691
|
+
"requires": {}
|
|
673
692
|
}
|
|
674
693
|
}
|
|
675
694
|
}
|
packages/example/bun.lockb
ADDED
|
Binary file
|
packages/example/components/Counter/Counter.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import React, { useState } from "react";
|
|
2
2
|
|
|
3
3
|
const Counter = () => {
|
|
4
4
|
const [count, setCount] = useState(5);
|
packages/example/components/Todo/Todo.jsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
1
3
|
const Todo = ({ id, text }) => {
|
|
2
4
|
return (
|
|
3
5
|
<div id={id}>
|
packages/example/containers/TodoList/TodoList.jsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import Todo from "@/components/Todo/Todo";
|
|
2
3
|
|
|
3
4
|
const todos = [
|
packages/example/jsconfig.json
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
"@/*": [
|
|
5
5
|
"./*"
|
|
6
6
|
]
|
|
7
|
-
}
|
|
7
|
+
},
|
|
8
|
+
// TODO these options are not supported
|
|
9
|
+
"jsx": "react",
|
|
10
|
+
"jsxFactory": "React.createElement",
|
|
11
|
+
"jsxImportSource": "react"
|
|
8
12
|
}
|
|
9
13
|
}
|
packages/example/package.json
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"run": "docker run -p 3000:3000 example"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"parotta": "0.1.0",
|
|
12
11
|
"react": "18.2.0",
|
|
13
|
-
"react-dom": "^18.2.0"
|
|
12
|
+
"react-dom": "^18.2.0",
|
|
13
|
+
"swr": "2.1.0"
|
|
14
14
|
}
|
|
15
15
|
}
|
packages/example/routes/about/page.css
CHANGED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
.about-page {
|
|
2
|
+
padding: 100px;
|
|
3
|
+
}
|
packages/example/routes/about/page.jsx
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useRouter } from "parotta/router";
|
|
3
|
+
import "./page.css";
|
|
4
|
+
|
|
5
|
+
const AboutPage = () => {
|
|
6
|
+
const router = useRouter();
|
|
7
|
+
return (
|
|
8
|
+
<div className="about-page">
|
|
9
|
+
<div>
|
|
10
|
+
<h1>About Page</h1>
|
|
11
|
+
<p>
|
|
12
|
+
Path: {router.pathname}
|
|
13
|
+
</p>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default AboutPage;
|
packages/example/routes/app.jsx
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, { Suspense } from "react";
|
|
2
|
+
import { SWRConfig } from "swr";
|
|
3
|
+
import { RouterProvider } from "parotta/router";
|
|
4
|
+
import { ErrorBoundary } from "parotta/error";
|
|
5
|
+
|
|
6
|
+
const App = ({ routerProps, children }) => {
|
|
7
|
+
return (
|
|
8
|
+
<RouterProvider value={routerProps}>
|
|
9
|
+
<SWRConfig value={{
|
|
10
|
+
fallback: {
|
|
11
|
+
'https://jsonplaceholder.typicode.com/todos/1': { id: '123' },
|
|
12
|
+
},
|
|
13
|
+
// fallbackData: null,
|
|
14
|
+
fetcher: (resource, init) => fetch(resource, init).then(res => res.json()), suspense: true
|
|
15
|
+
}}>
|
|
16
|
+
<ErrorBoundary onError={(err) => console.log(err)} fallback={<p>Oops something went wrong</p>}>
|
|
17
|
+
<Suspense fallback={<p>Loading...</p>}>
|
|
18
|
+
{children}
|
|
19
|
+
</Suspense>
|
|
20
|
+
</ErrorBoundary>
|
|
21
|
+
</SWRConfig>
|
|
22
|
+
</RouterProvider>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default App;
|
packages/example/routes/page.css
CHANGED
|
@@ -8,4 +8,8 @@
|
|
|
8
8
|
font-size: 30px;
|
|
9
9
|
font-weight: 600;
|
|
10
10
|
}
|
|
11
|
+
|
|
12
|
+
& footer {
|
|
13
|
+
margin-top: 100px;
|
|
14
|
+
}
|
|
11
15
|
}
|
packages/example/routes/page.jsx
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import useSWR from "swr";
|
|
3
|
+
import { useRouter } from "parotta/router";
|
|
1
4
|
import Counter from "@/components/Counter/Counter";
|
|
2
|
-
// import { useRouter } from "muffinjs/router.js";
|
|
3
5
|
import "./page.css";
|
|
4
6
|
|
|
5
7
|
const HomePage = () => {
|
|
8
|
+
// const todo = useAsync('123', () => getData());
|
|
9
|
+
const { data } = useSWR(`https://jsonplaceholder.typicode.com/todos/1`);
|
|
6
|
-
|
|
10
|
+
const router = useRouter();
|
|
7
11
|
return (
|
|
8
12
|
<div className="home-page">
|
|
9
13
|
<div>
|
|
10
14
|
<h1>Home Page</h1>
|
|
11
|
-
|
|
15
|
+
<p>
|
|
12
16
|
Path: {router.pathname}
|
|
13
|
-
</p>
|
|
17
|
+
</p>
|
|
14
18
|
<Counter />
|
|
15
19
|
</div>
|
|
20
|
+
<footer>
|
|
21
|
+
<a href="/about">About us</a>
|
|
22
|
+
</footer>
|
|
16
23
|
</div>
|
|
17
24
|
)
|
|
18
25
|
}
|
packages/parotta/cli.js
CHANGED
|
@@ -7,24 +7,19 @@ import autoprefixer from "autoprefixer";
|
|
|
7
7
|
import postcssCustomMedia from "postcss-custom-media";
|
|
8
8
|
// import postcssNormalize from 'postcss-normalize';
|
|
9
9
|
import postcssNesting from "postcss-nesting";
|
|
10
|
-
import { renderToReadableStream } from 'react-dom/server';
|
|
11
10
|
import { createRouter } from 'radix3';
|
|
12
11
|
import mimeTypes from "mime-types";
|
|
12
|
+
import { renderToReadableStream } from 'react-dom/server';
|
|
13
|
-
import {
|
|
13
|
+
// import { renderToStream } from './render';
|
|
14
14
|
|
|
15
|
+
const version = (await import(path.join(import.meta.dir, "package.json"))).default.version;
|
|
16
|
+
console.log(`parotta v${version}`)
|
|
15
17
|
console.log("running in folder:", path.basename(process.cwd()), "env:", process.env.NODE_ENV);
|
|
16
18
|
// console.log("deleting cache");
|
|
17
19
|
// rmSync(path.join(process.cwd(), ".cache"), { force: true, recursive: true })
|
|
18
20
|
|
|
19
21
|
const isProd = process.env.NODE_ENV === "production";
|
|
20
22
|
|
|
21
|
-
const transpiler = new Bun.Transpiler({
|
|
22
|
-
loader: "jsx",
|
|
23
|
-
autoImportJSX: true,
|
|
24
|
-
jsxOptimizationInline: true,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
|
|
28
23
|
const mapFiles = () => {
|
|
29
24
|
const routes = {};
|
|
30
25
|
const dirs = walkdir.sync(path.join(process.cwd(), "routes"))
|
|
@@ -65,16 +60,21 @@ const mapDeps = (dir) => {
|
|
|
65
60
|
}, {});
|
|
66
61
|
}
|
|
67
62
|
|
|
63
|
+
const removeCwd = (s) => s.replace(process.cwd(), "")
|
|
64
|
+
|
|
68
|
-
const hydrateScript = (
|
|
65
|
+
const hydrateScript = (appPath, pagePath, routerProps) => {
|
|
69
66
|
return `
|
|
70
|
-
import React from
|
|
67
|
+
import React from "react";
|
|
71
|
-
import { hydrateRoot } from
|
|
68
|
+
import { hydrateRoot } from "react-dom/client";
|
|
72
|
-
import
|
|
69
|
+
import App from "${removeCwd(appPath)}";
|
|
73
|
-
import Page from "${
|
|
70
|
+
import Page from "${removeCwd(pagePath)}";
|
|
74
71
|
|
|
75
|
-
|
|
72
|
+
const routerProps = ${JSON.stringify(routerProps)};
|
|
76
73
|
|
|
77
|
-
hydrateRoot(document.getElementById("root"), React.createElement(
|
|
74
|
+
hydrateRoot(document.getElementById("root"), React.createElement(App, {
|
|
75
|
+
routerProps: routerProps,
|
|
76
|
+
children: React.createElement(Page, {}),
|
|
77
|
+
}));
|
|
78
78
|
`;
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -113,23 +113,23 @@ const renderPage = async (filePath, url, params) => {
|
|
|
113
113
|
for (const key of url.searchParams.keys()) {
|
|
114
114
|
query[key] = url.searchParams.get(key);
|
|
115
115
|
}
|
|
116
|
-
const
|
|
116
|
+
const routerProps = {
|
|
117
117
|
query: query,
|
|
118
118
|
params: params,
|
|
119
119
|
pathname: url.pathname,
|
|
120
120
|
}
|
|
121
|
-
|
|
121
|
+
const appPath = path.join(process.cwd(), "routes", "app.jsx");
|
|
122
|
-
const
|
|
122
|
+
const pagePath = path.join(process.cwd(), filePath);
|
|
123
123
|
const packageJson = await import(path.join(process.cwd(), "package.json"));
|
|
124
124
|
const devTag = !isProd ? "?dev" : "";
|
|
125
125
|
const nodeDeps = Object.keys(packageJson.default.dependencies).reduce((acc, dep) => {
|
|
126
|
-
acc[dep] = `https://esm.sh/${dep}@${packageJson.default.dependencies[dep]}
|
|
126
|
+
acc[dep] = `https://esm.sh/${dep}@${packageJson.default.dependencies[dep]}`;
|
|
127
127
|
return acc;
|
|
128
128
|
}, {})
|
|
129
|
+
const App = (await import(appPath)).default;
|
|
129
|
-
const Page =
|
|
130
|
+
const Page = (await import(pagePath)).default;
|
|
130
131
|
const components = mapDeps("components");
|
|
131
132
|
const containers = mapDeps("containers");
|
|
132
|
-
const parottaVersion = packageJson.default.dependencies["parotta"];
|
|
133
133
|
const cssFile = `${filePath.replace("jsx", "css")}`;
|
|
134
134
|
const stream = await renderToReadableStream(
|
|
135
135
|
<html lang="en">
|
|
@@ -141,9 +141,12 @@ const renderPage = async (filePath, url, params) => {
|
|
|
141
141
|
{
|
|
142
142
|
"imports": {
|
|
143
143
|
"radix3": `https://esm.sh/radix3`,
|
|
144
|
-
"react
|
|
144
|
+
"react": `https://esm.sh/react@18.2.0`,
|
|
145
|
-
"react/jsx-dev-runtime": `https://esm.sh/react@18.2.0/jsx-dev-runtime
|
|
145
|
+
"react/jsx-dev-runtime": `https://esm.sh/react@18.2.0/jsx-dev-runtime`,
|
|
146
|
+
"react-dom/client": `https://esm.sh/react-dom@18.2.0/client`,
|
|
147
|
+
"react-streaming": "https://esm.sh/react-streaming",
|
|
146
|
-
"parotta/router": `https://esm.sh/parotta@${
|
|
148
|
+
"parotta/router": `https://esm.sh/parotta@${version}/router.js`,
|
|
149
|
+
"parotta/error": `https://esm.sh/parotta@${version}/error.js`,
|
|
147
150
|
...nodeDeps,
|
|
148
151
|
...components,
|
|
149
152
|
...containers,
|
|
@@ -152,8 +155,8 @@ const renderPage = async (filePath, url, params) => {
|
|
|
152
155
|
)
|
|
153
156
|
}}>
|
|
154
157
|
</script>
|
|
155
|
-
<script type="module" defer dangerouslySetInnerHTML={{
|
|
158
|
+
<script type="module" defer={true} dangerouslySetInnerHTML={{
|
|
156
|
-
__html: hydrateScript(
|
|
159
|
+
__html: hydrateScript(appPath, pagePath, routerProps)
|
|
157
160
|
}}></script>
|
|
158
161
|
<title>
|
|
159
162
|
Parotta
|
|
@@ -161,11 +164,14 @@ const renderPage = async (filePath, url, params) => {
|
|
|
161
164
|
</head>
|
|
162
165
|
<body>
|
|
163
166
|
<div id="root">
|
|
167
|
+
<App routerProps={routerProps}>
|
|
164
|
-
|
|
168
|
+
<Page />
|
|
169
|
+
</App>
|
|
165
170
|
</div>
|
|
166
171
|
</body>
|
|
167
172
|
</html >
|
|
168
173
|
);
|
|
174
|
+
// injectToStream('<script type="module" src="/main.js"></script>', { flush: true });
|
|
169
175
|
return new Response(stream, {
|
|
170
176
|
headers: { 'Content-Type': 'text/html' },
|
|
171
177
|
status: 200,
|
|
@@ -193,11 +199,23 @@ const renderCss = async (url) => {
|
|
|
193
199
|
}
|
|
194
200
|
}
|
|
195
201
|
|
|
202
|
+
const transpiler = new Bun.Transpiler({
|
|
203
|
+
loader: "jsx",
|
|
204
|
+
autoImportJSX: true,
|
|
205
|
+
jsxOptimizationInline: true,
|
|
206
|
+
|
|
207
|
+
// TODO
|
|
208
|
+
// autoImportJSX: false,
|
|
209
|
+
// jsxOptimizationInline: false,
|
|
210
|
+
});
|
|
211
|
+
|
|
196
|
-
const renderJs = async (
|
|
212
|
+
const renderJs = async (src) => {
|
|
197
213
|
try {
|
|
198
|
-
const jsText = await Bun.file(
|
|
214
|
+
const jsText = await Bun.file(src).text();
|
|
199
215
|
const result = await transpiler.transform(jsText);
|
|
200
216
|
const js = result.replaceAll(`import"./page.css";`, "");
|
|
217
|
+
// TODO
|
|
218
|
+
//.replaceAll("$jsx", "React.createElement");
|
|
201
219
|
return new Response(js, {
|
|
202
220
|
headers: { 'Content-Type': 'application/javascript' },
|
|
203
221
|
status: 200,
|
|
@@ -234,8 +252,12 @@ export default {
|
|
|
234
252
|
return renderCss(url);
|
|
235
253
|
}
|
|
236
254
|
if (url.pathname.endsWith(".js") || url.pathname.endsWith(".jsx")) {
|
|
237
|
-
return renderJs(url);
|
|
255
|
+
return renderJs(path.join(process.cwd(), url.pathname));
|
|
238
256
|
}
|
|
257
|
+
// maybe this is needed
|
|
258
|
+
// if (url.pathname.startsWith("/parotta/")) {
|
|
259
|
+
// return renderJs(path.join(import.meta.dir, url.pathname.replace("/parotta/", "")) + ".js");
|
|
260
|
+
// }
|
|
239
261
|
const match = radixRouter.lookup(url.pathname);
|
|
240
262
|
if (match) {
|
|
241
263
|
if (match.file) {
|