@constela/server 3.0.1 → 4.0.0
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 +112 -88
- package/dist/index.js +6 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @constela/server
|
|
2
2
|
|
|
3
|
-
Server-side rendering (SSR) for
|
|
3
|
+
Server-side rendering (SSR) for Constela JSON programs.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -11,76 +11,85 @@ npm install @constela/server
|
|
|
11
11
|
**Peer Dependencies:**
|
|
12
12
|
- `@constela/compiler` ^0.7.0
|
|
13
13
|
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
## How It Works
|
|
15
|
+
|
|
16
|
+
JSON program → HTML string
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"version": "1.0",
|
|
21
|
+
"state": { "name": { "type": "string", "initial": "World" } },
|
|
22
|
+
"view": {
|
|
23
|
+
"kind": "element",
|
|
24
|
+
"tag": "h1",
|
|
25
|
+
"children": [
|
|
26
|
+
{ "kind": "text", "value": { "expr": "lit", "value": "Hello, " } },
|
|
27
|
+
{ "kind": "text", "value": { "expr": "state", "name": "name" } }
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
22
32
|
|
|
23
|
-
|
|
33
|
+
↓ SSR
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
```html
|
|
36
|
+
<h1>Hello, World</h1>
|
|
37
|
+
```
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
## Features
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
import { renderToString } from '@constela/server';
|
|
41
|
+
### Markdown Rendering
|
|
31
42
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
imports: {
|
|
39
|
-
config: { siteName: 'My Site' },
|
|
40
|
-
},
|
|
41
|
-
});
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"kind": "markdown",
|
|
46
|
+
"content": { "expr": "data", "name": "article", "path": "content" }
|
|
47
|
+
}
|
|
42
48
|
```
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
- `program: CompiledProgram` - Compiled program from `@constela/compiler`
|
|
46
|
-
- `options?: RenderOptions` - Optional render configuration
|
|
50
|
+
Rendered with async parsing and Shiki syntax highlighting.
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
};
|
|
56
|
-
imports?: Record<string, unknown>;
|
|
52
|
+
### Code Highlighting
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"kind": "code",
|
|
57
|
+
"code": { "expr": "lit", "value": "const x = 1;" },
|
|
58
|
+
"language": { "expr": "lit", "value": "typescript" }
|
|
57
59
|
}
|
|
58
60
|
```
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
Features:
|
|
63
|
+
- Dual theme support (github-light, github-dark)
|
|
64
|
+
- CSS custom properties for theme switching
|
|
65
|
+
- Preloaded languages: javascript, typescript, json, html, css, python, rust, go, java, bash, markdown
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
### Route Context
|
|
63
68
|
|
|
64
|
-
|
|
69
|
+
Pass route parameters for dynamic pages:
|
|
65
70
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"route": { "path": "/users/:id" },
|
|
74
|
+
"view": {
|
|
75
|
+
"kind": "text",
|
|
76
|
+
"value": { "expr": "route", "name": "id", "source": "param" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
- Dual theme support (github-light, github-dark)
|
|
72
|
-
- CSS custom properties for theme switching
|
|
73
|
-
- Preloaded languages: javascript, typescript, json, html, css, python, rust, go, java, bash, markdown
|
|
81
|
+
### Import Data
|
|
74
82
|
|
|
75
|
-
|
|
76
|
-
```css
|
|
77
|
-
/* Light mode */
|
|
78
|
-
.shiki { background-color: var(--shiki-light-bg); }
|
|
79
|
-
.shiki span { color: var(--shiki-light); }
|
|
83
|
+
Pass external data at render time:
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"imports": { "config": "./data/config.json" },
|
|
88
|
+
"view": {
|
|
89
|
+
"kind": "text",
|
|
90
|
+
"value": { "expr": "import", "name": "config", "path": "siteName" }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
84
93
|
```
|
|
85
94
|
|
|
86
95
|
## Output Structure
|
|
@@ -91,23 +100,23 @@ The package internally handles:
|
|
|
91
100
|
<div class="constela-code" data-code-content="...">
|
|
92
101
|
<div class="group relative">
|
|
93
102
|
<div class="language-badge">typescript</div>
|
|
94
|
-
<button class="constela-copy-btn">
|
|
95
|
-
<!-- Copy icon SVG -->
|
|
96
|
-
</button>
|
|
103
|
+
<button class="constela-copy-btn"><!-- Copy icon --></button>
|
|
97
104
|
<pre><code class="shiki">...</code></pre>
|
|
98
105
|
</div>
|
|
99
106
|
</div>
|
|
100
107
|
```
|
|
101
108
|
|
|
102
|
-
|
|
109
|
+
### CSS Variables
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
```css
|
|
112
|
+
/* Light mode */
|
|
113
|
+
.shiki { background-color: var(--shiki-light-bg); }
|
|
114
|
+
.shiki span { color: var(--shiki-light); }
|
|
107
115
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
116
|
+
/* Dark mode */
|
|
117
|
+
.dark .shiki { background-color: var(--shiki-dark-bg); }
|
|
118
|
+
.dark .shiki span { color: var(--shiki-dark); }
|
|
119
|
+
```
|
|
111
120
|
|
|
112
121
|
## Security
|
|
113
122
|
|
|
@@ -115,29 +124,37 @@ SSR evaluates expressions server-side with some limitations:
|
|
|
115
124
|
- **DOMPurify** - Markdown content is sanitized
|
|
116
125
|
- **Prototype Pollution Prevention** - Same as runtime
|
|
117
126
|
|
|
118
|
-
##
|
|
127
|
+
## Internal API
|
|
128
|
+
|
|
129
|
+
> For framework developers only. End users should use the CLI.
|
|
130
|
+
|
|
131
|
+
### renderToString
|
|
119
132
|
|
|
120
133
|
```typescript
|
|
121
|
-
import { compile } from '@constela/compiler';
|
|
122
134
|
import { renderToString } from '@constela/server';
|
|
123
135
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
{ kind: 'text', value: { expr: 'lit', value: 'Hello, ' } },
|
|
133
|
-
{ kind: 'text', value: { expr: 'state', name: 'name' } },
|
|
134
|
-
],
|
|
136
|
+
const html = await renderToString(compiledProgram, {
|
|
137
|
+
route: {
|
|
138
|
+
params: { id: '123' },
|
|
139
|
+
query: { tab: 'overview' },
|
|
140
|
+
path: '/users/123',
|
|
141
|
+
},
|
|
142
|
+
imports: {
|
|
143
|
+
config: { siteName: 'My Site' },
|
|
135
144
|
},
|
|
136
145
|
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**RenderOptions:**
|
|
137
149
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
150
|
+
```typescript
|
|
151
|
+
interface RenderOptions {
|
|
152
|
+
route?: {
|
|
153
|
+
params?: Record<string, string>;
|
|
154
|
+
query?: Record<string, string>;
|
|
155
|
+
path?: string;
|
|
156
|
+
};
|
|
157
|
+
imports?: Record<string, unknown>;
|
|
141
158
|
}
|
|
142
159
|
```
|
|
143
160
|
|
|
@@ -145,14 +162,21 @@ if (program.ok) {
|
|
|
145
162
|
|
|
146
163
|
Server-rendered HTML can be hydrated on the client:
|
|
147
164
|
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"version": "1.0",
|
|
168
|
+
"lifecycle": { "onMount": "initializeClient" },
|
|
169
|
+
"state": { ... },
|
|
170
|
+
"actions": [
|
|
171
|
+
{
|
|
172
|
+
"name": "initializeClient",
|
|
173
|
+
"steps": [
|
|
174
|
+
{ "do": "storage", "operation": "get", "key": { "expr": "lit", "value": "preferences" }, ... }
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
"view": { ... }
|
|
179
|
+
}
|
|
156
180
|
```
|
|
157
181
|
|
|
158
182
|
## License
|
package/dist/index.js
CHANGED
|
@@ -213,6 +213,12 @@ function evaluate(expr, ctx) {
|
|
|
213
213
|
if (typeof key === "string" && forbiddenKeys.has(key)) return void 0;
|
|
214
214
|
return base[key];
|
|
215
215
|
}
|
|
216
|
+
case "param": {
|
|
217
|
+
return void 0;
|
|
218
|
+
}
|
|
219
|
+
case "style": {
|
|
220
|
+
return "";
|
|
221
|
+
}
|
|
216
222
|
default: {
|
|
217
223
|
const _exhaustiveCheck = expr;
|
|
218
224
|
throw new Error(`Unknown expression type: ${JSON.stringify(_exhaustiveCheck)}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Server-side rendering for Constela UI framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@constela/compiler": "^0.
|
|
18
|
+
"@constela/compiler": "^0.8.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"isomorphic-dompurify": "^2.35.0",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"tsup": "^8.0.0",
|
|
29
29
|
"typescript": "^5.3.0",
|
|
30
30
|
"vitest": "^2.0.0",
|
|
31
|
-
"@constela/compiler": "0.
|
|
31
|
+
"@constela/compiler": "0.8.0"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=20.0.0"
|