@nestjs-ssr/react 0.1.8 → 0.1.10
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 +39 -494
- package/dist/cli/init.js +178 -2499
- package/dist/cli/init.mjs +143 -2441
- package/dist/index.js +0 -2
- package/dist/index.mjs +0 -2
- package/dist/render/index.js +0 -2
- package/dist/render/index.mjs +0 -2
- package/dist/templates/entry-client.tsx +1 -0
- package/package.json +4 -6
- package/src/global.d.ts +16 -0
- package/src/templates/entry-client.tsx +1 -0
- package/dist/cli/init.js.map +0 -1
- package/dist/cli/init.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/render/index.js.map +0 -1
- package/dist/render/index.mjs.map +0 -1
- package/src/cli/init.ts +0 -260
package/README.md
CHANGED
|
@@ -1,176 +1,39 @@
|
|
|
1
1
|
# @nestjs-ssr/react
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
A lightweight, production-ready library that brings React to NestJS while preserving the architectural principles that make NestJS great: **Dependency Injection**, **SOLID principles**, and **clear separation of concerns**.
|
|
6
|
-
|
|
7
|
-
## Why This Library?
|
|
8
|
-
|
|
9
|
-
### Built for Clean Architecture
|
|
10
|
-
|
|
11
|
-
If you value [Uncle Bob's Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) and software craftsmanship, you'll appreciate how this library maintains architectural boundaries:
|
|
12
|
-
|
|
13
|
-
**Clear Separation of Concerns:**
|
|
14
|
-
```typescript
|
|
15
|
-
// View component with typed props (Presentation Layer)
|
|
16
|
-
export interface UserProfileProps {
|
|
17
|
-
user: User;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default function UserProfile(props: PageProps<UserProfileProps>) {
|
|
21
|
-
return <div>{props.user.name}</div>; // Pure presentation
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Server logic stays in controllers (Application Layer)
|
|
25
|
-
import UserProfile from './views/user-profile';
|
|
26
|
-
|
|
27
|
-
@Controller()
|
|
28
|
-
export class UserController {
|
|
29
|
-
constructor(private userService: UserService) {} // Proper DI
|
|
30
|
-
|
|
31
|
-
@Get('/users/:id')
|
|
32
|
-
@Render(UserProfile) // Type-safe! Cmd+Click to navigate
|
|
33
|
-
async getUserProfile(@Param('id') id: string) {
|
|
34
|
-
const user = await this.userService.findById(id); // Business logic
|
|
35
|
-
return { user }; // ✅ TypeScript validates this matches UserProfileProps
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**No Server/Client Confusion:**
|
|
41
|
-
- Server code is server code (Controllers, Services, Guards)
|
|
42
|
-
- Client code is client code (React components, hooks)
|
|
43
|
-
- No `'use server'` / `'use client'` directives scattered throughout
|
|
44
|
-
- No mixing of database queries with JSX
|
|
45
|
-
- No hidden boundaries where code "magically" switches execution context
|
|
46
|
-
|
|
47
|
-
**True Dependency Injection:**
|
|
48
|
-
```typescript
|
|
49
|
-
// Use NestJS DI throughout your application
|
|
50
|
-
@Injectable()
|
|
51
|
-
export class ProductService {
|
|
52
|
-
constructor(
|
|
53
|
-
private db: DatabaseService,
|
|
54
|
-
private cache: CacheService,
|
|
55
|
-
) {}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Testable, mockable, follows IoC principle
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Why Not Next.js?
|
|
62
|
-
|
|
63
|
-
Next.js is excellent for many use cases, but if you care about architectural integrity:
|
|
64
|
-
|
|
65
|
-
**Next.js encourages coupling:**
|
|
66
|
-
```tsx
|
|
67
|
-
// ❌ Server and client code mixed in the same file
|
|
68
|
-
export default function Page() {
|
|
69
|
-
const data = await fetch('...').then(r => r.json()); // Server
|
|
70
|
-
const [count, setCount] = useState(0); // Client
|
|
71
|
-
return <button onClick={() => setCount(count + 1)}>{data.title}</button>;
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
- Server and client logic intertwined
|
|
75
|
-
- No dependency injection - just imports and function calls
|
|
76
|
-
- Difficult to test business logic in isolation
|
|
77
|
-
- Routes are files, not proper routing with guards/interceptors
|
|
78
|
-
- Framework-specific patterns instead of universal principles
|
|
79
|
-
|
|
80
|
-
**NestJS SSR maintains boundaries:**
|
|
81
|
-
```tsx
|
|
82
|
-
// ✅ View: Client-only, pure presentation
|
|
83
|
-
export interface ProductsProps {
|
|
84
|
-
products: Product[];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export default function Products(props: PageProps<ProductsProps>) {
|
|
88
|
-
const [selected, setSelected] = useState(null);
|
|
89
|
-
return <ProductList products={props.products} onSelect={setSelected} />;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ✅ Controller: Server-only, testable, uses DI
|
|
93
|
-
import Products from './views/products';
|
|
94
|
-
|
|
95
|
-
@Controller()
|
|
96
|
-
export class ProductController {
|
|
97
|
-
constructor(private productService: ProductService) {}
|
|
98
|
-
|
|
99
|
-
@Get('/products')
|
|
100
|
-
@UseGuards(AuthGuard) // Proper middleware
|
|
101
|
-
@Render(Products) // Type-safe component reference
|
|
102
|
-
async list() {
|
|
103
|
-
return { products: await this.productService.findAll() };
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### Performance as a Bonus
|
|
109
|
-
|
|
110
|
-
Following clean architecture doesn't mean sacrificing performance. In our benchmarks:
|
|
111
|
-
|
|
112
|
-
- **NestJS SSR:** 3,050 req/sec (32ms latency)
|
|
113
|
-
- **Next.js:** 2,965 req/sec (33ms latency)
|
|
114
|
-
- **Remix:** 915 req/sec (109ms latency)
|
|
115
|
-
|
|
116
|
-
**Equal performance** with **better architecture.**
|
|
3
|
+
Server-side rendering for React in NestJS with full TypeScript support and type-safe props.
|
|
117
4
|
|
|
118
5
|
## Features
|
|
119
6
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
✅ **Zero Configuration** - Works out of the box with sensible defaults
|
|
126
|
-
✅ **TypeScript First** - Fully typed with excellent IDE support
|
|
127
|
-
✅ **Streaming SSR** - Modern renderToPipeableStream support
|
|
128
|
-
✅ **HMR in Development** - Powered by Vite for instant feedback
|
|
129
|
-
✅ **Production Optimized** - Code splitting, compression, and caching
|
|
130
|
-
✅ **Testable** - Easy to unit test controllers and services separately
|
|
7
|
+
- **Type-Safe Props** - TypeScript validates controller returns match component props
|
|
8
|
+
- **Zero Config** - Works out of the box with sensible defaults
|
|
9
|
+
- **Streaming SSR** - Modern renderToPipeableStream support
|
|
10
|
+
- **HMR in Development** - Powered by Vite for instant feedback
|
|
11
|
+
- **Production Ready** - Code splitting, caching, and optimizations built-in
|
|
131
12
|
|
|
132
|
-
##
|
|
133
|
-
|
|
134
|
-
### Installation
|
|
13
|
+
## Installation
|
|
135
14
|
|
|
136
15
|
```bash
|
|
137
|
-
npm install @nestjs-ssr/react
|
|
16
|
+
npm install @nestjs-ssr/react
|
|
17
|
+
npx nestjs-ssr # Set up your project automatically
|
|
138
18
|
```
|
|
139
19
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
// vite.config.ts
|
|
144
|
-
import { defineConfig } from 'vite';
|
|
145
|
-
import react from '@vitejs/plugin-react';
|
|
146
|
-
import { resolve } from 'path';
|
|
20
|
+
The CLI installs dependencies, creates entry files, and configures TypeScript/Vite for you.
|
|
147
21
|
|
|
148
|
-
|
|
149
|
-
plugins: [react()],
|
|
150
|
-
resolve: {
|
|
151
|
-
alias: {
|
|
152
|
-
'@': resolve(__dirname, 'src'),
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
});
|
|
156
|
-
```
|
|
22
|
+
## Usage
|
|
157
23
|
|
|
158
|
-
|
|
24
|
+
**1. Register the module**
|
|
159
25
|
|
|
160
26
|
```typescript
|
|
161
27
|
// app.module.ts
|
|
162
|
-
import { Module } from '@nestjs/common';
|
|
163
28
|
import { RenderModule } from '@nestjs-ssr/react';
|
|
164
29
|
|
|
165
30
|
@Module({
|
|
166
|
-
imports: [
|
|
167
|
-
RenderModule.register(), // Zero config!
|
|
168
|
-
],
|
|
31
|
+
imports: [RenderModule],
|
|
169
32
|
})
|
|
170
33
|
export class AppModule {}
|
|
171
34
|
```
|
|
172
35
|
|
|
173
|
-
|
|
36
|
+
**2. Create a view component**
|
|
174
37
|
|
|
175
38
|
```typescript
|
|
176
39
|
// src/views/home.tsx
|
|
@@ -185,7 +48,7 @@ export default function Home(props: PageProps<HomeProps>) {
|
|
|
185
48
|
}
|
|
186
49
|
```
|
|
187
50
|
|
|
188
|
-
|
|
51
|
+
**3. Use in a controller**
|
|
189
52
|
|
|
190
53
|
```typescript
|
|
191
54
|
// app.controller.ts
|
|
@@ -196,379 +59,61 @@ import Home from './views/home';
|
|
|
196
59
|
@Controller()
|
|
197
60
|
export class AppController {
|
|
198
61
|
@Get()
|
|
199
|
-
@Render(Home)
|
|
62
|
+
@Render(Home)
|
|
200
63
|
getHome() {
|
|
201
|
-
return { message: 'Hello
|
|
64
|
+
return { message: 'Hello World' }; // TypeScript validates this!
|
|
202
65
|
}
|
|
203
66
|
}
|
|
204
67
|
```
|
|
205
68
|
|
|
206
|
-
That's it!
|
|
207
|
-
|
|
208
|
-
### 5. Run
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
npm run dev
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Visit [http://localhost:3000](http://localhost:3000) 🎉
|
|
215
|
-
|
|
216
|
-
## Core Concepts
|
|
217
|
-
|
|
218
|
-
### The `@Render` Decorator
|
|
219
|
-
|
|
220
|
-
The decorator takes a React component and automatically validates that your controller returns the correct props:
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
import UserProfile from './views/user-profile';
|
|
224
|
-
|
|
225
|
-
@Get('/users/:id')
|
|
226
|
-
@Render(UserProfile) // Type-safe! Cmd+Click to navigate
|
|
227
|
-
async getUser(@Param('id') id: string) {
|
|
228
|
-
const user = await this.userService.findOne(id);
|
|
229
|
-
return { user }; // ✅ TypeScript validates this matches component props
|
|
230
|
-
}
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### Type-Safe Props
|
|
234
|
-
|
|
235
|
-
Components receive props with full TypeScript support and validation:
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
import type { PageProps } from '@nestjs-ssr/react';
|
|
239
|
-
|
|
240
|
-
export interface UserProfileProps {
|
|
241
|
-
user: User;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export default function UserProfile(props: PageProps<UserProfileProps>) {
|
|
245
|
-
return (
|
|
246
|
-
<div>
|
|
247
|
-
<h1>{props.user.name}</h1>
|
|
248
|
-
<p>Requested from: {props.context.path}</p>
|
|
249
|
-
</div>
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
**Benefits:**
|
|
255
|
-
- ✅ Build-time validation - wrong props = compilation error
|
|
256
|
-
- ✅ Cmd+Click navigation from controller to view file
|
|
257
|
-
- ✅ No manual type annotations needed
|
|
258
|
-
- ✅ Refactoring-friendly - rename props with confidence
|
|
69
|
+
That's it! Run `npm run dev` and visit http://localhost:3000
|
|
259
70
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
Every component receives the request context:
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
interface RenderContext {
|
|
266
|
-
url: string;
|
|
267
|
-
path: string;
|
|
268
|
-
query: Record<string, any>;
|
|
269
|
-
params: Record<string, string>;
|
|
270
|
-
userAgent?: string;
|
|
271
|
-
acceptLanguage?: string;
|
|
272
|
-
referer?: string;
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
You can extend it with custom data using TypeScript declaration merging!
|
|
71
|
+
## API
|
|
277
72
|
|
|
278
73
|
### React Hooks
|
|
279
74
|
|
|
280
|
-
Access context in any component:
|
|
281
|
-
|
|
282
75
|
```typescript
|
|
283
76
|
import { usePageContext, useParams, useQuery } from '@nestjs-ssr/react';
|
|
284
77
|
|
|
285
78
|
function MyComponent() {
|
|
286
|
-
const context = usePageContext();
|
|
287
|
-
const params = useParams();
|
|
288
|
-
const query = useQuery();
|
|
289
|
-
|
|
79
|
+
const context = usePageContext(); // { url, path, query, params, ... }
|
|
80
|
+
const params = useParams(); // Route params
|
|
81
|
+
const query = useQuery(); // Query string
|
|
290
82
|
return <div>User ID: {params.id}</div>;
|
|
291
83
|
}
|
|
292
84
|
```
|
|
293
85
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
### SSR Modes
|
|
297
|
-
|
|
298
|
-
Choose between string mode (simple) or stream mode (faster):
|
|
86
|
+
### Head Tags & SEO
|
|
299
87
|
|
|
300
88
|
```typescript
|
|
301
|
-
|
|
302
|
-
mode: 'stream', // or 'string' (default)
|
|
303
|
-
})
|
|
304
|
-
```
|
|
89
|
+
import { Head } from '@nestjs-ssr/react';
|
|
305
90
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
### Environment Variables
|
|
318
|
-
|
|
319
|
-
```bash
|
|
320
|
-
SSR_MODE=stream # 'string' or 'stream'
|
|
321
|
-
NODE_ENV=production # Enables production optimizations
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Vite Development Setup
|
|
325
|
-
|
|
326
|
-
You have two options for integrating Vite during development:
|
|
327
|
-
|
|
328
|
-
#### Option 1: Simple Setup (Recommended for Getting Started)
|
|
329
|
-
|
|
330
|
-
Use Vite in middleware mode directly within NestJS. This approach is simpler but requires manual page refresh to see changes.
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
// main.ts
|
|
334
|
-
import { createServer as createViteServer } from 'vite';
|
|
335
|
-
import { RenderService } from '@nestjs-ssr/react';
|
|
336
|
-
|
|
337
|
-
async function bootstrap() {
|
|
338
|
-
const app = await NestFactory.create(AppModule);
|
|
339
|
-
const renderService = app.get(RenderService);
|
|
340
|
-
|
|
341
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
342
|
-
const vite = await createViteServer({
|
|
343
|
-
server: { middlewareMode: true },
|
|
344
|
-
appType: 'custom',
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
app.use(vite.middlewares);
|
|
348
|
-
renderService.setViteServer(vite);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
await app.listen(3000);
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
**Pros:**
|
|
356
|
-
- Simple setup (~10 lines of code)
|
|
357
|
-
- Single server on port 3000
|
|
358
|
-
- Auto-restart on file changes
|
|
359
|
-
|
|
360
|
-
**Cons:**
|
|
361
|
-
- Requires manual page refresh to see changes
|
|
362
|
-
- No hot module replacement (HMR)
|
|
363
|
-
|
|
364
|
-
See [`minimal-simple`](../../examples/minimal-simple) example.
|
|
365
|
-
|
|
366
|
-
#### Option 2: Full HMR Setup (Best Developer Experience)
|
|
367
|
-
|
|
368
|
-
Run a separate Vite dev server with proxy middleware for instant hot reloading.
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
// main.ts
|
|
372
|
-
import { createServer as createViteServer } from 'vite';
|
|
373
|
-
import { RenderService } from '@nestjs-ssr/react';
|
|
374
|
-
|
|
375
|
-
async function bootstrap() {
|
|
376
|
-
const app = await NestFactory.create(AppModule);
|
|
377
|
-
const renderService = app.get(RenderService);
|
|
378
|
-
|
|
379
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
380
|
-
// Proxy to external Vite server for HMR
|
|
381
|
-
const { createProxyMiddleware } = await import('http-proxy-middleware');
|
|
382
|
-
const viteProxy = createProxyMiddleware({
|
|
383
|
-
target: 'http://localhost:5173',
|
|
384
|
-
changeOrigin: true,
|
|
385
|
-
ws: true,
|
|
386
|
-
pathFilter: (pathname: string) => {
|
|
387
|
-
return (
|
|
388
|
-
pathname.startsWith('/src/') ||
|
|
389
|
-
pathname.startsWith('/@') ||
|
|
390
|
-
pathname.startsWith('/node_modules/')
|
|
391
|
-
);
|
|
392
|
-
},
|
|
393
|
-
});
|
|
394
|
-
app.use(viteProxy);
|
|
395
|
-
|
|
396
|
-
// Vite instance for SSR
|
|
397
|
-
const vite = await createViteServer({
|
|
398
|
-
server: { middlewareMode: true },
|
|
399
|
-
appType: 'custom',
|
|
400
|
-
});
|
|
401
|
-
renderService.setViteServer(vite);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
await app.listen(3000);
|
|
405
|
-
}
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
**Additional dependencies:**
|
|
409
|
-
```bash
|
|
410
|
-
npm install -D http-proxy-middleware concurrently
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
**package.json scripts:**
|
|
414
|
-
```json
|
|
415
|
-
{
|
|
416
|
-
"scripts": {
|
|
417
|
-
"start:dev": "concurrently \"vite --port 5173\" \"nest start --watch\""
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
**vite.config.js:**
|
|
423
|
-
```javascript
|
|
424
|
-
export default defineConfig({
|
|
425
|
-
server: {
|
|
426
|
-
port: 5173,
|
|
427
|
-
strictPort: true,
|
|
428
|
-
hmr: { port: 5173 }, // Critical for HMR
|
|
429
|
-
},
|
|
430
|
-
});
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
**Pros:**
|
|
434
|
-
- Instant hot module replacement (HMR)
|
|
435
|
-
- Best developer experience for rapid iteration
|
|
436
|
-
- No page refresh needed
|
|
437
|
-
|
|
438
|
-
**Cons:**
|
|
439
|
-
- More complex setup (~40 lines)
|
|
440
|
-
- Requires two servers (NestJS + Vite)
|
|
441
|
-
- Additional dependencies
|
|
442
|
-
|
|
443
|
-
See [`minimal`](../../examples/minimal) example.
|
|
444
|
-
|
|
445
|
-
## Advanced Features
|
|
446
|
-
|
|
447
|
-
### Error Monitoring (Coming in v0.2.0)
|
|
448
|
-
|
|
449
|
-
Error monitoring integration is planned for the next release. It will support integrations with Sentry, Datadog, and custom error reporters.
|
|
450
|
-
|
|
451
|
-
For now, you can use NestJS's built-in exception filters and logging for error handling.
|
|
452
|
-
|
|
453
|
-
### Extending Context
|
|
454
|
-
|
|
455
|
-
Add custom data to the render context:
|
|
456
|
-
|
|
457
|
-
```typescript
|
|
458
|
-
// types/render-context.d.ts
|
|
459
|
-
declare module '@nestjs-ssr/react' {
|
|
460
|
-
interface RenderContext {
|
|
461
|
-
user?: User;
|
|
462
|
-
tenant?: string;
|
|
463
|
-
}
|
|
91
|
+
export default function MyPage(props: PageProps<MyProps>) {
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<Head>
|
|
95
|
+
<title>My Page</title>
|
|
96
|
+
<meta name="description" content="Page description" />
|
|
97
|
+
</Head>
|
|
98
|
+
<div>{props.content}</div>
|
|
99
|
+
</>
|
|
100
|
+
);
|
|
464
101
|
}
|
|
465
102
|
```
|
|
466
103
|
|
|
467
|
-
Then inject it in a custom interceptor.
|
|
468
|
-
|
|
469
|
-
## Examples
|
|
470
|
-
|
|
471
|
-
Choose the example that matches your needs:
|
|
472
|
-
|
|
473
|
-
- **[Minimal Simple](../../examples/minimal-simple/)** - Simplest setup with Vite middleware (no HMR)
|
|
474
|
-
- Perfect for getting started quickly
|
|
475
|
-
- Single server, minimal configuration
|
|
476
|
-
|
|
477
|
-
- **[Minimal](../../examples/minimal/)** - Full HMR setup with dual-server architecture
|
|
478
|
-
- Best developer experience with instant hot reloading
|
|
479
|
-
- Recommended for active development
|
|
480
|
-
|
|
481
|
-
- **[Full-Featured](../../examples/full-featured/)** - Production-ready example
|
|
482
|
-
- Security headers, caching, error handling
|
|
483
|
-
- Streaming SSR with React Suspense
|
|
484
|
-
|
|
485
104
|
## Documentation
|
|
486
105
|
|
|
487
|
-
- [
|
|
488
|
-
- [
|
|
489
|
-
- [
|
|
490
|
-
- [Testing Guide](../../docs/TESTING_STRATEGY.md)
|
|
491
|
-
- [Production Deployment](../../docs/PRODUCTION_RISKS.md)
|
|
492
|
-
|
|
493
|
-
## Philosophy
|
|
494
|
-
|
|
495
|
-
This package is built on two foundational principles:
|
|
496
|
-
|
|
497
|
-
### Clean Architecture & SOLID Principles
|
|
498
|
-
|
|
499
|
-
Following [Uncle Bob's Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) and software craftsmanship principles:
|
|
500
|
-
|
|
501
|
-
**Single Responsibility Principle (SRP):**
|
|
502
|
-
- Controllers handle HTTP routing and orchestration
|
|
503
|
-
- Services contain business logic
|
|
504
|
-
- Views handle presentation
|
|
505
|
-
- Each has one reason to change
|
|
506
|
-
|
|
507
|
-
**Dependency Inversion Principle (DIP):**
|
|
508
|
-
- Controllers depend on service abstractions (interfaces)
|
|
509
|
-
- Services are injected via NestJS DI
|
|
510
|
-
- Views receive data as props (dependency injection via props)
|
|
511
|
-
- No concrete dependencies on frameworks in your business logic
|
|
512
|
-
|
|
513
|
-
**Interface Segregation & Open/Closed:**
|
|
514
|
-
- Use NestJS Guards for authentication/authorization
|
|
515
|
-
- Use Interceptors for cross-cutting concerns
|
|
516
|
-
- Views are pure functions - open for extension, closed for modification
|
|
517
|
-
|
|
518
|
-
**Clear Architectural Boundaries:**
|
|
519
|
-
```
|
|
520
|
-
┌─────────────────────────────────────────┐
|
|
521
|
-
│ Presentation Layer (React Components) │
|
|
522
|
-
│ - Pure presentation logic │
|
|
523
|
-
│ - Client-side interactivity │
|
|
524
|
-
│ - No business logic │
|
|
525
|
-
└─────────────────────────────────────────┘
|
|
526
|
-
↓ Props (Data Flow)
|
|
527
|
-
┌─────────────────────────────────────────┐
|
|
528
|
-
│ Application Layer (Controllers) │
|
|
529
|
-
│ - Request handling │
|
|
530
|
-
│ - Orchestration │
|
|
531
|
-
│ - DTO validation │
|
|
532
|
-
└─────────────────────────────────────────┘
|
|
533
|
-
↓ DI (Dependency Injection)
|
|
534
|
-
┌─────────────────────────────────────────┐
|
|
535
|
-
│ Domain Layer (Services) │
|
|
536
|
-
│ - Business logic │
|
|
537
|
-
│ - Domain models │
|
|
538
|
-
│ - Use cases │
|
|
539
|
-
└─────────────────────────────────────────┘
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
### UnJS Philosophy
|
|
543
|
-
|
|
544
|
-
Following the [UnJS philosophy](https://unjs.io/) for modern JavaScript libraries:
|
|
545
|
-
|
|
546
|
-
1. **Unintrusive** - Integrates seamlessly with existing NestJS apps
|
|
547
|
-
2. **Zero-Config** - Works out of the box with sensible defaults
|
|
548
|
-
3. **Fully Extensible** - Customize everything when needed
|
|
549
|
-
4. **Framework Agnostic** - No opinions on routing, state, or business logic
|
|
550
|
-
5. **TypeScript First** - Excellent type safety and IDE support
|
|
551
|
-
|
|
552
|
-
**The Result:** Clean, maintainable, testable code that scales with your team and product.
|
|
106
|
+
- [Full Documentation](https://georgialexandrov.github.io/nestjs-ssr/)
|
|
107
|
+
- [Examples](https://github.com/georgialexandrov/nestjs-ssr/tree/main/examples)
|
|
108
|
+
- [GitHub](https://github.com/georgialexandrov/nestjs-ssr)
|
|
553
109
|
|
|
554
110
|
## Requirements
|
|
555
111
|
|
|
556
|
-
- Node.js
|
|
112
|
+
- Node.js 20+
|
|
557
113
|
- NestJS 11+
|
|
558
114
|
- React 19+
|
|
559
|
-
- Vite 6+
|
|
560
115
|
- TypeScript 5+
|
|
561
116
|
|
|
562
117
|
## License
|
|
563
118
|
|
|
564
|
-
MIT © Georgi Alexandrov
|
|
565
|
-
|
|
566
|
-
## Contributing
|
|
567
|
-
|
|
568
|
-
Contributions welcome! Please see [CONTRIBUTING.md](../../CONTRIBUTING.md).
|
|
569
|
-
|
|
570
|
-
## Support
|
|
571
|
-
|
|
572
|
-
- [GitHub Issues](https://github.com/georgialexandrov/nestjs-ssr/issues)
|
|
573
|
-
- [Documentation](../../docs/)
|
|
574
|
-
- [Examples](../../examples/)
|
|
119
|
+
MIT © [Georgi Alexandrov](https://github.com/georgialexandrov)
|