@coherent.js/core 1.1.2 → 2.0.0-rc.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 +60 -72
- package/dist/index.js +849 -506
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
- package/types/index.d.ts +123 -21
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@coherent.js/core)
|
|
4
4
|
[](../../LICENSE)
|
|
5
|
-
[](https://nodejs.org)
|
|
6
6
|
|
|
7
|
-
Core runtime for Coherent.js — an object-based SSR framework
|
|
7
|
+
Core runtime for Coherent.js — an object-based SSR framework: components are plain JavaScript objects rendered to HTML.
|
|
8
8
|
|
|
9
|
-
- ESM-only, Node
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
9
|
+
- ESM-only, Node 22.12+
|
|
10
|
+
- Synchronous `render()` to a string, and `renderToStream()` for large pages
|
|
11
|
+
- Escaped text and attribute values by default; raw HTML only through `html:` or `dangerouslySetInnerContent()`
|
|
12
|
+
- Opt-in scoped CSS, memoization and whole-render caching
|
|
13
13
|
|
|
14
14
|
For a high-level overview and repository-wide instructions, see the root README: ../../README.md
|
|
15
15
|
|
|
@@ -19,103 +19,91 @@ For a high-level overview and repository-wide instructions, see the root README:
|
|
|
19
19
|
pnpm add @coherent.js/core
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Requirements:
|
|
23
|
-
- Node.js >= 20
|
|
24
|
-
- ESM module system
|
|
25
|
-
|
|
26
22
|
## Quick start
|
|
27
23
|
|
|
28
|
-
JavaScript (ESM):
|
|
29
24
|
```js
|
|
30
25
|
import { render } from '@coherent.js/core';
|
|
31
26
|
|
|
32
|
-
const
|
|
33
|
-
div: {
|
|
27
|
+
const Greeting = ({ name }) => ({
|
|
28
|
+
div: {
|
|
29
|
+
className: ['greeting', name === 'Ada' && 'greeting--vip'],
|
|
30
|
+
children: [
|
|
31
|
+
{ h1: { text: `Hello ${name}` } }, // text is escaped
|
|
32
|
+
name === 'Ada' && { p: { text: 'Welcome back' } } // false renders nothing
|
|
33
|
+
]
|
|
34
|
+
}
|
|
34
35
|
});
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
render(Greeting({ name: 'Ada' }));
|
|
38
|
+
// <div class="greeting greeting--vip"><h1>Hello Ada</h1><p>Welcome back</p></div>
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
import { render } from '@coherent.js/core';
|
|
41
|
+
## Rendering
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
console.log(html);
|
|
47
|
-
```
|
|
43
|
+
- `render(component, options?)` returns an HTML string. It is synchronous: await data and async components first (a Promise in the tree throws).
|
|
44
|
+
- A function component that throws makes `render()` throw a `RenderingError` naming the component's path, with the original error as `cause`. Pass `onError: (error, { path }) => replacement` to render something else in its place (`null` omits it).
|
|
45
|
+
- Options: `scoped` (scoped CSS), `minify`, `maxDepth`, `enableMonitoring`, `enableCache` / `cache` (see below), `onError`.
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
### Streaming
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
import { Readable } from 'node:stream';
|
|
51
|
+
import { renderToStream, streamingUtils } from '@coherent.js/core';
|
|
52
|
+
|
|
53
|
+
// An async generator of HTML chunks with exactly render()'s output
|
|
54
|
+
Readable.from(renderToStream(Page(), { chunkSize: 16384 })).pipe(res);
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
// or: writes with backpressure, aborts the response if rendering fails and
|
|
57
|
+
// stops rendering if the client disconnects
|
|
58
|
+
await streamingUtils.streamToResponse(renderToStream(Page()), res);
|
|
59
|
+
```
|
|
52
60
|
|
|
53
|
-
|
|
54
|
-
- Rendering
|
|
55
|
-
- `render(input, options?)` – renders a component object to an HTML string
|
|
56
|
-
- Component system (re-exported from internal modules)
|
|
57
|
-
- `createComponent`, `defineComponent`, `registerComponent`, `getComponent`, `getRegisteredComponents`
|
|
58
|
-
- State helpers: `withState`, `withStateUtils`, `createStateManager`
|
|
59
|
-
- Lazy: `lazy`, `isLazy`, `evaluateLazy`
|
|
60
|
-
- Error boundaries (selected)
|
|
61
|
-
- `createErrorBoundary`, `withErrorBoundary`, `createAsyncErrorBoundary`
|
|
62
|
-
- `createGlobalErrorHandler`, `GlobalErrorHandler`
|
|
61
|
+
The event loop gets a turn after every chunk, so the first bytes of a large page leave early and other requests keep being served; total render time is somewhat higher than `render()`.
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
### Caching
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
Nothing is cached unless you ask:
|
|
67
66
|
|
|
68
67
|
```js
|
|
69
|
-
import {
|
|
68
|
+
import { memo, render, createCacheManager } from '@coherent.js/core';
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
]
|
|
77
|
-
}
|
|
78
|
-
}));
|
|
70
|
+
// Per-component memoization; every memoized component has its own LRU
|
|
71
|
+
const Row = memo(({ item }) => ({ li: { text: item.name } }), {
|
|
72
|
+
keyFn: ({ item }) => `${item.id}:${item.version}`,
|
|
73
|
+
maxSize: 1000
|
|
74
|
+
});
|
|
79
75
|
|
|
80
|
-
|
|
76
|
+
// Whole-render cache, keyed on the complete tree (trees containing
|
|
77
|
+
// functions are never cached). Only useful for re-rendering identical trees.
|
|
78
|
+
const cache = createCacheManager({ maxCacheSize: 500, ttlMs: 60_000 });
|
|
79
|
+
render(StaticPage(), { enableCache: true, cache });
|
|
81
80
|
```
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
import { createComponent, render } from '@coherent.js/core';
|
|
82
|
+
### Raw HTML
|
|
86
83
|
|
|
87
|
-
|
|
84
|
+
Text and attribute values are always escaped. Raw markup goes through the `html:` key or `dangerouslySetInnerContent()`; markers from that function carry a symbol brand, so objects parsed from JSON are never treated as trusted. Attribute names that could break out of the tag (whitespace, quotes, `<`, `>`, `/`, `=`) make `render()` throw.
|
|
88
85
|
|
|
89
|
-
|
|
90
|
-
div: {
|
|
91
|
-
class: 'counter',
|
|
92
|
-
children: [ { span: { text: `Count: ${props.count ?? 0}` } } ]
|
|
93
|
-
}
|
|
94
|
-
}));
|
|
86
|
+
### Event handlers
|
|
95
87
|
|
|
96
|
-
|
|
97
|
-
```
|
|
88
|
+
Function-valued `on*` props render nothing on the server; `@coherent.js/client`'s `hydrate()` attaches them in the browser. Inline string handlers (`onclick: 'history.back()'`) are rendered as attributes.
|
|
98
89
|
|
|
99
|
-
##
|
|
90
|
+
## Exports overview
|
|
100
91
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
- Rendering: `render`, `renderToStream`, `streamingUtils`, `formatAttributes`, `escapeHtml`, `isValidAttributeName`, `dangerouslySetInnerContent`, `isTrustedContent`
|
|
93
|
+
- Components: `createComponent`, `defineComponent`, `registerComponent`, `memo`, `memoComponent`, `lazy`, `withState`, `withStateUtils`
|
|
94
|
+
- Error boundaries: `createErrorBoundary`, `withErrorBoundary`, `createAsyncErrorBoundary`, `createGlobalErrorHandler`
|
|
95
|
+
- Caching and monitoring: `createCacheManager`, `cacheManager`, `memoize`, `performanceMonitor`
|
|
96
|
+
- Events: `createEventBus`, `globalEventBus`, `withEventBus`, `eventSystem`
|
|
105
97
|
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
pnpm --filter @coherent.js/core run test:watch
|
|
109
|
-
```
|
|
98
|
+
`createComponent()` returns a *stateful instance* (`mount`, `update`, `destroy`, instance state) meant for the browser. On the server, pass per-request data through props: instance state is shared by every request that renders the same component.
|
|
110
99
|
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
pnpm --filter @coherent.js/core run typecheck
|
|
114
|
-
```
|
|
100
|
+
## Development
|
|
115
101
|
|
|
116
|
-
Build (from package dir or via workspace filter):
|
|
117
102
|
```bash
|
|
103
|
+
pnpm vitest run packages/core # tests (from the repo root)
|
|
104
|
+
pnpm --filter @coherent.js/core run typecheck
|
|
118
105
|
pnpm --filter @coherent.js/core run build
|
|
106
|
+
pnpm perf:render # rendering benchmark
|
|
119
107
|
```
|
|
120
108
|
|
|
121
109
|
## License
|