@webqit/webflo 0.11.20 → 0.11.23

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 CHANGED
@@ -7,41 +7,81 @@
7
7
 
8
8
  <!-- /BADGES -->
9
9
 
10
- Webflo is a universal *web*, *mobile*, and *API backend* framework built to solve for the underrated `.html` + `.css` + `.js` stack! This has been written specifically to draw directly on the plain old stack at the language level - to facilitate building web-native applications!
10
+ Webflo is a universal *web*, *mobile*, and *API backend* framework that gets it all done in vanilla HTML, CSS, and JavaScript! It's a powerful little thing written to facilitate building more authentic, web-native applications!
11
11
 
12
- Ok, we've put all of that up for a straight read!
12
+ Here, we've put all of that up for a 10min straight read!
13
13
 
14
- > **Note**
15
- > <br>Depending on your current framework background, the hardest part of Webflo might be having to break ties with something that isn't conventional to the `.html` + `.css` + `.js` stack: all of that JSX, CSS-in-JS, etc.!
14
+ TL;DR: here's what's ahead...
15
+
16
+ + web-native development and the vanilla advantage!
17
+ + the path of least engineering!
18
+
19
+ ## The Catch...
20
+
21
+ Webflo is a framework on its own track - working and thinking in vanilla HTML, CSS and JavaScript! Instead of trying to follow certain norms, it takes a plunge to draw on native web platform features - plus some more futurisric, fascinating stuffs we're proposing as standards! This means that you also have to be excited about taking a plunge to happily meet Webflo!
22
+
23
+ ## The Wins...
24
+
25
+ Much of what eludes the web today...
16
26
 
17
- ## Documentation
27
+ + the long-missing framework design and architecture for a HTML-first thinking!
28
+ + a focused standards-based philosophy that breeds more authentic applications!
29
+
30
+ Plus native support for how you want to work...
31
+
32
+ + a new approach to reactivity that's based on no syntax at all but plain old JavaScript!
33
+ + a new "imports" feature for HTML that makes HTML more reusable!
34
+ + and much more.
35
+
36
+ ## Documentation
37
+
38
+ All of Webflo in a 10-min read!
18
39
 
19
40
  + [Overview](#overview)
20
41
  + [Installation](#installation)
21
42
  + [Concepts](#concepts)
43
+ + [Handler Functions and Layout](#handler-functions-and-layout)
44
+ + [Step Functions and Workflows](#step-functions-and-workflows)
45
+ + [Pages, Layout and Templating](#pages-layout-and-templating)
46
+ + [Client and Server-Side Rendering](#client-and-server-side-rendering)
47
+ + [Requests and Responses](#requests-and-responses)
22
48
  + [Webflo Applications](#webflo-applications)
49
+ + [Client-Side Applications](#client-side-applications)
50
+ + [Progressive Web Apps](#progressive-web-apps)
51
+ + [API Backends](#api-backends)
52
+ + [Static Sites](#static-sites)
23
53
  + [Webflo Config](#webflo-config)
24
- + [Technology Stack](#technology-stack)
54
+ + [Webflo Tooling](#webflo-tooling)
55
+ + [OOHTML](#oohtml)
56
+ + [OOHTML SSR](#oohtml-ssr)
57
+ + [OOHTML CLI](#oohtml-cli)
58
+ + [The Observer API](#the-observer-api)
25
59
  + [Getting Started](#getting-started)
26
60
  + [Getting Involved](#getting-involved)
27
61
 
28
62
  ## Overview
29
63
 
30
64
  <details>
31
- <summary><b>Build <i>anything</i></b> - from as basic as a static <code>index.html</code> page to as rich as a universal app that's either a <i>Multi Page Application (MPA)</i>, <i>Single Page Application (SPA)</i>, or a hybrid of these, implementing <i>Server Side Rendering (SSR)</i>, <i>Client Side Rendering (CSR)</i>, or a hybrid of these, offline and <i>PWA</i> capabilities, etc. - this time, <i>without loosing the vanilla advantage</i>!
65
+ <summary><b>Build <i>anything</i></b> - from as basic as a static <code>index.html</code> page to as rich as a universal app that's either a <i>Multi Page Application (MPA)</i>, <i>Single Page Application (SPA)</i>, or a hybrid of both, implementing <i>Server Side Rendering (SSR)</i>, <i>Client Side Rendering (CSR)</i>, or a hybrid of both, offline and <i>PWA</i> capabilities, etc. - this time, <i>without loosing the vanilla advantage</i>!
32
66
  </summary>
33
67
 
34
68
  Here's a glimpse of your Webflo app.
35
69
 
36
- For when your application has a Server side.
70
+ For when your application is a static site, or has static files to serve.
37
71
  + The `public` directory for static files.
38
- + The `server` directory for server-side routing. (i.e. dynamic request handling on the server - in the case of Multi Page Applications, API backends, etc.)
39
72
 
40
73
  ```shell
41
74
  my-app
42
- ├── server/index.js
43
75
  └── public/logo.png
44
76
  ```
77
+
78
+ For when your application has a Server side.
79
+ + The `server` directory for server-side routing. (i.e. dynamic request handling on the server - in the case of Multi Page Applications, API backends, etc.)
80
+
81
+ ```shell
82
+ my-app
83
+ └── server/index.js
84
+ ```
45
85
 
46
86
  And a typical `index.js` route handler has the following anatomy.
47
87
 
@@ -100,7 +140,7 @@ For when your application has a Client side.
100
140
  └── worker/index.js
101
141
  ```
102
142
 
103
- And in both cases, a typical `index.js` route handler has the following anatomy.
143
+ And in both cases, a typical `index.js` route handler has the following anatomy. (Same with server-side handlers.)
104
144
 
105
145
  ```js
106
146
  /**
@@ -385,7 +425,7 @@ export default function(event, context, next) {
385
425
  }
386
426
  ```
387
427
 
388
- This step-based workflow helps to decomplicate routing and gets us scaling horizontally as our application grows larger.
428
+ We get a step-based workflow that helps to decomplicate routing and lets us scale horizontally as our application grows larger.
389
429
 
390
430
  <details>
391
431
  <summary>More details...</summary>
@@ -525,7 +565,7 @@ So, above, should our handler receive static file requests like `http://localhos
525
565
 
526
566
  ```shell
527
567
  my-app
528
- ├── server/index.js ------------------------- http://localhost:3000, http://localhost:3000/prodcuts, http://localhost:3000/prodcuts/stickers, etc
568
+ ├── server/index.js ------------------------- http://localhost:3000, http://localhost:3000/products, http://localhost:3000/products/stickers, etc
529
569
  └── public/logo.png ------------------------- http://localhost:3000/logo.png
530
570
  ```
531
571
 
@@ -567,7 +607,7 @@ Now we get the following handler-to-URL mapping for our application:
567
607
  ```shell
568
608
  my-app
569
609
  ├── worker/index.js ------------------------- http://localhost:3000/about, http://localhost:3000/logo.png
570
- ├── server/index.js ------------------------- http://localhost:3000, http://localhost:3000/prodcuts, http://localhost:3000/prodcuts/stickers, etc
610
+ ├── server/index.js ------------------------- http://localhost:3000, http://localhost:3000/products, http://localhost:3000/products/stickers, etc
571
611
  └── public/logo.png ------------------------- http://localhost:3000/logo.png
572
612
  ```
573
613
 
@@ -606,7 +646,7 @@ Our overall handler-to-URL mapping for this application now becomes:
606
646
  my-app
607
647
  ├── client/index.js ------------------------- http://localhost:3000/login
608
648
  ├── worker/index.js ------------------------- http://localhost:3000/about, http://localhost:3000/logo.png
609
- ├── server/index.js ------------------------- http://localhost:3000, http://localhost:3000/prodcuts, http://localhost:3000/prodcuts/stickers, etc
649
+ ├── server/index.js ------------------------- http://localhost:3000, http://localhost:3000/products, http://localhost:3000/products/stickers, etc
610
650
  └── public/logo.png ------------------------- http://localhost:3000/logo.png
611
651
  ```
612
652
 
@@ -692,7 +732,7 @@ In a Multi Page Application (with an individual-page architecture), each page is
692
732
  my-app
693
733
  └── public
694
734
  ├── about/index.html ------------------------- <!DOCTYPE html>
695
- ├── prodcuts/index.html ---------------------- <!DOCTYPE html>
735
+ ├── products/index.html ---------------------- <!DOCTYPE html>
696
736
  ├── index.html ------------------------------- <!DOCTYPE html>
697
737
  ├── header.html ------------------------------ <header></header> <!-- To appear at top of each index.html page -->
698
738
  └── footer.html ------------------------------ <footer></footer> <!-- To appear at bottom of each index.html page -->
@@ -704,7 +744,7 @@ In a Single Page Application, each page is the same `index.html` document, and i
704
744
  my-app
705
745
  └── public
706
746
  ├── about/main.html -------------------------- <main></main> <!-- To appear at main area of index.html -->
707
- ├── prodcuts/main.html ----------------------- <main></main> <!-- To appear at main area of index.html -->
747
+ ├── products/main.html ----------------------- <main></main> <!-- To appear at main area of index.html -->
708
748
  ├── main.html -------------------------------- <main></main> <!-- To appear at main area of index.html -->
709
749
  └── index.html ------------------------------- <!DOCTYPE html>
710
750
  ```
@@ -733,7 +773,7 @@ Here, you are able to define reusable contents in a `<template>` element...
733
773
  </body>
734
774
  ```
735
775
 
736
- The *module* element - `<template>` - is able to load its contents from a remote `.html` file that serves as a bundle:
776
+ The *module* element - `<template>` - is also able to load its contents from a remote `.html` file that serves as a bundle:
737
777
 
738
778
  ```html
739
779
  <!--
@@ -825,7 +865,7 @@ public/products
825
865
 
826
866
  #### In a Single Page Layout
827
867
 
828
- In a Single Page layout (as seen [earlier](#layout-and-templating-overview)), page-specific contents - e.g. main sections - are typically bundled together into one `bundle.html` file that can be embedded on the document root. Nested routes end up as nested `<template>` elements that form the equivalent of the application's URL structure.
868
+ In a Single Page layout (as seen [earlier](#layout-and-templating-overview)), page-specific contents - e.g. main sections - are typically bundled together into one `bundle.html` file that can be embedded on the document root. Notice how nested routes end up as nested `<template>` elements that form the equivalent of the application's URL structure.
829
869
 
830
870
  ```html
831
871
  <!--
@@ -876,7 +916,7 @@ It's all a *layout* thing, so a hybrid of the two architectures above is possibl
876
916
  my-app
877
917
  └── public
878
918
  ├── about/index.html ------------------------- <!DOCTYPE html> <!-- Document root 1 -->
879
- ├── prodcuts
919
+ ├── products
880
920
  │ ├── free/main.html --------------------------- <main></main> <!-- To appear at main area of document root 2 -->
881
921
  │ ├── paid/main.html --------------------------- <main></main> <!-- To appear at main area of document root 2 -->
882
922
  │ ├── main.html -------------------------------- <main></main> <!-- To appear at main area of document root 2 -->
@@ -886,7 +926,7 @@ my-app
886
926
  └── footer.html ------------------------------ <footer></footer> <!-- To appear at bottom of each document root -->
887
927
  ```
888
928
 
889
- The above gives us three document roots: `/index.html`, `/about/index.html`, `/prodcuts/index.html`. The `/prodcuts` route doubles as a Single Page Application such that visiting the `/prodcuts` route loads the document root `/prodcuts/index.html` and lets Webflo SPA routing determine which of `/prodcuts/main.html`, `/prodcuts/free/main.html`, `/prodcuts/paid/main.html` is imported on a given URL.
929
+ The above gives us three document roots: `/index.html`, `/about/index.html`, `/products/index.html`. The `/products` route doubles as a Single Page Application such that visiting the `/products` route loads the document root `/products/index.html` and lets Webflo SPA routing determine which of `/products/main.html`, `/products/free/main.html`, `/products/paid/main.html` is imported on a given URL.
890
930
 
891
931
  Webflo ensures that only the amount of JavaScript for a document root is actually loaded! So, above, a common JavaScript build is shared across the three document roots alongside an often tiny root-specific build.
892
932
 
@@ -1224,7 +1264,7 @@ Observer.observe(document.state, 'data', e => {
1224
1264
 
1225
1265
  #### The `document.state.url` Object
1226
1266
 
1227
- 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](#the-observer-api).
1267
+ 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 of a standard [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) object, but, here, as *live* properties that can be observed as navigation happens, and modified to initiate navigation - all using the [Observer API](#the-observer-api).
1228
1268
 
1229
1269
  ```js
1230
1270
  console.log(document.state.url) // { hash, host, hostname, href, origin, password, pathname, port, protocol, search, searchParams, username }
@@ -1973,10 +2013,15 @@ A simple tool, like [`staticgen`](https://github.com/tj/staticgen), or the basic
1973
2013
 
1974
2014
  Webflo comes *convention-first*! But it is entirely configurable for when you need it! The easiest way to do this is to run the command `webflo config` and follow the walkthrough. To simply get an overview, use the command `webflo config help`, and all commands and their description are shown.
1975
2015
 
1976
- ## Technology Stack
2016
+ ## Webflo Tooling
1977
2017
 
1978
2018
  Webflo applications are often built on/with the following technologies.
1979
2019
 
2020
+ + [OOHTML](#oohtml)
2021
+ + [OOHTML SSR](#oohtml-ssr)
2022
+ + [OOHTML CLI](#oohtml-cli)
2023
+ + [The Observer API](#the-observer-api)
2024
+
1980
2025
  ### OOHTML
1981
2026
 
1982
2027
  [OOHTML](https://github.com/webqit/oohtml) is a proposed set of new features for HTML that makes it fun to hand-author your HTML documents! Within OOHTML are [HTML Modules](https://github.com/webqit/oohtml#html-modules) and [HTML Imports](https://github.com/webqit/oohtml#html-imports), [Reactive Scripts](https://github.com/webqit/oohtml#subscript) and more!
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.11.20",
15
+ "version": "0.11.23",
16
16
  "license": "MIT",
17
17
  "repository": {
18
18
  "type": "git",
@@ -52,7 +52,6 @@ export default class Runtime {
52
52
  * @return void
53
53
  */
54
54
  constructor(cx, clientCallback) {
55
-
56
55
  // ---------------
57
56
  this.cx = cx;
58
57
  this.clients = new Map;
@@ -97,12 +96,12 @@ export default class Runtime {
97
96
  // Capture all link-clicks
98
97
  // and fire to this router.
99
98
  window.addEventListener('click', e => {
100
- var anchor = e.target.closest('a');
101
- if (!anchor || !anchor.href) return;
102
- if (!anchor.target && !anchor.download && this.isSpaRoute(anchor, e)) {
99
+ var anchorEl = e.target.closest('a');
100
+ if (!anchorEl || !anchorEl.href) return;
101
+ if (!anchorEl.target && !anchorEl.download && this.isSpaRoute(anchorEl, e)) {
103
102
  // Publish everything, including hash
104
- this.go(Url.copy(anchor), {}, { src: anchor, srcType: 'link', });
105
- if (!(_before(window.document.location.href, '#') === _before(anchor.href, '#') && anchor.href.includes('#'))) {
103
+ this.go(Url.copy(anchorEl), {}, { src: anchorEl, srcType: 'link', });
104
+ if (!this.isHashAction(anchorEl)) {
106
105
  e.preventDefault();
107
106
  }
108
107
  }
@@ -143,7 +142,7 @@ export default class Runtime {
143
142
  method: submitParams.method,
144
143
  body: formData,
145
144
  }, { ...submitParams, src: form, srcType: 'form', });
146
- if (!(_before(window.document.location.href, '#') === _before(actionEl.href, '#') && actionEl.href.includes('#'))) {
145
+ if (!this.isHashAction(actionEl)) {
147
146
  e.preventDefault();
148
147
  }
149
148
  }
@@ -188,8 +187,14 @@ export default class Runtime {
188
187
  return window.history;
189
188
  }
190
189
 
191
- // Check is-route
192
- isSpaRoute(url, e) {
190
+ // Check is-hash-action
191
+ isHashAction(urlObj) {
192
+ const isHashNav = _before(window.document.location.href, '#') === _before(urlObj.href, '#') && urlObj.href.includes('#');
193
+ return isHashNav && urlObj.hash.length > 1 && document.querySelector(urlObj.hash);
194
+ }
195
+
196
+ // Check is-spa-route
197
+ isSpaRoute(url, e = undefined) {
193
198
  url = typeof url === 'string' ? new whatwag.URL(url) : url;
194
199
  if (url.origin && url.origin !== this.location.origin) return false;
195
200
  if (e && (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)) return false;
@@ -278,13 +283,14 @@ export default class Runtime {
278
283
  // ------------
279
284
  if (response.redirected) {
280
285
  Observer.set(this.location, { href: response.url }, { detail: { redirected: true }, });
286
+ Observer.set(this.network, 'requesting', null);
281
287
  } else if (![302, 301].includes(finalResponse.status)) {
282
- Observer.set(this.location, url);
288
+ Observer.set(this.location, Url.copy(url)/* copy() is important */);
289
+ Observer.set(this.network, 'requesting', null);
283
290
  }
284
291
  // ------------
285
292
  // States
286
293
  // ------------
287
- Observer.set(this.network, 'requesting', null);
288
294
  if (['link', 'form'].includes(detail.srcType)) {
289
295
  detail.src.state && (detail.src.state.active = false);
290
296
  detail.submitter && detail.submitter.state && (detail.submitter.state.active = false);
@@ -330,10 +336,20 @@ export default class Runtime {
330
336
  if (!(response instanceof Response)) { response = new Response(response); }
331
337
  if (!response.redirected) {
332
338
  let location = response.headers.get('Location');
333
- if (location && response.status === this._xRedirectCode) {
334
- response.attrs.status = parseInt(response.headers.get('X-Redirect-Code'));
335
- Observer.set(this.network, 'redirecting', location);
336
- window.location = location;
339
+ if (location) {
340
+ let xActualRedirectCode = parseInt(response.headers.get('X-Redirect-Code'));
341
+ if (xActualRedirectCode && response.status === this._xRedirectCode) {
342
+ response.attrs.status = xActualRedirectCode;
343
+ Observer.set(this.network, 'redirecting', location);
344
+ window.location = location;
345
+ } else if ([302,301].includes(response.status)) {
346
+ if (!this.isSpaRoute(location)) {
347
+ Observer.set(this.network, 'redirecting', location);
348
+ window.location = location;
349
+ } else {
350
+ this.go(location, {}, { srcType: 'rdr' });
351
+ }
352
+ }
337
353
  }
338
354
  }
339
355
  return response;
@@ -1,10 +1,11 @@
1
+
1
2
  /**
2
3
  * @imports
3
4
  */
4
5
  import { config, runtime, Context } from '../src/index.js';
5
6
 
6
7
  let client = {
7
- handle: function(httpEvent) {
8
+ handle: function( httpEvent ) {
8
9
  return new httpEvent.Response({ abcd: '1234' }, {
9
10
  status: 302,
10
11
  headers: {
@@ -18,8 +19,8 @@ let client = {
18
19
  },
19
20
  };
20
21
 
21
- const cx = Context.create({ config: config, });
22
- const clientCallback = (_cx, hostName, defaultClientCallback) => client;
23
- const app = await runtime.server.start.call(cx, clientCallback);
22
+ const cx = Context.create( { config: config, } );
23
+ const clientCallback = ( _cx, hostName, defaultClientCallback ) => client;
24
+ const app = await runtime.server.start.call( cx, clientCallback );
24
25
 
25
- const response = await app.go('http://localhost/', { headers: { range: 'bytes=0-5, 6' } } );
26
+ const response = await app.go( 'http://localhost/', { headers: { range: 'bytes=0-5, 6' } } );