@loadbare/app 0.18.2 → 0.19.1
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 +17 -17
- package/dist/build/assemble.d.ts +7 -1
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +81 -11
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/cli.d.ts +3 -0
- package/dist/build/cli.d.ts.map +1 -1
- package/dist/build/cli.js +6 -1
- package/dist/build/cli.js.map +1 -1
- package/dist/build/declared.d.ts +25 -0
- package/dist/build/declared.d.ts.map +1 -0
- package/dist/build/declared.js +62 -0
- package/dist/build/declared.js.map +1 -0
- package/dist/build/pages.d.ts +6 -0
- package/dist/build/pages.d.ts.map +1 -1
- package/dist/build/pages.js +32 -12
- package/dist/build/pages.js.map +1 -1
- package/docs/comparison.md +697 -484
- package/docs/departures.md +63 -0
- package/docs/miswarts.md +140 -0
- package/docs/opinions.md +155 -0
- package/docs/reference/builder.md +20 -4
- package/docs/reference/chrome.md +45 -10
- package/docs/reference/css.md +0 -1
- package/docs/reference/custom-elements.md +3 -25
- package/docs/reference/data-binding.md +265 -48
- package/docs/reference/names.md +250 -0
- package/docs/reference/overview.md +6 -0
- package/docs/reference/page-files.md +77 -9
- package/docs/reference/server.md +54 -1
- package/docs/roadmap.md +55 -43
- package/docs/testing.md +62 -28
- package/docs/theory.md +348 -108
- package/docs/tutorials/040-displaying-data.md +1 -1
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +19 -13
- package/skills/loadbare-app/references/builder.md +20 -4
- package/skills/loadbare-app/references/chrome.md +45 -10
- package/skills/loadbare-app/references/css.md +0 -1
- package/skills/loadbare-app/references/custom-elements.md +3 -25
- package/skills/loadbare-app/references/data-binding.md +265 -48
- package/skills/loadbare-app/references/miswarts.md +140 -0
- package/skills/loadbare-app/references/names.md +250 -0
- package/skills/loadbare-app/references/overview.md +6 -0
- package/skills/loadbare-app/references/page-files.md +77 -9
- package/skills/loadbare-app/references/server.md +54 -1
- package/docs/TECHREF-1.0.md +0 -2312
- package/docs/possible-ideas.md +0 -314
- package/docs/theory-old.md +0 -839
- package/docs/what-does-loadbare-extend.md +0 -124
- package/skills/loadbare-app/references/TECHREF-1.0.md +0 -2312
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Departures
|
|
2
|
+
|
|
3
|
+
The theory says Loadbare/app follows HTML wherever HTML already has an
|
|
4
|
+
opinion, and does not reimplement browser behavior. In two places it
|
|
5
|
+
departs from HTML's model on purpose, both for the 300ms budget.
|
|
6
|
+
|
|
7
|
+
A departure is not a [miswart](./miswarts.md). A miswart is small,
|
|
8
|
+
orthogonal and terminating. A departure is large, other behavior rests
|
|
9
|
+
on it, and it cannot be removed without redesigning the framework.
|
|
10
|
+
|
|
11
|
+
Each entry states what HTML does, what Loadbare/app does instead, what
|
|
12
|
+
that buys, what it costs, and what rests on it.
|
|
13
|
+
|
|
14
|
+
## Navigation
|
|
15
|
+
|
|
16
|
+
**What HTML does.** One document per URL. Following a link fetches a
|
|
17
|
+
new document from the server, and a URL that names nothing is answered
|
|
18
|
+
with a 404.
|
|
19
|
+
|
|
20
|
+
**What Loadbare/app does.** One document holds every page, each as a
|
|
21
|
+
`<template>`. The server answers every route with that one document,
|
|
22
|
+
and the hub shows the page the path names by cloning its template into
|
|
23
|
+
`<main>`. A path that names no page is found out in the browser, not
|
|
24
|
+
answered with a 404.
|
|
25
|
+
|
|
26
|
+
**What it buys.** Performance. Moving between pages fetches no HTML
|
|
27
|
+
and no code, only the page's data. The browser parses every page once,
|
|
28
|
+
when the document first loads.
|
|
29
|
+
|
|
30
|
+
**What it costs.**
|
|
31
|
+
|
|
32
|
+
- The first load carries every page, whether or not the user visits it.
|
|
33
|
+
- There is no 404 status for a path that names no page. Loadbare/app is
|
|
34
|
+
for applications, not sites, so no crawler is expected to care.
|
|
35
|
+
- The application must be served from the origin root, not a subpath.
|
|
36
|
+
|
|
37
|
+
**What rests on it.** The hub's link handling, the URL as the query
|
|
38
|
+
`lb-url`, the server's catch-all route, and the unknown-page dialog.
|
|
39
|
+
|
|
40
|
+
## The wire
|
|
41
|
+
|
|
42
|
+
**What HTML does.** The server sends HTML, and the browser renders it.
|
|
43
|
+
Libraries that extend HTML, such as htmx, keep that model and send HTML
|
|
44
|
+
fragments.
|
|
45
|
+
|
|
46
|
+
**What Loadbare/app does.** After the first load, the server sends only
|
|
47
|
+
data: rows as JSON, a patch of the rows that changed, or a refusal. The
|
|
48
|
+
HTML that shows the rows is already in the browser, and the hub lands
|
|
49
|
+
the rows into it.
|
|
50
|
+
|
|
51
|
+
**What it buys.** Performance. Rows are far smaller than the markup
|
|
52
|
+
that displays them, the server renders nothing, and nearly all of its
|
|
53
|
+
time for a request is the database's time.
|
|
54
|
+
|
|
55
|
+
**What it costs.**
|
|
56
|
+
|
|
57
|
+
- The application does not work without JavaScript.
|
|
58
|
+
- The server cannot shape the markup per request. What varies by
|
|
59
|
+
request must be data, landed by the rules every row follows.
|
|
60
|
+
|
|
61
|
+
**What rests on it.** Landing, patches, the response items every
|
|
62
|
+
request answers with, and the server's page code, which returns rows
|
|
63
|
+
and never markup.
|
package/docs/miswarts.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Miswarts
|
|
2
|
+
|
|
3
|
+
A miswart is a place where Loadbare/app breaks one of its own rules.
|
|
4
|
+
Anybody paying attention will see it as a violation, and they will be
|
|
5
|
+
right. Yet in context it turns out to be the RightThing(tm), and doing it
|
|
6
|
+
any other way would be worse for the user or the developer.
|
|
7
|
+
|
|
8
|
+
The reference describes each miswart's behavior where it applies, and
|
|
9
|
+
links here. This document is the one place that admits they are
|
|
10
|
+
exceptions, and says why each one is allowed to stay.
|
|
11
|
+
|
|
12
|
+
## The test
|
|
13
|
+
|
|
14
|
+
A miswart must be:
|
|
15
|
+
|
|
16
|
+
- **Small.** It can be stated in a sentence or two.
|
|
17
|
+
- **Orthogonal.** It has no interaction with any other miswart.
|
|
18
|
+
- **Terminating.** It does not, by logical extension, require another
|
|
19
|
+
miswart. If fixing the edges of one exception calls for a second, we
|
|
20
|
+
probably should be looking for a weakness in earlier implementation
|
|
21
|
+
decisions.
|
|
22
|
+
|
|
23
|
+
Each entry also names two things:
|
|
24
|
+
|
|
25
|
+
- **The rule it breaks.** If we cannot name the rule, it is not a
|
|
26
|
+
miswart, it is undocumented behavior.
|
|
27
|
+
- **The motivation that justifies it**: performance, correctness or
|
|
28
|
+
ergonomics, as set out in the theory document. That is what makes it
|
|
29
|
+
the RightThing(tm) rather than a convenience.
|
|
30
|
+
|
|
31
|
+
## Radio button names in a row template
|
|
32
|
+
|
|
33
|
+
**What.** The hub stamps the `name` of each radio button in a row
|
|
34
|
+
template with the `name` written, or its column when none is, followed by
|
|
35
|
+
`-` and the live row's key.
|
|
36
|
+
|
|
37
|
+
**Rule broken.** The hub writes only its own stamps, which always
|
|
38
|
+
begin with `lb-`.
|
|
39
|
+
|
|
40
|
+
**Why it is the RightThing(tm).** Correctness. The browser groups radio
|
|
41
|
+
buttons by `name`, and a row template repeats one `name` in every live
|
|
42
|
+
row, so without the stamp every row's buttons would form a single group,
|
|
43
|
+
and checking one row would uncheck all the others.
|
|
44
|
+
|
|
45
|
+
**Why it terminates.** It applies only to radio buttons inside a row
|
|
46
|
+
template, and only the `name`.
|
|
47
|
+
|
|
48
|
+
## Checkboxes and radio groups always gather a value
|
|
49
|
+
|
|
50
|
+
**What.** An unchecked checkbox gathers `"false"`, a checked one
|
|
51
|
+
`"true"`, and its `value` attribute means nothing to the hub. A radio
|
|
52
|
+
group with none checked gathers `""`.
|
|
53
|
+
|
|
54
|
+
**Rule broken.** Where HTML already has an opinion, Loadbare/app
|
|
55
|
+
follows it. HTML sends a checkbox's `value` when it
|
|
56
|
+
is checked, and sends nothing for an unchecked checkbox or an empty radio
|
|
57
|
+
group.
|
|
58
|
+
|
|
59
|
+
**Why it is the RightThing(tm).** Correctness. A write must be able to
|
|
60
|
+
set a flag back to false, or clear a choice, and nothing on the wire
|
|
61
|
+
cannot say either.
|
|
62
|
+
|
|
63
|
+
**Why it terminates.** It applies only to gathering from these two
|
|
64
|
+
controls. Landing still follows HTML's own idea of checked.
|
|
65
|
+
|
|
66
|
+
## Rows hidden by a filter
|
|
67
|
+
|
|
68
|
+
**What.** A row that does not pass the user's filter gets the `hidden`
|
|
69
|
+
attribute, and so does a group whose rows are all hidden.
|
|
70
|
+
|
|
71
|
+
**Rule broken.** The hub writes only its own stamps, which always
|
|
72
|
+
begin with `lb-`.
|
|
73
|
+
|
|
74
|
+
**Why it is the RightThing(tm).** Performance and ergonomics. A filter
|
|
75
|
+
over rows already on the page needs no round trip, and `hidden` is HTML's
|
|
76
|
+
own word for an element that is present but not shown. A stamp of our
|
|
77
|
+
own would make every stylesheet restate what the browser already does.
|
|
78
|
+
|
|
79
|
+
**Why it terminates.** It applies only to live rows and groups under a
|
|
80
|
+
filter.
|
|
81
|
+
|
|
82
|
+
## Leaving rows are inert
|
|
83
|
+
|
|
84
|
+
**What.** A row on its way out takes `inert` while its animation runs,
|
|
85
|
+
and is removed when the animation finishes.
|
|
86
|
+
|
|
87
|
+
**Rule broken.** The hub writes only its own stamps, which always
|
|
88
|
+
begin with `lb-`.
|
|
89
|
+
|
|
90
|
+
**Why it is the RightThing(tm).** Correctness. A row that is gone from
|
|
91
|
+
the database must not take a click or the focus during its exit
|
|
92
|
+
animation, and `inert` is exactly HTML's word for that.
|
|
93
|
+
|
|
94
|
+
**Why it terminates.** It applies only to a row already stamped
|
|
95
|
+
`lb-row-leaving`, which never comes back.
|
|
96
|
+
|
|
97
|
+
## Busy elements carry aria-busy
|
|
98
|
+
|
|
99
|
+
**What.** While an element's request is in flight, it carries
|
|
100
|
+
`aria-busy="true"` alongside `lb-request-pending`.
|
|
101
|
+
|
|
102
|
+
**Rule broken.** The hub writes only its own stamps, which always
|
|
103
|
+
begin with `lb-`.
|
|
104
|
+
|
|
105
|
+
**Why it is the RightThing(tm).** Correctness, for a user of assistive
|
|
106
|
+
technology. `lb-request-pending` tells a stylesheet, and `aria-busy` tells
|
|
107
|
+
a screen reader, the same fact.
|
|
108
|
+
|
|
109
|
+
**Why it terminates.** It rides with `lb-request-pending` and nothing
|
|
110
|
+
else.
|
|
111
|
+
|
|
112
|
+
## The hub unhides the body
|
|
113
|
+
|
|
114
|
+
**What.** When the chrome writes `<body hidden>`, the hub removes
|
|
115
|
+
`hidden` once the first page has landed.
|
|
116
|
+
|
|
117
|
+
**Rule broken.** The hub writes only its own stamps, which always
|
|
118
|
+
begin with `lb-`.
|
|
119
|
+
|
|
120
|
+
**Why it is the RightThing(tm).** Performance, as the user perceives it.
|
|
121
|
+
Without it, the first load blinks an empty page before the data lands.
|
|
122
|
+
Only the hub knows when the first page has landed.
|
|
123
|
+
|
|
124
|
+
**Why it terminates.** It happens once, to `<body>`, and only when the
|
|
125
|
+
application opted in by writing `hidden`.
|
|
126
|
+
|
|
127
|
+
## `lb-url` lands every parm it names
|
|
128
|
+
|
|
129
|
+
**What.** When `lb-url` lands, a query parm the URL does not carry lands
|
|
130
|
+
empty on every element naming it as a column.
|
|
131
|
+
|
|
132
|
+
**Rule broken.** Landing a row sets the columns the row carries, and
|
|
133
|
+
leaves the rest as they were.
|
|
134
|
+
|
|
135
|
+
**Why it is the RightThing(tm).** Correctness. A control must show what
|
|
136
|
+
the address bar says, after Back as well as after a reload, and a parm
|
|
137
|
+
that is absent from the URL is a parm whose value is empty.
|
|
138
|
+
|
|
139
|
+
**Why it terminates.** It applies only to `lb-url`, the one query whose
|
|
140
|
+
columns are the URL itself.
|
package/docs/opinions.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# The Opinions of Loadbare/app
|
|
2
|
+
|
|
3
|
+
Every framework forces some decisions on the people who use it. This
|
|
4
|
+
document lists the ones Loadbare/app forces, so a developer can see
|
|
5
|
+
them in one place before writing an application. The reasons for each
|
|
6
|
+
are in the [theory](./theory.md).
|
|
7
|
+
|
|
8
|
+
## What counts as an opinion
|
|
9
|
+
|
|
10
|
+
An opinion is a position that is:
|
|
11
|
+
|
|
12
|
+
1. Forced. There is no supported way around it. A position the
|
|
13
|
+
developer can opt out of is a default.
|
|
14
|
+
2. Contested. Competent frameworks in the wild decide otherwise. A
|
|
15
|
+
position nobody takes differently is just how the platform works.
|
|
16
|
+
3. Pervasive. It shows up in most of what the developer writes, most
|
|
17
|
+
pages and most handlers, rather than in one feature.
|
|
18
|
+
|
|
19
|
+
An opinion limits what the developer can express. A convention limits
|
|
20
|
+
only where they put it. The file names `<stub>.page.html`,
|
|
21
|
+
`<stub>.queries.ts` and `<stub>.requests.ts` are forced and pervasive,
|
|
22
|
+
but they are a convention, and are not listed here.
|
|
23
|
+
|
|
24
|
+
The [departures](./departures.md) are measured against HTML, and the
|
|
25
|
+
[miswarts](./miswarts.md) against Loadbare/app's own rules. The
|
|
26
|
+
opinions are measured against the developer's freedom. An entry can be
|
|
27
|
+
more than one of these: the wire is both a departure and an opinion.
|
|
28
|
+
|
|
29
|
+
## Two shapes, and every row has a key
|
|
30
|
+
|
|
31
|
+
Loadbare/app understands two data shapes, a `row` and a set of `rows`.
|
|
32
|
+
Every row arrives with its key. Column values are atomic. A document
|
|
33
|
+
that embeds child rows in a parent row must be split into two query
|
|
34
|
+
results before Loadbare/app can show it.
|
|
35
|
+
|
|
36
|
+
Other frameworks accept any JSON the server sends, nested to any depth,
|
|
37
|
+
and leave identity to the developer. In Loadbare/app, every query a
|
|
38
|
+
developer writes answers in one of the two shapes, and every element
|
|
39
|
+
that shows data is bound to one of them.
|
|
40
|
+
|
|
41
|
+
## HTML is static
|
|
42
|
+
|
|
43
|
+
The developer writes each page's markup once. The server does not
|
|
44
|
+
generate markup per request, and there is no templating language in
|
|
45
|
+
the browser. Whatever varies from one request to the next must be
|
|
46
|
+
data, and it reaches the screen by the same rules every row follows.
|
|
47
|
+
|
|
48
|
+
Server-side templates, JSX, and libraries that send HTML fragments all
|
|
49
|
+
generate markup at run time. In Loadbare/app, every page is plain
|
|
50
|
+
HTML, and every visible difference between two users or two moments is
|
|
51
|
+
a column value.
|
|
52
|
+
|
|
53
|
+
## The server answers only with data
|
|
54
|
+
|
|
55
|
+
After the first load, the server sends rows, a patch of the rows that
|
|
56
|
+
changed, or a refusal. It never sends markup, and it never sends
|
|
57
|
+
instructions for the browser to carry out.
|
|
58
|
+
|
|
59
|
+
Applications in the wild answer with HTML, with JSON, with redirects,
|
|
60
|
+
with scripts, and with every combination of them. In Loadbare/app,
|
|
61
|
+
every handler a developer writes returns rows or refuses. See
|
|
62
|
+
[the wire](./departures.md#the-wire).
|
|
63
|
+
|
|
64
|
+
## The screen changes only when the server answers
|
|
65
|
+
|
|
66
|
+
Loadbare/app changes the screen from what the server sent, and never
|
|
67
|
+
ahead of it. There are no optimistic updates. A write shows on screen
|
|
68
|
+
when the rows it changed come back.
|
|
69
|
+
|
|
70
|
+
Many frameworks update the screen first and reconcile when the server
|
|
71
|
+
answers. In Loadbare/app, every write a developer designs is shown by
|
|
72
|
+
the rows its handler returns.
|
|
73
|
+
|
|
74
|
+
## Requests come from the document
|
|
75
|
+
|
|
76
|
+
A request is named on an element with `lb-request`. The hub supplies
|
|
77
|
+
the query and the key from where the element sits, and gathers the
|
|
78
|
+
values from the controls bound to columns. The developer writes no
|
|
79
|
+
`fetch`, designs no endpoints, and never passes a key by hand.
|
|
80
|
+
|
|
81
|
+
Most frameworks have the developer write the call to the server, choose
|
|
82
|
+
its URL, and assemble its body. In Loadbare/app, every button, form,
|
|
83
|
+
and control that writes is a named request on an element.
|
|
84
|
+
|
|
85
|
+
## A page declares what it shows and what it allows
|
|
86
|
+
|
|
87
|
+
A page's queries are what it shows, and its requests are what it
|
|
88
|
+
allows. The server refuses any request a page did not declare.
|
|
89
|
+
Nothing is reachable from the browser that a page has not published.
|
|
90
|
+
|
|
91
|
+
Elsewhere, any route the server registers is reachable, and access is
|
|
92
|
+
checked inside each handler. In Loadbare/app, every page carries its
|
|
93
|
+
own list, and the list is the whole of what the browser can ask for.
|
|
94
|
+
|
|
95
|
+
## The URL names a place
|
|
96
|
+
|
|
97
|
+
The path names a page. It never names a resource, so `/accounts/42`
|
|
98
|
+
is not a way to reach account 42. The query string describes what the
|
|
99
|
+
page has on screen, and it never commands. The server remembers
|
|
100
|
+
nothing about the view, so a URL reloads, bookmarks, and mails as the
|
|
101
|
+
same view.
|
|
102
|
+
|
|
103
|
+
REST names resources in the path, and many applications keep view
|
|
104
|
+
state on the server or in the browser's memory. In Loadbare/app,
|
|
105
|
+
every link and every query parm follows this rule. See
|
|
106
|
+
[Query parms](./reference/chrome.md#query-parms).
|
|
107
|
+
|
|
108
|
+
## Framework state is a row
|
|
109
|
+
|
|
110
|
+
What the framework itself keeps is presented as rows. The URL is the
|
|
111
|
+
query `lb-url`, of kind `row`, and lands like any server query. User
|
|
112
|
+
preferences and choices on a page are sent as `lb-row-update` for `lb-choices`,
|
|
113
|
+
and can land anywhere on the page.
|
|
114
|
+
|
|
115
|
+
Most frameworks keep their own state in a store with its own interface.
|
|
116
|
+
In Loadbare/app, a developer shows the current page's label or a
|
|
117
|
+
query parm the same way they show a customer's name.
|
|
118
|
+
|
|
119
|
+
## Mistakes stop the build or the server
|
|
120
|
+
|
|
121
|
+
What can be checked before the application runs is checked, and a
|
|
122
|
+
mistake stops the build or the server. The builder refuses a custom
|
|
123
|
+
element it cannot find, and any `lb-` attribute the developer is not
|
|
124
|
+
allowed to write. The server refuses known wrong patterns at startup.
|
|
125
|
+
What cannot be checked ahead of time is reported on the console when
|
|
126
|
+
it happens.
|
|
127
|
+
|
|
128
|
+
Many frameworks tolerate a mistake and render what they can. In
|
|
129
|
+
Loadbare/app, every page and every handler passes these checks before
|
|
130
|
+
it runs.
|
|
131
|
+
|
|
132
|
+
## Constraints belong to the database
|
|
133
|
+
|
|
134
|
+
Business rules are enforced by the database or by the application's
|
|
135
|
+
server code. A handler refuses a request with words written for the
|
|
136
|
+
user, for the request as a whole or for each column, and the browser
|
|
137
|
+
shows them on the controls they belong to. Any other failure reaches
|
|
138
|
+
the browser as a plain failure, with no stack trace or database
|
|
139
|
+
message.
|
|
140
|
+
|
|
141
|
+
Many frameworks validate in the browser and again on the server, with
|
|
142
|
+
two sets of rules to keep in step. In Loadbare/app, every rule the
|
|
143
|
+
user can break is answered by a refusal from the server.
|
|
144
|
+
|
|
145
|
+
## Widgets are custom elements
|
|
146
|
+
|
|
147
|
+
A widget, what other frameworks call a component, is a custom element.
|
|
148
|
+
There is no component model of Loadbare/app's own. A widget talks to
|
|
149
|
+
the hub through the attributes, events, and methods described in
|
|
150
|
+
[Custom Elements](./reference/custom-elements.md#code).
|
|
151
|
+
|
|
152
|
+
Most frameworks define their own component model, with its own
|
|
153
|
+
lifecycle and its own way of passing data. In Loadbare/app, every
|
|
154
|
+
widget, those in `@loadbare/widgets` and those an application writes,
|
|
155
|
+
is a standard custom element.
|
|
@@ -44,11 +44,16 @@ The builder classifies by name, not location.
|
|
|
44
44
|
| `*.queries.ts` | A page's queries, matched by base name |
|
|
45
45
|
| `imports.ts` | The packages this app takes widgets from |
|
|
46
46
|
| `*.css` | A stylesheet — see [CSS](./css.md) |
|
|
47
|
-
|
|
|
47
|
+
| `<tag-name>.html` | A widget definition, named for the tag it defines |
|
|
48
48
|
| `<tag>.browser.ts` | A widget script, named for the tag it registers |
|
|
49
49
|
|
|
50
50
|
Give the application exactly one `chrome.html` and at most one `imports.ts`.
|
|
51
|
-
Give every `.requests.ts` and `.queries.ts` a `.page.html` of the same base name
|
|
51
|
+
Give every `.requests.ts` and `.queries.ts` a `.page.html` of the same base name;
|
|
52
|
+
one with no page is a build error.
|
|
53
|
+
|
|
54
|
+
A widget definition is exactly `<kebab-case-name>.html`. Any other `.html`
|
|
55
|
+
file is an error when it looks like a definition with capitals in its name,
|
|
56
|
+
and is skipped otherwise.
|
|
52
57
|
|
|
53
58
|
Name a widget script `<tag>.browser.ts`, not `<tag>.ts`. Only a file whose
|
|
54
59
|
name carries `.browser` is bundled for the browser; every other module under
|
|
@@ -128,11 +133,22 @@ substitution rules — wraps each expanded page in
|
|
|
128
133
|
`<template lb-page="<stub>">`, and splices them into the chrome's `<body>`.
|
|
129
134
|
It removes a page file's `<title>` and stamps its text on the page's
|
|
130
135
|
template as `lb-page-title`; see [The page title](./page-files.md#the-page-title).
|
|
131
|
-
It formats the result with Prettier
|
|
136
|
+
It formats the result with Prettier, which ships with `@loadbare/app`, and
|
|
137
|
+
keeps the unformatted result if Prettier fails.
|
|
132
138
|
|
|
133
139
|
The builder checks the `lb-` attributes of the chrome and every page after
|
|
134
140
|
expansion, and stops on the first file with a problem; see
|
|
135
|
-
[The markup checks](./data-binding.md#the-markup-checks).
|
|
141
|
+
[The markup checks](./data-binding.md#the-markup-checks). The names
|
|
142
|
+
`lb-query` and `lb-request` carry are checked against what each page
|
|
143
|
+
declares, which the builder reads by loading the page's `.queries.ts` and
|
|
144
|
+
`.requests.ts` modules. Their import-time code runs during the build, as it
|
|
145
|
+
does when the server starts, so a module that connects to a database at
|
|
146
|
+
import connects during the build too; open connections in `contextFor`
|
|
147
|
+
instead.
|
|
148
|
+
|
|
149
|
+
It also writes `client-entry.ts`, the generated entry `client.js` is bundled
|
|
150
|
+
from, and leaves it there. Nothing reads it after the bundle, and an
|
|
151
|
+
application neither writes nor imports it.
|
|
136
152
|
|
|
137
153
|
The builder writes `app.css` only when it finds a stylesheet, and `pages.ts`
|
|
138
154
|
only when some page has a `.requests.ts` or a `.queries.ts` file. Import `hub`
|
package/docs/reference/chrome.md
CHANGED
|
@@ -103,6 +103,12 @@ server's row lands, so a chrome shows where the page is with no code:
|
|
|
103
103
|
| `lb-page-unknown` | `true` when no page's stub matches the path |
|
|
104
104
|
| Any other name | The query parm of that name, or empty when it is absent |
|
|
105
105
|
|
|
106
|
+
The path names a page, never a resource: `/accounts/42` is not a way to
|
|
107
|
+
reach account 42, and an application designs no endpoints. The query string
|
|
108
|
+
describes what that page has on screen, `/accounts?acct=23`, and never
|
|
109
|
+
commands. The server remembers nothing about the view, so a URL reloads,
|
|
110
|
+
bookmarks and mails as the same view.
|
|
111
|
+
|
|
106
112
|
A path names a page by its stub: `/members` shows `members.page.html`, and
|
|
107
113
|
`/` shows `index.page.html`. A page's title is the text of the `<title>` its
|
|
108
114
|
page file carries; see [page files](./page-files.md#the-page-title). The hub
|
|
@@ -139,11 +145,17 @@ Write `lb-url-link` on an `<a>` to move between pages:
|
|
|
139
145
|
</nav>
|
|
140
146
|
```
|
|
141
147
|
|
|
142
|
-
On a plain primary click, the
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
the browser has them behave
|
|
146
|
-
|
|
148
|
+
On a plain primary click, the first button with no modifier key and not
|
|
149
|
+
already handled, the hub pushes a history entry for the `href`, path and
|
|
150
|
+
query string both, and shows the page it names. Any other click, and a link
|
|
151
|
+
without `lb-url-link`, behave as the browser has them behave, so leaving the
|
|
152
|
+
application is the default and staying in it is the opt-in. The attribute
|
|
153
|
+
takes no value. Back and Forward show the page at the URL they arrive at.
|
|
154
|
+
|
|
155
|
+
Path space is flat: `/members` shows `members.page.html` wherever under
|
|
156
|
+
`--src` it sits. The query string is kept, so
|
|
157
|
+
`/transactions?date_begin=2026-09-01` opens the page narrowed to those
|
|
158
|
+
dates.
|
|
147
159
|
|
|
148
160
|
### Query parms
|
|
149
161
|
|
|
@@ -170,11 +182,28 @@ pushes one instead when the element carrying `lb-request` also carries
|
|
|
170
182
|
|
|
171
183
|
The hub answers the request itself, with no round trip, then reloads the
|
|
172
184
|
page's queries at the new URL. The page stays in place, and rows that come
|
|
173
|
-
back keep their place.
|
|
185
|
+
back keep their place. A request that leaves the URL as it was does
|
|
186
|
+
nothing. `lb-page-label` and `lb-page-unknown` are the hub's, and a request
|
|
187
|
+
never sets them.
|
|
188
|
+
|
|
189
|
+
A request that gives `lb-path` a new value enters that page, pushes a
|
|
190
|
+
history entry, and the new URL carries only the query parms the request
|
|
191
|
+
names.
|
|
174
192
|
|
|
175
193
|
A control whose column the URL does not carry lands empty, so every control
|
|
176
194
|
inside `lb-query="lb-url"` shows what the address bar says, after a reload
|
|
177
|
-
and after Back alike
|
|
195
|
+
and after Back alike
|
|
196
|
+
([miswart](../miswarts.md#lb-url-lands-every-parm-it-names)).
|
|
197
|
+
|
|
198
|
+
Loadbare assigns no parm a meaning, and a column of `lb-url` whose name
|
|
199
|
+
begins with `lb-` is never a query parm.
|
|
200
|
+
|
|
201
|
+
A query parm is user input. A query still takes no argument from the
|
|
202
|
+
browser, and a parm arrives the way the session cookie does, as part of the
|
|
203
|
+
request the context is built from, but a user who types `?acct=99999`
|
|
204
|
+
influences what a query returns. Validate it where the application reads
|
|
205
|
+
it; a per-session database role means an id outside the caller's reach
|
|
206
|
+
finds nothing.
|
|
178
207
|
|
|
179
208
|
An order or a filter the hub applies to rows the page already holds is not
|
|
180
209
|
a query parm. It is a [choice](./data-binding.md#choices), which holds until
|
|
@@ -198,8 +227,13 @@ show the path:
|
|
|
198
227
|
```
|
|
199
228
|
|
|
200
229
|
When no page's stub matches the path, `lb-page-unknown` is `true`,
|
|
201
|
-
`lb-page-label` is null, `<main>` keeps the page it had,
|
|
202
|
-
`showModal()` on the dialog.
|
|
230
|
+
`lb-page-label` is null, `<main>` keeps the page it had, the hub calls
|
|
231
|
+
`showModal()` on the dialog, and reports the path to the console. A chrome
|
|
232
|
+
with no dialog shows nothing. `lb-url` lands before the page is looked up,
|
|
233
|
+
so the dialog shows the path by naming it like any other element.
|
|
234
|
+
|
|
235
|
+
Every route gets the same document, so an unknown path is found out in the
|
|
236
|
+
browser after a successful 200, and there is no server-delivered 404.
|
|
203
237
|
|
|
204
238
|
`@loadbare/widgets` ships this dialog as `<lb-unknown-page>`, for a chrome
|
|
205
239
|
that would rather write one tag; see
|
|
@@ -224,7 +258,8 @@ being visibly empty — so it's the whole document that needs to wait, not
|
|
|
224
258
|
just the piece that was empty.
|
|
225
259
|
|
|
226
260
|
The `<noscript>` block is the escape hatch for a visitor with JavaScript
|
|
227
|
-
disabled. `<lb-hub>` is what removes `hidden` from `<body
|
|
261
|
+
disabled. `<lb-hub>` is what removes `hidden` from `<body>`
|
|
262
|
+
([miswart](../miswarts.md#the-hub-unhides-the-body)), so a browser
|
|
228
263
|
that never runs `client.js` would otherwise be stuck looking at a
|
|
229
264
|
permanently blank page. `<noscript>` content is only rendered when scripting
|
|
230
265
|
is off, so the fallback rule only ever applies in exactly that case — it
|
package/docs/reference/css.md
CHANGED
|
@@ -41,7 +41,6 @@ Serve it at `/app.css` and link it from the chrome:
|
|
|
41
41
|
See [`chrome.html`](./chrome.md) for the link, [The Express
|
|
42
42
|
server](./server.md) for the route, and
|
|
43
43
|
[`loadbare-app-build`](./builder.md#running-the-builder) for `--minify`.
|
|
44
|
-
</content>
|
|
45
44
|
|
|
46
45
|
## Selecting what the hub stamps
|
|
47
46
|
|
|
@@ -250,30 +250,8 @@ takes part in data binding in one of four ways: it is a control, it renders
|
|
|
250
250
|
a value, it sends a request, or it holds rows.
|
|
251
251
|
|
|
252
252
|
Import every Loadbare name from `@loadbare/app/constants`, and never write
|
|
253
|
-
one as a string literal:
|
|
254
|
-
|
|
255
|
-
| Constant | Value |
|
|
256
|
-
|------------------------|----------------------|
|
|
257
|
-
| `ATTR_QUERY` | `lb-query` |
|
|
258
|
-
| `ATTR_COLUMN` | `lb-column` |
|
|
259
|
-
| `ATTR_SHOW` | `lb-show` |
|
|
260
|
-
| `ATTR_REQUEST` | `lb-request` |
|
|
261
|
-
| `ATTR_COLUMN_VALUE` | `lb-column-value` |
|
|
262
|
-
| `ATTR_KEY_VALUE` | `lb-key-value` |
|
|
263
|
-
| `ATTR_ROW_LIVE` | `lb-row-live` |
|
|
264
|
-
| `LIVE_ROW` | `[lb-row-live]` |
|
|
265
|
-
| `ATTR_QUERY_ROW_COUNT` | `lb-query-row-count` |
|
|
266
|
-
| `ATTR_REQUEST_PENDING` | `lb-request-pending` |
|
|
267
|
-
| `ATTR_REQUEST_ERROR` | `lb-request-error` |
|
|
268
|
-
| `REQUEST_ROW_INSERT`, `REQUEST_ROW_UPDATE`, `REQUEST_ROW_DELETE` | The requests Loadbare provides |
|
|
269
|
-
| `LB_ROW_REQUESTS` | All three, in one array |
|
|
270
|
-
| `LB_EVENT_NAME` | `lb-request`, the event every request travels as |
|
|
271
|
-
| `LB_DONE_EVENT_NAME` | `lb-request-done`, the event that says how it turned out |
|
|
272
|
-
| `SHOW_NOT` | `!`, written before a column in `lb-show` |
|
|
273
|
-
| `URL_QUERY` | `lb-url` |
|
|
274
|
-
| `CHOICES_QUERY` | `lb-choices` |
|
|
275
|
-
| `URL_COLUMN_PATH`, `URL_COLUMN_PAGE_LABEL`, `URL_COLUMN_PAGE_UNKNOWN` | `lb-path`, `lb-page-label`, `lb-page-unknown` |
|
|
276
|
-
| `LB_RESERVED_PREFIX` | `lb-` |
|
|
253
|
+
one as a string literal: `ATTR_COLUMN_VALUE` rather than `"lb-column-value"`.
|
|
254
|
+
[Constants](./names.md#constants) lists them all.
|
|
277
255
|
|
|
278
256
|
A custom element reads `lb-` attributes and never assigns one. The developer
|
|
279
257
|
writes them in markup, and the hub and the builder write their stamps.
|
|
@@ -290,7 +268,7 @@ Each direction has one mechanism for each kind of message:
|
|
|
290
268
|
|
|
291
269
|
| Direction | What | How | Today |
|
|
292
270
|
|----------------|--------------------------------------------|-----------------------------|-------|
|
|
293
|
-
| Hub to element | State that lasts | An attribute the hub stamps | `lb-column-value`, `lb-key-value`, `lb-query-row-count`, `lb-group-*`, `lb-row-*`, `lb-request-pending`, `lb-request-error` |
|
|
271
|
+
| Hub to element | State that lasts | An attribute the hub stamps | `lb-column-value`, `lb-key-value`, `lb-query-row-count`, `lb-group-*`, `lb-row-*`, `lb-request-pending`, `lb-request-error`, `lb-request-refused` |
|
|
294
272
|
| Hub to element | State the platform already names | A property | A control's `value` |
|
|
295
273
|
| Hub to element | What the hub did | An optional `lb` method | `lbAttached`, `lbRowsLanded`, `lbRequestDone`, `lbDetached` |
|
|
296
274
|
| Hub to element | A moment an element started | A bubbling event | `lb-request-done` |
|