Skip to content

ES6 modules and Closure Library

Stephen Hicks edited this page Oct 21, 2019 · 3 revisions

While Closure Library does not currently have any ES modules (formerly "ES6 modules"), the Closure Compiler and the Library's Debug Loader are compatible with ES modules.

For more information on interop see ES6 modules and Closure interop

For a migration guide from goog.modules to ES modules, see Migrating from goog.modules to ES6 modules.

The Debug Loader and ES modules

Closure Library comes equipped with a code loader in base.js. It was originally designed to load uncompiled goog.provide and goog.module files in a browser. The Debug Loader needs the dependency graph of your files ahead of time, which is done with repeated calls to goog.addDependency (see deps.js for an example).

Even though browsers can load ES modules, if you program has any goog.requires anywhere, you will need to make Closure Library aware of all your ES modules with goog.addDependency calls, and include a module: 'es6' load flag. You should not need to be writing these calls yourself. The npm package google-closure-deps can scan your source files and write these files for you.

Additionally you should not import your program's entry point - you will need to either goog.require or goog.bootstrap it. Thus it is recommended your program entry point call goog.declareModuleId if it is an ES module, so that you have something to pass to goog.require / goog.bootstrap.

Closure Library needs to know about your ES modules and load them for you (rather than allow the browser to do so) as it must load all Closure files that are goog.required before the goog.requires for them are executed.

Example project:

// es6.js

// The file that defines "goog.math" must be loaded before this statement
// executes, so the Debug Loader must be made aware of this.
const math = goog.require('goog.math');

export const CONSTANT = math.sum(1, 1, 2, 3, 5, 8, 13, 21);
// entry.js
import {CONSTANT} from './es6.js';

goog.declareModuleId('entry-point');

console.log(CONSTANT);
// mydeps.js

// Notice: ES modules do not provide anything unless they call declareModuleId.
goog.addDependency('../../es6.js', [], ['goog.math'], {'lang': 'es6', 'module': 'es6'});
// Notice: Imports for ES modules end up adding require for the ES module's relative path
// from Closure Library.
goog.addDependency('../../entry.js', ['entry-point'], ['../../es6.js'], {'lang': 'es6', 'module': 'es6'});
<script src="closure/goog/base.js"></script>
<script src="mydeps.js"></script>
<script>
  goog.bootstrap(['entry-point'], () => console.log('Program loaded!'));
</script>

goog.require'ing ES modules

It is important to note that, while goog.modules may be declared to export a "legacy namespace" (via goog.module.declareLegacyNamespace() there is no such analogue for ES modules. This means that it is impossible to goog.require an ES module directly in a goog.provide script (assuming you plan to use the module's exports). The exports from a goog.declareModuleId module may only be accessed within a goog.module and only by aliasing (or destructuring) the result of goog.require()ing the module ID.

// es-module.js
goog.declareModuleId('esmod');
export const x = 42;
export default 'default';
// goog-module.js
goog.module('googmod');
const esmod = goog.require('esmod');
console.log(esmod.x, esmod.default);