create-modulo
Version:
Starter projects for Modulo.html - Ready for all uses - Markdown-SSG / SSR / API-backed SPA
276 lines (201 loc) • 9.3 kB
HTML
<meta charset=utf8><script src=../static/Modulo.html></script><script type=md>---
title: Processors
description: Overview of definition processors.
---
# Processors
**Definition processors** are a feature of Modulo that allows for component
parts and other definitions to support special attributes that trigger certain
behavior. They are commonly used for configuring, loading, or tranforming
definitions.
Definition processors are conventionally prefixed with a dash (that is, `-`).
This distinguishes them from regular attributes. Some processors can only be
used with a certain type of component parts or definitions. For example,
examine the `-store=` processor for _State_:
```
<State
-store="userdata"
username="crash0veride"
></State>
```
Others are supported by all component parts. For example, examine the `-src=`
processor for loading content from external files.
```modulo
<Template -src="my-template.html"></Template>
<Style -src="fancy-look.css"></Style>
```
## Behavior
Definition processors have three important rules of behavior:
1. As the name implies, definition processors are run while Modulo first loads
definitions, meaning all the _Processors_ will all complete before your web
components register their tag names. Definition processors are applied _before_
any other behavior. That is to say, _every_ processor finishes its tasks before
_any_ components are mounted on the screen.
2. Processors can be asyncronous, load data, process data, and can even do
"slow" operations compared to other aspects of Modulo. CParts can load
asyncronously, or even block loading if they choose to do so. This is what
allows Modulo to self-configure and users to "invent" their own CParts:
`<Configuration -src="...">` will block loading any future `-src=` attributes
until it's finished with all it's Processors; however, `<Template -src="...">`
is written to assumed to not need any particular ordering, and will be loaded
asynchrously.
3. Definition processors are _not_ run in built or packed scripts. That is, the
definitions stored in the compiled JS file are "pre-processed", and thus the
processor only will run during development or when building. If accumulating
many files and definition processors is slowing down your growing site, the
good news is that after building, no one will notice, since _Processors_ are
(typically) only run during development.
# Built-in Processors
> **Why no dash for `<Component name="...">`?** Note that for _Component_, you
> use `name=` (without the `-`), and use a valid JavaScript identifier as the
> Web Component name. However, that behavior is specific to the _Component_
> definition, and is not available on Component Parts or other definitions.
> Definition types (e.g. [core definitions](/docs/core/) like _Library_ or a
> [component parts](/docs/cparts/) like _State_) can each specify their own,
> unique behavior for processors.
## -name
* Supported by: **All Definitions**
The `-name` directive allows you to override the default name that Modulo will
generate with something else. This allows you to have multiple Component Parts
of the same type without conflict.
For a simple example, see below:
```modulo
<Template -name="footer_template">
```
### Example: `-name` for multiple Component Parts
Note that _Template_ has special behavior around `-name`. If you specify a
name, it will _not_ by default still render, since it will assume you are going
to include it somewhere else.
```modulo_demo
<Template>
{# This becomes the "primary template" (named "template") #}
<h3>Welcome to my blog</h3>
<p>Things I like: {{ likes_data }}</p>
<p>Things I dislike: {{ dislikes_data }}</p>
{% include footer_template %}
</Template>
<Template -name="footer_template">
{# This becomes a non-primary template (named "footer_template") #}
<p>(C) 2095 Tux the Penguin</p>
</Template>
<StaticData -name="likes_data">
[ "Fish", "radishes", "hackable software" ]
</StaticData>
<StaticData -name="dislikes_data">
[ "Wet towels" ]
</StaticData>
```
## -src
* Supported by: **All Definitions**
```modulo
<Template
-src="./MyComponent/MyComponent.html"
></Template>
<Script -src="./MyComponent/MyComponent.js">
function anotherFunction() {
// Etc...
}
<-Script>
<Style
-src="./MyComponent/MyComponent.css"
></Style>
```
### -src for JavaScript extension
Note that the -src= combines the retrieved content with whatever is embedded
between the opening and closing tag. It _does not_ replace the embedded
content, but instead places the retrieved content before content _BEFORE_ the
embedded content. This ordering is important, since it allows the internal
content to "extend" the content that is being brought in.
In this case, due to the order of function declaration behavior, the
`anotherFunction` declaration will take precendence (since it's declared last)
over whatever `anotherFunction` might have been declared in `MyComponent.js`.
### -src for _Component_ extension
The `-src` attribute is designed to allow for many types of "inheritence" or a
sort of primitive extension, depending on the CPart. For example, _Components_
can "inherit" CParts of base components (e.g., the _Template_ and _Script_
could be the same across two _Components_, but they only differ in _Style_), or
_Style_ can "inherit" another style file, but get to append some modifications
to the end. (e.g., loading from a third party, then override certain
properties). Similarly, _Library_ or _Modulo_ can load entire Modulo libraries,
and then apply _Configuration_ scripts at the end to modify configuration
settings within that other libraries' execution context.
## -filter-content
* Supported by: **Template**, **StaticData**, **Style**
Allows you to apply [template filters](/templating/filters.html) at load time.
##### Example 1: Trim excess code
You can use `trim` to remove excess characters from a remotely loaded file. For
example, here we load content from an external document file, and then use
`|trim` to clean up the doctype information, text we don't want in the _Template_:
```modulo
<Template
-src="https://some-site.com/some-old-document.xhtml"
-filter-content="trim:'<xml version=1.0><html>,</html>'"
></Template>
```
In this case, the `trim` filter will remove the XML doctype and an HTML opening
tag, along withe the HTML closing tag, if they are found at the beginning and
end of the document retrieved from:
`https://some-site.com/some-old-document.xhtml`. Processors all happen during
initial loading of components and definitions, meaning the trimmed text will be
ignored and omitted from the JS builds.
##### Example 2: Style template with trim
By defining a `style Template`, we can template style for inclusion. By using
`trim` we can use a placeholder of `x { .. }` to make editing this CSS easier
to read. Note that this is, in fact, a _Template_ CPart, however, we will use a
`style` initial tag to make it easier to read and syntax highlight.
See below for a concrete example of how to use this technique for making a
quick button designer component:
```modulo_demo
edit: demo=modulo
<Template>
<label><input state.bind name="bg" type="color" /> Color</label>
<label><input state.bind name="size" type="range" min="5" max="20" /> Size</label>
<button style="{% include button_style %}">Sample Button</button>
<pre>button { {% include button_style %} }</pre>
</Template>
<style Template -filter-content="trim:'x {,}'" -name="button_style">
x {
background-color: {{ state.bg }};
font-size: {{ state.size }}px;
}
</style>
<State
bg="#a0caa0"
size:=10
></State>
```
##### Example 3: Tagswap for `<table>`
Modulo uses HTML syntax for most everything. This, unfortunately, means that
`<table>` tags can behave differently when it comes to how content is processed
and loaded, causing content to "escape" when you are still just assembling the
initial Template's DOM. Similarly, the closing `script` tag can have special
meanings as well. To get around limitations like this, we can use the
`|tagswap` to convert innocuous placeholder tags into other ones:
```modulo_demo
edit: demo=modulo
<Template -filter-content="tagswap:'t=table r=tr d=td'">
<t>
<r> <d>Col 1</d> <d>Col 2</d> <d>Col 3</d> </r>
<r> <d>A</d> <d>B</d> <d>C</d> </r>
<r> <d>1</d> <d>2</d> <d>3</d> </r>
<r> <d>X</d> <d>Y</d> <d>Z</d> </r>
</t>
</Template>
<Style>
table {
border: 2px solid Tomato;
}
td {
border: 1px dotted Tomato;
padding: 2px;
}
</Style>
```
> **Gotcha: Applied at loading time** Remember that it is applied "pre-baked"
> to the content itself during initial content load, and NOT at _Template_ run
> time, meaning it will affect (and potentially disrupt) the tempting language
> itself as well (e.g. using `-filter-content="upper"` will cause `{{
> state.stuff }}` to become `{{ STATE.STUFF }}`, which _will not_ work since
> capitalization matters in this case).
This will be applied at load time, so there are ultimately no performance
penalties, as the final JavaScript file will have the tag transpositions "baked
in" (and with no trace of the original template, either).