Debugging Javascript and Require JS – Part 2

In the last section we talk about the Network tab of the browser. In this post we are going to dig into how to control the way files are output to the browser from Magento. This is going place you in the drive seat of this massive application. Get your crash helmet!!!

The Require JS Configuration file

When we looked at the page source in a past post, we saw we have a requirejs-config.js file. This file is in the pub directory and is the combined output of all the requirejs-config.js files that exist in the modules and themes of the site. Opening up this file (you can do this in your code editor here: pub/static/frontend/{{vendor_namespace}}/{{theme}}/en_US/requirejs-config.js or in the browser itself in the page source view of the site) you will see chunks of code.

This picture is just an arbitrary chunk. Each section starts with an anonymous function that wraps a config object. Inside that object is our configurations (map is just on of the configurations we can do). We then see require.config(config); followed by () with execute this chunk of code.

Inside the map you can think of this as a key/value pair, where the name is the first element and the path to the file is the second. Actually, you don’t have to think of it that way, that is exactly what this is. We have already see this in a past post, in there we have this code:

...
map: {
    '*': {
        slick: 'Magento_Theme/js/vendor/slick.min'
    }
}
...

Here we are pointing to a file location (given Magento’s shorthand path system that omits the web directory and the .js file extension) and then giving it a name: slick. Later in that post we “grabbed” this file to use it in our define statement. This configuration file is what makes the connection between these elements. In plain language: we register the file under the label slick and then use that label to call the script into our custom file.

When the page is loaded, all the Javascript that is rendered in the HTML document will have been defined but this configuration file. All the interdependent assets needed will be loaded by Require JS in the background. We have already talked about debugging this load order in the network tab of the bowser. This file is the starting point of how that order is defined.

That leads up to one of the superpowers of Require JS. It stores its configuration file in a way that makes all modules defined accessible from anywhere else in the application. To find the definition of “jquery” (using a search like find . -name 'requirejs-config.js' | xargs grep -r 'jquery') you will find that this is loaded in vendor/magento/module-theme/view/base/requirejs-config.js. But once loaded, any other module in the system can now use that instance of jQuery.

This frees us as end users of the system to just grab the things we need to use and not worry about where they are or how to get them. You need the underscore library. Place 'underscore' in your file. Need the validation library? 'mage/validation' gets the job done.

It also means that we can load in our own libraries and dependencies into the framework without worry of name space conflicts and global variables causing havoc on our pages.

To continue our tour, another part of the file is this:

'shim': {
    'jquery/jquery-migrate': ['jquery'],
...
},

Here we see a Require JS shim (https://requirejs.org/docs/api.html#config-shim). In this we can set dependencies. In this case jquery/jquery-migrate depends on ['jquery']. This makes sense, but it’s a way to explicitly say “hey, not matter what, load my file after this other file, i have to have it first”. The dependency is and array and can contain multiple dependencies if needed: ['jquery, 'underscore', 'tacos'].

The next thing i want to cover in this file is mixins. There will be a lot of use of this in future posts, but i need to do a quick introduction here.

config: {
    mixins: {
        'Magento_Theme/js/view/breadcrumbs': {
            'Magento_Theme/js/view/add-home-breadcrumb': true
        }
    }
}

Mixins are a override system in place that will “extend” the existing Javascript module with changes to the methods inside it, add new methods or take output of those methods for further processing. I cannot over state the value of this functionality. I use this almost everyday, and it is a critical tool in the front end developers box.

For a deep dive into mixins, Alan Storm has written an amazing article on this topic.

Wrapping up

So we have solved a big problems with the use of Require JS. But is all that worth it? Well in the case of Magento 2, there really is no other choice. This new iteration of the platform is Javascript powered in a way Magento 1 never was. To accomplish a truly modular system the idea of just “dealing with” Javascript conflicts is too much to ask. These kind of errors aren’t even an option for a platform like Magento. So good or bad, right or wrong, a system like Require JS had to be used.