node-turbo 1.0.1 → 1.1.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/.c8rc.json +3 -1
- package/README.md +111 -18
- package/docs/API.md +250 -30
- package/lib/express/express-turbo-stream.js +5 -0
- package/lib/koa/koa-turbo-stream.js +3 -1
- package/lib/turbo-element.js +8 -2
- package/lib/turbo-frame.js +5 -0
- package/lib/turbo-readable.js +9 -2
- package/lib/turbo-stream-element.js +27 -21
- package/lib/turbo-stream.js +52 -96
- package/lib/ws/ws-turbo-stream.js +8 -0
- package/package.json +30 -15
- package/test/unit/core/turbo-element.test.js +29 -0
- package/test/unit/core/turbo-stream-element.test.js +7 -0
- package/test/unit/core/turbo-stream.test.js +31 -0
package/.c8rc.json
CHANGED
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# node-turbo
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
node-turbo is a library for Node.js to assist with the server side of [37signals](https://37signals.com)' [Hotwire Turbo](https://turbo.hotwired.dev) framework. It provides classes and functions for Web servers and also convenience functions for the frameworks [Koa](https://koajs.com) and [Express](https://expressjs.com) as well as for [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) and [SSE](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events).
|
|
4
4
|
|
|
5
5
|
This documentation assumes that you are familiar with Turbo and its [handbook](https://turbo.hotwired.dev/handbook/introduction).
|
|
6
6
|
|
|
7
7
|
## Table of Contents
|
|
8
|
+
|
|
8
9
|
- [Installation](#installation)
|
|
9
10
|
- [Compatibility](#compatibility)
|
|
10
11
|
- [Browser](#browser)
|
|
@@ -14,7 +15,10 @@ This documentation assumes that you are familiar with Turbo and its [handbook](h
|
|
|
14
15
|
- [Usage](#usage)
|
|
15
16
|
- [Basics\/Standalone](#basicsstandalone)
|
|
16
17
|
- [Turbo Stream](#turbo-stream)
|
|
18
|
+
- [Action shortcut functions](#action-shortcut-functions)
|
|
19
|
+
- [Additional attributes](#additional-attributes)
|
|
17
20
|
- [Target multiple elements](#target-multiple-elements)
|
|
21
|
+
- [Refresh action](#refresh-action)
|
|
18
22
|
- [Custom actions](#custom-actions)
|
|
19
23
|
- [Using the Node.js streams API](#using-the-nodejs-streams-api)
|
|
20
24
|
- [Turbo Frame](#turbo-frame)
|
|
@@ -32,7 +36,8 @@ This documentation assumes that you are familiar with Turbo and its [handbook](h
|
|
|
32
36
|
- [License](#license)
|
|
33
37
|
|
|
34
38
|
## Installation
|
|
35
|
-
|
|
39
|
+
|
|
40
|
+
```shell
|
|
36
41
|
npm install node-turbo
|
|
37
42
|
```
|
|
38
43
|
|
|
@@ -49,11 +54,11 @@ node-turbo has been tested with:
|
|
|
49
54
|
|
|
50
55
|
| Name | Version(s) |
|
|
51
56
|
| :--- | :--- |
|
|
52
|
-
| [Node.js](https://nodejs.org/) | 16.6
|
|
53
|
-
| [Hotwire Turbo](https://turbo.hotwired.dev/) | 7.3.0
|
|
54
|
-
| [Koa](https://koajs.com/) | 2.14.2 |
|
|
55
|
-
| [Express](https://expressjs.com/) | 4.18.2 |
|
|
56
|
-
| [ws](https://github.com/websockets/ws) | 8.15.1 |
|
|
57
|
+
| [Node.js](https://nodejs.org/) | 16.6 - 20.11.1 |
|
|
58
|
+
| [Hotwire Turbo](https://turbo.hotwired.dev/) | 7.3.0 - 8.0.4 |
|
|
59
|
+
| [Koa](https://koajs.com/) | 2.14.2 - 2.15.0 |
|
|
60
|
+
| [Express](https://expressjs.com/) | 4.18.2 - 4.18.3 |
|
|
61
|
+
| [ws](https://github.com/websockets/ws) | 8.15.1 - 8.16.0 |
|
|
57
62
|
|
|
58
63
|
## API docs
|
|
59
64
|
See [`/docs/API.md`](./docs/API.md) for a documentation of all node-turbo classes and functions.
|
|
@@ -85,7 +90,8 @@ This will render the following HTML fragment:
|
|
|
85
90
|
</turbo-stream>
|
|
86
91
|
```
|
|
87
92
|
|
|
88
|
-
|
|
93
|
+
##### Action shortcut functions
|
|
94
|
+
For all supported [official actions](https://turbo.hotwired.dev/handbook/streams#stream-messages-and-actions) (`append`, `prepend`, `replace`, `update`, `remove`, `before`, `after`, `morph` and `refresh`), there are chainable shortcut functions:
|
|
89
95
|
|
|
90
96
|
```javascript
|
|
91
97
|
import { TurboStream } from 'node-turbo';
|
|
@@ -115,14 +121,41 @@ Result:
|
|
|
115
121
|
</turbo-stream>
|
|
116
122
|
```
|
|
117
123
|
|
|
124
|
+
##### Additional attributes
|
|
125
|
+
If you want/need to add additional attributes to an Turbo Stream element, you can always pass an object instead of the target ID string. Attributes with value `null` will be rendered as boolean attributes.
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
import { TurboStream } from 'node-turbo';
|
|
129
|
+
|
|
130
|
+
const ts = new TurboStream()
|
|
131
|
+
.morph({
|
|
132
|
+
target: 'target-id',
|
|
133
|
+
'children-only': null,
|
|
134
|
+
custom: 'attribute'
|
|
135
|
+
},
|
|
136
|
+
'<p>My content</p>');
|
|
137
|
+
|
|
138
|
+
const html = ts.render();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Result:
|
|
142
|
+
|
|
143
|
+
```html
|
|
144
|
+
<turbo-stream action="morph" target="target-id" children-only custom="attribute">
|
|
145
|
+
<template>
|
|
146
|
+
<p>My content</p>
|
|
147
|
+
</template>
|
|
148
|
+
</turbo-stream>
|
|
149
|
+
```
|
|
150
|
+
|
|
118
151
|
##### Target multiple elements
|
|
119
|
-
If you want to [target multiple elements](https://turbo.hotwired.dev/handbook/streams#actions-with-multiple-targets), you can use the `[action]All()` function:
|
|
152
|
+
If you want to [target multiple elements](https://turbo.hotwired.dev/handbook/streams#actions-with-multiple-targets), you can use the `[action]All()` function (not available when using the `refresh` action):
|
|
120
153
|
|
|
121
154
|
```javascript
|
|
122
155
|
import { TurboStream } from 'node-turbo';
|
|
123
156
|
|
|
124
|
-
|
|
125
|
-
|
|
157
|
+
const ts = new TurboStream().appendAll('.my-targets', '<p>My content</p>');
|
|
158
|
+
const html = ts.render();
|
|
126
159
|
```
|
|
127
160
|
|
|
128
161
|
Result:
|
|
@@ -135,13 +168,45 @@ Result:
|
|
|
135
168
|
</turbo-stream>
|
|
136
169
|
```
|
|
137
170
|
|
|
171
|
+
##### Refresh action
|
|
172
|
+
The action `refresh` works differently as it does not have a target or targets.
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
import { TurboStream } from 'node-turbo';
|
|
176
|
+
|
|
177
|
+
let ts = new TurboStream().refresh();
|
|
178
|
+
let html = ts.render();
|
|
179
|
+
// Renders <turbo-stream action="refresh"></turbo-stream>
|
|
180
|
+
|
|
181
|
+
ts.refresh('1234');
|
|
182
|
+
html = ts.render();
|
|
183
|
+
// Renders <turbo-stream action="refresh" request-id="1234"></turbo-stream>
|
|
184
|
+
|
|
185
|
+
ts.refresh({
|
|
186
|
+
'request-id': '1234',
|
|
187
|
+
'custom': 'param'
|
|
188
|
+
});
|
|
189
|
+
html = ts.render();
|
|
190
|
+
// Renders <turbo-stream action="refresh" request-id="1234" custom="param"></turbo-stream>
|
|
191
|
+
```
|
|
192
|
+
|
|
138
193
|
##### Custom actions
|
|
139
194
|
If you want to use [custom actions](https://turbo.hotwired.dev/handbook/streams#custom-actions), you can use the `custom()`/`customAll()` functions:
|
|
140
195
|
```javascript
|
|
141
196
|
import { TurboStream } from 'node-turbo';
|
|
142
197
|
|
|
143
|
-
|
|
144
|
-
|
|
198
|
+
const ts = new TurboStream().custom('custom-action', 'target-id', '<p>My content</p>');
|
|
199
|
+
const html = ts.render();
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Result:
|
|
203
|
+
|
|
204
|
+
```html
|
|
205
|
+
<turbo-stream action="custom-action" target="target-id">
|
|
206
|
+
<template>
|
|
207
|
+
<p>My content</p>
|
|
208
|
+
</template>
|
|
209
|
+
</turbo-stream>
|
|
145
210
|
```
|
|
146
211
|
|
|
147
212
|
##### Using the Node.js streams API
|
|
@@ -154,7 +219,13 @@ import { TurboStream } from 'node-turbo';
|
|
|
154
219
|
const ts = new TurboStream();
|
|
155
220
|
const readable = ts.createReadableStream();
|
|
156
221
|
|
|
157
|
-
readable.pipe(process.stdout)
|
|
222
|
+
readable.pipe(process.stdout);
|
|
223
|
+
|
|
224
|
+
// These elements get piped immediately:
|
|
225
|
+
ts
|
|
226
|
+
.append('target-id', '<p>My content</p>')
|
|
227
|
+
.replace('target-id-2', '<p>New content</p>')
|
|
228
|
+
.remove('target-id-3');
|
|
158
229
|
```
|
|
159
230
|
|
|
160
231
|
See [Koa](#koa), [SSE](#sse) or [WebSocket](#websocket) for further examples.
|
|
@@ -164,7 +235,7 @@ See [Koa](#koa), [SSE](#sse) or [WebSocket](#websocket) for further examples.
|
|
|
164
235
|
import { TurboFrame } from 'node-turbo';
|
|
165
236
|
|
|
166
237
|
const tf = new TurboFrame('my-id', '<p>content</p>');
|
|
167
|
-
const html =
|
|
238
|
+
const html = tf.render();
|
|
168
239
|
```
|
|
169
240
|
|
|
170
241
|
This will render the following HTML fragment:
|
|
@@ -175,10 +246,32 @@ This will render the following HTML fragment:
|
|
|
175
246
|
</turbo-stream>
|
|
176
247
|
```
|
|
177
248
|
|
|
249
|
+
You can add additional attributes by passing an object instead of the id string:
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
import { TurboFrame } from 'node-turbo';
|
|
253
|
+
|
|
254
|
+
const tf = new TurboFrame({
|
|
255
|
+
id: 'my-id',
|
|
256
|
+
custom: 'foo'
|
|
257
|
+
}, '<p>content</p>');
|
|
258
|
+
const html = tf.render();
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Result:
|
|
262
|
+
|
|
263
|
+
```html
|
|
264
|
+
<turbo-frame id="my-id" custom="foo">
|
|
265
|
+
<p>My content</p>
|
|
266
|
+
</turbo-stream>
|
|
267
|
+
```
|
|
268
|
+
|
|
178
269
|
#### Request Helper Functions
|
|
270
|
+
|
|
179
271
|
node-turbo also provides the following helper functions. You can use these to adapt the behaviour of your server to the differend kind of requests.
|
|
180
272
|
|
|
181
273
|
##### isTurboStreamRequest(request)
|
|
274
|
+
|
|
182
275
|
```javascript
|
|
183
276
|
import { isTurboStreamRequest } from 'node-turbo';
|
|
184
277
|
|
|
@@ -426,7 +519,7 @@ const httpServer = http.createServer((req, res) => {
|
|
|
426
519
|
padding: 10px;
|
|
427
520
|
}
|
|
428
521
|
</style>
|
|
429
|
-
<script type="module" src="https://unpkg.com/@hotwired/turbo@8.0.
|
|
522
|
+
<script type="module" src="https://unpkg.com/@hotwired/turbo@8.0.4/dist/turbo.es2017-esm.js"></script>
|
|
430
523
|
<script>
|
|
431
524
|
var eventSource = new EventSource('/sse');
|
|
432
525
|
eventSource.onmessage = function(event) {
|
|
@@ -513,7 +606,7 @@ app.use(async (ctx, next) => {
|
|
|
513
606
|
padding: 10px;
|
|
514
607
|
}
|
|
515
608
|
</style>
|
|
516
|
-
<script type="module" src="https://unpkg.com/@hotwired/turbo@8.0.
|
|
609
|
+
<script type="module" src="https://unpkg.com/@hotwired/turbo@8.0.4/dist/turbo.es2017-esm.js"></script>
|
|
517
610
|
<script>
|
|
518
611
|
var eventSource = new EventSource('/sse');
|
|
519
612
|
eventSource.onmessage = function(event) {
|
|
@@ -590,7 +683,7 @@ app.get('/', async (req, res) => {
|
|
|
590
683
|
padding: 10px;
|
|
591
684
|
}
|
|
592
685
|
</style>
|
|
593
|
-
<script type="module" src="https://unpkg.com/@hotwired/turbo@8.0.
|
|
686
|
+
<script type="module" src="https://unpkg.com/@hotwired/turbo@8.0.4/dist/turbo.es2017-esm.js"></script>
|
|
594
687
|
<script>
|
|
595
688
|
var eventSource = new EventSource('/sse');
|
|
596
689
|
eventSource.onmessage = function(event) {
|