@lolyjs/core 0.2.0-alpha.13 → 0.2.0-alpha.15

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 CHANGED
@@ -37,7 +37,7 @@ Loly is a full-stack React framework that combines the simplicity of file-based
37
37
 
38
38
  - 🔌 **Native WebSocket Support** - Built-in Socket.IO integration with automatic namespace routing
39
39
  - 🎯 **Route-Level Middlewares** - Define middlewares directly in your routes for pages and APIs
40
- - 📁 **Separation of Concerns** - Server logic in `server.hook.ts` separate from React components
40
+ - 📁 **Separation of Concerns** - Server logic in `page.server.hook.ts` and `layout.server.hook.ts` separate from React components
41
41
  - 🚀 **Hybrid Rendering** - SSR, SSG, and CSR with streaming support
42
42
  - 🛡️ **Security First** - Built-in rate limiting, validation, sanitization, and security headers
43
43
  - ⚡ **Performance** - Fast bundling with Rspack and optimized code splitting
@@ -66,7 +66,7 @@ export default function Home() {
66
66
  ### Add Server-Side Data
67
67
 
68
68
  ```tsx
69
- // app/page/server.hook.ts
69
+ // app/page.server.hook.ts (preferred) or app/server.hook.ts (legacy)
70
70
  import type { ServerLoader } from "@lolyjs/core";
71
71
 
72
72
  export const getServerSideProps: ServerLoader = async (ctx) => {
@@ -157,7 +157,7 @@ Define middlewares directly in your routes for fine-grained control:
157
157
  **For Pages:**
158
158
 
159
159
  ```tsx
160
- // app/dashboard/server.hook.ts
160
+ // app/dashboard/page.server.hook.ts (preferred) or app/dashboard/server.hook.ts (legacy)
161
161
  import type { RouteMiddleware, ServerLoader } from "@lolyjs/core";
162
162
 
163
163
  export const beforeServerData: RouteMiddleware[] = [
@@ -233,22 +233,37 @@ Routes are automatically created from your file structure:
233
233
 
234
234
  ```tsx
235
235
  // app/layout.tsx (Root layout)
236
- export default function RootLayout({ children }) {
236
+ export default function RootLayout({ children, appName, navigation }) {
237
237
  return (
238
238
  <div>
239
- <nav>Navigation</nav>
239
+ <nav>{navigation}</nav>
240
240
  {children}
241
- <footer>Footer</footer>
241
+ <footer>{appName}</footer>
242
242
  </div>
243
243
  );
244
244
  }
245
245
  ```
246
246
 
247
+ ```tsx
248
+ // app/layout.server.hook.ts (Root layout server hook - same directory as layout.tsx)
249
+ import type { ServerLoader } from "@lolyjs/core";
250
+
251
+ export const getServerSideProps: ServerLoader = async (ctx) => {
252
+ return {
253
+ props: {
254
+ appName: "My App",
255
+ navigation: ["Home", "About", "Blog"],
256
+ },
257
+ };
258
+ };
259
+ ```
260
+
247
261
  ```tsx
248
262
  // app/blog/layout.tsx (Nested layout)
249
- export default function BlogLayout({ children }) {
263
+ export default function BlogLayout({ children, sectionTitle }) {
250
264
  return (
251
265
  <div>
266
+ <h1>{sectionTitle}</h1>
252
267
  <aside>Sidebar</aside>
253
268
  <main>{children}</main>
254
269
  </div>
@@ -256,6 +271,31 @@ export default function BlogLayout({ children }) {
256
271
  }
257
272
  ```
258
273
 
274
+ ```tsx
275
+ // app/blog/layout.server.hook.ts (Nested layout server hook - same directory as layout.tsx)
276
+ import type { ServerLoader } from "@lolyjs/core";
277
+
278
+ export const getServerSideProps: ServerLoader = async (ctx) => {
279
+ return {
280
+ props: {
281
+ sectionTitle: "Blog Section",
282
+ },
283
+ };
284
+ };
285
+ ```
286
+
287
+ **Layout Server Hooks:**
288
+
289
+ Layouts can have their own server hooks that provide stable data across all pages. Props from layout server hooks are automatically merged with page props:
290
+
291
+ - **Layout props** (from `layout.server.hook.ts`) are stable and available to both the layout and all pages
292
+ - **Page props** (from `page.server.hook.ts`) are specific to each page and override layout props if there's a conflict
293
+ - **Combined props** are available to both layouts and pages
294
+
295
+ **File Convention:**
296
+ - Layout server hooks: `app/layout.server.hook.ts` (same directory as `layout.tsx`)
297
+ - Page server hooks: `app/page.server.hook.ts` (preferred) or `app/server.hook.ts` (legacy, backward compatible)
298
+
259
299
  ### 🚀 Hybrid Rendering
260
300
 
261
301
  Choose the best rendering strategy for each page:
@@ -263,7 +303,7 @@ Choose the best rendering strategy for each page:
263
303
  **SSR (Server-Side Rendering):**
264
304
 
265
305
  ```tsx
266
- // app/posts/server.hook.ts
306
+ // app/posts/page.server.hook.ts (preferred) or app/posts/server.hook.ts (legacy)
267
307
  export const dynamic = "force-dynamic" as const;
268
308
 
269
309
  export const getServerSideProps: ServerLoader = async (ctx) => {
@@ -275,7 +315,7 @@ export const getServerSideProps: ServerLoader = async (ctx) => {
275
315
  **SSG (Static Site Generation):**
276
316
 
277
317
  ```tsx
278
- // app/blog/[slug]/server.hook.ts
318
+ // app/blog/[slug]/page.server.hook.ts (preferred) or app/blog/[slug]/server.hook.ts (legacy)
279
319
  export const dynamic = "force-static" as const;
280
320
 
281
321
  export const generateStaticParams: GenerateStaticParams = async () => {
@@ -292,7 +332,7 @@ export const getServerSideProps: ServerLoader = async (ctx) => {
292
332
  **CSR (Client-Side Rendering):**
293
333
 
294
334
  ```tsx
295
- // app/dashboard/page.tsx (No server.hook.ts)
335
+ // app/dashboard/page.tsx (No page.server.hook.ts)
296
336
  import { useState, useEffect } from "react";
297
337
 
298
338
  export default function Dashboard() {
@@ -407,16 +447,18 @@ logger.error("Error occurred", error);
407
447
  your-app/
408
448
  ├── app/
409
449
  │ ├── layout.tsx # Root layout
450
+ │ ├── layout.server.hook.ts # Root layout server hook (stable props)
410
451
  │ ├── page.tsx # Home page (/)
411
- │ ├── server.hook.ts # Server logic for home
452
+ │ ├── page.server.hook.ts # Page server hook (preferred) or server.hook.ts (legacy)
412
453
  │ ├── _not-found.tsx # Custom 404
413
454
  │ ├── _error.tsx # Custom error page
414
455
  │ ├── blog/
415
456
  │ │ ├── layout.tsx # Blog layout
457
+ │ │ ├── layout.server.hook.ts # Blog layout server hook
416
458
  │ │ ├── page.tsx # /blog
417
459
  │ │ └── [slug]/
418
460
  │ │ ├── page.tsx # /blog/:slug
419
- │ │ └── server.hook.ts # Server logic
461
+ │ │ └── page.server.hook.ts # Page server hook
420
462
  │ ├── api/
421
463
  │ │ └── posts/
422
464
  │ │ └── route.ts # /api/posts
@@ -437,7 +479,10 @@ your-app/
437
479
 
438
480
  ### Server Loader
439
481
 
482
+ **Page Server Hook:**
483
+
440
484
  ```tsx
485
+ // app/page.server.hook.ts (preferred) or app/server.hook.ts (legacy)
441
486
  import type { ServerLoader } from "@lolyjs/core";
442
487
 
443
488
  export const getServerSideProps: ServerLoader = async (ctx) => {
@@ -468,6 +513,48 @@ export const getServerSideProps: ServerLoader = async (ctx) => {
468
513
  };
469
514
  ```
470
515
 
516
+ **Layout Server Hook:**
517
+
518
+ ```tsx
519
+ // app/layout.server.hook.ts (same directory as layout.tsx)
520
+ import type { ServerLoader } from "@lolyjs/core";
521
+
522
+ export const getServerSideProps: ServerLoader = async (ctx) => {
523
+ // Fetch stable data that persists across all pages
524
+ const user = await getCurrentUser();
525
+ const navigation = await getNavigation();
526
+
527
+ return {
528
+ props: {
529
+ user, // Available to layout and all pages
530
+ navigation, // Available to layout and all pages
531
+ },
532
+ };
533
+ };
534
+ ```
535
+
536
+ **Props Merging:**
537
+
538
+ - Layout props (from `layout.server.hook.ts`) are merged first
539
+ - Page props (from `page.server.hook.ts`) are merged second and override layout props
540
+ - Both layouts and pages receive the combined props
541
+
542
+ ```tsx
543
+ // app/layout.tsx
544
+ export default function Layout({ user, navigation, children }) {
545
+ // Receives: user, navigation (from layout.server.hook.ts)
546
+ // Also receives: any props from page.server.hook.ts
547
+ return <div>{/* ... */}</div>;
548
+ }
549
+
550
+ // app/page.tsx
551
+ export default function Page({ user, navigation, posts }) {
552
+ // Receives: user, navigation (from layout.server.hook.ts)
553
+ // Receives: posts (from page.server.hook.ts)
554
+ return <div>{/* ... */}</div>;
555
+ }
556
+ ```
557
+
471
558
  ### API Route Handler
472
559
 
473
560
  ```tsx