@coherent.js/koa 1.0.0-beta.3 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,421 @@
1
+ # @coherent.js/koa
2
+
3
+ Koa.js adapter for Coherent.js - High-performance server-side rendering with Koa integration.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @coherent.js/koa
9
+ # or
10
+ pnpm add @coherent.js/koa
11
+ # or
12
+ yarn add @coherent.js/koa
13
+ ```
14
+
15
+ **Note:** You also need to install Koa and Coherent.js core:
16
+
17
+ ```bash
18
+ npm install koa @coherent.js/core
19
+ # or
20
+ pnpm add koa @coherent.js/core
21
+ ```
22
+
23
+ ## Overview
24
+
25
+ The `@coherent.js/koa` package provides seamless integration between Coherent.js and Koa.js, enabling you to build high-performance server-side rendered applications with Koa's middleware ecosystem.
26
+
27
+ ## Quick Start
28
+
29
+ ```javascript
30
+ import Koa from 'koa';
31
+ import { createCoherentHandler } from '@coherent.js/koa';
32
+
33
+ // Create your Coherent.js component
34
+ function App({ name = 'World' }) {
35
+ return {
36
+ div: {
37
+ children: [
38
+ { h1: { text: `Hello, ${name}!` } },
39
+ { p: { text: 'This is rendered with Coherent.js' } }
40
+ ]
41
+ }
42
+ };
43
+ }
44
+
45
+ // Create Koa app
46
+ const app = new Koa();
47
+
48
+ // Add Coherent.js handler
49
+ app.use(createCoherentHandler(App, {
50
+ // Optional configuration
51
+ template: ({ html, head, body }) => `
52
+ <!DOCTYPE html>
53
+ <html>
54
+ <head>
55
+ <title>Coherent.js Koa App</title>
56
+ ${head}
57
+ </head>
58
+ <body>
59
+ <div id="app">${body}</div>
60
+ </body>
61
+ </html>
62
+ `
63
+ }));
64
+
65
+ // Start server
66
+ const PORT = process.env.PORT || 3000;
67
+ app.listen(PORT, () => {
68
+ console.log(`Server running on http://localhost:${PORT}`);
69
+ });
70
+ ```
71
+
72
+ ## Features
73
+
74
+ ### Middleware Integration
75
+
76
+ Use Koa middleware alongside Coherent.js rendering:
77
+
78
+ ```javascript
79
+ import Koa from 'koa';
80
+ import logger from 'koa-logger';
81
+ import { createCoherentHandler } from '@coherent.js/koa';
82
+
83
+ const app = new Koa();
84
+
85
+ // Add Koa middleware
86
+ app.use(logger());
87
+
88
+ // Add Coherent.js rendering
89
+ app.use(createCoherentHandler(App));
90
+
91
+ app.listen(3000);
92
+ ```
93
+
94
+ ### Request Context Access
95
+
96
+ Access Koa request context in your components:
97
+
98
+ ```javascript
99
+ function App({ ctx }) {
100
+ // ctx is the Koa context object
101
+ const userAgent = ctx.get('User-Agent');
102
+ const ipAddress = ctx.ip;
103
+
104
+ return {
105
+ div: {
106
+ children: [
107
+ { p: { text: `Your IP: ${ipAddress}` } },
108
+ { p: { text: `User Agent: ${userAgent}` } }
109
+ ]
110
+ }
111
+ };
112
+ }
113
+ ```
114
+
115
+ ### Custom Routes
116
+
117
+ Handle specific routes with Coherent.js:
118
+
119
+ ```javascript
120
+ import Koa from 'koa';
121
+ import Router from '@koa/router';
122
+ import { createCoherentHandler } from '@coherent.js/koa';
123
+
124
+ const app = new Koa();
125
+ const router = new Router();
126
+
127
+ // Handle specific routes
128
+ router.get('/', createCoherentHandler(HomePage));
129
+ router.get('/about', createCoherentHandler(AboutPage));
130
+ router.get('/users/:id', createCoherentHandler(UserProfile));
131
+
132
+ app.use(router.routes());
133
+ app.listen(3000);
134
+ ```
135
+
136
+ ### Error Handling
137
+
138
+ Integrate with Koa's error handling:
139
+
140
+ ```javascript
141
+ import Koa from 'koa';
142
+ import { createCoherentHandler } from '@coherent.js/koa';
143
+
144
+ const app = new Koa();
145
+
146
+ // Error handling middleware
147
+ app.use(async (ctx, next) => {
148
+ try {
149
+ await next();
150
+ } catch (err) {
151
+ ctx.status = err.status || 500;
152
+ ctx.body = { error: err.message };
153
+ ctx.app.emit('error', err, ctx);
154
+ }
155
+ });
156
+
157
+ // Coherent.js handler
158
+ app.use(createCoherentHandler(App));
159
+
160
+ app.listen(3000);
161
+ ```
162
+
163
+ ## Configuration Options
164
+
165
+ ### Template Function
166
+
167
+ Customize the HTML template:
168
+
169
+ ```javascript
170
+ app.use(createCoherentHandler(App, {
171
+ template: ({ html, head, body, ctx }) => `
172
+ <!DOCTYPE html>
173
+ <html lang="${ctx.acceptsLanguages()[0] || 'en'}">
174
+ <head>
175
+ <meta charset="utf-8">
176
+ <meta name="viewport" content="width=device-width, initial-scale=1">
177
+ ${head}
178
+ </head>
179
+ <body>
180
+ <div id="app">${body}</div>
181
+ <script>
182
+ window.__INITIAL_DATA__ = ${JSON.stringify(ctx.state)};
183
+ </script>
184
+ </body>
185
+ </html>
186
+ `
187
+ }));
188
+ ```
189
+
190
+ ### Props Function
191
+
192
+ Customize component props based on Koa context:
193
+
194
+ ```javascript
195
+ app.use(createCoherentHandler(App, {
196
+ props: (ctx) => ({
197
+ userAgent: ctx.get('User-Agent'),
198
+ url: ctx.url,
199
+ user: ctx.state.user || null,
200
+ query: ctx.query
201
+ })
202
+ }));
203
+ ```
204
+
205
+ ### Error Component
206
+
207
+ Provide a custom error component:
208
+
209
+ ```javascript
210
+ function ErrorPage({ error, status }) {
211
+ return {
212
+ div: {
213
+ className: 'error-page',
214
+ children: [
215
+ { h1: { text: `Error ${status}` } },
216
+ { p: { text: error.message } }
217
+ ]
218
+ }
219
+ };
220
+ }
221
+
222
+ app.use(createCoherentHandler(App, {
223
+ errorComponent: ErrorPage
224
+ }));
225
+ ```
226
+
227
+ ## Performance Optimizations
228
+
229
+ ### Caching
230
+
231
+ Enable response caching:
232
+
233
+ ```javascript
234
+ import cache from 'koa-cache-lite';
235
+
236
+ app.use(cache({
237
+ '/api/*': 5 * 60 * 1000, // 5 minutes for API routes
238
+ '/static/*': 60 * 60 * 1000 // 1 hour for static assets
239
+ }));
240
+
241
+ app.use(createCoherentHandler(App));
242
+ ```
243
+
244
+ ### Compression
245
+
246
+ Add response compression:
247
+
248
+ ```javascript
249
+ import compress from 'koa-compress';
250
+
251
+ app.use(compress({
252
+ threshold: 2048,
253
+ gzip: { flush: require('zlib').constants.Z_SYNC_FLUSH }
254
+ }));
255
+
256
+ app.use(createCoherentHandler(App));
257
+ ```
258
+
259
+ ## Advanced Usage
260
+
261
+ ### Server-Side State Management
262
+
263
+ Manage state during server rendering:
264
+
265
+ ```javascript
266
+ function App({ ctx }) {
267
+ // Create request-scoped state
268
+ const requestState = {
269
+ requestId: Math.random().toString(36),
270
+ renderStartTime: Date.now()
271
+ };
272
+
273
+ ctx.state.requestState = requestState;
274
+
275
+ return {
276
+ div: {
277
+ children: [
278
+ { p: { text: `Request ID: ${requestState.requestId}` } }
279
+ ]
280
+ }
281
+ };
282
+ }
283
+ ```
284
+
285
+ ### Integration with Koa Router
286
+
287
+ Advanced routing with parameters:
288
+
289
+ ```javascript
290
+ import Router from '@koa/router';
291
+
292
+ const router = new Router();
293
+
294
+ router.get('/', createCoherentHandler(HomePage));
295
+ router.get('/users/:id', createCoherentHandler(UserProfile, {
296
+ props: (ctx) => ({
297
+ userId: ctx.params.id,
298
+ query: ctx.query
299
+ })
300
+ }));
301
+ router.get('/api/*', createCoherentHandler(ApiDocs));
302
+
303
+ app.use(router.routes());
304
+ app.use(router.allowedMethods());
305
+ ```
306
+
307
+ ## API Reference
308
+
309
+ ### createCoherentHandler(component, options)
310
+
311
+ Create a Koa middleware for Coherent.js rendering.
312
+
313
+ **Parameters:**
314
+ - `component` - Coherent.js component function
315
+ - `options.template` - Function to customize HTML template
316
+ - `options.props` - Function to generate component props from Koa context
317
+ - `options.errorComponent` - Component to render on errors
318
+ - `options.enableHydration` - Boolean to enable client-side hydration (default: true)
319
+
320
+ **Returns:** Koa middleware function
321
+
322
+ ### Options
323
+
324
+ - `template` - Function receiving { html, head, body, ctx } and returning HTML string
325
+ - `props` - Function receiving Koa context and returning component props
326
+ - `errorComponent` - Component for error rendering
327
+ - `enableHydration` - Enable/disable hydration support
328
+
329
+ ## Examples
330
+
331
+ ### Full Application Example
332
+
333
+ ```javascript
334
+ import Koa from 'koa';
335
+ import Router from '@koa/router';
336
+ import bodyParser from 'koa-bodyparser';
337
+ import logger from 'koa-logger';
338
+ import session from 'koa-session';
339
+ import { createCoherentHandler } from '@coherent.js/koa';
340
+
341
+ // Components
342
+ function HomePage({ user }) {
343
+ return {
344
+ div: {
345
+ children: [
346
+ { h1: { text: 'Welcome to Coherent.js + Koa' } },
347
+ user
348
+ ? { p: { text: `Hello, ${user.name}!` } }
349
+ : { a: { href: '/login', text: 'Login' } }
350
+ ]
351
+ }
352
+ };
353
+ }
354
+
355
+ function LoginPage() {
356
+ return {
357
+ form: {
358
+ action: '/login',
359
+ method: 'POST',
360
+ children: [
361
+ { input: { type: 'email', name: 'email', placeholder: 'Email' } },
362
+ { input: { type: 'password', name: 'password', placeholder: 'Password' } },
363
+ { button: { type: 'submit', text: 'Login' } }
364
+ ]
365
+ }
366
+ };
367
+ }
368
+
369
+ // Create app
370
+ const app = new Koa();
371
+ const router = new Router();
372
+
373
+ // Middleware
374
+ app.use(logger());
375
+ app.use(bodyParser());
376
+ app.keys = ['secret-key'];
377
+ app.use(session(app));
378
+
379
+ // Routes
380
+ router.get('/', createCoherentHandler(HomePage, {
381
+ props: (ctx) => ({ user: ctx.session.user })
382
+ }));
383
+
384
+ router.get('/login', createCoherentHandler(LoginPage));
385
+ router.post('/login', async (ctx) => {
386
+ // Simple auth (in production, use proper authentication)
387
+ const { email, password } = ctx.request.body;
388
+ if (email && password) {
389
+ ctx.session.user = { name: email.split('@')[0], email };
390
+ ctx.redirect('/');
391
+ } else {
392
+ ctx.status = 400;
393
+ ctx.body = { error: 'Invalid credentials' };
394
+ }
395
+ });
396
+
397
+ router.get('/logout', (ctx) => {
398
+ ctx.session = null;
399
+ ctx.redirect('/');
400
+ });
401
+
402
+ // Setup
403
+ app.use(router.routes());
404
+ app.use(router.allowedMethods());
405
+
406
+ const PORT = process.env.PORT || 3000;
407
+ app.listen(PORT, () => {
408
+ console.log(`Server running on http://localhost:${PORT}`);
409
+ });
410
+ ```
411
+
412
+ ## Related Packages
413
+
414
+ - [@coherent.js/core](../core/README.md) - Core framework
415
+ - [@coherent.js/express](../express/README.md) - Express.js adapter
416
+ - [@coherent.js/fastify](../fastify/README.md) - Fastify adapter
417
+ - [@coherent.js/nextjs](../nextjs/README.md) - Next.js integration
418
+
419
+ ## License
420
+
421
+ MIT