edge-city

#react#js#ssr

git clone https://git.pyrossh.dev/edge-city

edge-city is a next level meta-framework for react that runs only on edge runtimes


c35b08d — Peter John 2023-05-22T11:10:26+05:30
rename app

Generated files not shown: package-lock.json, pnpm-lock.yaml

Files changed (44) hide show
  1. packages/cli/index.js → edge-city/cli.js +18 -11
  2. {packages/runtime → edge-city}/index.js +0 -0
  3. {packages/cli → edge-city}/package.json +12 -5
  4. {packages/example → example}/.gitignore +0 -0
  5. {packages/example → example}/.vscode/extensions.json +0 -0
  6. {packages/example → example}/.vscode/settings.json +0 -0
  7. {packages/example → example}/components/Counter/Counter.jsx +0 -0
  8. {packages/example → example}/components/Layout/Layout.css +0 -0
  9. {packages/example → example}/components/Layout/Layout.jsx +1 -1
  10. {packages/example → example}/components/Timer/Timer.jsx +0 -0
  11. {packages/example → example}/components/Todo/Todo.css +0 -0
  12. {packages/example → example}/components/Todo/Todo.jsx +0 -0
  13. {packages/example → example}/db/index.js +0 -0
  14. {packages/example → example}/db/migrations/0000_empty_shatterstar.sql +0 -0
  15. {packages/example → example}/db/migrations/meta/0000_snapshot.json +0 -0
  16. {packages/example → example}/db/migrations/meta/_journal.json +0 -0
  17. {packages/example → example}/drizzle.config.json +0 -0
  18. {packages/example → example}/jsconfig.json +0 -0
  19. {packages/example → example}/package.json +5 -9
  20. {packages/example → example}/pages/_404/page.css +0 -0
  21. {packages/example → example}/pages/_404/page.jsx +0 -0
  22. {packages/example → example}/pages/_500/page.css +0 -0
  23. {packages/example → example}/pages/_500/page.jsx +0 -0
  24. {packages/example → example}/pages/about/page.css +0 -0
  25. {packages/example → example}/pages/about/page.jsx +8 -5
  26. {packages/example → example}/pages/page.css +0 -0
  27. {packages/example → example}/pages/page.jsx +2 -2
  28. {packages/example → example}/pages/page.spec.js +1 -1
  29. {packages/example → example}/playwright.config.js +3 -4
  30. example/readme.md +22 -0
  31. {packages/example → example}/services/auth.service.js +0 -0
  32. {packages/example → example}/services/todos.service.js +0 -0
  33. {packages/example → example}/services/todos.service.test.js +0 -0
  34. {packages/example → example}/static/favicon.ico +0 -0
  35. {packages/example → example}/static/logo192.png +0 -0
  36. {packages/example → example}/static/logo512.png +0 -0
  37. {packages/example → example}/static/manifest.json +0 -0
  38. {packages/example → example}/static/robots.txt +0 -0
  39. {packages/cli → example/static}/todos/page.css +0 -0
  40. {packages/cli → example/static}/todos/page.jsx +1 -1
  41. packages/example/readme.md +0 -18
  42. packages/runtime/package.json +0 -16
  43. pnpm-workspace.yaml +2 -1
  44. readme.md +16 -9
packages/cli/index.js → edge-city/cli.js RENAMED
@@ -14,13 +14,14 @@ import pc from 'picocolors';
14
14
  import ms from 'ms';
15
15
 
16
16
  const __dirname = path.dirname(import.meta.url.replace("file://", ""));
17
+ const appName = "edge-city";
17
18
  const version = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"))).version;
18
19
  const cli = meow(`
19
- parotta v${version}
20
+ ${appName} v${version}
20
21
 
21
22
  Usage
22
- $ parotta build cloudflare
23
+ $ ${appName} build cloudflare
23
- $ parotta build vercel
24
+ $ ${appName} build vercel
24
25
  `, {
25
26
  importMeta: import.meta,
26
27
  autoVersion: true,
@@ -29,7 +30,7 @@ if (cli.input.length != 2) {
29
30
  cli.showHelp();
30
31
  process.exit(0);
31
32
  }
32
- console.log(`parotta v${version}`)
33
+ console.log(`${appName} v${version}`)
33
34
  console.log(`running with NODE_ENV=${process.env.NODE_ENV}`);
34
35
 
35
36
  const ensureDir = (d) => {
@@ -38,11 +39,17 @@ const ensureDir = (d) => {
38
39
  }
39
40
  }
40
41
 
42
+ const cleanDir = (d) => {
43
+ if (fs.existsSync(d)) {
44
+ fs.rmSync(d, { recursive: true });
45
+ }
46
+ }
47
+
41
48
  const isProd = process.env.NODE_ENV === "production";
42
49
  const buildDir = path.join(process.cwd(), "build");
43
50
  const staticDir = path.join(buildDir, "static");
44
51
  const createDirs = () => {
45
- fs.rmSync(buildDir, { recursive: true });
52
+ cleanDir(buildDir);
46
53
  ensureDir(buildDir);
47
54
  ensureDir(staticDir);
48
55
  }
@@ -133,12 +140,12 @@ const bundlePages = async () => {
133
140
  const buildStart = Date.now();
134
141
  const outfile = `build/functions${r.out}`;
135
142
  await bundleJs({ entryPoints: [r.in], outfile }, {
136
- name: "parotta-page-plugin",
143
+ name: "page-plugin",
137
144
  setup(build) {
138
145
  build.onLoad({ filter: /\\*.page.jsx/, namespace: undefined }, (args) => {
139
146
  const data = fs.readFileSync(args.path);
140
147
  const newSrc = `
141
- import { renderPage } from "parotta-runtime";
148
+ import { renderPage } from "edge-city";
142
149
  ${data.toString()}
143
150
 
144
151
  export function onRequest(context) {
@@ -175,12 +182,12 @@ const bundlePages = async () => {
175
182
  entryNames: '[dir]/[name]',
176
183
  chunkNames: 'chunks/[name]-[hash]'
177
184
  }, {
178
- name: "parotta-page-js-plugin",
185
+ name: "page-js-plugin",
179
186
  setup(build) {
180
187
  build.onLoad({ filter: /\\*.page.jsx/, namespace: undefined }, (args) => {
181
188
  const data = fs.readFileSync(args.path);
182
189
  const newSrc = `
183
- import { hydrateApp } from "parotta-runtime";
190
+ import { hydrateApp } from "edge-city";
184
191
  ${data.toString()}
185
192
 
186
193
  const searchParams = new URL(import.meta.url).searchParams;
@@ -216,7 +223,7 @@ const bundleServices = async () => {
216
223
  for (const p of Object.keys(pkg)) {
217
224
  const buildStart = Date.now();
218
225
  const result = await bundleJs({ write: false }, s, `build/functions/_rpc${dest}.js`, {
219
- name: "parotta-service-plugin",
226
+ name: "service-plugin",
220
227
  setup(build) {
221
228
  build.onLoad({ filter: /\\*.service.js/, namespace: undefined }, async (args) => {
222
229
  const src = fs.readFileSync(args.path);
@@ -301,7 +308,7 @@ main();
301
308
  // }
302
309
  // })
303
310
  // if (addRpcImport) {
304
- // lines.unshift(`import { rpc } from "parotta/runtime";`);
311
+ // lines.unshift(`import { rpc } from "edge-city";`);
305
312
  // }
306
313
  // // remove .css and .service imports
307
314
  // const filteredJsx = lines.filter((ln) => !ln.includes(`.css"`) && !ln.includes(`.service"`)).join("\n");
{packages/runtime → edge-city}/index.js RENAMED
File without changes
{packages/cli → edge-city}/package.json RENAMED
@@ -1,15 +1,19 @@
1
1
  {
2
- "name": "parotta-cli",
2
+ "name": "edge-city",
3
3
  "version": "0.5.0",
4
4
  "type": "module",
5
+ "main": "index.js",
5
6
  "dependencies": {
7
+ "history": "^5.3.0",
8
+ "radix3": "^1.0.0"
9
+ },
10
+ "devDependencies": {
6
11
  "autoprefixer": "^10.4.14",
7
12
  "bytes": "3.1.2",
8
13
  "esbuild": "0.17.19",
9
14
  "meow": "12.0.1",
10
15
  "mime-types": "2.1.35",
11
16
  "ms": "2.1.3",
12
- "parotta-runtime": "workspace:*",
13
17
  "picocolors": "1.0.0",
14
18
  "postcss": "^8.4.21",
15
19
  "postcss-custom-media": "^9.1.2",
@@ -19,9 +23,12 @@
19
23
  },
20
24
  "peerDependencies": {
21
25
  "react": "*",
22
- "react-dom": "*"
26
+ "react-dom": "*",
27
+ "nprogress": "*",
28
+ "react-error-boundary": "*",
29
+ "react-helmet-async": "*"
23
30
  },
24
31
  "bin": {
25
- "parotta": "index.js"
32
+ "edge-city": "cli.js"
26
33
  }
27
- }
34
+ }
{packages/example → example}/.gitignore RENAMED
File without changes
{packages/example → example}/.vscode/extensions.json RENAMED
File without changes
{packages/example → example}/.vscode/settings.json RENAMED
File without changes
{packages/example → example}/components/Counter/Counter.jsx RENAMED
File without changes
{packages/example → example}/components/Layout/Layout.css RENAMED
File without changes
{packages/example → example}/components/Layout/Layout.jsx RENAMED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Link } from "parotta-runtime";
2
+ import { Link } from "edge-city";
3
3
  import "modern-normalize";
4
4
  import "nprogress";
5
5
  import "./Layout.css";
{packages/example → example}/components/Timer/Timer.jsx RENAMED
File without changes
{packages/example → example}/components/Todo/Todo.css RENAMED
File without changes
{packages/example → example}/components/Todo/Todo.jsx RENAMED
File without changes
{packages/example → example}/db/index.js RENAMED
File without changes
{packages/example → example}/db/migrations/0000_empty_shatterstar.sql RENAMED
File without changes
{packages/example → example}/db/migrations/meta/0000_snapshot.json RENAMED
File without changes
{packages/example → example}/db/migrations/meta/_journal.json RENAMED
File without changes
{packages/example → example}/drizzle.config.json RENAMED
File without changes
{packages/example → example}/jsconfig.json RENAMED
File without changes
{packages/example → example}/package.json RENAMED
@@ -1,10 +1,10 @@
1
1
  {
2
- "name": "parotta-example",
2
+ "name": "edge-city-example",
3
3
  "type": "module",
4
4
  "scripts": {
5
- "dev": "parotta build cloudflare",
5
+ "dev": "edge-city build cloudflare",
6
6
  "dev-server": "wrangler pages dev static --local --live-reload",
7
- "build": "NODE_ENV=production parotta build cloudflare",
7
+ "build": "NODE_ENV=production edge-city build cloudflare",
8
8
  "test": "bun test",
9
9
  "test-e2e": "playwright test"
10
10
  },
@@ -14,7 +14,7 @@
14
14
  "modern-normalize": "^2.0.0",
15
15
  "normalize.css": "^8.0.1",
16
16
  "nprogress": "0.2.0",
17
- "parotta-runtime": "workspace:*",
17
+ "edge-city": "workspace:*",
18
18
  "react": "18.2.0",
19
19
  "react-aria-components": "1.0.0-alpha.3",
20
20
  "react-dom": "18.2.0",
@@ -27,11 +27,7 @@
27
27
  "devDependencies": {
28
28
  "@playwright/test": "^1.31.2",
29
29
  "eslint": "^8.35.0",
30
- "eslint-config-react-app": "^7.0.1",
30
+ "eslint-config-react-app": "^7.0.1"
31
- "parotta-cli": "workspace:*"
32
- },
33
- "parotta": {
34
- "hydrate": true
35
31
  },
36
32
  "prettier": {
37
33
  "printWidth": 120
{packages/example → example}/pages/_404/page.css RENAMED
File without changes
{packages/example → example}/pages/_404/page.jsx RENAMED
File without changes
{packages/example → example}/pages/_500/page.css RENAMED
File without changes
{packages/example → example}/pages/_500/page.jsx RENAMED
File without changes
{packages/example → example}/pages/about/page.css RENAMED
File without changes
{packages/example → example}/pages/about/page.jsx RENAMED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Link, useRouter } from "parotta-runtime";
2
+ import { Link, useRouter } from "edge-city";
3
3
  import { Helmet } from 'react-helmet-async';
4
4
  import Layout from '@/components/Layout/Layout';
5
5
  import "./page.css";
@@ -10,12 +10,15 @@ export const Page = () => {
10
10
  <Layout>
11
11
  <div className="about-page">
12
12
  <Helmet>
13
- <title>About Page @ {router.pathname}</title>
13
+ <title>About | Edge City</title>
14
- <meta name="description" content="Showcase of using parotta meta-framework." />
14
+ <meta name="description" content="Showcase of using edge-city meta-framework." />
15
15
  </Helmet>
16
16
  <div>
17
- <h1>About Page @ {router.pathname}</h1>
17
+ <h1>About Page</h1>
18
+ <p>
19
+ Path: {router.pathname}
20
+ </p>
18
- <p>Showcase of using parotta meta-framework.</p>
21
+ <p>Showcase of using edge-city meta-framework.</p>
19
22
  </div>
20
23
  <footer>
21
24
  <Link href="/">Back</Link>
{packages/example → example}/pages/page.css RENAMED
File without changes
{packages/example → example}/pages/page.jsx RENAMED
@@ -1,5 +1,5 @@
1
1
  import { useEffect } from 'react';
2
- import { useRouter } from "parotta-runtime";
2
+ import { useRouter } from "edge-city";
3
3
  import Layout from '@/components/Layout/Layout';
4
4
  import Counter from "@/components/Counter/Counter";
5
5
  import { Helmet } from 'react-helmet-async';
@@ -13,7 +13,7 @@ const Page = () => {
13
13
  return (
14
14
  <Layout>
15
15
  <Helmet>
16
- <title>Parotta App</title>
16
+ <title>Edge City</title>
17
17
  </Helmet>
18
18
  <div className="home-page">
19
19
  <h1>Home Page</h1>
{packages/example → example}/pages/page.spec.js RENAMED
@@ -6,7 +6,7 @@
6
6
  // })
7
7
 
8
8
  // test('has title', async ({ page }) => {
9
- // await expect(page).toHaveTitle(/Parotta/);
9
+ // await expect(page).toHaveTitle(/Edge City/);
10
10
  // });
11
11
 
12
12
  // test('has links', async ({ page }) => {
{packages/example → example}/playwright.config.js RENAMED
@@ -58,8 +58,7 @@ export default defineConfig({
58
58
  ],
59
59
  outputDir: 'test-results/',
60
60
  webServer: {
61
- command: '../parotta/cli.js',
61
+ command: 'npm run dev',
62
- port: 3000,
62
+ port: 8788,
63
63
  },
64
- });
64
+ });
65
-
example/readme.md ADDED
@@ -0,0 +1,22 @@
1
+ # Sample edge-city app
2
+
3
+ ## Requirements
4
+
5
+ 1. node >= v20
6
+
7
+ ## Setup
8
+
9
+ 1. `npm i`
10
+ 2. `npx playright install`
11
+
12
+ ## Running
13
+
14
+ `npm run dev`
15
+
16
+ ## Testing
17
+
18
+ `npm test`
19
+
20
+ ## Build
21
+
22
+ `npm run build`
{packages/example → example}/services/auth.service.js RENAMED
File without changes
{packages/example → example}/services/todos.service.js RENAMED
File without changes
{packages/example → example}/services/todos.service.test.js RENAMED
File without changes
{packages/example → example}/static/favicon.ico RENAMED
File without changes
{packages/example → example}/static/logo192.png RENAMED
File without changes
{packages/example → example}/static/logo512.png RENAMED
File without changes
{packages/example → example}/static/manifest.json RENAMED
File without changes
{packages/example → example}/static/robots.txt RENAMED
File without changes
{packages/cli → example/static}/todos/page.css RENAMED
File without changes
{packages/cli → example/static}/todos/page.jsx RENAMED
@@ -1,6 +1,6 @@
1
1
  import React, { Suspense } from 'react';
2
2
  import { Helmet } from 'react-helmet-async';
3
- import { useQuery, useMutation } from "parotta-runtime";
3
+ import { useQuery, useMutation } from "edge-city";
4
4
  import { useForm } from 'react-hook-form';
5
5
  import Todo from "@/components/Todo/Todo";
6
6
  import { TextField, Label, Input } from 'react-aria-components';
packages/example/readme.md DELETED
@@ -1,18 +0,0 @@
1
- # Sample Parotta Application
2
-
3
- ## Requirements
4
-
5
- 1. bun >= v0.5.8
6
-
7
- ## Setup
8
-
9
- 1. `bun i`
10
- 2. `bunx playright install`
11
-
12
- ## Running
13
-
14
- `bun run dev`
15
-
16
- ## Testing
17
-
18
- `bun test`
packages/runtime/package.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "name": "parotta-runtime",
3
- "version": "0.5.0",
4
- "type": "module",
5
- "dependencies": {
6
- "history": "^5.3.0",
7
- "radix3": "^1.0.0"
8
- },
9
- "peerDependencies": {
10
- "react": "*",
11
- "react-dom": "*",
12
- "nprogress": "*",
13
- "react-error-boundary": "*",
14
- "react-helmet-async": "*"
15
- }
16
- }
pnpm-workspace.yaml CHANGED
@@ -1,2 +1,3 @@
1
1
  packages:
2
- - 'packages/*'
2
+ - 'edge-city'
3
+ - 'example'
readme.md CHANGED
@@ -1,20 +1,27 @@
1
- # parotta
1
+ # Edge City
2
2
 
3
- parotta is a next level meta-framework for react that runs only on edge runtimes.
3
+ edge-city is a next level meta-framework for react that runs only on edge runtimes.
4
- It uses bun as its bundler/transpiler and development mode as its quick and fast.
4
+ It uses esbuild as its bundler/transpiler.
5
- It uses File System routing with streaming SSR + CSR as the method to render pages.
5
+ It uses file system routing (similar to next app router) with streaming SSR + CSR render pages.
6
6
  It is very opionated and has set of idiomatic ways of doing things.
7
7
  It has an inbuilt rpc mechanism to access server resources instead of a typical REST API.
8
+ It aims to have almost the same router api as nextjs router for ease of use.
8
9
 
9
- During development each request for a page is executed in a separate vercel edge-runtime vm.
10
+ During development each request for a page is executed in a separate edge-runtime (miniflare/vercel) vm.
10
11
  During production each page is packaged to an esm function adapted to the platform of your choice.
11
12
 
12
- ### Todo
13
+ ## Why?
13
- 1. Hydrate rpc cache
14
- 2. Build a docs website using parotta
14
+ Because its really hard to have a streaming SSR + CSR setup in nextjs currently.
15
+ The only other framework is rakkasjs but it doesn't maitaing as smooth transition from nextjs.
15
16
 
16
17
  ### Supported platforms
17
18
  1. [Cloudflare page functions](https://developers.cloudflare.com/pages/platform/functions/routing/)
18
19
  2. [Vercel edge functions](https://vercel.com/docs/concepts/functions/edge-functions)
19
20
  3. [Netlify edge functions](https://docs.netlify.com/edge-functions/overview/)
20
- 4. [Deno Deploy](https://deno.com/deploy)
21
+ 4. [Deno Deploy](https://deno.com/deploy)
22
+
23
+ ### Todo
24
+ 1. Hydrate rpc cache
25
+ 2. Build a docs website
26
+ 3. Fix 404/500 pages not routing
27
+ 3. Add Env variables `PUBLIC_` for client