Components
We have three types of components:
- Dynamic server-side or page components
- Client-side components with some functionality
- Static components with some functionality or markup
Server-side components will have a <script> tag without context,
or <script context="module"> for module-level functionality.
Client-side components will have a <script context="client">
Static components may not contain script tags, but can access their props through the
$$propsvariable.We explore other kind of scripts later, for now we'll focus on static or dynamic components with or without context.
File-naming
Any .{md,html} file within the ./pages directory is a component,
if the filename ends on +page, +error or +layout then it will
be used to declare and decorate your application routes.
You can also place +server.mjs files aside your components,
they'll also decorate your routes with additional middleware definitions,
handlers and actions.
This results in a tree of all your declared routes with their nearest layout, error and middleware modules found.
We save this information with your compiled files for later usage in a
index.jsonfile, i.e.jamrock routeuse this file.
Composition
To use other components to compose the UI you need to import them.
<script>
import Hello from './components/hello.html';
</script>
<Hello>World</Hello>You can't import components in your own modules as they are resolved at compile time.
Also, importing page-components from other pages is disallowed.
Content
Use the children prop to render any given content.
<script>
export let children;
</script>
<div>Hello {@render children?.()}</div>The result from above would be <div>Hello World</div>.
Props
Top-level export declarations are the props, e.g.
<script>
export let test;
export let value;
</script>
Got: {test} ({typeof value} {value})Using
lethelps to omit initial values, whileconstwill enforce you otherwise, however the former is preferred.
Now your component can be used this way:
<Example test="OSOM" value={42} />It would yield: Got: OSOM (number 42)
Passing props between server-side components is granted for any type (almost!), but when you pass props to client-side components they should be serializable values.
In the case of static components without a <script> tag you should use $$props.thing syntax to access any given prop.
Templating
We've been using stuff like {...}, {@render ...} and {#snippet ...},
they are template-tags or expressions.
They just render any given values on specific ways, enabling you to compose using logical expressions, loops and so on.
Let's explore all the available tags:
{...}
They can render simple values or basic JavaScript expressions.
Try to keep things simple, we don't support fully featured JavaScript expressions to abuse from!
{#snippet ...}...{/snippet}
Declare reusable chunks of markup in your components.
They can appear at component root to behave as fallbacks if they're not given as props, i.e.
<script>
export let sample;
</script>
{#snippet sample(value)}
Got: {value}
{/snippet}
<div>{@render sample(42)}</div>In this example, the component will receive a sample prop
that will fallback to the inlined version if omitted.
<Example>
{#snippet sample(value)}
OSOM: {value}
{/snippet}
</Example>This would yield: <div>OSOM: 42</div>
Snippets are values, so they can be passed down as arguments that you can pass again or render, etc.
{@render ...}
Will take any expression to produce markup.
It's encouraged to call these expressions with
?.()to avoid unexpected exceptions if you don't provide them.
{#if ...}...{/if}
It'll render the underlying block if the expressions is truthy, i.e.
{#if true}
42
{/if}As any other expression given, keep it simple for now!
{:else ...}
You can use {:else} or {:else if ...} blocks
to render as fallbacks from their previous condition.
These tags are not limited to if's, they can be used to declare fallbacks from
{#each ...}blocks, see below.
{#each ...}...{/each}
Allows to iterate values within the template, it can take arrays, generators, promises, etc.
Almost anything that can produce an iterator, e.g.
<script>
const empty = Promise.resolve([]);
const numbers = [1, 2, 3];
function *values() {
yield 1;
yield 2;
yield 3;
}
</script>
{#each empty as _}
Not empty
{:else}
Empty
{/each}
{#each numbers as num}
{num}
{/each}
{#each values as val}
{val}
{/each}Iterators are constrained by time and length, so they'll be stopped once a given limit or maximum execution-time is reached!
{@raw ...}
These expressions will be inlined as is on the compiled code, be wise and careful as you're inlining code!
Usually this is required to inline markup on its AST form, e.g.
{@raw ['h1', {}, 'It works!']}{@html ...}
This will render any given string as HTML.
Its contents is not processed, so it'll be rendered as is.
{@debug ...}
It'll print out the JSON.stringify({ ... }) result from any given argument,
variables are just treated as object fields.
This will not support expressions, just variable names.
Markdown
Jamrock supports some markdown content through kramed on
*-page.html components and on any *.md component.
For pages it's allowed on the top-level of the file only.
Example of page component
<script>
export let children;
</script>
# Markdown works here
- This is the top-level of the file,
- you don't need to wrap your content
- in body or head tags on your components
<div>
## Markdown here does not work!
{@render children?.()}
</div><mkd>
You can use the <mkd> element to render Markdown within other html nodes,
it may work with some expressions!
You can import and include other components in your Markdown, that's expected and works out of the box.
Code blocks
Tagged blocks are ignored by the parser as they are handled by highlight.js, this produces highlighted code as the resulting markup.
```html
<h1>It works!</h1>
```Jamrock includes support for:
shell,less,css,html,xmlandjslanguages for now.
Untagged blocks are parsed by the framework instead, this way components can be rendered within.
You'll need to escape HTML tags and other entities to render them as text, i.e.
Examples of html-entities encoded
```
<h1>It works!</h1>
```
or
`{ ... }`
- You MUST encode the
{character as{outside tagged blocks, otherwise they'll be parsed. - Any other HTML tag or entity within inline
`...`backticks MUST be encoded as well. - Only
```blocks are handlded this way, code blocks made by white-space indentation are ignored.
This way the markup is rendered as is, so you can decorate the code by yourself with components or regular HTML tags.
Emoji support
Inside markdown we can use emojis, or shortcuts like :beer: ().
To render the shortcut as text just encode it as :beer:.
Emoji support is enabled through the
emojifyoption.Enable
twemojito inline the emojis as images, it'll work for both shortcuts and any other emojis found.
If you use emojis or shortcuts outside markdown they'll be kept as is,
use the <mkd>:beer:</mkd> tag to render or inline emojis.
For now, this is what you can do within components for authoring markup,
next we'll be learning about live updates on the DOM!