-
Notifications
You must be signed in to change notification settings - Fork 601
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split architecture doc into multiple explainers
- Loading branch information
Showing
6 changed files
with
168 additions
and
136 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
63 changes: 63 additions & 0 deletions
63
packages/web-components/fast-element/ARCHITECTURE_FASTELEMENT.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# FASTElement | ||
|
||
The `FASTElement` is our extension of the `HTMLElement`. As such it leverages the lifecycles but also requires additional setup before before the class `constructor` or the `connectedCallback` method is executed which are explained in the [overview](./ARCHITECTURE_OVERVIEW.md). This document explains specifically what `FASTElement` leverages inside the `HTMLElement`s lifecycle hooks. | ||
|
||
For an explanation into `HTMLElement` lifecycle hooks refer to the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks). | ||
|
||
## A Custom Element is Detected by the Browser | ||
|
||
Because the `FASTElement` is an extension of the `HTMLElement`, it makes use of the same lifecycle hooks and extends them with `$fastController`. It also initializes using another class `ElementController`, the methods this are called during the custom elements native `constructor`, `connectedCallback`, `disconnectedCallback`, and `attributeChangedCallback` lifecycle hooks. | ||
|
||
### 🔄 **Lifecycle**: Initialization | ||
|
||
```mermaid | ||
flowchart TD | ||
A[A <code>FASTElement</code> web component is added to the <code>DOM</code>] --> B | ||
B[<code>FASTElement</code> initializes the <code>ElementController.forCustomElement</code> passing the Custom Element instance] --> C | ||
B --> F[Observables applied to the <code>FASTElement</code> are updated on the FAST global without values] | ||
C{Is an <code>ElementController</code> available?} | ||
C --> |yes|E | ||
C --> |no|D | ||
D[Initialize a new <code>ElementController</code> referred to as setting an element controller strategy] | ||
D --> F | ||
E[<code>ElementController</code> captures the Custom Element instance and the definition and attaches them to the <code>$fastController</code> which is then attached to the instance] | ||
``` | ||
|
||
### 🔄 **Lifecycle**: Component is connected | ||
|
||
```mermaid | ||
flowchart TD | ||
A[browser <code>HTMLElement</code>'s <code>connectedCallback</code> is called] --> B | ||
B[<code>this.$fastController.connect</code> in FASTElement is called] --> C | ||
B --> D | ||
B --> E | ||
B --> F | ||
C[bind observables by capturing the Custom Elements properties and setting the values from the bound observables on the Custom Element] | ||
D[connect behaviors by call the <code>connectedCallback</code> on all behaviors] | ||
E[render template, execute an <code>ElementViewTemplate</code>'s render method] | ||
F[add styles either as an appended <code>StyleElement</code> node or an <code>adoptedStylesheet</code> which may include and attach behaviors] | ||
``` | ||
|
||
#### Render Template | ||
|
||
The rendering of the template on the `ElementController` is by the `renderTemplate` method which is called during the `ElementController.connect` method which is triggered by `HTMLElement`s `connectedCallback` lifecycle. | ||
|
||
The `renderTemplate` identifies the Custom Element, and the shadow root associated with the Custom Element. This then places a rendering of the template (an `ElementView`) onto the internal `view` of the controller. When creating the `ElementView`/`HTMLView` using the `ViewTemplate.render`, the `Compile.compile()` method identifies a `DocumentFragment` either by using an existing `<template>` tag, or creating one to wrap the contents of the shadow root. A new `CompilationContext` is created and the `compileAttributes` function is called, this results in the replacement of the placeholder attributes initally set-up during the pre-render step with their values if a value has been assigned. The factories with the associated nodes identified are then passed to the context. The view then binds all behaviors to the source element. The `CompilationContext.createView` is executed with the `DocumentFragment` as the root, and returns an `HTMLView`. This `HTMLView` includes an `appendTo` method to attach the fragment to the host element, which it then does. It should be noted that the compiled HTML is a `string`, which when set on the `DocumentFragment` as `innerHTML`, this allows the browser to dictate the creation of HTML nodes. | ||
|
||
### 🔄 **Lifecycle**: Component is disconnected | ||
|
||
When a component is disconnected, a cleanup step is created to remove associated behaviors. | ||
|
||
### 🔄 **Lifecycle**: Attribute has been changed | ||
|
||
Attributes have an `AttributeDefinition` which allows for converters, attachment of the `<attributName>Changed` aspect of the `@attr` decorator among other capabilities. | ||
|
||
```mermaid | ||
flowchart TD | ||
A[The browser <code>HTMLElement</code>'s <code>attributeChangedCallback</code> is called] --> B | ||
B[<code>this.$fastController.onAttributeChangedCallback</code> in <code>FASTElement</code> is called] --> C | ||
C[calls the attribute definitions <code>onAttributeChangedCallback</code> method with the updated value] --> D | ||
D[An <code>Updates.enqueue</code> is called which places the update in the task queue which is then executed, these are performed async unless otherwise specified] | ||
``` | ||
|
||
These changes are observed and similar to the way `Observables` work, they utilize an `Accessor` pattern which has a `getValue` and `setValue` in which DOM updates are applied. |
32 changes: 32 additions & 0 deletions
32
packages/web-components/fast-element/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# `html` tagged template literal | ||
|
||
## Pre-render Template | ||
|
||
The `html` tagged template function creates a `ViewTemplate` object via the `ViewTemplate.create()` method. This is then used during the `compose` step, before `FASTElement` is instantiated. | ||
|
||
During the `Compiler.compile()` method triggered by `ViewTemplate.create()` method, the following happens for each string: | ||
- Factories with unique IDs are created for each tag template literal argument (or `TemplateValue`) which matches with the corresponding string | ||
- A binding is created from the `TemplateValue` | ||
|
||
A resulting string using a `createHTML()` function is produced using the `HTMLDirective`s executed for each factory. The behavior is augmented by the previous string from the `html` tag template which determines the aspect if one exists, these aspects are the `@`, `:`, or other binding aspect attached to attributes. | ||
|
||
The `createHTML()` function utilizes a `Markup` attribute which is assigned to a factory's unique ID. The strings are concatenated and passed to a new `ViewTemplate` with all the factories (empty until one is assigned) that act as a dictionary with the unique IDs as the key to look up each factory once it has been created. The string this creates is injected into a `<template>` as `innerHTML`, which allows the browser to create the nodes and placeholder factory IDs, with the only `DOM` node that is explicitly created being the wrapping `<template>` element. | ||
|
||
## Directives | ||
|
||
The `HTMLBindingDirective` applies bindings to items identified as various `TemplateValue`s within the `html` tagged template. The `createHTML` step uses the factory associated with the binding to create strings in the markup using the factory's ID. | ||
|
||
```mermaid | ||
flowchart TD | ||
A[A <code>new HTMLBindingDirective</code> is created with a data binding which has a policy, options, <code>createObserver</code>, and an evaluate method assigned to the passed arrow function such as <pre>x => x.foo</pre>] | ||
B[<code>oneTime</code> binding passes the corresponding tag template argument, an arrow function] | ||
C[<code>oneWay</code> binding passes a copy of the corresponding tag template argument, an arrow function] | ||
D[An already specified binding such as a <code>repeat</code> or <code>when</code> directive is passed] | ||
A --> B | ||
A --> C | ||
A --> D | ||
E[When a <code>createObserver</code> is called, an <code>Observable.binding</code> is created passing the arrow function to be evaluated and the subscriber to be notified] | ||
C --> E | ||
F[When a <code>createObserver</code> is called, the instance of the one time binding is returned which includes a bind method returning the arrow function executed against the controller source and context] | ||
B --> F | ||
``` |
10 changes: 10 additions & 0 deletions
10
packages/web-components/fast-element/ARCHITECTURE_INTRO.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Introduction | ||
|
||
This document (and the linked documents) explains how the exports and side effects of `@microsoft/fast-element` are used to create custom elements. | ||
|
||
## Glossary | ||
|
||
- [Overview](./ARCHITECTURE_OVERVIEW.md): How the `@microsoft/fast-element` should be used by a developer and what code is executed during the first render. | ||
- [`FASTElement`](./ARCHITECTURE_FASTELEMENT.md): How the `FASTElement` is architected. | ||
- [`html` tagged template literal](./ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md): How the `html` tagged template literal takes and converts the contents into a `VIEWTemplate`. | ||
- [`Updates` queue](./ARCHITECTURE_UPDATES.md): How updates to attributes and observables are processed. |
Oops, something went wrong.