@webqit/webflo 0.20.4-next.2 → 0.20.4-next.3
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/package.json +5 -20
- package/site/docs/concepts/realtime.md +45 -44
- package/site/docs/getting-started.md +40 -40
- package/src/{Context.js → CLIContext.js} +9 -8
- package/src/build-pi/esbuild-plugin-livejs-transform.js +35 -0
- package/src/{runtime-pi/webflo-client/webflo-codegen.js → build-pi/index.js} +145 -141
- package/src/index.js +3 -1
- package/src/init-pi/index.js +6 -3
- package/src/init-pi/templates/pwa/package.json +2 -2
- package/src/init-pi/templates/web/package.json +2 -2
- package/src/runtime-pi/AppBootstrap.js +38 -0
- package/src/runtime-pi/WebfloRuntime.js +50 -47
- package/src/runtime-pi/apis.js +9 -0
- package/src/runtime-pi/index.js +2 -4
- package/src/runtime-pi/webflo-client/WebfloClient.js +31 -35
- package/src/runtime-pi/webflo-client/WebfloRootClient1.js +16 -14
- package/src/runtime-pi/webflo-client/WebfloSubClient.js +13 -13
- package/src/runtime-pi/webflo-client/bootstrap.js +37 -0
- package/src/runtime-pi/webflo-client/index.js +2 -8
- package/src/runtime-pi/webflo-client/webflo-devmode.js +3 -3
- package/src/runtime-pi/webflo-fetch/LiveResponse.js +127 -96
- package/src/runtime-pi/webflo-fetch/index.js +435 -5
- package/src/runtime-pi/webflo-routing/HttpCookies.js +1 -1
- package/src/runtime-pi/webflo-routing/HttpEvent.js +5 -6
- package/src/runtime-pi/webflo-routing/HttpUser.js +7 -7
- package/src/runtime-pi/webflo-server/ServerSideCookies.js +3 -1
- package/src/runtime-pi/webflo-server/ServerSideSession.js +2 -1
- package/src/runtime-pi/webflo-server/WebfloServer.js +98 -195
- package/src/runtime-pi/webflo-server/bootstrap.js +59 -0
- package/src/runtime-pi/webflo-server/index.js +2 -6
- package/src/runtime-pi/webflo-server/webflo-devmode.js +13 -24
- package/src/runtime-pi/webflo-worker/WebfloWorker.js +11 -15
- package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +2 -1
- package/src/runtime-pi/webflo-worker/bootstrap.js +38 -0
- package/src/runtime-pi/webflo-worker/index.js +3 -7
- package/src/webflo-cli.js +1 -2
- package/src/runtime-pi/webflo-fetch/cookies.js +0 -10
- package/src/runtime-pi/webflo-fetch/fetch.js +0 -16
- package/src/runtime-pi/webflo-fetch/formdata.js +0 -54
- package/src/runtime-pi/webflo-fetch/headers.js +0 -151
- package/src/runtime-pi/webflo-fetch/message.js +0 -49
- package/src/runtime-pi/webflo-fetch/request.js +0 -62
- package/src/runtime-pi/webflo-fetch/response.js +0 -110
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"vanila-javascript"
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://webqit.io/tooling/webflo",
|
|
15
|
-
"version": "0.20.4-next.
|
|
15
|
+
"version": "0.20.4-next.3",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
"site:build": "vitepress build site",
|
|
34
34
|
"site:preview": "vitepress preview site --port 4173"
|
|
35
35
|
},
|
|
36
|
+
"exports": {
|
|
37
|
+
"./apis": "./src/runtime-pi/apis.js"
|
|
38
|
+
},
|
|
36
39
|
"bin": {
|
|
37
40
|
"webflo": "src/webflo-cli.js",
|
|
38
41
|
"webflo-certbot-http-auth-hook": "src/services-pi/cert/http-auth-hook.js",
|
|
@@ -73,23 +76,5 @@
|
|
|
73
76
|
"maintainers": [
|
|
74
77
|
"Oxford Harrison <oxharris.dev@gmail.com>"
|
|
75
78
|
],
|
|
76
|
-
"contributors": []
|
|
77
|
-
"funding": {
|
|
78
|
-
"type": "patreon",
|
|
79
|
-
"url": "https://patreon.com/ox_harris"
|
|
80
|
-
},
|
|
81
|
-
"badges": {
|
|
82
|
-
"list": [
|
|
83
|
-
"npmversion",
|
|
84
|
-
"npmdownloads",
|
|
85
|
-
"patreon"
|
|
86
|
-
],
|
|
87
|
-
"config": {
|
|
88
|
-
"patreonUsername": "ox_harris",
|
|
89
|
-
"githubUsername": "webqit",
|
|
90
|
-
"githubRepository": "webflo",
|
|
91
|
-
"githubSlug": "webqit/webflo",
|
|
92
|
-
"npmPackageName": "@webqit/webflo"
|
|
93
|
-
}
|
|
94
|
-
}
|
|
79
|
+
"contributors": []
|
|
95
80
|
}
|
|
@@ -20,17 +20,17 @@ event.waitUntilNavigate();
|
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
```js
|
|
23
|
-
event.client.addEventListener(
|
|
24
|
-
event.client.postMessage({ message:
|
|
23
|
+
event.client.addEventListener("message", handle);
|
|
24
|
+
event.client.postMessage({ message: "You seem to be typing something." });
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
```js
|
|
28
|
-
const result = await event.user.confirm({ message:
|
|
29
|
-
const result = await event.user.prompt({ message:
|
|
28
|
+
const result = await event.user.confirm({ message: "Should we proceed?" });
|
|
29
|
+
const result = await event.user.prompt({ message: "What is your name?" });
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
```js
|
|
33
|
-
const { channel, leave } = event.client.enterChannel(
|
|
33
|
+
const { channel, leave } = event.client.enterChannel("test-channel");
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## The Traditional Setup
|
|
@@ -124,7 +124,7 @@ The **primary** realtime API here is `event.client` — a Webflo `MessagePort` s
|
|
|
124
124
|
|
|
125
125
|
```js
|
|
126
126
|
export default async function (event) {
|
|
127
|
-
event.client.postMessage({ hello:
|
|
127
|
+
event.client.postMessage({ hello: "world" });
|
|
128
128
|
}
|
|
129
129
|
```
|
|
130
130
|
|
|
@@ -138,10 +138,10 @@ These HTTP clients or handlers are the _Port B_.
|
|
|
138
138
|
The primary realtime API here is `liveResponse.background` — the same Webflo `MessagePort` interface as `event.client`, supporting things like: `.postMessage()`, `.addEventListener()`, etc.
|
|
139
139
|
|
|
140
140
|
```js
|
|
141
|
-
const response = await fetch(
|
|
142
|
-
const liveResponse = LiveResponse.from(response);
|
|
141
|
+
const response = await fetch("https://api.example.com/data");
|
|
142
|
+
const liveResponse = await LiveResponse.from(response);
|
|
143
143
|
|
|
144
|
-
liveResponse.background.addEventListener(
|
|
144
|
+
liveResponse.background.addEventListener("message", (message) => {
|
|
145
145
|
console.log(message);
|
|
146
146
|
});
|
|
147
147
|
```
|
|
@@ -172,7 +172,7 @@ The `app.background` port is also a _multi-port_ hub housing all _active_ backgr
|
|
|
172
172
|
Every interaction on this API is thus an interaction over all active realtime conversations.
|
|
173
173
|
|
|
174
174
|
```js
|
|
175
|
-
app.background.addEventListener(
|
|
175
|
+
app.background.addEventListener("message", (message) => {
|
|
176
176
|
console.log(message);
|
|
177
177
|
});
|
|
178
178
|
```
|
|
@@ -193,8 +193,8 @@ export default async function (event, next) {
|
|
|
193
193
|
if (next.stepname) return await next(); // The conventional delegation line
|
|
194
194
|
|
|
195
195
|
const response = await next();
|
|
196
|
-
const liveResponse = LiveResponse.from(response);
|
|
197
|
-
liveResponse.background.addEventListener(
|
|
196
|
+
const liveResponse = await LiveResponse.from(response);
|
|
197
|
+
liveResponse.background.addEventListener("message", (message) => {
|
|
198
198
|
console.log(message);
|
|
199
199
|
});
|
|
200
200
|
|
|
@@ -209,7 +209,7 @@ The handler’s own `event.client` port remains its own _Port A_ for communicati
|
|
|
209
209
|
---
|
|
210
210
|
|
|
211
211
|
::: tip
|
|
212
|
-
While not explicitly mentioned, external Webflo servers are just as accessible and interactive as the local server. A server-to-server interaction, for example, is just a matter of `LiveResponse.from(await fetch('https://api.example.com/data'))`.
|
|
212
|
+
While not explicitly mentioned, external Webflo servers are just as accessible and interactive as the local server. A server-to-server interaction, for example, is just a matter of `await LiveResponse.from(await fetch('https://api.example.com/data'))`.
|
|
213
213
|
:::
|
|
214
214
|
|
|
215
215
|
## Entering Background Mode
|
|
@@ -230,7 +230,7 @@ event.client.postMessage({ progress: 10 });
|
|
|
230
230
|
2. or achieving the same through higher-level APIs like `event.user.confirm()`:
|
|
231
231
|
|
|
232
232
|
```js
|
|
233
|
-
const result = await event.user.confirm({ message:
|
|
233
|
+
const result = await event.user.confirm({ message: "Are you sure?" });
|
|
234
234
|
```
|
|
235
235
|
|
|
236
236
|
### _Handler returns a response and explicitly marks it **not done**_
|
|
@@ -278,9 +278,9 @@ event.respondWith(
|
|
|
278
278
|
```js
|
|
279
279
|
event.respondWith(data, async ($data /* reactive copy of data */) => {
|
|
280
280
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
281
|
-
$data.someProp =
|
|
281
|
+
$data.someProp = "someValue";
|
|
282
282
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
283
|
-
$data.someProp =
|
|
283
|
+
$data.someProp = "someOtherValue";
|
|
284
284
|
});
|
|
285
285
|
```
|
|
286
286
|
|
|
@@ -294,7 +294,7 @@ A handler may return a `Generator` object by either:
|
|
|
294
294
|
export default async function* (event) {
|
|
295
295
|
yield data1;
|
|
296
296
|
yield new Response(data2);
|
|
297
|
-
yield new LiveResponse(null, { headers: { Location:
|
|
297
|
+
yield new LiveResponse(null, { headers: { Location: "/" } });
|
|
298
298
|
}
|
|
299
299
|
```
|
|
300
300
|
|
|
@@ -352,14 +352,14 @@ This handler returns a `LiveResponse` whose body starts as `{ step: 1 }` and is
|
|
|
352
352
|
**_Result_:** The page first renders step: 1, then updates to step: 2 after ~200ms.
|
|
353
353
|
|
|
354
354
|
```js
|
|
355
|
-
import { LiveResponse } from '@webqit/webflo';
|
|
355
|
+
import { LiveResponse } from '@webqit/webflo/apis';
|
|
356
356
|
```
|
|
357
357
|
|
|
358
358
|
```js
|
|
359
359
|
export async function GET(event, next) {
|
|
360
360
|
if (next.stepname) return await next(); // The conventional delegation line
|
|
361
361
|
|
|
362
|
-
const res = LiveResponse.from({ step: 1 }, { done: false });
|
|
362
|
+
const res = await LiveResponse.from({ step: 1 }, { done: false });
|
|
363
363
|
setTimeout(() => res.replaceWith({ step: 2 }), 200); // [!code highlight]
|
|
364
364
|
|
|
365
365
|
return res;
|
|
@@ -373,7 +373,7 @@ This handler returns a skeleton object immediately for fast page load and then b
|
|
|
373
373
|
**_Result_:** The UI renders a skeleton first, then progressively fills in as the object tree is built from the server.
|
|
374
374
|
|
|
375
375
|
```js
|
|
376
|
-
import Observer from '@webqit/
|
|
376
|
+
import { Observer } from '@webqit/webflo/apis';
|
|
377
377
|
```
|
|
378
378
|
|
|
379
379
|
```js
|
|
@@ -382,30 +382,30 @@ export async function GET(event, next) {
|
|
|
382
382
|
|
|
383
383
|
const data = {
|
|
384
384
|
menu: [
|
|
385
|
-
{ name:
|
|
386
|
-
{ name:
|
|
387
|
-
{ name:
|
|
385
|
+
{ name: "Home", href: "/" },
|
|
386
|
+
{ name: "About", href: "/about" },
|
|
387
|
+
{ name: "Contact", href: "/contact" },
|
|
388
388
|
],
|
|
389
389
|
content: {
|
|
390
|
-
header:
|
|
390
|
+
header: "Loading...",
|
|
391
391
|
body: [],
|
|
392
392
|
},
|
|
393
393
|
};
|
|
394
394
|
|
|
395
395
|
event.waitUntil(
|
|
396
396
|
new Promise(async (resolve) => {
|
|
397
|
-
const someData = await fetch(
|
|
398
|
-
Observer.set(data.content,
|
|
397
|
+
const someData = await fetch("https://api.example.com/data");
|
|
398
|
+
Observer.set(data.content, "header", someData.header);
|
|
399
399
|
|
|
400
400
|
Observer.proxy(data.content.body).push(
|
|
401
|
-
{ text:
|
|
402
|
-
{ text:
|
|
401
|
+
{ text: "Inventory 1:" + someData.items[0] },
|
|
402
|
+
{ text: "Inventory 2:" + someData.items[1] }
|
|
403
403
|
);
|
|
404
404
|
|
|
405
|
-
const someData2 = await fetch(
|
|
405
|
+
const someData2 = await fetch("https://api.example.com/data2");
|
|
406
406
|
Observer.proxy(data.content.body).push(
|
|
407
|
-
{ text:
|
|
408
|
-
{ text:
|
|
407
|
+
{ text: "Inventory 3:" + someData2.items[0] },
|
|
408
|
+
{ text: "Inventory 4:" + someData2.items[1] }
|
|
409
409
|
);
|
|
410
410
|
|
|
411
411
|
resolve();
|
|
@@ -450,12 +450,12 @@ export async function POST(event, next) {
|
|
|
450
450
|
// Initiate response
|
|
451
451
|
event.respondWith({ step: 1 }, { done: false });
|
|
452
452
|
// Make API call
|
|
453
|
-
await fetch(
|
|
453
|
+
await fetch("https://api.example.com/data");
|
|
454
454
|
// Update response
|
|
455
455
|
event.respondWith({ step: 2 }, { done: false });
|
|
456
456
|
|
|
457
457
|
// Redirect
|
|
458
|
-
event.respondWith(null, { status: 302, headers: { Location:
|
|
458
|
+
event.respondWith(null, { status: 302, headers: { Location: "/done" } }); // [!code highlight]
|
|
459
459
|
}
|
|
460
460
|
```
|
|
461
461
|
|
|
@@ -471,7 +471,7 @@ This handler pauses request processing to interact with the user before proceedi
|
|
|
471
471
|
export async function DELETE(event, next) {
|
|
472
472
|
if (next.stepname) return await next(); // The conventional delegation line
|
|
473
473
|
|
|
474
|
-
const message =
|
|
474
|
+
const message = "This item will be permanently deleted. Are you sure?";
|
|
475
475
|
const answer = await event.user.confirm({ message }); // [!code highlight]
|
|
476
476
|
if (answer?.data === true) {
|
|
477
477
|
// proceed
|
|
@@ -487,7 +487,7 @@ Customization is as simple as intercepting these via `preventDefault()` to rende
|
|
|
487
487
|
|
|
488
488
|
```javascript
|
|
489
489
|
// Intercept at window.webqit.app.background
|
|
490
|
-
window.webqit.app.background.addEventListener(
|
|
490
|
+
window.webqit.app.background.addEventListener("prompt", (e) => {
|
|
491
491
|
e.preventDefault(); // [!code highlight]
|
|
492
492
|
customDialog(e.data.message).then((result) => {
|
|
493
493
|
// Reply to the request on the provided port
|
|
@@ -509,17 +509,17 @@ export async function GET(event, next) {
|
|
|
509
509
|
if (next.stepname) return await next(); // The conventional delegation line
|
|
510
510
|
|
|
511
511
|
// Channel ID - must tally with the client-side ID
|
|
512
|
-
const channelID =
|
|
512
|
+
const channelID = "test-channel";
|
|
513
513
|
|
|
514
514
|
const { channel, leave } = event.client.enterChannel(channelID, {
|
|
515
515
|
// Optionally annotate user's messages with user's name
|
|
516
|
-
resolveData: (message) => ({ ...message, user:
|
|
516
|
+
resolveData: (message) => ({ ...message, user: "sample name" }),
|
|
517
517
|
});
|
|
518
518
|
|
|
519
519
|
event.waitUntilNavigate(); // keep open
|
|
520
|
-
event.client.addEventListener(
|
|
520
|
+
event.client.addEventListener("close", (e) => {
|
|
521
521
|
//e.preventDefault();
|
|
522
|
-
console.log(
|
|
522
|
+
console.log("Chat closed");
|
|
523
523
|
});
|
|
524
524
|
}
|
|
525
525
|
```
|
|
@@ -531,15 +531,15 @@ export default async function (event, next) {
|
|
|
531
531
|
if (next.stepname) return await next(); // The conventional delegation line
|
|
532
532
|
|
|
533
533
|
// Initialize states
|
|
534
|
-
const data = { messageTrail: [{ message:
|
|
534
|
+
const data = { messageTrail: [{ message: "Beginning of chat..." }] };
|
|
535
535
|
await event.respondWith(data, { done: false }); // [!code highlight]
|
|
536
536
|
|
|
537
537
|
// The messaging part
|
|
538
538
|
const response = await next(); // Call server
|
|
539
|
-
const chatPort = LiveResponse.from(response).background;
|
|
539
|
+
const chatPort = (await LiveResponse.from(response)).background;
|
|
540
540
|
|
|
541
541
|
// Channel ID - must tally with the server-side ID
|
|
542
|
-
const channelID =
|
|
542
|
+
const channelID = "test-channel";
|
|
543
543
|
|
|
544
544
|
// Listen to upstream messages - from others in the same channel
|
|
545
545
|
chatPort.addEventListener(`${channelID}:message`, (e) => {
|
|
@@ -599,9 +599,10 @@ export default async function (event, next) {
|
|
|
599
599
|
:::
|
|
600
600
|
|
|
601
601
|
::: warning
|
|
602
|
+
|
|
602
603
|
- Channel IDs must be unique and unguessable across the app.
|
|
603
604
|
- Channels are not persistent and are only active for the duration of the request. A database is required to store channel data.
|
|
604
|
-
:::
|
|
605
|
+
:::
|
|
605
606
|
|
|
606
607
|
## Appendix A – The Realtime Lifecycle
|
|
607
608
|
|
|
@@ -625,7 +626,7 @@ sequenceDiagram
|
|
|
625
626
|
On entering background mode, Webflo initiates a handshake sequence as follows:
|
|
626
627
|
|
|
627
628
|
1. Webflo gives the initial response a unique `X-Background-Messaging-Port` header that tells the client to connect in the background after rendering the initial response.
|
|
628
|
-
> If the scenario is that the handler tiggers `event.client` messaging
|
|
629
|
+
> If the scenario is that the handler tiggers `event.client` messaging _before_ yielding a response, Webflo sends a temporary `202 Accepted` response to the client carrying this header.
|
|
629
630
|
2. The client reads that header and opens the background channel.
|
|
630
631
|
> If the client fails to connect within the handshake window, Webflo abandons the wait and concludes the request normally.
|
|
631
632
|
3. On connecting, both sides resume the same request context — now in live mode.
|
|
@@ -22,23 +22,23 @@ This documentation is a work in progress. Please expect some rough edges, missin
|
|
|
22
22
|
|
|
23
23
|
## Installation
|
|
24
24
|
|
|
25
|
-
### Option 1:
|
|
25
|
+
### Option 1: Local Installation (Recommended)
|
|
26
26
|
|
|
27
|
-
Install Webflo
|
|
27
|
+
Install Webflo as a dependency in your project:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npm install
|
|
30
|
+
npm install @webqit/webflo
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
### Option 2:
|
|
33
|
+
### Option 2: Global Installation
|
|
34
34
|
|
|
35
|
-
Install Webflo
|
|
35
|
+
Install Webflo globally to use the CLI from anywhere:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
npm install @webqit/webflo
|
|
38
|
+
npm install -g @webqit/webflo
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
The scope you choose will determine how you run Webflo commands. The Webflo commands in the rest of this page will show in both `
|
|
41
|
+
The scope you choose will determine how you run Webflo commands. The Webflo commands in the rest of this page will show in both `local` and `global` styles.
|
|
42
42
|
|
|
43
43
|
## Creating a New Project
|
|
44
44
|
|
|
@@ -46,14 +46,14 @@ Webflo provides a CLI command to scaffold new projects:
|
|
|
46
46
|
|
|
47
47
|
::: code-group
|
|
48
48
|
|
|
49
|
-
```bash [global]
|
|
50
|
-
webflo init my-webflo-app
|
|
51
|
-
```
|
|
52
|
-
|
|
53
49
|
```bash [local]
|
|
54
50
|
npx webflo init my-webflo-app
|
|
55
51
|
```
|
|
56
52
|
|
|
53
|
+
```bash [global]
|
|
54
|
+
webflo init my-webflo-app
|
|
55
|
+
```
|
|
56
|
+
|
|
57
57
|
:::
|
|
58
58
|
|
|
59
59
|
This will create a new directory called `my-webflo-app` with a basic Webflo project structure.
|
|
@@ -70,28 +70,28 @@ The above command could take a project title and project description too:
|
|
|
70
70
|
|
|
71
71
|
::: code-group
|
|
72
72
|
|
|
73
|
-
```bash [global]
|
|
74
|
-
webflo init my-webflo-app "My Webflo App" "My first ever Webflo app"
|
|
75
|
-
```
|
|
76
|
-
|
|
77
73
|
```bash [local]
|
|
78
74
|
npx webflo init my-webflo-app "My Webflo App" "My first ever Webflo app"
|
|
79
75
|
```
|
|
80
76
|
|
|
77
|
+
```bash [global]
|
|
78
|
+
webflo init my-webflo-app "My Webflo App" "My first ever Webflo app"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
81
|
:::
|
|
82
82
|
|
|
83
83
|
And you can specify a template to use:
|
|
84
84
|
|
|
85
85
|
::: code-group
|
|
86
86
|
|
|
87
|
-
```bash [global]
|
|
88
|
-
webflo init my-webflo-app --template=web
|
|
89
|
-
```
|
|
90
|
-
|
|
91
87
|
```bash [local]
|
|
92
88
|
npx webflo init my-webflo-app --template=web
|
|
93
89
|
```
|
|
94
90
|
|
|
91
|
+
```bash [global]
|
|
92
|
+
webflo init my-webflo-app --template=web
|
|
93
|
+
```
|
|
94
|
+
|
|
95
95
|
:::
|
|
96
96
|
|
|
97
97
|
The default is: `web`.
|
|
@@ -151,11 +151,11 @@ The generated `package.json` for your project will include scripts like `dev`, `
|
|
|
151
151
|
"scripts": {
|
|
152
152
|
// Builds HTML templates and client bundles into public/assets
|
|
153
153
|
"build:html": "oohtml bundle --recursive --outdir=public/assets --auto-embed=app",
|
|
154
|
-
"build:js": "webflo
|
|
154
|
+
"build:js": "webflo build --client --worker --server --recursive --outdir=public/assets --auto-embed",
|
|
155
155
|
// Production build: runs both steps
|
|
156
156
|
"build": "npm run build:html && npm run build:js",
|
|
157
157
|
// Development server with auto-rebuilds and fine-grained HMR
|
|
158
|
-
"dev": "webflo start --dev --build-sensitivity=
|
|
158
|
+
"dev": "webflo start --dev --build-sensitivity=1",
|
|
159
159
|
// Production server
|
|
160
160
|
"start": "webflo start"
|
|
161
161
|
},
|
|
@@ -181,7 +181,7 @@ You can customize as necessary.
|
|
|
181
181
|
::: info Scripts & customization
|
|
182
182
|
- You can customize `build:html` or `build:js` scripts if you need finer control
|
|
183
183
|
- Add a `build:css` script if your CSS requires a build step; it'll be called in dev mode as necessary on CSS file changes
|
|
184
|
-
- Adjust dev mode's rebuild frequency for assets with `--build-sensitivity` (e.g., `--build-sensitivity=
|
|
184
|
+
- Adjust dev mode's rebuild frequency for assets with `--build-sensitivity` (e.g., `--build-sensitivity=1` — to defer rebuild until page reload; `0` — to turn off)
|
|
185
185
|
:::
|
|
186
186
|
|
|
187
187
|
## Running Your Application
|
|
@@ -194,14 +194,14 @@ Start the development server:
|
|
|
194
194
|
|
|
195
195
|
::: code-group
|
|
196
196
|
|
|
197
|
-
```bash [global]
|
|
198
|
-
webflo start --dev
|
|
199
|
-
```
|
|
200
|
-
|
|
201
197
|
```bash [npm]
|
|
202
198
|
npm run dev
|
|
203
199
|
```
|
|
204
200
|
|
|
201
|
+
```bash [global]
|
|
202
|
+
webflo start --dev
|
|
203
|
+
```
|
|
204
|
+
|
|
205
205
|
:::
|
|
206
206
|
|
|
207
207
|
The server starts on `http://localhost:3000` by default.
|
|
@@ -220,14 +220,14 @@ The server starts on `http://localhost:3000` by default.
|
|
|
220
220
|
|
|
221
221
|
::: code-group
|
|
222
222
|
|
|
223
|
-
```bash [global]
|
|
224
|
-
webflo start --dev --open --port 8080
|
|
225
|
-
```
|
|
226
|
-
|
|
227
223
|
```bash [npm]
|
|
228
224
|
npm run dev -- --open --port 8080
|
|
229
225
|
```
|
|
230
226
|
|
|
227
|
+
```bash [global]
|
|
228
|
+
webflo start --dev --open --port 8080
|
|
229
|
+
```
|
|
230
|
+
|
|
231
231
|
:::
|
|
232
232
|
|
|
233
233
|
### Webflo Build
|
|
@@ -254,14 +254,14 @@ Start the production server when ready:
|
|
|
254
254
|
|
|
255
255
|
::: code-group
|
|
256
256
|
|
|
257
|
-
```bash [global]
|
|
258
|
-
webflo start
|
|
259
|
-
```
|
|
260
|
-
|
|
261
257
|
```bash [npm]
|
|
262
258
|
npm start
|
|
263
259
|
```
|
|
264
260
|
|
|
261
|
+
```bash [global]
|
|
262
|
+
webflo start
|
|
263
|
+
```
|
|
264
|
+
|
|
265
265
|
Your app runs in production mode. Production can be in any filesystem-enabled JavaScript runtime.
|
|
266
266
|
|
|
267
267
|
::: warning Production differences
|
|
@@ -354,22 +354,22 @@ You’ve:
|
|
|
354
354
|
|
|
355
355
|
```bash
|
|
356
356
|
# Initialize a new project
|
|
357
|
-
webflo init <project-name>
|
|
357
|
+
npx webflo init <project-name>
|
|
358
358
|
|
|
359
359
|
# Start development server
|
|
360
|
-
webflo start --dev
|
|
360
|
+
npx webflo start --dev
|
|
361
361
|
|
|
362
362
|
# Start production server
|
|
363
|
-
webflo start
|
|
363
|
+
npx webflo start
|
|
364
364
|
|
|
365
365
|
# Build for production
|
|
366
|
-
webflo build
|
|
366
|
+
npx webflo build
|
|
367
367
|
|
|
368
368
|
# Configure Webflo
|
|
369
|
-
webflo config
|
|
369
|
+
npx webflo config
|
|
370
370
|
|
|
371
371
|
# View help
|
|
372
|
-
webflo --help
|
|
372
|
+
npx webflo --help
|
|
373
373
|
```
|
|
374
374
|
|
|
375
375
|
</details>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class CLIContext {
|
|
2
2
|
|
|
3
3
|
constructor(dict, CD = null) {
|
|
4
4
|
// dict can be plain object or some Context instance itself
|
|
@@ -14,15 +14,16 @@ export class Context {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
get name() {
|
|
18
|
-
return 'webflo';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
17
|
// create
|
|
22
18
|
static create(...args) {
|
|
23
19
|
return new this(...args);
|
|
24
20
|
}
|
|
25
21
|
|
|
22
|
+
// name
|
|
23
|
+
get name() {
|
|
24
|
+
return 'webflo';
|
|
25
|
+
}
|
|
26
|
+
|
|
26
27
|
// CWD
|
|
27
28
|
get CWD() {
|
|
28
29
|
return this.dict.CWD || '';
|
|
@@ -33,7 +34,7 @@ export class Context {
|
|
|
33
34
|
return this.dict.meta || {};
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
//
|
|
37
|
+
// appMeta
|
|
37
38
|
get appMeta() {
|
|
38
39
|
return this.dict.appMeta || {};
|
|
39
40
|
}
|
|
@@ -63,10 +64,10 @@ export class Context {
|
|
|
63
64
|
|
|
64
65
|
// logger
|
|
65
66
|
get logger() {
|
|
66
|
-
return this.dict.logger;
|
|
67
|
+
return this.dict.logger || console;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
set logger(value) {
|
|
70
71
|
Object.defineProperty(this.dict, 'logger', { value } );
|
|
71
72
|
}
|
|
72
|
-
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Fs from 'fs/promises';
|
|
2
|
+
//import { transformQuantum } from '@webqit/quantum-js';
|
|
3
|
+
|
|
4
|
+
export function LiveJSTransform() {
|
|
5
|
+
return {
|
|
6
|
+
name: 'livejs-transform',
|
|
7
|
+
setup(build) {
|
|
8
|
+
build.onLoad({ filter: /\.(js|mjs|ts|jsx|tsx)$/ }, async (args) => {
|
|
9
|
+
let code = await Fs.readFile(args.path, 'utf8');
|
|
10
|
+
|
|
11
|
+
//console.log('LiveJS -- transform:', args);
|
|
12
|
+
|
|
13
|
+
// super dirty detection
|
|
14
|
+
if (!/\bquantum\s+function\b/.test(code) &&
|
|
15
|
+
!/\basync\s+quantum\s+function\b/.test(code)) {
|
|
16
|
+
return { contents: code, loader: 'default' };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
console.log('LiveJS transform:', args.path);
|
|
21
|
+
|
|
22
|
+
return { contents: code, loader: 'default' };
|
|
23
|
+
const result = await transformQuantum(code, {
|
|
24
|
+
filename: args.path,
|
|
25
|
+
sourceMaps: true
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
contents: result.code,
|
|
30
|
+
loader: 'js' // or 'ts' if you want esbuild TS transform after
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|