Add Javascript via RequireJs in Magento 2

Published Thursday, January 16, 2020

How Magento 2 deals with javascript can feel cumbersome, bulky, heavy, clumsy, ineffecient, unnecessary, and even pretentious. Ha! That gets me right in the feels. Doesn't that describe how every part of Magento 2 comes off at first?

That's how it felt for me, at least.

The goal of this article is to streamline your understanding of how Magento 2 works with javascript files. It uses RequireJs, which is a cool library that takes care of loading js files for you, and it loads them in the correct order so error messages don't overflow your console. That's basically what it is -- don't overcomplicate it.

You need 4 things:

  • a javascript file
  • an entry in requirejs-config
  • a template file with an x-magento-init script
    • and corresponding layout xml that adds your template

Below is an example with these four items, and some exposition along the way. I include the entire module code, so module.xml and registration.php are shown, but they are not related to the four items.

File List

  • Joki/RequireJs/registration.php
  • Joki/RequireJs/etc/module.xml
  • Joki/RequireJs/view/frontend/requirejs-config.js
  • Joki/RequireJs/view/frontend/templates/example.phtml
  • Joki/RequireJs/view/frontend/web/js/example.js
  • Joki/RequireJs/view/frontend/layout/catalog_product_view.xml

registration.php [copy] [view]

 
  1<?php
  2use \Magento\Framework\Component\ComponentRegistrar;
  3
  4ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Joki_RequireJs', __DIR__);
 

etc/module.xml [copy] [view]

 
  1<?xml version="1.0"?>
  2<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  3    <module name="Joki_RequireJs" />
  4</config>
 

First, let's declare our javascript file in the RequireJs config. This maps the name (alias) to the path of the javascript file in your module.

view/frontend/requirejs-config.js [copy] [hide]

  1var config = {
  2    map: {
  3        '*': {
  4            jokiRequireJsExample:   'Joki_RequireJs/js/example'
  5        }
  6    }
  7};

Now you can include it by referencing its alias in the template file.

view/frontend/templates/example.phtml [copy] [hide]

  1<script type="text/x-magento-init">
  2{
  3    "*":
  4    {
  5        "jokiRequireJsExample": { "test": "somedata1234" }
  6    }
  7}
  8</script>

This is where Magento will load our javascript file. It won't be loaded until Magento parses this "x-magento-init" script and sees the "jokiRequireJsExample" alias. From there, it knows which file to load from our definition in "requirejs-config.js". The asterisk denotes that our javascript function will *not* be bound to any elements on the page. The json following the alias is config data that is passed to a specific function in our javascript file.

Here's our javascript file.

view/frontend/web/js/example.js [copy] [hide]

  1define([
  2    'jquery'
  3], function($) {
  4    'use strict';
  5    
  6    return function(config)
  7    {
  8        console.log('loaded');
  9        console.log(config);
 10    }
 11});

This is the basic template for a javascript component in Magento 2. Notice how we return a function? When we do this, Magento will keep a reference to the function and then pass the config object upon initialization. In this example, the config object is `{ "test": "somedata1234" }` from our "x-magento-init" script. Doing things this way allows for Magento to conveniently instantiate javascript objects with necessary the config data.

It's also a cool way to keep your javascript separate from code that generates the config data.

Let's not forget to add our template file to the product page via layout xml.

view/frontend/layout/catalog_product_view.xml [copy] [hide]

  1<?xml version="1.0"?>
  2<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
  3    <body>
  4        <referenceContainer name="content">
  5            <block class="Magento\Framework\View\Element\Template" name="joki.requirejs.example.block" template="Joki_RequireJs::example.phtml" />
  6        </referenceContainer>
  7    </body>
  8</page>

Now, when we visit the product page, we can see when our javascript file is loaded and what config data was passed to it.