Coming up: 14 Jun - Reacticon 4 - Workshops

Yireo - Developer training

Open main menu

11 April 2021

Prefer require() over Magento declaritive notation

I've heard it before: To use the x-magento-init or data-mage-init syntax for loading Magento scripts, instead of using a simple inline require() call. Just because Magento says so. But is that really a good practice? Let's do a comparison.

A simple background-color example

This blog assumes that you have played with Magento 2 JavaScript before. We can create a simple script within our theme Magento_Theme/web/js/example.js with the following contents:

define(['jquery'], function($) {
    return function(config, domElement) {
        $(domElement).css({backgroundColor: config.color});
    }
});

This simple library returns a function with two input arguments (config and domElement) for some user side to call upon it. It could have lived without the return function as well, perhaps. But by returning a function with specifically these input arguments in this specific order, we anticipate a Magento convention used by x-magento-init and data-mage-init. We'll see this in a bit.

First try: A simple inline script

To put this script to the test, we'll need a block. Let's create a PHTML template Magento_Theme/templates/example.phtml and an XML layout to display this block:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:View/Layout:etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block template="Magento_Theme::example.phtml"/>
        </referenceContainer>
    </body>
</page>

The PHTML template is nothing fancy: It contains a div with a header. And the inline script calls upon the JavaScript component that we created earlier, with a simple configuration containing a color and a HTML identifier to base a jQuery object upon:

<div class="example1">
    <h1>Hello World 1</h1>
</div>
<script>
    require(['Magento_Theme/js/example'], function(example) {
        example({color: "green"}, '.example1');
    });
</script>

If this is all in place, you should be able to navigate to your frontend and see this dummy script in action. All good? Then lets' continue.

Adding data-mage-init

Now we can add the following snippet to the existing PHTML templates:

<div class="example2" data-mage-init='{"Magento_Theme/js/example": {"color": "orange"}}'>
    <h1>Hello World 2</h1>
</div>

There is no inline script. The modification is much shorted. But it still has the same effect ... well, no longer with a green color but an orange color. The function returned from our JavaScript component adheres to a Magento convention, through which some core script (mage/apply/main.js) is able to instantiate the same effect - just like earlier.

Adding x-magento-init

Let's add the third variation, using x-magento-init. This requires an inline script of unknown type (so it is not seen as JavaScript by search engines), is about the same length as the first example, but the color is dark-orange.

<div class="example3">
    <h1>Hello World 3</h1>
</div>
<script type="text/x-magento-init">
    {
        ".example3": {
            "Magento_Theme/js/example": {
                "color": "darkorange"
            }
        }
    }
</script>

Now compare the loading time

Now reload the page: All three effects should be working, each modifying their own area of HTML, applying a background color: Green, orange, dark-orange. But did you notice something on the loading time as well? First, the regular require() variant changes the background. Next, a slight pause. And then x-magento-init and data-mage-init are applying their colors.

This simple proof-of-concept points to a simple truth: Using x-magento-init and data-mage-init load slower than a simple require(). Period.

Use require() at most times ...

Back to the original opening of this blog: Some people say it is better to use x-magento-init and data-mage-init (also known as the declaritive notation) because that's what Magento uses for everything. I would say that it is nice that Magento is doing something, but if Magento asks you to set yourself on fire, because it is good for SEO, are you really going to do so? Instead, simply realize that the imperative notation (require()) is better for performance and that it helps the client gain performance. We can debate on this, but it will not change this simple fact. I would personally rather help out the client, then to repeat in my code what Magento has done wrong.

... unless you can't

Unfortunately, this does not always work. And that's an understatement. As soon as you want to use Knockout in your own components, you will need to stick to the declaritive notation instead. For instance, if you want to create a Knockout scope and insert a KO ViewModel into it, the only way (?) is to use text/x-magento-init to initialize Magento_Ui/js/core/app and add your own JavaScript to its component configuration. Or, if you want to use the customerData library. And in practice, this happens quite a lot.

Theoretically, mage/apply/main.js could be rewritten so that you can apply Knockout via the imperative notation instead. I've tried it, broke the code, ran out of time, still need to try it again. But perhaps, all of this simply shows that the JavaScript execution in Magento its Luma system is not the brightest. Which shows perhaps the popularity of Magento PWA Studio, Vue Storefront and Hyva Themes?

This message will self-destruct in 10 seconds.

Posted on 11 April 2021

Free videos only cover things up to a certain length. Want to take a full deep-dive into Magento 2? Then a professional training with 3x Magento Master Jisse Reitsma might be your thing!

Learn more about our Magento 2 training

Looking for a training in-house?

Let's get to it!

Do not miss out on what we say

This will be the most interesting spam you've ever read

We don't write too commercial stuff, we focus on the technology (which we love) and we regularly come up with innovative solutions. Via our newsletter, you can keep yourself up to date on all of this coolness. Subscribing only takes seconds.

Sign up for the Yireo newsletter

Extensions

GitHub organizations

Legal information

Other Yireo sites

Get Social

About Yireo