@loadbare/app 0.21.0 → 0.23.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 +18 -0
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +8 -3
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/build.d.ts +78 -0
- package/dist/build/build.d.ts.map +1 -0
- package/dist/build/build.js +220 -0
- package/dist/build/build.js.map +1 -0
- package/dist/build/cli.d.ts +6 -1
- package/dist/build/cli.d.ts.map +1 -1
- package/dist/build/cli.js +25 -78
- package/dist/build/cli.js.map +1 -1
- package/dist/build/declared.d.ts.map +1 -1
- package/dist/build/declared.js +3 -0
- package/dist/build/declared.js.map +1 -1
- package/dist/build/skills-cli.d.ts +2 -1
- package/dist/build/skills-cli.d.ts.map +1 -1
- package/dist/build/skills-cli.js +8 -1
- package/dist/build/skills-cli.js.map +1 -1
- package/dist/build/skills.d.ts +2 -0
- package/dist/build/skills.d.ts.map +1 -1
- package/dist/build/skills.js +2 -0
- package/dist/build/skills.js.map +1 -1
- package/dist/core/lb-constants.d.ts +14 -0
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +25 -0
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/dev/lb-dev.d.ts +128 -0
- package/dist/dev/lb-dev.d.ts.map +1 -0
- package/dist/dev/lb-dev.js +289 -0
- package/dist/dev/lb-dev.js.map +1 -0
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +12 -6
- package/dist/hub/lb-apply.js.map +1 -1
- package/dist/hub/lb-hub.browser.d.ts.map +1 -1
- package/dist/hub/lb-hub.browser.js +119 -15
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/docs/comparison.md +4 -3
- package/docs/miswarts.md +3 -2
- package/docs/reference/builder.md +12 -4
- package/docs/reference/chrome.md +52 -1
- package/docs/reference/data-binding.md +28 -18
- package/docs/reference/dev-server.md +178 -0
- package/docs/reference/names.md +14 -1
- package/docs/reference/overview.md +1 -0
- package/docs/reference/server.md +8 -3
- package/docs/reference/widgets.md +10 -277
- package/docs/temp-proposals.md +251 -0
- package/docs/testing.md +2 -1
- package/docs/tutorials/000-getting-started.md +1 -1
- package/docs/tutorials/040-displaying-data.md +1 -1
- package/docs/tutorials/090-using-widget-libraries.md +1 -1
- package/package.json +4 -2
- package/skills/loadbare-app/SKILL.md +30 -11
- package/skills/loadbare-app/references/builder.md +12 -4
- package/skills/loadbare-app/references/chrome.md +52 -1
- package/skills/loadbare-app/references/data-binding.md +28 -18
- package/skills/loadbare-app/references/dev-server.md +178 -0
- package/skills/loadbare-app/references/miswarts.md +3 -2
- package/skills/loadbare-app/references/names.md +14 -1
- package/skills/loadbare-app/references/overview.md +1 -0
- package/skills/loadbare-app/references/server.md +8 -3
- package/skills/loadbare-app/references/widgets.md +10 -277
package/docs/comparison.md
CHANGED
|
@@ -421,7 +421,8 @@ directory named by `loadbare.widgets` in its `package.json`, or the whole
|
|
|
421
421
|
package when that key is absent. Only tags used in the chrome or a page are
|
|
422
422
|
bundled. `@loadbare/widgets` ships `lb-input`, `lb-select`, `lb-options`,
|
|
423
423
|
`lb-picker`, `lb-table`, `lb-confirm`, `lb-form`, `lb-insert-dialog`,
|
|
424
|
-
`lb-master`, `lb-checkbox`, `lb-number`, `lb-date`
|
|
424
|
+
`lb-master`, `lb-checkbox`, `lb-number`, `lb-date`, `lb-tel`, `lb-mailto`
|
|
425
|
+
and `lb-unknown-page`.
|
|
425
426
|
|
|
426
427
|
### Using web components and other libraries
|
|
427
428
|
|
|
@@ -988,7 +989,7 @@ cross-reference.
|
|
|
988
989
|
| Owned | Count | Names |
|
|
989
990
|
| ------------------------------------ | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
990
991
|
| `lb-*` attributes a developer writes | 17 | `lb-query`, `lb-column`, `lb-show`, `lb-group`, `lb-count`, `lb-sum`, `lb-avg`, `lb-min`, `lb-max`, `lb-order`, `lb-filter`, `lb-request`, `lb-select`, `lb-url-link`, `lb-url-parm`, `lb-url-push`, `lb-url-unknown` |
|
|
991
|
-
| `lb-*` stamps |
|
|
992
|
+
| `lb-*` stamps | 28 | `lb-column-value`, `lb-key-value`, `lb-row-live`, `lb-query-row-count`, `lb-query-unsorted-count`, `lb-query-order`, `lb-group-live`, `lb-group-column`, `lb-group-value`, `lb-row-created`, `lb-row-changed`, `lb-row-moved`, `lb-row-requested`, `lb-row-unsorted`, `lb-row-leaving`, `lb-group-leaving`, `lb-row-editing`, `lb-row-selected`, `lb-request-pending`, `lb-request-error`, `lb-request-refused`, `lb-page`, `lb-page-title`, and on `<lb-hub>` `lb-load-state`, `lb-server-state`, `lb-error`, `lb-pending`, `lb-as-of` |
|
|
992
993
|
| `lb-*` build-time attributes | 2 | `lb-exp-slot`, `lb-exp-template` |
|
|
993
994
|
| Requests Loadbare provides | 3 | `lb-row-insert`, `lb-row-update`, `lb-row-delete` |
|
|
994
995
|
| Commands for `commandfor` | 4 | `--lb-edit`, `--lb-new`, `--lb-release`, `--lb-sort` |
|
|
@@ -996,7 +997,7 @@ cross-reference.
|
|
|
996
997
|
| Attribute namespace for expansion | 1 | `exp-*` |
|
|
997
998
|
| Reserved tags | 1 | `<lb-hub>` |
|
|
998
999
|
| Reserved events | 2 | `lb-request`, `lb-request-done` |
|
|
999
|
-
| Queries the hub serves |
|
|
1000
|
+
| Queries the hub serves | 3 | `lb-url`, with columns `lb-path`, `lb-page-label`, `lb-page-unknown`; `lb-choices`, keyed by `lb-path`; `lb-hub`, with columns `lb-load-state`, `lb-server-state`, `lb-error`, `lb-pending`, `lb-as-of` |
|
|
1000
1001
|
| Builder flags | 4 | `--src`, `--out`, `--watch`, `--minify` |
|
|
1001
1002
|
| Reserved file names and patterns | 8 | `chrome.html`, `imports.ts`, `*.page.html`, `*.queries.ts`, `*.requests.ts`, `<tag>.html`, `<tag>.browser.ts`, `*.css` |
|
|
1002
1003
|
| Reserved `package.json` keys | 1 | `loadbare.widgets` |
|
package/docs/miswarts.md
CHANGED
|
@@ -60,8 +60,9 @@ group.
|
|
|
60
60
|
set a flag back to false, or clear a choice, and nothing on the wire
|
|
61
61
|
cannot say either.
|
|
62
62
|
|
|
63
|
-
**Why it terminates.** It applies only to
|
|
64
|
-
|
|
63
|
+
**Why it terminates.** It applies only to these two controls. A
|
|
64
|
+
checkbox lands `"false"` and `""` as unchecked, so it lands what it
|
|
65
|
+
gathered.
|
|
65
66
|
|
|
66
67
|
## Rows hidden by a filter
|
|
67
68
|
|
|
@@ -16,19 +16,27 @@ loadbare-app-build [--src src] [--out dist] [--watch] [--minify]
|
|
|
16
16
|
| `--watch` | Build once, then again on every change under `--src` |
|
|
17
17
|
| `--minify` | Minify `client.js` and `app.css` |
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
During development, [the dev server](./dev-server.md) runs the build in
|
|
20
|
+
watch mode, and restarts the server when it needs to. To run the builder and
|
|
21
|
+
the server side by side without it, from the application's own
|
|
22
|
+
`package.json`:
|
|
20
23
|
|
|
21
24
|
```json
|
|
22
25
|
{
|
|
23
26
|
"scripts": {
|
|
24
|
-
"dev": "loadbare-app-build --watch & tsx server.ts"
|
|
27
|
+
"dev": "loadbare-app-build --watch & trap 'kill $! 2>/dev/null' EXIT INT TERM; tsx server.ts"
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
```
|
|
28
31
|
|
|
32
|
+
The trap stops the watcher when the server exits. Without it, a
|
|
33
|
+
backgrounded watcher ignores Ctrl-C under `sh` and outlives the server.
|
|
34
|
+
|
|
29
35
|
`--watch` watches every `.html`, `.ts`, and `.css` file under `--src`, and
|
|
30
|
-
reports a failed build to the console without stopping. It runs no
|
|
31
|
-
and reloads no browser.
|
|
36
|
+
reports a failed build to the console without stopping. It runs no server
|
|
37
|
+
and reloads no browser. A program that builds or watches as part of its own
|
|
38
|
+
work imports `buildApp` and `watchApp` from `@loadbare/app/build` instead;
|
|
39
|
+
see [Assembling your own](./dev-server.md#assembling-your-own).
|
|
32
40
|
|
|
33
41
|
`--minify` leaves `app.html` alone.
|
|
34
42
|
|
package/docs/reference/chrome.md
CHANGED
|
@@ -277,7 +277,58 @@ browser after a successful 200, and there is no server-delivered 404.
|
|
|
277
277
|
|
|
278
278
|
`@loadbare/widgets` ships this dialog as `<lb-unknown-page>`, for a chrome
|
|
279
279
|
that would rather write one tag; see
|
|
280
|
-
[The Basic Widget Library](./widgets.md
|
|
280
|
+
[The Basic Widget Library](./widgets.md).
|
|
281
|
+
|
|
282
|
+
## The hub's state
|
|
283
|
+
|
|
284
|
+
The hub serves a third query of its own, `lb-hub`: one row, keyed by
|
|
285
|
+
`lb-path`, saying whether the page's data arrived and whether the server
|
|
286
|
+
answers. A page whose load failed shows its markup with nothing landed on
|
|
287
|
+
it, and without this row nothing on the page can tell a list that is empty
|
|
288
|
+
from a server that is down.
|
|
289
|
+
|
|
290
|
+
| Column | Holds |
|
|
291
|
+
|-------------------|------------------------------------------------------------------------|
|
|
292
|
+
| `lb-load-state` | `loading`, `loaded` or `failed`: the page load for the URL showing |
|
|
293
|
+
| `lb-server-state` | `reachable`, `failing` or `unreachable`: how the latest round trip went |
|
|
294
|
+
| `lb-error` | Empty, or why the latest round trip failed |
|
|
295
|
+
| `lb-pending` | How many round trips are in flight, page loads and requests together |
|
|
296
|
+
| `lb-as-of` | When rows last came from the server, as an ISO timestamp |
|
|
297
|
+
|
|
298
|
+
- `lb-load-state` is `loading` while the page load is in flight, `loaded`
|
|
299
|
+
once the server answered it, and `failed` when it did not. A request whose
|
|
300
|
+
answer moves the URL and carries the page's queries loads the page too. A
|
|
301
|
+
load overtaken by a newer one says nothing, and a request that fails
|
|
302
|
+
later leaves the page `loaded`, since what it shows did arrive.
|
|
303
|
+
- `lb-server-state` is `reachable` when the server answered, a refusal
|
|
304
|
+
included; `failing` when it answered with an HTTP error status; and
|
|
305
|
+
`unreachable` when no answer came, because the network failed or the
|
|
306
|
+
ten-second deadline passed. It is empty until the first round trip
|
|
307
|
+
returns.
|
|
308
|
+
- `lb-error` is `network`, `timeout`, or the status the server answered
|
|
309
|
+
with, such as `500`. The next answer empties it.
|
|
310
|
+
- `lb-as-of` is unchanged by a refusal, which brings no rows.
|
|
311
|
+
|
|
312
|
+
The hub also stamps each column on `<lb-hub>` itself, as the attribute of
|
|
313
|
+
the same name, and leaves off one that is empty. A stylesheet reaches the
|
|
314
|
+
whole document that way, and the markup names the query only to show its
|
|
315
|
+
text:
|
|
316
|
+
|
|
317
|
+
```css
|
|
318
|
+
.load-failed { display: none; }
|
|
319
|
+
lb-hub[lb-load-state="failed"] .load-failed { display: block; }
|
|
320
|
+
lb-hub[lb-load-state="failed"] main { opacity: 0.4; }
|
|
321
|
+
lb-hub:not([lb-pending="0"]) .banner { cursor: progress; }
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
```html
|
|
325
|
+
<p class="load-failed" lb-query="lb-hub">
|
|
326
|
+
This page did not load: the server is <span lb-column="lb-server-state"></span>
|
|
327
|
+
(<span lb-column="lb-error"></span>).
|
|
328
|
+
</p>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Nothing writes `lb-hub` but the hub. The builder refuses a request for it.
|
|
281
332
|
|
|
282
333
|
## Preventing the first-load blink
|
|
283
334
|
|
|
@@ -119,9 +119,9 @@ from its nearest ancestor row: the live row it is in, or the element a
|
|
|
119
119
|
it reads from that query's rows.
|
|
120
120
|
|
|
121
121
|
An element with `lb-query` and `lb-column` both shows the rows of its own
|
|
122
|
-
query and holds the column of the row around it. This
|
|
123
|
-
[
|
|
124
|
-
|
|
122
|
+
query and holds the column of the row around it. This `<lb-options>`, from
|
|
123
|
+
[`@loadbare/widgets`](./widgets.md), lists the accounts and holds its row's
|
|
124
|
+
`account`:
|
|
125
125
|
|
|
126
126
|
```html
|
|
127
127
|
<lb-options lb-query="accounts" lb-column="account">
|
|
@@ -167,24 +167,27 @@ option for the value shows no selection.
|
|
|
167
167
|
|
|
168
168
|
The hub hands every value to the browser as the server sent it. What a
|
|
169
169
|
number, a date or a null looks like is decided in the query, or by a custom
|
|
170
|
-
element that formats it, such as
|
|
171
|
-
[`
|
|
170
|
+
element that formats it, such as `lb-number` and `lb-date` in
|
|
171
|
+
[`@loadbare/widgets`](./widgets.md). Send a
|
|
172
172
|
column the user sorts or filters raw, and format it in the element.
|
|
173
173
|
|
|
174
174
|
### Checkboxes
|
|
175
175
|
|
|
176
|
-
A checkbox is a control. It
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
A checkbox is a control. It sends `"true"` or `"false"`
|
|
177
|
+
([miswart](../miswarts.md#checkboxes-and-radio-groups-always-gather-a-value)),
|
|
178
|
+
and it is checked when its column is anything but `false`, null, `"false"`
|
|
179
|
+
or `""`:
|
|
179
180
|
|
|
180
181
|
```html
|
|
181
182
|
<input type="checkbox" lb-column="active" lb-request="lb-row-update" />
|
|
182
183
|
```
|
|
183
184
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
A checkbox lands what it sends, so it shows the same state after a round
|
|
186
|
+
trip through a query whose values are strings, such as `lb-url` or
|
|
187
|
+
`lb-choices`. A query parm the URL does not carry lands as `""`, so the
|
|
188
|
+
checkbox is unchecked. Unchecked sends `"false"` rather than nothing, so a
|
|
189
|
+
flag can be set back. The checkbox's `value` attribute means nothing to the
|
|
190
|
+
hub.
|
|
188
191
|
|
|
189
192
|
### Radio buttons
|
|
190
193
|
|
|
@@ -464,8 +467,9 @@ are heading rows beside their rows:
|
|
|
464
467
|
Content after the nested template lands after the group's rows, which is
|
|
465
468
|
where a group's footer goes.
|
|
466
469
|
|
|
467
|
-
A heading is filled from its group's first row
|
|
468
|
-
|
|
470
|
+
A heading is filled from its group's first row as an element in a row is,
|
|
471
|
+
`href`s from `lb-url-parm` included, so it may show a column other than the
|
|
472
|
+
one the group breaks on. A row an edit from inside the list
|
|
469
473
|
moved to another group stays under its old heading, and the heading shows
|
|
470
474
|
the row as it stood, until the rows are placed again. The hub stamps each top-level
|
|
471
475
|
element of a group with `lb-group-live`, `lb-group-column` and
|
|
@@ -944,7 +948,8 @@ nothing is not sent.
|
|
|
944
948
|
|
|
945
949
|
For a query the hub serves, `lb-url` or `lb-choices`, the hub answers
|
|
946
950
|
`lb-row-update` itself, with no round trip; see
|
|
947
|
-
[Query parms](./chrome.md#query-parms) and [Choices](#choices).
|
|
951
|
+
[Query parms](./chrome.md#query-parms) and [Choices](#choices). The third,
|
|
952
|
+
`lb-hub`, takes no request.
|
|
948
953
|
|
|
949
954
|
A key comes from a live row, or from an element a `row` landed on, so all
|
|
950
955
|
three work against either kind:
|
|
@@ -961,8 +966,11 @@ update from a form or a live row sends every control it gathers. The
|
|
|
961
966
|
application writes one `rowUpdate` for both, setting the columns `values`
|
|
962
967
|
names, as an SQL UPDATE does.
|
|
963
968
|
|
|
964
|
-
After a successful insert gathered from a form, the hub resets the form
|
|
965
|
-
|
|
969
|
+
After a successful insert gathered from a form, the hub resets the form,
|
|
970
|
+
unless the answer landed the new row on it. A form over a `row` query not
|
|
971
|
+
yet entered, whose insert answers `url()` to the new key, then shows the row
|
|
972
|
+
just saved, on record. A failed insert leaves the entry for the user to
|
|
973
|
+
correct.
|
|
966
974
|
|
|
967
975
|
Leave `lb-request` off a control inside a form or a live row that sends its
|
|
968
976
|
own update, or the same edit is written twice.
|
|
@@ -1254,7 +1262,9 @@ A reset of any form, whether the hub's, a reset button's or a script's,
|
|
|
1254
1262
|
returns its controls to their defaults, and the hub removes
|
|
1255
1263
|
`lb-column-value` from each of them. A cancelled reset keeps both.
|
|
1256
1264
|
|
|
1257
|
-
A page load that fails lands nothing and is reported to the console
|
|
1265
|
+
A page load that fails lands nothing and is reported to the console, and
|
|
1266
|
+
the query `lb-hub` says so; see [The hub's state](./chrome.md#the-hubs-state).
|
|
1267
|
+
A load
|
|
1258
1268
|
started by a request for `lb-url` stamps the element that sent it, as any
|
|
1259
1269
|
request stamps its element.
|
|
1260
1270
|
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# The Dev Server
|
|
2
|
+
|
|
3
|
+
`@loadbare/app/dev` runs an application while it is being written. After
|
|
4
|
+
any change, to markup, CSS, a query, a handler, a server module or the
|
|
5
|
+
server's entry file, the developer refreshes the browser. Nothing is ever
|
|
6
|
+
restarted by hand, a refresh never meets a refused connection, and it never
|
|
7
|
+
loads a half-written `client.js`.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// dev.ts
|
|
11
|
+
import { devServer } from "@loadbare/app/dev";
|
|
12
|
+
|
|
13
|
+
await devServer({ server: "server.ts" });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"scripts": {
|
|
19
|
+
"dev": "node dev.ts"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Why a refresh is enough
|
|
25
|
+
|
|
26
|
+
- **The static output is read per request.** The server reads
|
|
27
|
+
`dist/app.html`, and sends `client.js` and `app.css` from disk, so markup,
|
|
28
|
+
CSS and browser code need only a rebuild.
|
|
29
|
+
- **Only server modules need a restart.** `dist/pages.ts` and everything it
|
|
30
|
+
imports are loaded once, and Node cannot unload a module. A new process is
|
|
31
|
+
the honest answer, and a Loadbare server starts in well under a second.
|
|
32
|
+
- **The URL holds the page's state.** A refresh returns the user to the
|
|
33
|
+
same page, row and query parms, so swapping code into a live page buys
|
|
34
|
+
almost nothing.
|
|
35
|
+
|
|
36
|
+
## What it does
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
browser --> devServer :port --> the application's server :appPort (a child)
|
|
40
|
+
|
|
|
41
|
+
+-- the build, watching src (in process)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
1. Builds `dist/`, then rebuilds whenever an `.html`, `.ts` or `.css` file
|
|
45
|
+
under `src` changes. A burst of changes, such as an editor's save or a
|
|
46
|
+
branch switch, is one build.
|
|
47
|
+
2. Runs the application's server as a child process, exactly as it runs in
|
|
48
|
+
production, on `appPort`.
|
|
49
|
+
3. Restarts that server after a build when a server-side file changed: any
|
|
50
|
+
`.ts` under `src` other than a `.browser.ts`, or a change to the page
|
|
51
|
+
registry `dist/pages.ts`, which a page gained or lost changes. It also
|
|
52
|
+
restarts it when the server's entry file changes. CSS, HTML and browser
|
|
53
|
+
code never restart it.
|
|
54
|
+
4. Holds every request while a build runs or the server restarts, and sends
|
|
55
|
+
it on when both are done.
|
|
56
|
+
5. Keeps serving the last good build when a build fails, and says why in
|
|
57
|
+
the console.
|
|
58
|
+
6. Answers 502, "The app server is down; see the dev console.", when the
|
|
59
|
+
server has exited, for example on a throw at import, and starts it again
|
|
60
|
+
on the next save.
|
|
61
|
+
7. Says plainly when its port is in use, and exits.
|
|
62
|
+
8. Passes everything else through, method, path, headers and body,
|
|
63
|
+
`POST /lb/*` included.
|
|
64
|
+
9. Stops the server however the dev server ends: Ctrl-C, a kill, or a
|
|
65
|
+
crash.
|
|
66
|
+
|
|
67
|
+
The application's server reads its port from the environment, as the
|
|
68
|
+
[server recipe](./server.md) does:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
app.listen(Number(process.env.PORT ?? 8787));
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Options
|
|
75
|
+
|
|
76
|
+
Every option but `server` has a default.
|
|
77
|
+
|
|
78
|
+
| Option | Default | Meaning |
|
|
79
|
+
|-----------|----------------------------------|--------------------------------------------------------|
|
|
80
|
+
| `server` | (required) | The application's server entry file |
|
|
81
|
+
| `port` | `PORT` from the environment, or `8787` | The port the browser uses |
|
|
82
|
+
| `host` | `127.0.0.1` | The host that port listens on |
|
|
83
|
+
| `appPort` | `port + 10000` | Where the application's server listens |
|
|
84
|
+
| `portEnv` | `PORT` | The variable the application's server reads its port from |
|
|
85
|
+
| `node` | `["--env-file-if-exists=.env"]` | Node's arguments before the entry file |
|
|
86
|
+
| `src` | `src` | The builder's source tree |
|
|
87
|
+
| `out` | `dist` | The builder's output |
|
|
88
|
+
| `log` | the console | Where progress goes, one line at a time |
|
|
89
|
+
|
|
90
|
+
A server written in TypeScript runs under Node's own type stripping, Node
|
|
91
|
+
22.18 and later. For a runner such as tsx, name it in `node`:
|
|
92
|
+
`node: ["--import", "tsx"]`.
|
|
93
|
+
|
|
94
|
+
`devServer` resolves once the first build is done and the server accepts
|
|
95
|
+
connections, with `{ port, close() }`.
|
|
96
|
+
|
|
97
|
+
## Assembling your own
|
|
98
|
+
|
|
99
|
+
`devServer` is a short composition of parts that are exported on their own.
|
|
100
|
+
An application that wants something else, such as other files that restart
|
|
101
|
+
the server, a second server, or a reload pushed to the browser, builds its
|
|
102
|
+
own from them.
|
|
103
|
+
|
|
104
|
+
| Part | From | Does |
|
|
105
|
+
|--------------|------------------------|--------------------------------------------------------------|
|
|
106
|
+
| `watchApp` | `@loadbare/app/build` | Builds, rebuilds on a change, and reports each build |
|
|
107
|
+
| `buildApp` | `@loadbare/app/build` | Builds once |
|
|
108
|
+
| `watchTree` | `@loadbare/app/build` | Reports each changed file under a directory |
|
|
109
|
+
| `appServer` | `@loadbare/app/dev` | The application's server as a child process, restarted on demand |
|
|
110
|
+
| `gate` | `@loadbare/app/dev` | Holds requests while any reason to hold them stands |
|
|
111
|
+
| `devProxy` | `@loadbare/app/dev` | The browser's port, passing requests through a gate |
|
|
112
|
+
|
|
113
|
+
`watchApp({ src, out, minify, onStart, onBuilt })` builds at once, then
|
|
114
|
+
again on each change. `onStart(changed)` is called as a build begins, with
|
|
115
|
+
the files under `src` that changed, relative to it, and an empty list for
|
|
116
|
+
the first. `onBuilt(outcome)` is called as it ends, with `{ ok: true,
|
|
117
|
+
changed, built }` or `{ ok: false, changed, error }`; `built.files` lists
|
|
118
|
+
what was written. Builds never overlap: changes during one are gathered into
|
|
119
|
+
the next. It returns `{ ready, close() }`, where `ready` resolves with the
|
|
120
|
+
first build's outcome. Paths resolve against the working directory.
|
|
121
|
+
|
|
122
|
+
`buildApp({ src, out, minify })` builds once, and throws when the build
|
|
123
|
+
fails. A build writes nothing until every output is ready, so a failed one
|
|
124
|
+
leaves the last good build in place. `loadbare-app-build` is a thin command
|
|
125
|
+
over these two.
|
|
126
|
+
|
|
127
|
+
`watchTree(root, onFile)` calls `onFile(file)` for each file under `root`
|
|
128
|
+
that is changed, added or removed, with its path relative to `root`. It
|
|
129
|
+
watches each directory, including those made later, so a file saved by
|
|
130
|
+
replacing it, as `sed -i` and many editors save, is reported on every save.
|
|
131
|
+
Node's `fs.watch` with `recursive: true` loses such a file on Linux after
|
|
132
|
+
its first save. It returns `{ close() }`. `watchApp` watches `src` with it.
|
|
133
|
+
|
|
134
|
+
`appServer({ entry, port, portEnv, node, log })` returns `{ restart(),
|
|
135
|
+
stop(), state }`. `restart()` stops the server if it runs, starts it, and
|
|
136
|
+
resolves once it accepts connections, or has exited instead. `state` is
|
|
137
|
+
`starting`, `running`, `down` for a server that exited on its own, or
|
|
138
|
+
`stopped`. Once stopped, it never starts again. The child is killed when
|
|
139
|
+
this process exits, however it exits.
|
|
140
|
+
|
|
141
|
+
`gate()` returns `{ close(reason), open(reason), wait(), isOpen }`. Each
|
|
142
|
+
`close` is matched by its own `open`, and `wait()` resolves once every
|
|
143
|
+
close has been. A build and a restart can each hold requests without one
|
|
144
|
+
ending the other's hold.
|
|
145
|
+
|
|
146
|
+
`devProxy({ port, host, target, gate, isDown })` listens on `port` and
|
|
147
|
+
passes every request to `target` once the gate is open, answering 502 while
|
|
148
|
+
`isDown()` is true. It resolves with the listening server, and rejects with
|
|
149
|
+
a plain message when the port is in use.
|
|
150
|
+
|
|
151
|
+
A dev server that also restarts on a change to `config/`:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { watchApp, watchTree } from "@loadbare/app/build";
|
|
155
|
+
import { appServer, devProxy, gate } from "@loadbare/app/dev";
|
|
156
|
+
|
|
157
|
+
const held = gate();
|
|
158
|
+
const app = appServer({ entry: "server.ts", port: 18787 });
|
|
159
|
+
const restart = async () => {
|
|
160
|
+
held.close("server");
|
|
161
|
+
await app.restart();
|
|
162
|
+
held.open("server");
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const watcher = watchApp({
|
|
166
|
+
onStart: () => held.close("build"),
|
|
167
|
+
onBuilt: async (outcome) => {
|
|
168
|
+
console.log(outcome.ok ? outcome.built.summary : outcome.error.message);
|
|
169
|
+
if (outcome.changed.some((f) => f.endsWith(".ts"))) await restart();
|
|
170
|
+
held.open("build");
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
watchTree("config", () => void restart());
|
|
174
|
+
|
|
175
|
+
await watcher.ready;
|
|
176
|
+
await restart();
|
|
177
|
+
await devProxy({ port: 8787, target: 18787, gate: held, isDown: () => app.state === "down" });
|
|
178
|
+
```
|
package/docs/reference/names.md
CHANGED
|
@@ -103,6 +103,7 @@ assigns one.
|
|
|
103
103
|
| `lb-request-pending` | Hub | [Request state](./data-binding.md#request-state) |
|
|
104
104
|
| `lb-request-error` | Hub | [Request state](./data-binding.md#request-state) |
|
|
105
105
|
| `lb-request-refused` | Hub | [Refusals](./data-binding.md#refusals) |
|
|
106
|
+
| `lb-load-state`, `lb-server-state`, `lb-error`, `lb-pending`, `lb-as-of` on `<lb-hub>` | Hub | [The hub's state](./chrome.md#the-hubs-state) |
|
|
106
107
|
| `lb-show` on a `<template>` | Hub and builder | [Where an absent element is](./data-binding.md#where-an-absent-element-is) |
|
|
107
108
|
| `lb-page` | Builder | [What the builder writes](./builder.md#what-the-builder-writes) |
|
|
108
109
|
| `lb-page-title` | Builder | [The page title](./page-files.md#the-page-title) |
|
|
@@ -110,12 +111,13 @@ assigns one.
|
|
|
110
111
|
## Reserved queries
|
|
111
112
|
|
|
112
113
|
The hub serves these in the browser. Every page and the chrome may name
|
|
113
|
-
them, and a page declares
|
|
114
|
+
them, and a page declares none.
|
|
114
115
|
|
|
115
116
|
| Query | Kind | Key | Columns | Defined in |
|
|
116
117
|
| ------------ | ----- | --------- | --------------------------------------------------------------- | ------------------------------------- |
|
|
117
118
|
| `lb-url` | `row` | `lb-path` | `lb-path`, `lb-page-label`, `lb-page-unknown`, every query parm | [The URL](./chrome.md#the-url) |
|
|
118
119
|
| `lb-choices` | `row` | `lb-path` | `lb-path`, every choice | [Choices](./data-binding.md#choices) |
|
|
120
|
+
| `lb-hub` | `row` | `lb-path` | `lb-path`, `lb-load-state`, `lb-server-state`, `lb-error`, `lb-pending`, `lb-as-of` | [The hub's state](./chrome.md#the-hubs-state) |
|
|
119
121
|
|
|
120
122
|
No query parm is reserved: a column of `lb-url` whose name begins with
|
|
121
123
|
`lb-` is never a query parm.
|
|
@@ -175,6 +177,8 @@ accessor or field named `lb` and a capital.
|
|
|
175
177
|
| -------------------------- | ---------------------------------------------------------------- | ---------------------------------------------- |
|
|
176
178
|
| `@loadbare/app/server` | `row`, `rows`, `patch`, `url`, `choices`, `refusal`, `createHub`, and the types `Queries`, `Requests`, `HubContext`, `Hub` | [Page Files](./page-files.md), [The data channel](./server.md#the-data-channel) |
|
|
177
179
|
| `@loadbare/app/express` | `hubRoutes` | [The Express Server](./server.md) |
|
|
180
|
+
| `@loadbare/app/dev` | `devServer`, `appServer`, `gate`, `devProxy`, `DOWN_MESSAGE` | [The Dev Server](./dev-server.md) |
|
|
181
|
+
| `@loadbare/app/build` | `buildApp`, `watchApp` | [Assembling your own](./dev-server.md#assembling-your-own) |
|
|
178
182
|
| `@loadbare/app/types` | `HubRequest`, `ResponseItem`, `HubRequestDone`, `HubLifecycle`, and the rules the hub applies: `readAs`, `parseFilter`, `passes`, `passesTerm` | [The data channel](./server.md#the-data-channel), [Order](./data-binding.md#order), [Filters](./data-binding.md#filters) |
|
|
179
183
|
| `@loadbare/app` | `applyRow` | [Filling a subtree by hand](./custom-elements.md#filling-a-subtree-by-hand) |
|
|
180
184
|
| `@loadbare/app/constants` | Every name on this page; see [Constants](#constants) | [Code](./custom-elements.md#code) |
|
|
@@ -244,6 +248,15 @@ imports them rather than writing a string.
|
|
|
244
248
|
| `URL_COLUMN_PATH` | `lb-path` |
|
|
245
249
|
| `URL_COLUMN_PAGE_LABEL` | `lb-page-label` |
|
|
246
250
|
| `URL_COLUMN_PAGE_UNKNOWN` | `lb-page-unknown` |
|
|
251
|
+
| `HUB_QUERY` | `lb-hub` |
|
|
252
|
+
| `HUB_COLUMN_LOAD_STATE` | `lb-load-state` |
|
|
253
|
+
| `HUB_COLUMN_SERVER_STATE` | `lb-server-state` |
|
|
254
|
+
| `HUB_COLUMN_ERROR` | `lb-error` |
|
|
255
|
+
| `HUB_COLUMN_PENDING` | `lb-pending` |
|
|
256
|
+
| `HUB_COLUMN_AS_OF` | `lb-as-of` |
|
|
257
|
+
| `HUB_LOAD_LOADING`, `HUB_LOAD_LOADED`, `HUB_LOAD_FAILED` | `loading`, `loaded`, `failed` |
|
|
258
|
+
| `HUB_SERVER_REACHABLE`, `HUB_SERVER_FAILING`, `HUB_SERVER_UNREACHABLE` | `reachable`, `failing`, `unreachable` |
|
|
259
|
+
| `HUB_ERROR_NETWORK`, `HUB_ERROR_TIMEOUT` | `network`, `timeout` |
|
|
247
260
|
| `ATTR_URL_LINK` | `lb-url-link` |
|
|
248
261
|
| `ATTR_URL_PARM` | `lb-url-parm` |
|
|
249
262
|
| `ATTR_URL_PUSH` | `lb-url-push` |
|
|
@@ -19,6 +19,7 @@ serves, and the custom elements those pages are made of.
|
|
|
19
19
|
| [`imports.ts`](./builder.md#widgets-from-packages) | The packages this app takes widgets from |
|
|
20
20
|
| [`loadbare-app-build`](./builder.md#running-the-builder) | Configuring the build command |
|
|
21
21
|
| [CSS](./css.md) | How the builder packages css |
|
|
22
|
+
| [The dev server](./dev-server.md) | Refresh after any change, never restart |
|
|
22
23
|
|
|
23
24
|
## Application Pages
|
|
24
25
|
|
package/docs/reference/server.md
CHANGED
|
@@ -35,7 +35,7 @@ app.get(/.*/, (_req, res) =>
|
|
|
35
35
|
res.type("html").send(readFileSync(path.join(DIST, "app.html"), "utf-8")),
|
|
36
36
|
);
|
|
37
37
|
|
|
38
|
-
app.listen(8787);
|
|
38
|
+
app.listen(Number(process.env.PORT ?? 8787));
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## What the server serves
|
|
@@ -96,16 +96,21 @@ The limit covers every page's requests.
|
|
|
96
96
|
## Running the server
|
|
97
97
|
|
|
98
98
|
Run the server under a TypeScript-capable runner. The builder writes
|
|
99
|
-
`dist/pages.ts`, which exports `hub`, as TypeScript
|
|
99
|
+
`dist/pages.ts`, which exports `hub`, as TypeScript. During development,
|
|
100
|
+
[the dev server](./dev-server.md) runs it, and restarts it when a server
|
|
101
|
+
module changes:
|
|
100
102
|
|
|
101
103
|
```json
|
|
102
104
|
{
|
|
103
105
|
"scripts": {
|
|
104
|
-
"dev": "
|
|
106
|
+
"dev": "node dev.ts"
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
109
|
```
|
|
108
110
|
|
|
111
|
+
The server reads its port from `PORT`, which is how the dev server tells it
|
|
112
|
+
where to listen.
|
|
113
|
+
|
|
109
114
|
Node 22.18 and later also runs it with no runner at all, since Node strips
|
|
110
115
|
TypeScript types itself. `dist/pages.ts` imports each `.requests.ts` and
|
|
111
116
|
`.queries.ts` file by its full name, extension included, because Node looks
|