~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


1fc95d95 Peter John

2 years ago
Fix example
Files changed (49) hide show
  1. .gitignore +5 -1
  2. {example/.vscode → .vscode}/extensions.json +0 -0
  3. {example/.vscode → .vscode}/settings.json +0 -0
  4. example/Dockerfile → Dockerfile +0 -0
  5. bin/create-app.js +0 -31
  6. bun.lockb +0 -0
  7. {example/components → components}/Counter/Counter.jsx +0 -0
  8. {example/components → components}/Timer/Timer.jsx +0 -0
  9. {example/components → components}/Todo/Todo.css +0 -0
  10. {example/components → components}/Todo/Todo.jsx +0 -0
  11. {example/containers → containers}/TodoList/TodoList.jsx +0 -0
  12. {example/db → db}/index.js +0 -0
  13. {example/db → db}/migrations/0000_empty_shatterstar.sql +0 -0
  14. {example/db → db}/migrations/meta/0000_snapshot.json +0 -0
  15. {example/db → db}/migrations/meta/_journal.json +0 -0
  16. example/drizzle.config.json → drizzle.config.json +0 -0
  17. example/.gitignore +0 -5
  18. example/bun.lockb +0 -0
  19. example/main.js +0 -3
  20. example/package.json +0 -55
  21. example/readme.md +0 -18
  22. example/jsconfig.json → jsconfig.json +0 -0
  23. main.js +8 -0
  24. package.json +48 -21
  25. {example/pages → pages}/404/page.css +0 -0
  26. {example/pages → pages}/404/page.jsx +0 -0
  27. {example/pages → pages}/about/page.css +0 -0
  28. {example/pages → pages}/about/page.jsx +0 -0
  29. {example/pages → pages}/layout.css +0 -0
  30. {example/pages → pages}/layout.jsx +0 -0
  31. {example/pages → pages}/page.css +0 -0
  32. {example/pages → pages}/page.jsx +0 -0
  33. {example/pages → pages}/page.spec.js +0 -0
  34. {example/pages → pages}/todos/page.css +0 -0
  35. {example/pages → pages}/todos/page.jsx +0 -0
  36. parotta/bun.lockb +0 -0
  37. parotta/package.json +15 -0
  38. parotta/readme.md +13 -0
  39. runtime.js → parotta/runtime.js +0 -0
  40. bin/cli.js → parotta/server.js +40 -50
  41. example/playwright.config.js → playwright.config.js +0 -0
  42. readme.md +18 -13
  43. {example/services → services}/auth.service.js +0 -0
  44. {example/services → services}/todos.service.js +0 -0
  45. {example/static → static}/favicon.ico +0 -0
  46. {example/static → static}/logo192.png +0 -0
  47. {example/static → static}/logo512.png +0 -0
  48. {example/static → static}/manifest.json +0 -0
  49. {example/static → static}/robots.txt +0 -0
.gitignore CHANGED
@@ -1 +1,5 @@
1
+ .cache
2
+ .dist
1
- node_modules
3
+ node_modules
4
+ .env
5
+ test-results
{example/.vscode → .vscode}/extensions.json RENAMED
File without changes
{example/.vscode → .vscode}/settings.json RENAMED
File without changes
example/Dockerfile → Dockerfile RENAMED
File without changes
bin/create-app.js DELETED
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- import { Command } from 'commander';
4
- import path from 'path';
5
- import fs from 'fs';
6
- import os from 'os';
7
- import chalk from 'chalk';
8
- import gunzip from 'gunzip-file';
9
- import packageJson from './package.json'
10
-
11
- process.on('SIGINT', () => process.exit(0))
12
- process.on('SIGTERM', () => process.exit(0))
13
-
14
- let projectPath = "";
15
- const program = new Command(packageJson.name)
16
- .version(packageJson.version)
17
- .arguments('<project-directory>')
18
- .usage(`${chalk.green('<project-directory>')} [options]`)
19
- .action((name) => {
20
- projectPath = name
21
- })
22
-
23
- // program.parse();
24
-
25
-
26
- const tmpDir = os.tmpdir();
27
- console.log('tmpDir', tmpDir);
28
- const tmpFile = path.join(tmpDir, "main.zip");
29
- const res = await fetch("https://github.com/pyrossh/parotta/archive/refs/heads/main.zip");
30
- await Bun.write(tmpFile, res);
31
- await gunzip(tmpFile, os.tmpdir());
bun.lockb CHANGED
Binary file
{example/components → components}/Counter/Counter.jsx RENAMED
File without changes
{example/components → components}/Timer/Timer.jsx RENAMED
File without changes
{example/components → components}/Todo/Todo.css RENAMED
File without changes
{example/components → components}/Todo/Todo.jsx RENAMED
File without changes
{example/containers → containers}/TodoList/TodoList.jsx RENAMED
File without changes
{example/db → db}/index.js RENAMED
File without changes
{example/db → db}/migrations/0000_empty_shatterstar.sql RENAMED
File without changes
{example/db → db}/migrations/meta/0000_snapshot.json RENAMED
File without changes
{example/db → db}/migrations/meta/_journal.json RENAMED
File without changes
example/drizzle.config.json → drizzle.config.json RENAMED
File without changes
example/.gitignore DELETED
@@ -1,5 +0,0 @@
1
- .cache
2
- .dist
3
- node_modules
4
- .env
5
- test-results
example/bun.lockb DELETED
Binary file
example/main.js DELETED
@@ -1,3 +0,0 @@
1
- import DevServer from "parotta/bin/cli";
2
-
3
- export default DevServer;
example/package.json DELETED
@@ -1,55 +0,0 @@
1
- {
2
- "name": "parotta-example",
3
- "type": "module",
4
- "scripts": {
5
- "dev": "bunx parotta",
6
- "start": "bunx parotta",
7
- "build": "docker build . -t example",
8
- "run": "docker run -p 3000:3000 example",
9
- "test": "playwright test",
10
- "test:report": "playwright show-report"
11
- },
12
- "dependencies": {
13
- "@neondatabase/serverless": "^0.2.9",
14
- "drizzle-auth-adaptor-pg": "^0.0.3",
15
- "drizzle-orm": "0.25.4",
16
- "next-auth": "^4.22.1",
17
- "normalize.css": "^8.0.1",
18
- "parotta": "file:../",
19
- "react": "18.2.0",
20
- "react-dom": "^18.2.0",
21
- "sql-highlight": "^4.3.2"
22
- },
23
- "devDependencies": {
24
- "drizzle-kit": "0.17.6",
25
- "@playwright/test": "^1.31.2",
26
- "eslint": "^8.35.0",
27
- "eslint-config-react-app": "^7.0.1",
28
- "eslint-config-recommended": "^4.1.0"
29
- },
30
- "parotta": {
31
- "hydrate": true,
32
- "css": [
33
- "node_modules/normalize.css/normalize.css"
34
- ]
35
- },
36
- "eslintConfig": {
37
- "root": true,
38
- "parserOptions": {
39
- "ecmaVersion": "latest",
40
- "sourceType": "module"
41
- },
42
- "extends": [
43
- "eslint:recommended",
44
- "react-app"
45
- ],
46
- "ignorePatterns": [
47
- "dist"
48
- ],
49
- "rules": {
50
- "react/prop-types": "warn",
51
- "react/react-in-jsx-scope": "off",
52
- "no-unused-vars": "warn"
53
- }
54
- }
55
- }
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`
example/jsconfig.json → jsconfig.json RENAMED
File without changes
main.js ADDED
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import ReactDom from "react-dom/server";
3
+ import server from "parotta/server.js";
4
+
5
+ export default {
6
+ port: 3000,
7
+ fetch: server,
8
+ }
package.json CHANGED
@@ -1,27 +1,54 @@
1
1
  {
2
- "name": "parotta",
2
+ "name": "parotta-example",
3
- "version": "0.3.0",
4
3
  "type": "module",
4
+ "scripts": {
5
+ "dev": "bun --hot main.js",
6
+ "start": "bun main.js",
7
+ "build": "docker build . -t example",
8
+ "run": "docker run -p 3000:3000 example",
9
+ "test": "bun test",
10
+ "test-e2e": "playwright test"
11
+ },
5
12
  "dependencies": {
13
+ "@neondatabase/serverless": "^0.2.9",
14
+ "drizzle-auth-adaptor-pg": "^0.0.3",
6
- "autoprefixer": "^10.4.14",
15
+ "drizzle-orm": "0.25.4",
7
- "chalk": "^5.2.0",
16
+ "next-auth": "^4.22.1",
8
- "commander": "10.0.0",
9
- "extract-files": "^13.0.0",
10
- "gunzip-file": "^0.1.1",
11
- "history": "^5.3.0",
12
- "mime-types": "2.1.35",
13
- "nprogress": "^0.2.0",
17
+ "normalize.css": "^8.0.1",
14
- "postcss": "^8.4.21",
15
- "postcss-custom-media": "^9.1.2",
16
- "postcss-nesting": "^11.2.1",
17
- "radix3": "^1.0.0",
18
- "react": "^18.2.0",
18
+ "react": "18.2.0",
19
19
  "react-dom": "^18.2.0",
20
+ "sql-highlight": "^4.3.2"
21
+ },
22
+ "devDependencies": {
20
- "tar": "^6.1.13",
23
+ "drizzle-kit": "0.17.6",
24
+ "@playwright/test": "^1.31.2",
21
- "unzip": "^0.1.11",
25
+ "eslint": "^8.35.0",
22
- "walkdir": "0.4.1"
26
+ "eslint-config-react-app": "^7.0.1",
27
+ "eslint-config-recommended": "^4.1.0"
28
+ },
29
+ "parotta": {
30
+ "hydrate": true,
31
+ "css": [
32
+ "node_modules/normalize.css/normalize.css"
33
+ ]
23
34
  },
35
+ "eslintConfig": {
36
+ "root": true,
37
+ "parserOptions": {
38
+ "ecmaVersion": "latest",
39
+ "sourceType": "module"
40
+ },
41
+ "extends": [
42
+ "eslint:recommended",
43
+ "react-app"
44
+ ],
45
+ "ignorePatterns": [
46
+ "dist"
47
+ ],
24
- "bin": {
48
+ "rules": {
49
+ "react/prop-types": "warn",
50
+ "react/react-in-jsx-scope": "off",
25
- "parotta": "./bin/cli.js"
51
+ "no-unused-vars": "warn"
52
+ }
26
53
  }
27
- }
54
+ }
{example/pages → pages}/404/page.css RENAMED
File without changes
{example/pages → pages}/404/page.jsx RENAMED
File without changes
{example/pages → pages}/about/page.css RENAMED
File without changes
{example/pages → pages}/about/page.jsx RENAMED
File without changes
{example/pages → pages}/layout.css RENAMED
File without changes
{example/pages → pages}/layout.jsx RENAMED
File without changes
{example/pages → pages}/page.css RENAMED
File without changes
{example/pages → pages}/page.jsx RENAMED
File without changes
{example/pages → pages}/page.spec.js RENAMED
File without changes
{example/pages → pages}/todos/page.css RENAMED
File without changes
{example/pages → pages}/todos/page.jsx RENAMED
File without changes
parotta/bun.lockb ADDED
Binary file
parotta/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "parotta",
3
+ "version": "0.5.0",
4
+ "type": "module",
5
+ "dependencies": {
6
+ "autoprefixer": "^10.4.14",
7
+ "history": "^5.3.0",
8
+ "mime-types": "2.1.35",
9
+ "postcss": "^8.4.21",
10
+ "postcss-custom-media": "^9.1.2",
11
+ "postcss-nesting": "^11.2.1",
12
+ "radix3": "^1.0.0",
13
+ "walkdir": "0.4.1"
14
+ }
15
+ }
parotta/readme.md ADDED
@@ -0,0 +1,13 @@
1
+ # parotta
2
+
3
+ parotta 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.
5
+ It uses File System routing with streaming SSR + CSR as the method to render pages. Basically a MPA + SPA Transitional App.
6
+ It is very opionated and has set of idiomatic ways of doing things.
7
+ It has inbuilt rpc mechanism to access server resources instead of a typical REST API.
8
+
9
+ ### Todo
10
+ 1. Add build step
11
+ 2. Deploy to Node (using edge-runtime), Docker, Deno deploy, Vercel edge functions, Cloudflare workers, Bun edge (whenever it releases)
12
+ 3. Hydrate rpc cache
13
+ 4. Build a Website with Docs using parotta
runtime.js → parotta/runtime.js RENAMED
File without changes
bin/cli.js → parotta/server.js RENAMED
@@ -1,5 +1,5 @@
1
- #!/usr/bin/env bun --hot
1
+ import React from "react";
2
-
2
+ import { renderToReadableStream } from "react-dom/server";
3
3
  import path from 'path';
4
4
  import fs from 'fs';
5
5
  import walkdir from 'walkdir';
@@ -10,12 +10,10 @@ import postcssNesting from "postcss-nesting";
10
10
  import { createMemoryHistory } from "history";
11
11
  import { createRouter } from 'radix3';
12
12
  import mimeTypes from "mime-types";
13
- import React from "react";
14
- import { renderToReadableStream } from "react-dom/server";
15
- import { HeadApp, BodyApp } from "../runtime";
13
+ import { HeadApp, BodyApp } from "./runtime";
16
14
 
17
- const version = (await import(path.join(import.meta.dir, "../package.json"))).default.version;
15
+ // const version = (await import(path.join(import.meta.dir, "package.json"))).default.version;
18
- console.log(`parotta v${version}`)
16
+ // console.log(`parotta v${version}`)
19
17
  console.log(`running with cwd=${path.basename(process.cwd())} node_env=${process.env.NODE_ENV}`);
20
18
 
21
19
  const isProd = process.env.NODE_ENV === "production";
@@ -178,7 +176,7 @@ const renderPage = async (url) => {
178
176
  "react-dom/client": `https://esm.sh/react-dom@18.2.0${devTag}/client`,
179
177
  "nprogress": "https://esm.sh/nprogress@0.2.0",
180
178
  // "parotta/runtime": `https://esm.sh/parotta@${version}/runtime.js`,
181
- "parotta/runtime": `../parotta/runtime.js`,
179
+ "parotta/runtime": `/parotta/runtime.js`,
182
180
  ...nodeDeps,
183
181
  ...components,
184
182
  ...containers,
@@ -241,6 +239,7 @@ const renderJs = async (srcFile) => {
241
239
  const result = await transpiler.transform(jsText);
242
240
  // inject code which calls the api for that function
243
241
  const lines = result.split("\n");
242
+ // lines.unshift(`import React from "react";`);
244
243
 
245
244
  // replace all .service imports which rpc interface
246
245
  let addRpcImport = false;
@@ -256,7 +255,7 @@ const renderJs = async (srcFile) => {
256
255
  }
257
256
  })
258
257
  if (addRpcImport) {
259
- lines.unshift(`import { rpc } from "parotta/runtime"`);
258
+ lines.unshift(`import { rpc } from "parotta/runtime";`);
260
259
  }
261
260
  // remove .css and .service imports
262
261
  const filteredJsx = lines.filter((ln) => !ln.includes(".css") && !ln.includes(".service")).join("\n");
@@ -291,47 +290,38 @@ const sendFile = async (src) => {
291
290
  }
292
291
  }
293
292
 
294
- export default {
295
- port: 3000,
296
- async fetch(req) {
293
+ const server = async (req) => {
297
- const url = new URL(req.url);
294
+ const url = new URL(req.url);
298
- console.log(req.method, url.pathname);
295
+ console.log(req.method, url.pathname);
299
- // maybe this is needed
296
+ // maybe this is needed
300
- if (url.pathname.startsWith("/parotta/")) {
297
+ if (url.pathname.startsWith("/parotta/")) {
301
- return renderJs(path.join(import.meta.dir, url.pathname.replace("/parotta/", "../")));
298
+ return renderJs(path.join(import.meta.dir, url.pathname.replace("/parotta/", "")));
302
- }
299
+ }
303
- if (url.pathname.endsWith(".css")) {
300
+ if (url.pathname.endsWith(".css")) {
304
- return renderCss(path.join(process.cwd(), url.pathname));
301
+ return renderCss(path.join(process.cwd(), url.pathname));
305
- }
302
+ }
306
- if (url.pathname.endsWith(".js") || url.pathname.endsWith(".jsx")) {
303
+ if (url.pathname.endsWith(".js") || url.pathname.endsWith(".jsx")) {
307
- return renderJs(path.join(process.cwd(), url.pathname));
304
+ return renderJs(path.join(process.cwd(), url.pathname));
308
- }
305
+ }
309
- const match = serverRouter.lookup(url.pathname);
306
+ const match = serverRouter.lookup(url.pathname);
310
- if (match) {
307
+ if (match) {
311
- if (match.file) {
308
+ if (match.file) {
312
- return sendFile(path.join(process.cwd(), `/static${match.file}`));
309
+ return sendFile(path.join(process.cwd(), `/static${match.file}`));
313
- }
314
- if (match.page && req.headers.get("Accept")?.includes('text/html')) {
315
- return renderPage(url);
316
- }
317
- if (match.service) {
318
- return renderApi(match.key, match.service, req);
319
- }
320
310
  }
321
- if (req.headers.get("Accept")?.includes('text/html')) {
311
+ if (match.page && req.headers.get("Accept")?.includes('text/html')) {
322
312
  return renderPage(url);
323
313
  }
314
+ if (match.service) {
315
+ return renderApi(match.key, match.service, req);
316
+ }
317
+ }
318
+ if (req.headers.get("Accept")?.includes('text/html')) {
319
+ return renderPage(url);
320
+ }
324
- return new Response(`{"message": "not found"}`, {
321
+ return new Response(`{"message": "not found"}`, {
325
- headers: { 'Content-Type': 'application/json' },
322
+ headers: { 'Content-Type': 'application/json' },
326
- status: 404,
323
+ status: 404,
327
- });
324
+ });
328
- },
329
- error(error) {
330
- console.log("error", error);
331
- return new Response(`<pre>${error}\n${error.stack}</pre>`, {
332
- headers: {
333
- "Content-Type": "text/html",
334
- },
335
- });
336
- },
337
- }
325
+ }
326
+
327
+ export default server;
example/playwright.config.js → playwright.config.js RENAMED
File without changes
readme.md CHANGED
@@ -1,13 +1,18 @@
1
+ # Sample Parotta Application
2
+
1
- # parotta
3
+ ## Requirements
2
-
3
- parotta is a next level meta-framework for react that runs only on edge runtimes.
4
+
4
- It uses bun as its bundler/transpiler and development mode as its quick and fast.
5
- It uses File System routing with streaming SSR + CSR as the method to render pages. Basically a MPA + SPA Transitional App.
6
- It is very opionated and has set of idiomatic ways of doing things.
5
+ 1. bun >= v0.5.8
7
- It has inbuilt rpc mechanism to access server resources instead of a typical REST API.
6
+
8
-
9
- ### Todo
7
+ ## Setup
8
+
10
- 1. Add build step
9
+ 1. `bun i`
11
- 2. Deploy to Node (using edge-runtime), Docker, Deno deploy, Vercel edge functions, Cloudflare workers, Bun edge (whenever it releases)
12
- 3. Hydrate rpc cache
10
+ 2. `bunx playright install`
11
+
12
+ ## Running
13
+
13
- 4. Build a Website with Docs using parotta
14
+ `bun run dev`
15
+
16
+ ## Testing
17
+
18
+ `bun test`
{example/services → services}/auth.service.js RENAMED
File without changes
{example/services → services}/todos.service.js RENAMED
File without changes
{example/static → static}/favicon.ico RENAMED
File without changes
{example/static → static}/logo192.png RENAMED
File without changes
{example/static → static}/logo512.png RENAMED
File without changes
{example/static → static}/manifest.json RENAMED
File without changes
{example/static → static}/robots.txt RENAMED
File without changes