Magento 2 Add Global JS File Through RequireJS

Adding in a JavaScript library to Magento 2 is very different to how you might be used to doing things from Magento 1.

Magento 2 uses the RequireJS library for nearly every JavaScript feature it has. Today I’m going to show you the most basic example of how to utilise this library by adding a new JavaScript file globally across all pages in Magento 2.

So, what even is RequireJS?

RequireJS

RequireJS is essentially a modular script loader. Magento 2 uses this library for nearly every JavaScript feature it has, so we ought to know how to work with it. Using this library will bring speed improvements and improved quality of your code. You will only be loading in what you need for that particular page and your code will be a lot more modular and easier to structure.

For example, you might be writing a chunk of JavaScript that depends on a third-party library such as jQuery. When writing this code you would “require” the third-party library as a dependency, RequireJS would then do the leg work to ensure the file is delivered to you.

If you have multiple scripts on a page all requiring the same dependency it won’t add it multiple times to the page, it will only add it once.

An example JavaScript file would look something like this:

require([
    'jquery'
], function($) {
    'use strict';

    // do something
});

In the browser window if you view the source on a default Magento 2 store you will notice there are only a handful of JavaScript <script src="..."> tags, all the other files are loaded through the RequireJS library.

As well as requiring libraries as dependencies, you can also define your own which only get loaded if it’s required:

define([
    'jquery'
], function($) {
    'use strict';

    var moduleName = function() {
        // do something
    };

    return moduleName;
});

Configuring RequireJS

Now we have the very basic understanding of RequireJS we need to setup our JavaScript file and configuration. In this example we will load a JavaScript file to use globally across all pages in Magento.

First create a new file within your theme directory:

app/design/frontend/<VendorName>/<ThemeName>/web/js/app.js

Now add the following contents:

require([
    'jquery'
], function($) {
    'use strict';

    $(function() { // document.ready shorthand
        console.log('web/js/app.js loaded');
    });
});

Here we are adding jQuery as a dependency and logging out some text to the console so we can check the file has been loaded.

Now we need to tell RequireJS about our new file and get it loaded into the browser. Create a new file under your theme directory called requirejs-config.js:

app/design/frontend/<VendorName>/<ThemeName>/requirejs-config.js

Now add the following contents:

var config = {
    deps: ['js/app']
};

The deps parameter is essentially saying, when RequireJS is loaded please load this file. So whenever RequireJS is loaded, which is on every page in Magento 2 our global JavaScript file we be loaded as well.

In our example the configuration file is very basic, there are a lot more parameters you can use which I’ll cover in future blog posts, this is only an introduction.

Success! At this point if you refresh your browser window you should see the console.log message in your dev tools, you might need to clear magento cache.

But.. how?

So let’s rewind a bit and work out how this is actually working.

The RequireJS library gets loaded by Magento 2 by default along with some additional configuration. One of these is the baseUrl which we need to touch up on briefly. If you open up a Magento 2 store in the browser and view source you will find a snippet of code at the top in the <head> tag similar to the following:

var require = {
    "baseUrl": "http://m2.dev/pub/static/version1511090612/frontend/JasonAlvis/blank/en_US"
};

This baseUrl is based on the current theme, locale and base URL for static view files for the store. RequireJS uses this to calculate the full path for the JavaScript files:

baseUrl + file + '.js'

Using our new file as an example, it looks something like this:

http://m2.dev/pub/static/version1511090612/frontend/JasonAlvis/blank/en_US/js/app.js

It will then load this file and voila, we see the console.log message in the dev tools.

Tips

From working with Magento 2 for some time I’ve put together some useful tips when working with the configuration file for RequireJS as it can get confusing.

Checkout the RequireJS configuration below including detailed comments which I use to reference for a better understanding.

/**
 * Never set the 'baseUrl' Magento does this for you: 
 * <siteurl>/pub/static/<version>/frontend/<VendorName>/<ThemeName>/<language>
 *
 * Never includes a '.js' extension since the paths config could be for a directory.
 * 
 * Theme JS files located in: web/js
 * Module view JS files located in: Package_Module/view/frontend/web/js
 */
var config = {
    // When loading 'requirejs' always load the following files as well.
    // Global JS file for site wide functionality
    // web/js/app.js
    deps: [
        'js/app'
    ],
    // Path mappings for module names.
    // If it's a jQuery library please keep to the naming convention 'jquery/<name>'
    // web/js/vendor/slick.min.js
    paths: {
        'jquery/slick': 'js/vendor/slick.min' 
    },
    // Configure the dependencies, exports, and custom initialization for older, 
    // traditional 'browser globals' scripts that do not use define() 
    // to declare the dependencies and set a module value.    
    shim: {
        'jquery/slick': {
            // These script dependencies should be loaded before loading 'jquery/slick'
            deps: ['jquery'],
            // If the library is not AMD aware, you need to tell requirejs what 
            // to look for to know the script loaded correctly. The value must be a variable 
            // defined within the library.            
            exports: 'jQuery.fn.slick'
        }            
    }           
}; 

I also highly recommend reading through the RequireJS and Magento 2 documentation as well to get yourself more familiar.

In the next post I’ll be showing you how to load in a JavaScript file via the imperative and declarative notations. This will allow us to only load a JavaScript file when it’s requested, rather than loading on every single page like this post demonstrates.