@moriajs/renderer 0.4.32 → 0.4.34

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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @moriajs/renderer@0.4.32 build C:\Codes\node\2026\github\moriajs\packages\renderer
2
+ > @moriajs/renderer@0.4.34 build C:\Codes\node\2026\github\moriajs\packages\renderer
3
3
  > tsc
4
4
 
package/README.md CHANGED
@@ -11,6 +11,15 @@ Isomorphic renderer for Mithril.js.
11
11
  ## Usage
12
12
 
13
13
  ```ts
14
- import { render } from '@moriajs/renderer';
15
- const html = await render(MyComponent, initialData);
14
+ import { renderToString } from '@moriajs/renderer';
15
+ const html = await renderToString(MyComponent, initialData);
16
16
  ```
17
+
18
+ ## Isomorphic Components & SSR
19
+
20
+ When building components that run on both server and client, you must follow specific guidelines to avoid ReferenceErrors and state leaks:
21
+
22
+ > [!CAUTION]
23
+ > **Do not use top-level module variables for component state.** This can lead to server crashes (ReferenceError) during HMR and state bleeding across requests. Always use `vnode.state`.
24
+
25
+ See the full [SSR Guidelines](./SSR_GUIDELINES.md) for best practices and common pitfalls.
@@ -0,0 +1,91 @@
1
+ # MoriaJS SSR Guidelines: Isomorphic Mithril Components
2
+
3
+ MoriaJS uses Server-Side Rendering (SSR) with client-side hydration to provide fast initial page loads and SEO benefits. However, building isomorphic applications (code that runs on both server and client) requires careful consideration of state management and environment differences.
4
+
5
+ ## The Pitfall: Top-level Module Variables
6
+
7
+ One of the most common issues in Vite-based SSR is the use of top-level module variables for component state.
8
+
9
+ ### Why it fails
10
+
11
+ 1. **Vite SSR Closure Scope**: During development, Vite transforms SSR dependencies and handles Hot Module Replacement (HMR). Top-level variables in your component files can lose their declaration context or become undefined during HMR cycles, leading to `ReferenceError: [var] is not defined`.
12
+ 2. **State Leaks**: Top-level variables persist for the lifetime of the server process. If multiple requests share the same server process, state stored in module-scope variables will "bleed" across requests, leading to data leaks and inconsistent behavior.
13
+
14
+ ### ❌ Incorrect (Anti-pattern)
15
+
16
+ ```ts
17
+ // src/routes/pages/Profile.ts
18
+ let userId; // ERROR: This is shared across ALL server requests and may fail during HMR
19
+
20
+ export default {
21
+ oninit(vnode) {
22
+ userId = vnode.attrs.id;
23
+ },
24
+ view() {
25
+ return m('div', `User ID: ${userId}`);
26
+ }
27
+ }
28
+ ```
29
+
30
+ ### ✅ Correct (Recommended)
31
+
32
+ Always use `vnode.state` for local component state. This ensures the state is encapsulated within the component instance and cleared when the component is destroyed.
33
+
34
+ ```ts
35
+ // src/routes/pages/Profile.ts
36
+ export default {
37
+ oninit(vnode) {
38
+ vnode.state.userId = vnode.attrs.id;
39
+ },
40
+ view(vnode) {
41
+ return m('div', `User ID: ${vnode.state.userId}`);
42
+ }
43
+ }
44
+ ```
45
+
46
+ ## Browser-Only Globals
47
+
48
+ The server-side environment (Node.js) does not have access to browser globals like `window`, `document`, `localStorage`, or `navigator`.
49
+
50
+ ### Safe Access
51
+
52
+ Wrap access to browser globals in checks or use them only in lifecycle hooks that run ONLY on the client (like `oncreate` or `onupdate`).
53
+
54
+ > [!NOTE]
55
+ > MoriaJS's `renderToString` does **not** execute `oncreate` or `onupdate` hooks. These hooks are safe for browser-specific logic.
56
+
57
+ ```ts
58
+ export default {
59
+ oninit() {
60
+ // SSR SAFE: Check if window exists
61
+ if (typeof window !== 'undefined') {
62
+ console.log(window.location.href);
63
+ }
64
+ },
65
+ oncreate() {
66
+ // BROWSER ONLY: Safe to use window/document here
67
+ document.title = 'New Title';
68
+ },
69
+ view() {
70
+ return m('div', 'Hello World');
71
+ }
72
+ }
73
+ ```
74
+
75
+ ## Handling Side Effects
76
+
77
+ ### `m.request` and `m.redraw`
78
+
79
+ MoriaJS automatically patches `m.request` and `m.redraw` during SSR to prevent server crashes caused by lack of browser APIs (like `XMLHttpRequest`).
80
+
81
+ - `m.request` returns an immediately resolving promise on the server.
82
+ - `m.redraw` becomes a no-op on the server.
83
+
84
+ If you need data for SSR, use the `getServerData` pattern (if available in your route) or hydrate data via `initialData` in `renderToString`.
85
+
86
+ ## Summary Checklist
87
+
88
+ - [ ] Use `vnode.state` instead of top-level variables.
89
+ - [ ] Check `typeof window !== 'undefined'` before using browser globals.
90
+ - [ ] Keep DOM-heavy logic in `oncreate`.
91
+ - [ ] Use `initialData` to pass state from server to client.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moriajs/renderer",
3
- "version": "0.4.32",
3
+ "version": "0.4.34",
4
4
  "type": "module",
5
5
  "description": "MoriaJS renderer — Mithril.js SSR/CSR hybrid rendering engine",
6
6
  "main": "./dist/index.js",