@webqit/webflo 0.11.6 → 0.11.7
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 +120 -35
- package/package.json +1 -1
- package/src/runtime-pi/client/Runtime.js +3 -3
package/README.md
CHANGED
|
@@ -929,7 +929,9 @@ Going forward, we can get to write more succinct code! Using the [Namespaced HTM
|
|
|
929
929
|
document.title = title;
|
|
930
930
|
let { headline1, headline2 } = this.namespace;
|
|
931
931
|
$(headline1).html(title);
|
|
932
|
-
|
|
932
|
+
if (headline2) {
|
|
933
|
+
$(headline2).html(title);
|
|
934
|
+
}
|
|
933
935
|
</script>
|
|
934
936
|
</body>
|
|
935
937
|
</html>
|
|
@@ -1065,7 +1067,7 @@ For all things application state, Webflo leverages the [State API](https://githu
|
|
|
1065
1067
|
|
|
1066
1068
|
#### The `document.state.data` Object
|
|
1067
1069
|
|
|
1068
|
-
This property
|
|
1070
|
+
This property reperesents the application data at any point in time - obtained from route handers on each navigation. Webflo simply updates this property and lets the page's [rendering logic](#client-and-server-side-rendering), or other parts of the application, take over.
|
|
1069
1071
|
|
|
1070
1072
|
```js
|
|
1071
1073
|
Observer.observe(document.state, 'data', e => {
|
|
@@ -1073,6 +1075,13 @@ Observer.observe(document.state, 'data', e => {
|
|
|
1073
1075
|
});
|
|
1074
1076
|
```
|
|
1075
1077
|
|
|
1078
|
+
```html
|
|
1079
|
+
<script type="subscript">
|
|
1080
|
+
let { title } = document.state.data;
|
|
1081
|
+
document.title = title;
|
|
1082
|
+
</script>
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1076
1085
|
#### The `document.state.url` Object
|
|
1077
1086
|
|
|
1078
1087
|
This is a *live* object that reperesents the properties of the application URL at any point in time. The object exposes the same URL properties as with the [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) API, but as *live* properties that can be observed as navigation happens, and modified to initiate navigation - all using the [Observer API](https://github.com/webqit/observer).
|
|
@@ -1113,11 +1122,18 @@ document.addEventListener('synthetic-navigation', e => {
|
|
|
1113
1122
|
});
|
|
1114
1123
|
```
|
|
1115
1124
|
|
|
1125
|
+
```html
|
|
1126
|
+
<script type="subscript">
|
|
1127
|
+
let { query: { as: role } } = document.state.url;
|
|
1128
|
+
document.title = 'Login as ' + role;
|
|
1129
|
+
</script>
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1116
1132
|
### Requests and Responses
|
|
1117
1133
|
|
|
1118
|
-
On each request, the event object passed to route handlers exposes the incoming request as `event.request`. This is an instance of `event.Request` - an extension of the [WHATWG Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) class. The event object also exposes `event.Response` - an extension of the [WHATWG Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) class, for returning instance-based responses.
|
|
1134
|
+
On each request, the event object passed to route handlers exposes the incoming request as `event.request`. This is an instance of `event.Request` - an extension of the [WHATWG Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) class. The event object also exposes `event.Response` - an extension of the [WHATWG Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) class, for returning instance-based responses. You enjoy routing that is based on standard interfaces!
|
|
1119
1135
|
|
|
1120
|
-
|
|
1136
|
+
Routes in Webflo can be designed for different types of request/response scenarios. Here are some important ones:
|
|
1121
1137
|
|
|
1122
1138
|
#### Scenario 1: Static File Requests and Responses
|
|
1123
1139
|
|
|
@@ -1216,19 +1232,18 @@ console.log(event.request.headers.cookies); // { 'Cookie-1': 'cookie-val', 'Cook
|
|
|
1216
1232
|
|
|
1217
1233
|
### Webflo Applications
|
|
1218
1234
|
|
|
1219
|
-
In just a few concepts, Webflo comes ready for any type of application!
|
|
1235
|
+
In just a few concepts, Webflo comes ready for any type of application!
|
|
1220
1236
|
|
|
1221
1237
|
+ [Client-Side Applications](#client-side-applications)
|
|
1238
|
+
+ [Progressive Web Apps](#progressive-web-apps)
|
|
1222
1239
|
+ [API Backends](#api-backends)
|
|
1223
1240
|
+ [Static Sites](#static-sites)
|
|
1224
1241
|
|
|
1225
1242
|
#### Client-Side Applications
|
|
1226
1243
|
|
|
1227
|
-
Web pages that embed the Webflo client JS bundle deliver a great user experience.
|
|
1228
|
-
+ **First-paint-ready.** On the first page request, you get a [server-rendered](#client-and-server-side-rendering) HTML page that's optimized for the first paint of your application.
|
|
1229
|
-
+ **Fluid and app-like.** On being loaded, the state of the application is restored through hydration, and [subsequent navigations](#spa-navigation) are sleek and instant, while performing [Client-Side Rendering](#client-and-server-side-rendering).
|
|
1244
|
+
Web pages that embed the Webflo client JS bundle deliver a great user experience. It's simple: the `npm run generate` command does both the building and embedding of the script, or scripts, for the document root, or document roots (in a [Multi Page](#in-a-multi-page-layout) / [Multi SPA](#in-a-multi-spa-layout) layout)!
|
|
1230
1245
|
|
|
1231
|
-
|
|
1246
|
+
On being loaded, the state of the application is initialized, or is restored through hydration - where [Server-Side Rendering](#client-and-server-side-rendering) was involved to optimize for first paint, and an app-like experience kicks in! For [Single-Page Applications](#in-a-single-page-layout), [Client-Side Rendering](#client-and-server-side-rendering) is performed on each navigation.
|
|
1232
1247
|
|
|
1233
1248
|
##### SPA Navigation
|
|
1234
1249
|
|
|
@@ -1242,23 +1257,84 @@ Unless disabled in [config](#spa_navigation), it is factored-in at build time fo
|
|
|
1242
1257
|
|
|
1243
1258
|
##### SPA State
|
|
1244
1259
|
|
|
1245
|
-
On the client side of a Webflo application, [the idea of state](#the-idea-of-state) also
|
|
1260
|
+
On the client side of a Webflo application, [the idea of state](#the-idea-of-state) also includes the following aspects of the client-side lifecycle that can be used to provide visual cues on the UI.
|
|
1246
1261
|
|
|
1247
1262
|
###### The `document.state.network` Object
|
|
1248
1263
|
|
|
1249
1264
|
This is a *live* object that exposes the network activity and network state of the application.
|
|
1250
1265
|
|
|
1251
1266
|
```js
|
|
1252
|
-
console.log(document.state.network) // { requesting, remote, error, redirecting,
|
|
1267
|
+
console.log(document.state.network) // { requesting, remote, error, redirecting, connectivity, }
|
|
1253
1268
|
```
|
|
1254
1269
|
|
|
1255
1270
|
+ **`network.requesting`: `null|Object`** - This property tells when a request is ongoing, in which case it exposes the `params` object used to initiate the request.
|
|
1271
|
+
|
|
1272
|
+
On the UI, this could be used to hide a menu drawer that may have been open.
|
|
1273
|
+
|
|
1274
|
+
```html
|
|
1275
|
+
<menu-drawer>
|
|
1276
|
+
<script type="subscript">
|
|
1277
|
+
let { network: { requesting } } = document.state;
|
|
1278
|
+
if (requesting) {
|
|
1279
|
+
$(this).attr('open', false);
|
|
1280
|
+
}
|
|
1281
|
+
</script>
|
|
1282
|
+
</menu-drawer>
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1256
1285
|
+ **`network.remote`: `null|String`** - This property tells when a remote request is ongoing - usually the same navigation requests as at `network.requesting`, but when not handled by any client-side route handlers, or when `next()`ed to this point by route handlers. The `remote` property also goes live when a route handler calls the special `fetch()` function that they recieve on their fourth parameter.
|
|
1286
|
+
|
|
1287
|
+
On the UI, this could be used to show/hide a spinner, or progress bar, to provide a visual cue.
|
|
1288
|
+
|
|
1289
|
+
```html
|
|
1290
|
+
<progress-bar>
|
|
1291
|
+
<script type="subscript">
|
|
1292
|
+
let { network: { remote } } = document.state;
|
|
1293
|
+
$(this).attr('hidden', !remote);
|
|
1294
|
+
</script>
|
|
1295
|
+
</progress-bar>
|
|
1296
|
+
```
|
|
1297
|
+
|
|
1257
1298
|
+ **`network.error`: `null|Error`** - This property tells when a request is *errored* in which case it contains an `Error` instance of the error. For requests that can be retried, the `Error` instance also has a custom `retry()` method.
|
|
1299
|
+
|
|
1300
|
+
On the UI, this could be used to show/hide cute error elements.
|
|
1301
|
+
|
|
1302
|
+
```html
|
|
1303
|
+
<nice-error>
|
|
1304
|
+
<script type="subscript">
|
|
1305
|
+
let { network: { error } } = document.state;
|
|
1306
|
+
$(this).attr('hidden', !error);
|
|
1307
|
+
</script>
|
|
1308
|
+
</nice-error>
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1258
1311
|
+ **`network.redirecting`: `null|String`** - This property tells when a client-side redirect is ongoing - see [Scenario 4: Single Page Navigation Requests and Responses](#scenario-4-single-page-navigation-requests-and-responses) - in which case it exposes the destination URL.
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1312
|
+
|
|
1313
|
+
On the UI, this could be used to prevent further interactions with the outgoing page.
|
|
1314
|
+
|
|
1315
|
+
```html
|
|
1316
|
+
<body>
|
|
1317
|
+
<script type="subscript">
|
|
1318
|
+
let { network: { redirecting } } = document.state;
|
|
1319
|
+
$(this).css(redirecting ? { pointerEvents: 'none', filter: 'blur(2)' } : { pointerEvents: 'auto', filter: 'blur(0)' });
|
|
1320
|
+
</script>
|
|
1321
|
+
</body>
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
+ **`network.connectivity`: `String`** - This property tells of [the browser's ability to connect to the network](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine): `online`, `offline`.
|
|
1325
|
+
|
|
1326
|
+
On the UI, this could be used to show/hide a connectivity status.
|
|
1327
|
+
|
|
1328
|
+
```html
|
|
1329
|
+
<body>
|
|
1330
|
+
<script type="subscript">
|
|
1331
|
+
let { network: { connectivity } } = document.state;
|
|
1332
|
+
$(this).attr( 'connectivity', connectivity });
|
|
1333
|
+
</script>
|
|
1334
|
+
</body>
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1337
|
+
Here are some additional examples with the [Observer API](https://github.com/webqit/observer).
|
|
1262
1338
|
|
|
1263
1339
|
```js
|
|
1264
1340
|
// Visualize the network state
|
|
@@ -1272,12 +1348,12 @@ Observer.observe(document.state.network, onlineVisualizer);
|
|
|
1272
1348
|
```
|
|
1273
1349
|
|
|
1274
1350
|
```js
|
|
1275
|
-
// Visualize the '
|
|
1276
|
-
let
|
|
1277
|
-
console.log('You are ', e.value
|
|
1351
|
+
// Visualize the 'connectivity' property
|
|
1352
|
+
let connectivityVisualizer = e => {
|
|
1353
|
+
console.log('You are ', e.value);
|
|
1278
1354
|
};
|
|
1279
|
-
Observer.observe(document.state.network, '
|
|
1280
|
-
// Or: Observer.observe(document.state, [ ['network', '
|
|
1355
|
+
Observer.observe(document.state.network, 'connectivity', connectivityVisualizer);
|
|
1356
|
+
// Or: Observer.observe(document.state, [ ['network', 'connectivity'] ], connectivityeVisualizer);
|
|
1281
1357
|
```
|
|
1282
1358
|
|
|
1283
1359
|
```js
|
|
@@ -1292,17 +1368,32 @@ Observer.observe(document.state.network, 'error', e => {
|
|
|
1292
1368
|
});
|
|
1293
1369
|
```
|
|
1294
1370
|
|
|
1295
|
-
|
|
1371
|
+
##### Form Actions
|
|
1372
|
+
|
|
1373
|
+
When navigation occurs [via form submissions](#scenario-4-single-page-navigation-requests-and-responses), the form element and the submit button are made to go on the *active* state while the request is being processed. For both of these elements, the Webflo client simply sets the `element.state.active` to `true` on submission, then `false`, on completion.
|
|
1374
|
+
|
|
1375
|
+
```html
|
|
1376
|
+
<form method="post">
|
|
1377
|
+
<input name="username" placeholder="Your username..." />
|
|
1378
|
+
<script>
|
|
1379
|
+
$(this).css(this.state.active ? { pointerEvents: 'none', opacity: 'o.5' } : { pointerEvents: 'auto', opacity: '1' });
|
|
1380
|
+
</script>
|
|
1381
|
+
</form>
|
|
1382
|
+
```
|
|
1296
1383
|
|
|
1297
|
-
|
|
1384
|
+
One more thing: HTML forms can only accept two HTTP methods on their `method` attribute: `GET`, `POST`! The same constraint exists on the equivalent `formmethod` attribue in submit buttons. You are able to overcome this in Webflo by using alternative `data-` attributes: `data-method`, `data-formmethod`, respectively.
|
|
1298
1385
|
|
|
1299
|
-
|
|
1386
|
+
```html
|
|
1387
|
+
<form data-method="patch">
|
|
1388
|
+
<input name="price" placeholder="Enter new price..." />
|
|
1389
|
+
</form>
|
|
1390
|
+
```
|
|
1300
1391
|
|
|
1301
|
-
|
|
1392
|
+
#### Progressive Web Apps
|
|
1302
1393
|
|
|
1303
|
-
Webflo client-side applications are intended to provide an app-like-first experience. So unless disabled in [config](#enable_service_worker), a [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) is built as part of your application on running the `npm run generate` command. You may define [route handlers in the `/worker` directory](#handler-functions-and-layout) of your application, and these will be built into the service worker to handle Same-Origin requests of the application. Where there are no *worker* handlers, or where
|
|
1394
|
+
Webflo client-side applications are intended to provide an app-like-first experience. So unless disabled in [config](#enable_service_worker), a [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) is built as part of your application on running the `npm run generate` command. You may define [route handlers in the `/worker` directory](#handler-functions-and-layout) of your application, and these will be built into the service worker to handle Same-Origin requests of the application. Where there are no *worker* handlers, or where these forward incoming requests, requests are fetched, either from the cache, or from the network, depending on the fetching strategy built into the Service Worker.
|
|
1304
1395
|
|
|
1305
|
-
|
|
1396
|
+
##### Fetching Strategy
|
|
1306
1397
|
|
|
1307
1398
|
+ **Network First** - This strategy tells the Service Worker to always attempt fetching from the network first for given resources, before fetching from the cache. On every successful network fetch, a copy of the response is saved to the cache for next time. (This is good for resources that need to be fresh to the user on a "best effort" basis.) Unless [changed](#default_fetching_strategy), this is Webflo's default fetching strategy. When not the default strategy, a list of specific URLs that should be fetched this way can be [configured](#network_first_urls).
|
|
1308
1399
|
+ **Cache First** - This strategy tells the Service Worker to always attempt fetching from the cache first for given resources, before fetching from the network. After serving a cached response, or where not found in cache, a network fetch happens and a copy of the response is saved to the cache for next time. (This is good for resources that do not critially need to be fresh to the user.) When not the default strategy, a list of specific URLs that should be fetched this way can be [configured](#cache_first_urls).
|
|
@@ -1311,9 +1402,9 @@ Webflo client-side applications are intended to provide an app-like-first experi
|
|
|
1311
1402
|
|
|
1312
1403
|
In all cases above, the convention for specifying URLs for a strategy accepts [URL patterns](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) - against which URLs can be matched on the fly. For example, to place all files in an `/image` directory (and subdirectories) on the *Cache First* strategy, the pattern `/image/*` can be used. To place all `.svg` files in an `/icons` directory (including subdirectories) on the *Cache Only* strategy, the pattern `/icons/*.svg` can be used. (Specifically for the *Cache Only* strategy, patterns are resolved at Service Worker build-time, and each pattern must match, at least, a file.)
|
|
1313
1404
|
|
|
1314
|
-
|
|
1405
|
+
##### Cross-Thread Communications
|
|
1315
1406
|
|
|
1316
|
-
A couple APIs exists in browsers for establishing a two-way communication channel between a page and its
|
|
1407
|
+
A couple APIs exists in browsers for establishing a two-way communication channel between a page and its Service Worker, for firing UI Notifications from either ends, and for implementing Push Notifications. Webflo offers to simply this with a unifying set of conventions:
|
|
1317
1408
|
|
|
1318
1409
|
+ The `workport` API - an object with simple methods for working with *cross-thread* messages, UI and Push Notifications.
|
|
1319
1410
|
|
|
@@ -1467,10 +1558,10 @@ And if you will partition your backend for both page routes and a formal REST AP
|
|
|
1467
1558
|
```shell
|
|
1468
1559
|
server
|
|
1469
1560
|
├── index.js ──┐
|
|
1470
|
-
├── cart/index.js
|
|
1561
|
+
├── cart/index.js ├─ Page Routes
|
|
1471
1562
|
├── products/index.js ──┘
|
|
1472
1563
|
├── api/v1/index.js ──┐
|
|
1473
|
-
├── api/v1/orders/index.js
|
|
1564
|
+
├── api/v1/orders/index.js ├─ REST API
|
|
1474
1565
|
└── api/v1/products/index.js ──┘
|
|
1475
1566
|
```
|
|
1476
1567
|
|
|
@@ -1536,12 +1627,6 @@ You could soon be taking all your ideas to Webflo! 😃
|
|
|
1536
1627
|
|
|
1537
1628
|
All forms of contributions and PR are welcome! To report bugs or request features, please submit an [issue](https://github.com/webqit/webflo/issues). For general discussions, ideation or community help, please join our github [Discussions](https://github.com/webqit/webflo/discussions).
|
|
1538
1629
|
|
|
1539
|
-
## License
|
|
1540
|
-
|
|
1541
|
-
MIT.
|
|
1542
|
-
|
|
1543
|
-
...
|
|
1544
|
-
|
|
1545
1630
|
## Getting Involved
|
|
1546
1631
|
|
|
1547
1632
|
All forms of contributions and PR are welcome! To report bugs or request features, please submit an [issue](https://github.com/webqit/webflo/issues).
|
package/package.json
CHANGED
|
@@ -118,7 +118,7 @@ export default class Runtime {
|
|
|
118
118
|
return params;
|
|
119
119
|
}, {});
|
|
120
120
|
// We support method hacking
|
|
121
|
-
submitParams.method = (submitter && submitter.dataset.
|
|
121
|
+
submitParams.method = (submitter && submitter.dataset.formmethod) || form.dataset.method || submitParams.method;
|
|
122
122
|
submitParams.submitter = submitter;
|
|
123
123
|
// ---------------
|
|
124
124
|
var actionEl = window.document.createElement('a');
|
|
@@ -152,8 +152,8 @@ export default class Runtime {
|
|
|
152
152
|
// -----------------------
|
|
153
153
|
// Initialize network
|
|
154
154
|
Observer.set(this, 'network', {});
|
|
155
|
-
window.addEventListener('online', () => Observer.set(this.network, '
|
|
156
|
-
window.addEventListener('offline', () => Observer.set(this.network, '
|
|
155
|
+
window.addEventListener('online', () => Observer.set(this.network, 'connectivity', 'online'));
|
|
156
|
+
window.addEventListener('offline', () => Observer.set(this.network, 'connectivity', 'offline'));
|
|
157
157
|
|
|
158
158
|
// -----------------------
|
|
159
159
|
// Service Worker && COMM
|