Accessing ES6 Module Functions in the Browser Javascript Console

AKA 'why the @&#*$ is my module undefined?!'

Posted by Nate Eckerson on June 17, 2019 · 2 mins read

TL;DR

In your index.js file, or wherever you’re importing the module, do the following:

import ModuleName from 'SomeModule';
window.ModuleName = ModuleName;

Then in the browser console:

> ModuleName (...is defined...)

Why should I care?

If you’ve played with Javascript before, you’re accustomed to opening the console and exploring your objects and functions on the fly. For example, if you’re loading jQuery in your HTML like so:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>

You can open the Chrome developer console and type in:

> $(‘custom-header')

This will return all DOM objects with the ‘custom-header’ selector, which you can then open and investigate in the console. It’s a useful trick.

In the process of building a custom shopping cart using a combination of Webpack, and Shopify’s own ES6 JS modules, I soon found myself wanting to debug the cart state using the Chrome developer console. Unfortunately, this was not as simple as entering:

> cart.getState()
> Uncaught ReferenceError: cart is not defined at <anonymous>:1:1

Why does it break?

By design, ES6 Javascript modules are “modular”, and have “lexical top-level scope”, which (for the sake of brevity) means functions and variables declared inside the module are not available in the global scope. This is great from a software design perspective, since it prevents conflicts that occur when many variables and functions are defined in the same scope. The flipside is that modules have different behavior than you expect from classic JS scripts.

To work around this, you’ll need to attach the module to the global Window scope like so:

import ModuleName from 'SomeModule';
window.ModuleName = ModuleName;

Then in the browser console:

> ModuleName (...is defined...)

Thoughts

Attaching a module to the global scope defeats the intent of a module! However, it’s a useful trick if you’re trying to confirm that a module is loading properly, and you want the instant console feedback you’re accustomed to.