Skip to content

Commit 6b19c2b

Browse files
authored
Merge pull request #7 from dnsjm/main
Add koa js example 2d
2 parents 52530b8 + 861a8a1 commit 6b19c2b

12 files changed

Lines changed: 356 additions & 0 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Edit({ name }: { name: string }) {
2+
return (
3+
<p className="py-4">
4+
Edit <code>pages/{name}.tsx</code> and save to test HMR
5+
</p>
6+
)
7+
}

examples/with-koa/package.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"type": "module",
3+
"name": "reactus-with-koa",
4+
"version": "1.0.0",
5+
"private": true,
6+
"scripts": {
7+
"dev": "tsx scripts/develop.ts",
8+
"build": "tsx scripts/build.ts",
9+
"start": "tsx scripts/start.ts"
10+
},
11+
"dependencies": {
12+
"koa": "^2.15.0",
13+
"@koa/router": "^12.0.1",
14+
"koa-static": "^5.0.0",
15+
"react": "19.0.0",
16+
"react-dom": "19.0.0",
17+
"reactus": "0.2.10"
18+
},
19+
"devDependencies": {
20+
"@types/koa": "^2.15.0",
21+
"@types/koa__router": "^12.0.4",
22+
"@types/koa-static": "^4.0.4",
23+
"@types/node": "22.9.3",
24+
"@types/react": "19.0.10",
25+
"@types/react-dom": "19.0.4",
26+
"@vitejs/plugin-react": "4.3.4",
27+
"ts-node": "10.9.2",
28+
"tsx": "4.19.3",
29+
"typescript": "5.7.2",
30+
"vite": "6.1.1"
31+
}
32+
}

examples/with-koa/pages/about.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import './page.css';
2+
import Edit from '../components/Edit';
3+
4+
export function Head({ styles = [] }: { styles?: string[] }) {
5+
return (
6+
<>
7+
<title>About Reactus</title>
8+
<meta name="description" content="About Reactus" />
9+
<link rel="icon" type="image/svg+xml" href="/react.svg" />
10+
<link rel="stylesheet" type="text/css" href="/global.css" />
11+
{styles.map((href, index) => (
12+
<link key={index} rel="stylesheet" type="text/css" href={href} />
13+
))}
14+
</>
15+
)
16+
}
17+
18+
export default function AboutPage() {
19+
return (
20+
<>
21+
<h1 className="uppercase">About Reactus</h1>
22+
<div className="p-4">
23+
<Edit name="about" />
24+
<a href="/">Home Page</a>
25+
</div>
26+
</>
27+
)
28+
}

examples/with-koa/pages/home.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import './page.css';
2+
import { useState } from 'react';
3+
import Edit from '../components/Edit';
4+
5+
export function Head({ styles = [] }: { styles?: string[] }) {
6+
return (
7+
<>
8+
<title>Reactus</title>
9+
<meta name="description" content="Reactus" />
10+
<link rel="icon" type="image/svg+xml" href="/react.svg" />
11+
<link rel="stylesheet" type="text/css" href="/global.css" />
12+
{styles.map((href, index) => (
13+
<link key={index} rel="stylesheet" type="text/css" href={href} />
14+
))}
15+
</>
16+
)
17+
}
18+
19+
export default function HomePage() {
20+
const [count, setCount] = useState(0)
21+
22+
return (
23+
<>
24+
<h1>React + Reactus + Koa</h1>
25+
<div className="p-4">
26+
<button className="text-reactus" onClick={() => setCount((count) => count + 1)}>
27+
count is {count}
28+
</button>
29+
<Edit name="about" />
30+
<a href="/about">About Reactus</a>
31+
</div>
32+
</>
33+
)
34+
}

examples/with-koa/pages/page.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
:root { display: initial; }
2+
#root {
3+
max-width: 1280px;
4+
margin: 0 auto;
5+
padding: 2rem;
6+
text-align: center;
7+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
:root {
2+
/*display: none; */
3+
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
4+
line-height: 1.5;
5+
font-weight: 400;
6+
7+
color-scheme: light dark;
8+
color: rgba(255, 255, 255, 0.87);
9+
background-color: #242424;
10+
11+
font-synthesis: none;
12+
text-rendering: optimizeLegibility;
13+
-webkit-font-smoothing: antialiased;
14+
-moz-osx-font-smoothing: grayscale;
15+
-webkit-text-size-adjust: 100%;
16+
}
17+
18+
a {
19+
font-weight: 500;
20+
color: #646cff;
21+
text-decoration: inherit;
22+
}
23+
a:hover {
24+
color: #535bf2;
25+
}
26+
27+
body {
28+
margin: 0;
29+
display: flex;
30+
place-items: center;
31+
min-width: 320px;
32+
min-height: 100vh;
33+
}
34+
35+
h1 {
36+
font-size: 3.2em;
37+
line-height: 1.1;
38+
}
39+
40+
button {
41+
border-radius: 8px;
42+
border: 1px solid transparent;
43+
padding: 0.6em 1.2em;
44+
font-size: 1em;
45+
font-weight: 500;
46+
font-family: inherit;
47+
background-color: #1a1a1a;
48+
cursor: pointer;
49+
transition: border-color 0.25s;
50+
}
51+
button:hover {
52+
border-color: #646cff;
53+
}
54+
button:focus,
55+
button:focus-visible {
56+
outline: 4px auto -webkit-focus-ring-color;
57+
}
58+
59+
@media (prefers-color-scheme: light) {
60+
:root {
61+
color: #213547;
62+
background-color: #ffffff;
63+
}
64+
a:hover {
65+
color: #747bff;
66+
}
67+
button {
68+
background-color: #f9f9f9;
69+
}
70+
}

examples/with-koa/public/react.svg

Lines changed: 1 addition & 0 deletions
Loading

examples/with-koa/scripts/build.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//node
2+
import path from 'node:path';
3+
//reactus
4+
import { build } from 'reactus';
5+
6+
async function builder() {
7+
const cwd = process.cwd();
8+
const engine = build({
9+
cwd,
10+
//path where to save assets (css, images, etc)
11+
assetPath: path.join(cwd, 'public/assets'),
12+
//path where to save and load (live) the client scripts (js)
13+
clientPath: path.join(cwd, 'public/client'),
14+
//path where to save and load (live) the server script (js)
15+
pagePath: path.join(cwd, '.build/pages')
16+
});
17+
18+
await engine.set('@/pages/home');
19+
await engine.set('@/pages/about');
20+
21+
const responses = [
22+
...await engine.buildAllClients(),
23+
...await engine.buildAllAssets(),
24+
...await engine.buildAllPages()
25+
].map(response => {
26+
const results = response.results;
27+
if (typeof results?.contents === 'string') {
28+
results.contents = results.contents.substring(0, 100) + ' ...';
29+
}
30+
return results;
31+
});
32+
33+
//console.log(responses);
34+
//fix for unused variable :)
35+
if (responses.length) return;
36+
}
37+
38+
builder().catch(e => {
39+
console.error(e);
40+
process.exit(1);
41+
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { dev } from 'reactus';
2+
import Koa from 'koa';
3+
import Router from '@koa/router';
4+
5+
6+
async function develop() {
7+
const engine = dev({
8+
cwd: process.cwd(),
9+
basePath: '/',
10+
clientRoute: '/client',
11+
})
12+
13+
const app = new Koa();
14+
const router = new Router();
15+
16+
// Handle reactus http requests (public, assets, and hmr)
17+
app.use(async (ctx, next) => {
18+
await engine.http(ctx.req, ctx.res);
19+
20+
if (ctx.res.headersSent) return;
21+
await next();
22+
});
23+
24+
router.get('/', async (ctx) => {
25+
ctx.set('Content-Type', 'text/html');
26+
ctx.body = await engine.render('@/pages/home', { title: 'Home' });
27+
return;
28+
});
29+
30+
router.get('/about', async (ctx) => {
31+
ctx.set('Content-Type', 'text/html');
32+
ctx.body = await engine.render('@/pages/about');
33+
return;
34+
});
35+
36+
app.use(router.routes()).use(router.allowedMethods());
37+
38+
// Catch-all middleware for 404
39+
app.use(async (ctx) => {
40+
if (!ctx.body) {
41+
ctx.status = 404;
42+
ctx.body = '404 not found.';
43+
}
44+
});
45+
46+
app.listen(3000, () => {
47+
console.log('Server listening at http://localhost:3000');
48+
});
49+
}
50+
51+
develop().catch(e => {
52+
console.error(e);
53+
process.exit(1);
54+
});

examples/with-koa/scripts/start.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import path from 'node:path';
2+
import { serve } from 'reactus';
3+
import Koa from 'koa';
4+
import Router from '@koa/router';
5+
import koaStatic from 'koa-static';
6+
7+
async function start() {
8+
const app = new Koa();
9+
const router = new Router();
10+
const cwd = process.cwd();
11+
12+
const engine = serve({
13+
cwd,
14+
clientRoute: '/client',
15+
pagePath: path.join(cwd, '.build/pages'),
16+
cssRoute: '/assets'
17+
});
18+
19+
const assets = koaStatic(path.join(cwd, 'public'), {
20+
maxage: 31536000,
21+
immutable: true,
22+
});
23+
24+
// Middleware using koa-static to handle public assets
25+
app.use(assets);
26+
27+
router.get('/', async (ctx) => {
28+
try {
29+
ctx.set('Content-Type', 'text/html');
30+
ctx.body = await engine.render('@/pages/home');
31+
} catch (error) {
32+
console.error('Error rendering /home:', error);
33+
ctx.status = 500;
34+
ctx.body = 'Internal Server Error';
35+
}
36+
});
37+
38+
router.get('/about', async (ctx) => {
39+
try {
40+
ctx.set('Content-Type', 'text/html');
41+
ctx.body = await engine.render('@/pages/about');
42+
} catch (error) {
43+
console.error('Error rendering /about:', error);
44+
ctx.status = 500;
45+
ctx.body = 'Internal Server Error';
46+
}
47+
});
48+
49+
app.use(router.routes()).use(router.allowedMethods());
50+
51+
// Catch-all middleware for 404
52+
app.use(async (ctx) => {
53+
if (!ctx.body) {
54+
ctx.status = 404;
55+
ctx.body = 'Not Found.';
56+
}
57+
});
58+
59+
60+
app.listen(3000,() => {
61+
console.log('Server listening at http://localhost:3000');
62+
});
63+
}
64+
65+
start().catch(e => {
66+
console.error(e);
67+
process.exit(1);
68+
});

0 commit comments

Comments
 (0)