@webqit/oohtml 2.1.55-0 → 2.1.56
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 +257 -227
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[![bundle][bundle-src]][bundle-href]
|
|
6
6
|
[![License][license-src]][license-href]
|
|
7
7
|
|
|
8
|
-
**[Overview](#
|
|
8
|
+
**[Overview](#overview) • [Modular HTML](#modular-html) • [HTML Imports](#html-imports) • [Reactive HTML](#reactive-html) • [Polyfill](#polyfill) • [Examples](#examples) • [License](#license)**
|
|
9
9
|
|
|
10
10
|
Object-Oriented HTML (OOHTML) is a set of language features for authoring modular, reusable markup, and for translating that to functional DOM-level objects! Everything comes together as a delightful holistic component architecture for the modern UI!
|
|
11
11
|
|
|
@@ -25,7 +25,7 @@ This project is a proposal for a new standards work that revisits much of the ol
|
|
|
25
25
|
|
|
26
26
|
</details>
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Overview
|
|
29
29
|
|
|
30
30
|
OOHTML comes in three sets of features, and the following is an overview. A more detailed documentation for OOHTML is underway in the [project wiki](https://github.com/webqit/oohtml/wiki).
|
|
31
31
|
|
|
@@ -36,7 +36,7 @@ OOHTML comes in three sets of features, and the following is an overview. A more
|
|
|
36
36
|
|
|
37
37
|
> **Note** This is documentation for `OOHTML@2.x`. (Looking for [`OOHTML@1.x`](https://github.com/webqit/oohtml/tree/v1.10.4)?)
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
## Modular HTML
|
|
40
40
|
|
|
41
41
|
The first set of features covers authoring objects with self-contained structure, styling and *scripting*! This simply gets identifiers, style sheets and scripts to serve *at the object level* exactly as they do *at the document (object) level*.
|
|
42
42
|
|
|
@@ -86,7 +86,7 @@ let { styleSheets, scripts } = user; // APIs that are analogous to the document.
|
|
|
86
86
|
|
|
87
87
|
└ [Modular HTML concepts](#)
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
## HTML Imports
|
|
90
90
|
|
|
91
91
|
The next set of features covers *templating and reusing objects* - in both *declarative* and *programmatic* terms! It extends the language with the *module identifier* attribute `def`, and introduces a complementary new `<import>` element, and has everything working together as a real-time module system.
|
|
92
92
|
|
|
@@ -365,7 +365,7 @@ document.querySelector('div').import('#fragment2', divElement => {
|
|
|
365
365
|
|
|
366
366
|
└ [HTML Imports concepts](#)
|
|
367
367
|
|
|
368
|
-
|
|
368
|
+
## Reactive HTML
|
|
369
369
|
|
|
370
370
|
The last set of features covers the concept of "state", "bindings", and "reactivity" for those objects at the DOM level - in the most exciting form of the terms and as an upgrade path! This comes factored into the design as something intrinsic to the problem.
|
|
371
371
|
|
|
@@ -478,67 +478,219 @@ Observer.set(element, 'liveProperty'); // Live expressions rerun
|
|
|
478
478
|
|
|
479
479
|
└ [Reactive HTML concepts](#)
|
|
480
480
|
|
|
481
|
-
|
|
481
|
+
## Polyfill
|
|
482
482
|
|
|
483
|
-
|
|
483
|
+
OOHTML is being developed as something to be used today - via a polyfill.
|
|
484
484
|
|
|
485
|
-
|
|
485
|
+
<details><summary>Load from a CDN<br>
|
|
486
|
+
└───────── <a href="https://bundlephobia.com/result?p=@webqit/oohtml"><img align="right" src="https://img.shields.io/bundlephobia/minzip/@webqit/oohtml?label=&style=flat&colorB=black"></a></summary>
|
|
486
487
|
|
|
487
|
-
|
|
488
|
+
```html
|
|
489
|
+
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
└ This is to be placed early on in the document and should be a classic script without any `defer` or `async` directives!
|
|
493
|
+
|
|
494
|
+
└ For the Scoped Styles feature, you'd also need something like the [samthor/scoped](https://github.com/samthor/scoped) polyfill (more details below):
|
|
488
495
|
|
|
489
496
|
```html
|
|
490
|
-
<
|
|
497
|
+
<head>
|
|
498
|
+
<script src="https://unpkg.com/style-scoped/scoped.min.js"></script>
|
|
499
|
+
</head>
|
|
500
|
+
```
|
|
491
501
|
|
|
492
|
-
|
|
493
|
-
<header def="header"></header>
|
|
494
|
-
<footer def="footer"></footer>
|
|
495
|
-
</template>
|
|
502
|
+
</details>
|
|
496
503
|
|
|
497
|
-
|
|
498
|
-
<template def="home" extends="layout">
|
|
499
|
-
<main def="main" namespace>
|
|
500
|
-
<h1 id="banner">Home Page</h1>
|
|
501
|
-
<a id="cta" href="#/products">Go to Products</a>
|
|
502
|
-
<template scoped></template>
|
|
503
|
-
<style scoped></style>
|
|
504
|
-
<script scoped></script>
|
|
505
|
-
</main>
|
|
506
|
-
</template>
|
|
504
|
+
<details><summary>Extended usage concepts</summary>
|
|
507
505
|
|
|
508
|
-
|
|
509
|
-
<template def="products" extends="layout">
|
|
510
|
-
<main def="main" namespace>
|
|
511
|
-
<h1 id="banner">Products Page</h1>
|
|
512
|
-
<a id="cta" href="#/home">Go to Home</a>
|
|
513
|
-
<template scoped></template>
|
|
514
|
-
<style scoped></style>
|
|
515
|
-
<script scoped></script>
|
|
516
|
-
</main>
|
|
517
|
-
</template>
|
|
506
|
+
To use the polyfill on server-side DOM instances as made possible by libraries like [jsdom](https://github.com/jsdom/jsdom), simply install and initialize the library `@webqit/oohtml` with the DOM instance:
|
|
518
507
|
|
|
519
|
-
|
|
508
|
+
```bash
|
|
509
|
+
npm i @webqit/oohtml
|
|
520
510
|
```
|
|
521
511
|
|
|
522
|
-
|
|
512
|
+
```js
|
|
513
|
+
// Import
|
|
514
|
+
import init from '@webqit/oohtml';
|
|
523
515
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
<import ref="#header"></import>
|
|
528
|
-
<import ref="#main"></import>
|
|
529
|
-
<import ref="#footer"></import>
|
|
530
|
-
|
|
531
|
-
<script>
|
|
532
|
-
const route = () => { document.body.setAttribute('importscontext', '/pages' + location.hash.substring(1)); };
|
|
533
|
-
window.addEventListener('hashchange', route);
|
|
534
|
-
</script>
|
|
535
|
-
|
|
536
|
-
</body>
|
|
516
|
+
// Initialize the lib
|
|
517
|
+
init.call( window[, options = {} ]);
|
|
537
518
|
```
|
|
538
519
|
|
|
539
|
-
|
|
520
|
+
But all things "SSR" for OOHTML are best left to the [`@webqit/oohtml-ssr`](https://github.com/webqit/oohtml-ssr) package!
|
|
521
|
+
|
|
522
|
+
Also, if you'll be going ahead to build a real app to see OOHTML in action, you may want to consider also using:
|
|
523
|
+
|
|
524
|
+
+ the [`@webqit/oohtml-cli`](https://github.com/webqit/oohtml-cli) package for operating a file-based templating system.
|
|
525
|
+
|
|
526
|
+
+ the modest, OOHTML-based [Webflo](https://github.com/webqit/webflo) framework to greatly streamline your application development process!
|
|
527
|
+
|
|
528
|
+
</details>
|
|
529
|
+
|
|
530
|
+
<details><summary>Implementation Notes</summary>
|
|
531
|
+
|
|
532
|
+
+ **Loading Requirements**. As specified above, the OOHTML script tag is to be placed early on in the document and should be a classic script without any `defer` or `async` directives!
|
|
533
|
+
|
|
534
|
+
If you must load the script "async", one little trade-off has to be made for `<script scoped>` and `<script stateful>` elements to have them ignored by the browser until the polyfill comes picking them up: *employing a custom MIME type in place of the standard `text/javascript` and `module` types*, in which case, a `<meta name="scoped-js">` element is used to configure the polyfill to honor the custom MIME type:
|
|
535
|
+
|
|
536
|
+
```html
|
|
537
|
+
<head>
|
|
538
|
+
<meta name="scoped-js" content="script.mimeType=some-mime">
|
|
539
|
+
<script async src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
540
|
+
</head>
|
|
541
|
+
<body>
|
|
542
|
+
<script type="some-mime" scoped>
|
|
543
|
+
console.log(this); // body
|
|
544
|
+
</script>
|
|
545
|
+
</body>
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
The custom MIME type strategy also comes in as a "fix" for when in a browser or other runtime where the polyfill is not able to intercept `<script scoped>` and `<script stateful>` elements ahead of the runtime - e.g. where...
|
|
549
|
+
|
|
550
|
+
```html
|
|
551
|
+
<body>
|
|
552
|
+
<script scoped>
|
|
553
|
+
console.log(this); // body
|
|
554
|
+
</script>
|
|
555
|
+
</body>
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
...still gives the `window` object in the console.
|
|
559
|
+
|
|
560
|
+
+ **Scoped/Stateful Scripts**. This feature is an extension of [Stateful JS](https://github.com/webqit/stateful-js). The default OOHTML build is based on the [Stateful JS Lite APIs](https://github.com/webqit/stateful-js#stateful-js-lite) and this means that `<script stateful></script>` and `<script scoped></script>` elements are parsed "asynchronously", in the same timing as `<script type="module"></script>`!
|
|
561
|
+
|
|
562
|
+
This timing works perfectly generally, but if you have a requirment to have classic scripts follow their [native synchronous timing](https://html.spec.whatwg.org/multipage/parsing.html#scripts-that-modify-the-page-as-it-is-being-parsed), then you need to the *realtime* OOHTML build:
|
|
563
|
+
|
|
564
|
+
```html
|
|
565
|
+
<head>
|
|
566
|
+
<script src="https://unpkg.com/@webqit/oohtml/dist/main.realtime.js"></script>
|
|
567
|
+
</head>
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
+ **Scoped CSS**. This feature is only in "concept" implementation and doesn't work right now as is. The current implementation simply wraps `<style scoped>` blocks in an `@scope {}` block - which itself isn't supported in any browser. To try this "concept" implementation, set the `style.strategy` config to `@scope`:
|
|
571
|
+
|
|
572
|
+
```html
|
|
573
|
+
<head>
|
|
574
|
+
<meta name="scoped-css" content="style.strategy=@scope"> <!-- Must come before the polyfil -->
|
|
575
|
+
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
576
|
+
<head>
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
Now the following `<style scoped>`...
|
|
580
|
+
|
|
581
|
+
```html
|
|
582
|
+
<style scoped>
|
|
583
|
+
h2 { color: red; }
|
|
584
|
+
</style>
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
...will be wrapped to something like:
|
|
588
|
+
|
|
589
|
+
```html
|
|
590
|
+
<style ref="scoped8eff" scoped>
|
|
591
|
+
@scope from (:has(> style[ref="scoped8eff"])) {
|
|
592
|
+
h2 { color: red; }
|
|
593
|
+
}
|
|
594
|
+
</style>
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
A working implementation may be coming soon, but in the meantime, you could try one of the polyfills for `<style scoped>` out there; e.g. [samthor/scoped](https://github.com/samthor/scoped):
|
|
598
|
+
|
|
599
|
+
```html
|
|
600
|
+
<script src="https://unpkg.com/style-scoped/scoped.min.js"></script>
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
+ **HTML Imports**. The attribute names for exposing reusable modules and for referencing them - the `def` and `ref` keywords, respectively - aren't finalized. While the principle of operation remains, these attributes may be renamed in subsequent iterations. But the polyfill is designed to always defer to any syntax that has been explicitly specified using a meta tag. Here's an example:
|
|
604
|
+
|
|
605
|
+
```html
|
|
606
|
+
<head>
|
|
607
|
+
<meta name="html-imports" content="template.attr.moduledef=def; template.attr.fragmentdef=def; import.attr.moduleref=ref;"> <!-- Must come before the polyfil -->
|
|
608
|
+
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
609
|
+
<head>
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
Now, even when the default attribute names change, your `def` and `ref` implementation will still work:
|
|
613
|
+
|
|
614
|
+
</details>
|
|
615
|
+
|
|
616
|
+
## Examples
|
|
540
617
|
|
|
541
|
-
|
|
618
|
+
Here are a few examples in the wide range of use cases these features cover.
|
|
619
|
+
|
|
620
|
+
+ [Example 1: *Single Page Application*](#example-1-single-page-application)
|
|
621
|
+
+ [Example 2: *Multi-Level Namespacing*](#example-2-multi-level-namespacing)
|
|
622
|
+
+ [Example 3: *Dynamic Shadow DOM*](#example-3-dynamic-shadow-dom)
|
|
623
|
+
+ [Example 4: *List Items*](#example-4-list-items)
|
|
624
|
+
|
|
625
|
+
### Example 1: *Single Page Application*
|
|
626
|
+
|
|
627
|
+
The following is how something you could call a Single Page Application ([SPA](https://en.wikipedia.org/wiki/Single-page_application)) could be made - with zero tooling:
|
|
628
|
+
|
|
629
|
+
+ *First, two components that are themselves analogous to a Single File Component ([SFC](https://vuejs.org/guide/scaling-up/sfc.html))*:
|
|
630
|
+
|
|
631
|
+
<details><summary>Code</summary>
|
|
632
|
+
|
|
633
|
+
```html
|
|
634
|
+
<template def="pages">
|
|
635
|
+
|
|
636
|
+
<template def="layout">
|
|
637
|
+
<header def="header"></header>
|
|
638
|
+
<footer def="footer"></footer>
|
|
639
|
+
</template>
|
|
640
|
+
|
|
641
|
+
<!-- Home Page -->
|
|
642
|
+
<template def="home" extends="layout">
|
|
643
|
+
<main def="main" namespace>
|
|
644
|
+
<h1 id="banner">Home Page</h1>
|
|
645
|
+
<a id="cta" href="#/products">Go to Products</a>
|
|
646
|
+
<template scoped></template>
|
|
647
|
+
<style scoped></style>
|
|
648
|
+
<script scoped></script>
|
|
649
|
+
</main>
|
|
650
|
+
</template>
|
|
651
|
+
|
|
652
|
+
<!-- Products Page -->
|
|
653
|
+
<template def="products" extends="layout">
|
|
654
|
+
<main def="main" namespace>
|
|
655
|
+
<h1 id="banner">Products Page</h1>
|
|
656
|
+
<a id="cta" href="#/home">Go to Home</a>
|
|
657
|
+
<template scoped></template>
|
|
658
|
+
<style scoped></style>
|
|
659
|
+
<script scoped></script>
|
|
660
|
+
</main>
|
|
661
|
+
</template>
|
|
662
|
+
|
|
663
|
+
</template>
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
</details>
|
|
667
|
+
|
|
668
|
+
+ *Then a 2-line router that alternates the view based on the URL hash*:
|
|
669
|
+
|
|
670
|
+
<details><summary>Code</summary>
|
|
671
|
+
|
|
672
|
+
```html
|
|
673
|
+
<body importscontext="/pages/home">
|
|
674
|
+
|
|
675
|
+
<import ref="#header"></import>
|
|
676
|
+
<import ref="#main"></import>
|
|
677
|
+
<import ref="#footer"></import>
|
|
678
|
+
|
|
679
|
+
<script>
|
|
680
|
+
const route = () => { document.body.setAttribute('importscontext', '/pages' + location.hash.substring(1)); };
|
|
681
|
+
window.addEventListener('hashchange', route);
|
|
682
|
+
</script>
|
|
683
|
+
|
|
684
|
+
</body>
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
</details>
|
|
688
|
+
|
|
689
|
+
### Example 2: *Multi-Level Namespacing*
|
|
690
|
+
|
|
691
|
+
The following is a Listbox component lifted directly from the [ARIA Authoring Practices Guide (APG)](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/examples/listbox-grouped/#sc_label) but with IDs effectively "contained" at different levels within the component using the `namespace` attribute.
|
|
692
|
+
|
|
693
|
+
<details><summary>Code</summary>
|
|
542
694
|
|
|
543
695
|
```html
|
|
544
696
|
<div namespace class="listbox-area">
|
|
@@ -603,58 +755,76 @@ All of OOHTML brings to the platform much of the modern UI development paradigms
|
|
|
603
755
|
</div>
|
|
604
756
|
```
|
|
605
757
|
|
|
606
|
-
|
|
758
|
+
</details>
|
|
607
759
|
|
|
608
|
-
|
|
760
|
+
### Example 3: *Dynamic Shadow DOM*
|
|
609
761
|
|
|
610
|
-
|
|
611
|
-
<template def="vendor1">
|
|
762
|
+
The following is a custom element that derives its Shadow DOM from an imported `<tenplate>` element. The idea is to have different Shadow DOM layouts defined and let the "usage" context decide which variant is imported!
|
|
612
763
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
764
|
+
+ *First, two layout options defined for the Shadow DOM*:
|
|
765
|
+
|
|
766
|
+
<details><summary>Code</summary>
|
|
767
|
+
|
|
768
|
+
```html
|
|
769
|
+
<template def="vendor1">
|
|
770
|
+
|
|
771
|
+
<template def="components-layout1">
|
|
772
|
+
<template def="magic-button">
|
|
773
|
+
<span id="icon"></span> <span id="text"></span>
|
|
774
|
+
</template>
|
|
775
|
+
</template>
|
|
776
|
+
|
|
777
|
+
<template def="components-layout2">
|
|
778
|
+
<template def="magic-button">
|
|
779
|
+
<span id="text"></span> <span id="icon"></span>
|
|
780
|
+
</template>
|
|
781
|
+
</template>
|
|
618
782
|
|
|
619
|
-
<template def="components-layout2">
|
|
620
|
-
<template def="magic-button">
|
|
621
|
-
<span id="text"></span> <span id="icon"></span>
|
|
622
783
|
</template>
|
|
623
|
-
|
|
784
|
+
```
|
|
624
785
|
|
|
625
|
-
</
|
|
626
|
-
```
|
|
786
|
+
</details>
|
|
627
787
|
|
|
628
|
-
|
|
788
|
+
+ *Next, the Shadow DOM creation that imports its layout from context*:
|
|
629
789
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
790
|
+
<details><summary>Code</summary>
|
|
791
|
+
|
|
792
|
+
```js
|
|
793
|
+
customElements.define('magic-button', class extends HTMLElement {
|
|
794
|
+
connectedCallback() {
|
|
795
|
+
const shadowRoot = this.attachShadow({ mode: 'open' });
|
|
796
|
+
this.import('@vendor1/magic-button', template => {
|
|
797
|
+
shadowRoot.appendChild( template.content.cloneNode(true) );
|
|
798
|
+
});
|
|
799
|
+
}
|
|
636
800
|
});
|
|
637
|
-
|
|
638
|
-
});
|
|
639
|
-
```
|
|
801
|
+
```
|
|
640
802
|
|
|
641
|
-
|
|
803
|
+
</details>
|
|
642
804
|
|
|
643
|
-
|
|
644
|
-
<div contextname="vendor1" importscontext="/vendor1/components-layout1">
|
|
805
|
+
+ *Then, the part where we just drop the component in "layout" contexts*:
|
|
645
806
|
|
|
646
|
-
|
|
807
|
+
<details><summary>Code</summary>
|
|
647
808
|
|
|
648
|
-
|
|
649
|
-
<
|
|
650
|
-
</aside>
|
|
809
|
+
```html
|
|
810
|
+
<div contextname="vendor1" importscontext="/vendor1/components-layout1">
|
|
651
811
|
|
|
652
|
-
|
|
653
|
-
|
|
812
|
+
<magic-button></magic-button>
|
|
813
|
+
|
|
814
|
+
<aside contextname="vendor1" importscontext="/vendor1/components-layout2">
|
|
815
|
+
<magic-button></magic-button>
|
|
816
|
+
</aside>
|
|
817
|
+
|
|
818
|
+
</div>
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
</details>
|
|
654
822
|
|
|
655
|
-
|
|
823
|
+
### Example 4: *List Items*
|
|
656
824
|
|
|
657
|
-
|
|
825
|
+
The following is a "component" that derives its list items and other reusable snippets from "scoped" `<tenplate>` elements. The idea is to have a "self-contained" component that's all markup-based, not class-based!
|
|
826
|
+
|
|
827
|
+
<details><summary>Code</summary>
|
|
658
828
|
|
|
659
829
|
```html
|
|
660
830
|
<div namespace>
|
|
@@ -683,148 +853,8 @@ customElements.define('magic-button', class extends HTMLElement {
|
|
|
683
853
|
</div>
|
|
684
854
|
```
|
|
685
855
|
|
|
686
|
-
## The Polyfill
|
|
687
|
-
|
|
688
|
-
OOHTML is being developed as something to be used today - via a polyfill. This has been helping to facilitate the "release - iterations" loop and its overall evolution.
|
|
689
|
-
|
|
690
|
-
The polyfill can be loaded from the `unpkg.com` CDN, and should be placed early on in the document - before any OOHTML-specific features are used - and should be a classic script without any `defer` or `async` directives:
|
|
691
|
-
|
|
692
|
-
```html
|
|
693
|
-
<head>
|
|
694
|
-
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
695
|
-
</head>
|
|
696
|
-
```
|
|
697
|
-
|
|
698
|
-
> 22.5 kB min + gz | 77.5 KB min [↗](https://bundlephobia.com/package/@webqit/oohtml@2.1.45)
|
|
699
|
-
|
|
700
|
-
<details><summary>
|
|
701
|
-
Extended usage concepts
|
|
702
|
-
</summary>
|
|
703
|
-
|
|
704
|
-
If you must load the script "async", one little trade-off has to be made for `<script scoped>` and `<script stateful>` elements to have them ignored by the browser until the polyfill comes picking them up: *employing a custom MIME type in place of the standard `text/javascript` and `module` types*, in which case, a `<meta name="scoped-js">` element is used to configure the polyfill to honor the custom MIME type:
|
|
705
|
-
|
|
706
|
-
```html
|
|
707
|
-
<head>
|
|
708
|
-
<meta name="scoped-js" content="script.mimeType=some-mime">
|
|
709
|
-
<script async src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
710
|
-
</head>
|
|
711
|
-
<body>
|
|
712
|
-
<script type="some-mime" scoped>
|
|
713
|
-
console.log(this); // body
|
|
714
|
-
</script>
|
|
715
|
-
</body>
|
|
716
|
-
```
|
|
717
|
-
|
|
718
|
-
The custom MIME type strategy also comes in as a "fix" for when in a browser or other runtime where the polyfill is not able to intercept `<script scoped>` and `<script stateful>` elements ahead of the runtime - e.g. where...
|
|
719
|
-
|
|
720
|
-
```html
|
|
721
|
-
<body>
|
|
722
|
-
<script scoped>
|
|
723
|
-
console.log(this); // body
|
|
724
|
-
</script>
|
|
725
|
-
</body>
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
...still gives the `window` object in the console.
|
|
729
|
-
|
|
730
|
-
To use the polyfill on server-side DOM instances as made possible by libraries like [jsdom](https://github.com/jsdom/jsdom), simply install and initialize the library `@webqit/oohtml` with the DOM instance:
|
|
731
|
-
|
|
732
|
-
```bash
|
|
733
|
-
npm i @webqit/oohtml
|
|
734
|
-
```
|
|
735
|
-
|
|
736
|
-
```js
|
|
737
|
-
// Import
|
|
738
|
-
import init from '@webqit/oohtml';
|
|
739
|
-
|
|
740
|
-
// Initialize the lib
|
|
741
|
-
init.call( window[, options = {} ]);
|
|
742
|
-
```
|
|
743
|
-
|
|
744
|
-
But all things "SSR" for OOHTML are best left to the [`@webqit/oohtml-ssr`](https://github.com/webqit/oohtml-ssr) package!
|
|
745
|
-
|
|
746
|
-
Also, if you'll be going ahead to build a real world app to see OOHTML in action, you may want to consider also using:
|
|
747
|
-
|
|
748
|
-
+ the [`@webqit/oohtml-cli`](https://github.com/webqit/oohtml-cli) package for operating a file-based templating system.
|
|
749
|
-
|
|
750
|
-
+ the modest, OOHTML-based [Webflo](https://github.com/webqit/webflo) framework to greatly streamline your application development process!
|
|
751
|
-
|
|
752
856
|
</details>
|
|
753
857
|
|
|
754
|
-
<details><summary>
|
|
755
|
-
Implementation Notes
|
|
756
|
-
</summary>
|
|
757
|
-
|
|
758
|
-
Here are some performance-specific notes for this polyfill:
|
|
759
|
-
|
|
760
|
-
+ By default, the Stateful JS compiler (44.31 KB min+compressed | 157KB min) is excluded from the polyfill build and fetched separately on demand - on the first encounter with a Stateful Script. This is loaded into a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) and all compilations are able to happen off the main thread! This ensures near-zero cost to your application loading and runtime performance!
|
|
761
|
-
|
|
762
|
-
Note that this lazy-loading approach means that all Stateful Scripts will behave "async" just like module scripts; i.e. scripts are defered until the compiler has been loaded. In other words, the following two scripts will have the same timing semantics:
|
|
763
|
-
|
|
764
|
-
```html
|
|
765
|
-
<script stateful></script>
|
|
766
|
-
<script type="module" stateful></script>
|
|
767
|
-
```
|
|
768
|
-
|
|
769
|
-
This isn't necessarily bad unless there is a requirment to have classic scripts follow their [native synchronous timing](https://html.spec.whatwg.org/multipage/parsing.html#scripts-that-modify-the-page-as-it-is-being-parsed), in which case the Stateful JS compiler will need to be explicitly and synchronously loaded ahead of any encounter with classic Stateful Scripts:
|
|
770
|
-
|
|
771
|
-
```html
|
|
772
|
-
<head>
|
|
773
|
-
<script src="https://unpkg.com/@webqit/stateful-js/dist/compiler.js"></script> <!-- Must come before the polyfil -->
|
|
774
|
-
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
775
|
-
</head>
|
|
776
|
-
```
|
|
777
|
-
|
|
778
|
-
+ Whether loaded lazily or eagerly, the compiler also factors in additional optimizations. For example, identical scripts are handled only first time, and only ever have one Stateful JS instance!
|
|
779
|
-
|
|
780
|
-
Here are other notes:
|
|
781
|
-
|
|
782
|
-
+ **Scoped CSS**. This feature is only in "concept" implementation and doesn't work right now as is. The current implementation simply wraps `<style scoped>` blocks in an `@scope {}` block - which itself isn't supported in any browser. To try this "concept" implementation, set the `style.strategy` config to `@scope`:
|
|
783
|
-
|
|
784
|
-
```html
|
|
785
|
-
<head>
|
|
786
|
-
<meta name="scoped-css" content="style.strategy=@scope"> <!-- Must come before the polyfil -->
|
|
787
|
-
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
788
|
-
<head>
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
Now the following `<style scoped>`...
|
|
792
|
-
|
|
793
|
-
```html
|
|
794
|
-
<style scoped>
|
|
795
|
-
h2 { color: red; }
|
|
796
|
-
</style>
|
|
797
|
-
```
|
|
798
|
-
|
|
799
|
-
...will be wrapped to something like:
|
|
800
|
-
|
|
801
|
-
```html
|
|
802
|
-
<style ref="scoped8eff" scoped>
|
|
803
|
-
@scope from (:has(> style[ref="scoped8eff"])) {
|
|
804
|
-
h2 { color: red; }
|
|
805
|
-
}
|
|
806
|
-
</style>
|
|
807
|
-
```
|
|
808
|
-
|
|
809
|
-
A working implementation may be coming soon, but in the meantime, you could try one of the polyfills for `<style scoped>` out there; e.g. [samthor/scoped](https://github.com/samthor/scoped).
|
|
810
|
-
|
|
811
|
-
+ **HTML Imports**. The attribute names for exposing reusable modules and for referencing them - the `def` and `ref` keywords, respectively - aren't finalized. While the principle of operation remains, these attributes may be renamed in subsequent iterations. But the polyfill is designed to always defer to any syntax that has been explicitly specified using a meta tag. Here's an example:
|
|
812
|
-
|
|
813
|
-
```html
|
|
814
|
-
<head>
|
|
815
|
-
<meta name="html-imports" content="template.attr.moduledef=def; template.attr.fragmentdef=def; import.attr.moduleref=ref;"> <!-- Must come before the polyfil -->
|
|
816
|
-
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
817
|
-
<head>
|
|
818
|
-
```
|
|
819
|
-
|
|
820
|
-
Now, even when the default attribute names change, your `def` and `ref` implementation will still work:
|
|
821
|
-
|
|
822
|
-
</details>
|
|
823
|
-
|
|
824
|
-
## Design Discussion
|
|
825
|
-
|
|
826
|
-
*[TODO]*
|
|
827
|
-
|
|
828
858
|
## Getting Involved
|
|
829
859
|
|
|
830
860
|
All forms of contributions are welcome at this time. For example, syntax and other implementation details are all up for discussion. Also, help is needed with more formal documentation. And here are specific links:
|