-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Migrating from goog.modules to ES6 modules
Closure modules can have a "default" export via exports = value;. When using
this syntax the module's exports become the default export. This is frequently
used with modules that export a single class.
goog.module('my.Class');
class Class {}
// Default export. goog.require for this module returns this class.
exports = Class;goog.module('my.namespace');
// Non-default exports. goog.require for this module returns an object that
// has keys CONSTANT_0 and CONSTANT_1.
/** @const {number} */
exports.CONSTANT_0 = 0;
/** @const {number} */
exports.CONSTANT_1 = 1;It should be noted that this is not the same as an ES6 module's default
export, especially when it comes to goog.require. When goog.requireing an
ES6 module it always returns the module object (like import * as). If the
ES6 module has a default export then that means the object will have a key
default with the default export as value. Closure module default exports
directly change what goog.require returns. ES6 default exports always result in
goog.require returning an object with both any named exports and the default
export.
// This Closure module actually emulates an ES6 module's default export because
// it has an export named "default".
goog.module('my.namespace');
/** @const {number} */
exports.default = 0;As a result it is harder to migrate Closure modules with default exports than those without. Note that this is just the general rule and some default exports function like ES6 modules and thus are still easy to convert. If the default export is itself module-like (a static object with static keys), then it is equivalent to not having default exports and should also be easy to convert. For example, these two modules are the same even though one uses default exports and the other does not.
goog.module('my.namespace');
const THE_ANSWER = 42;
exports = {THE_ANSWER};goog.module('my.namespace');
/** @const */
exports.THE_ANSWER = 42;For Closure modules that use named exports we recommend migrating files in place over 3 changes.
- Edit the implementation file to be an ES6 module that calls
goog.declareModuleIdwith the old Closure module name (i.e. the old argument togoog.module). This should allow other files to continue usinggoog.requireon the Closure namespace.- Be sure to import Closure's
goog.jsfile rather than use the globalgoogsymbol!
- Be sure to import Closure's
- Edit all ES6 module files that are using
goog.requireon the module namespace to instead use ES6import. - Remove the call to
goog.declareModuleIdin the migrated file once it is not being referenced by anygoog.moduleorgoog.providefiles.
For Closure modules that do have default exports we recommend migrating files over 4 changes. This migration cannot be done purely in place. It requires adding new files.
- Edit the implementation file to be an ES6 module that calls
goog.declareModuleIdwith a new namspace. Create a new file *_shim.js next to it. This new file should be a Closure module with the original Closure namespace and shouldgoog.requirethe ES6 module and forward its exports. Remember that yourgoog.requirereturns an ES6 module object and you want to forward just one of its keys withexports = value. - Edit all ES6 module files that are using
goog.requireon the module namespace to instead use ES6import. - Delete the *_shim.js file and change any left over
goog.requires in Closure modules to the new namespace. - Remove the call to
goog.declareModuleIdin the migrated file once it is not being referenced by anygoog.moduleorgoog.providefiles.
goog.module.declareLegacyNamespace is not supported in ES6 modules. It breaks
a fundamental principle of modules: that modules do not create global values.
Its purpose was to allow migration from goog.provide to Closure modules. We do
not support it when moving to ES6 modules.
It is recommended you migrate all goog.provided files that are relying on the
declareLegacyNamespace call to Closure or ES6 modules first, or at the very
least have them call goog.module.get in a goog.scope to get references to
modules. If this is not possible and migration of the Closure module is still
desired, you'll need to follow similar steps to
migrating a Closure module with default exports,
except your *_shim.js file will call declareLegacyNamespace. You will only
be able to delete this file once all the goog.provide files have migrated.