Mounting Components

The mount statement uses a very similar syntax to the standard Twig include statement.

Syntax overview

{% mount "./Foo" as "foo" with props %}

Let's take a look at the individual parts that make up the mount statement.

Here, "./Foo" represents a path to the component you want to mount. Any path is valid, provided that it can be resolved by Webpack or similar tools to a JavaScript module that exports a Melody component as its default export.

"foo" is the key of the component. Providing a key is usually optional but strongly recommended if your component is mounted close to a conditional expression or within a loop. Keys must be unique in the parent DOM node. Melody limits the format of the key to be a string but you can use embedded literals to include expressions in it. For example "foo_#{ index }" would also be a valid key.

Finally, props should be an object that is made available to the mounted component. If you're using the melody-hooks API, this object will be the argument to the state hook function.

Variable Components

In addition to accepting a plain path the mount statement also allows you to specify a component directly. Note, however, that due to limitations Melody can't resolve dynamic paths for immediately mounted components. If you are looking for a way to achieve that, please look at dynamic paths.

<div class="home">
    <h1 class="title">
        {{ message }}
    </h1>
    {% mount Counter with { count: 5 } %}
</div>

While useful, this feature should be used with care. Melody works best if you manage to split state and UI logic from each other.

Loading Components on Demand

When building complex applications, it is often helpful to be able to load parts of them asynchronously as they are needed. Melody supports this use case through async component mounts.

<div>
    {% mount async './counter'
            as "counter"
            with { count: 5 }
            delay placeholder by 100ms
    %}
        <div class="placeholder">
            We're loading the counter, please stay patient...
        </div>
    {% catch error %}
        An error occured while loading the Counter component.
        <pre style="error">{{ error }}</pre>
    {% endmount %}
</div>

The above example will asynchronously load the counter component as the template is rendered. It'll show nothing for 100 milliseconds (delay placeholder by 100ms) and then, if the Counter component has still not finished loading, it'll show the placeholder content ("We're loading the counter..."). In case the Counter component finished loading before the 100 milliseconds are over, it will be displayed immediately and the placeholder will never show. The delay placeholder by $time part is optional and, when not specified, Melody will decide when to show the placeholder. At the moment that is configured to be immediately; however, we reserve the right to modify that behaviour and you should assume that it'll be shown whenever Melody thinks is best.

For readability reasons the delay is specified explicitly as either milliseconds or seconds. You must specify the unit. Values such as 100ms, 200ms, 1s, 2s are all valid.

If an error occurs while loading the component, the content after the {% catch error %} will be rendered. error is a variable name that becomes available within that block. You are free to choose whatever name you like best. The catch clause is optional and you don't have to specify it - even though we strongly recommend that you do.

Melody requires you to specify placeholder content that can be shown during the loading of the actual component.

Why should I delay the placeholder?

User experience research indicates that users will perceive a response time of up to 100 milliseconds to be instantaneous. So if your users have a lot of bandwidth and processing power or the chunk containing your async component is really small, then there's a good chance that you could offer your users a feeling of instantaneous performance by not showing a loading animation.

Source: https://www.nngroup.com/articles/response-times-3-important-limits/

Why is a delay of 100 milliseconds not hardcoded?

Because Melody doesn't know your user base nor the size of the chunk of the component you're loading. There's a chance that all of your chunks will be huge and that you really want to display the placeholder immediately because you know it'll take a while to load things. The perception of users might also change over time or even across markets or the type of application you're building. At the moment, we don't think a hardcoded value would be valuable.

What about prefetching?

You might wonder about options to improve the performance of components that are loaded on demand and Melody - with the help of Webpack - has you covered. Melody embeds the necessary comments so that Webpack will use the browsers native prefetching logic to preload asynchronous components when the browser has sufficient bandwidth and processing capabilities available.

Thanks to that, you won't have to think too much about performance implications of loading components asynchronously, but can instead focus on building amazing applications.

Dynamic paths

When using asynchronously mounted components, Melody allows you to use dynamic paths.

<section class="item__details">
    {% for part in parts %}
        {% mount async "./parts/#{part}" as "part-#{part}" %}
            {% include "./loading/part.twig" %}
        {% catch error %}
            {% include "./loading/error.twig" %}
        {% endmount %}
    {% endfor %}
</section>

This way you won't have to know the entire name of the component.

Last updated

Was this helpful?