I'm exploring using ES6 modules in a project which already uses J2CL (which only emits goog.module declarations, and assumes that all of its dependencies are also goog.module), but for the purposes of this question, I'll keep things to just plain Closure-flavored modules and JS. In short, this Closure JS follows this pattern in each module (greatly simplified):
goog.module("my.project.ProjectClass")
// declare that we depend on the class, for jsdoc and such
let DependencyClass = goog.forwardDeclare("some.dependency.DependencyClass");
class ProjectClass {
constructor() {
// actually get a reference to the class so we can use it, assign to top-level var
// note that this line itself cannot be top level to allow circular dependencies
DependencyClass = goog.module.get("some.dependency.DependencyClass");
// use the various dependencies that are now wired up
this.foo = new DependencyClass();
}
/**
* Read-only getter for foo
* @return {DependencyClass}
*/
get foo() {
return this.foo;
}
}
exports = ProjectClass;
On the other hand, we have some dependency made up of closure-compatible ES6 modules, and I would like to use them directly in this project. The first step is to make this file reachable by closure modules, something like this at the end:
//... imports, decl of DependencyClass, etc
goog.declareModuleId('some.dependency.DependencyClass');
export {DependencyClass};
Now, it seems as though this should be enough to let it be referenced by name from inside of a closure module, but instead the goog.forwardDeclare line results in an error:
ERROR - [JSC_FORWARD_DECLARE_FOR_ES6_SHOULD_BE_CONST] goog.forwardDeclare alias for ES6 module should be const.
Is there a way that this module can be referenced _and_ the type can be referenced?
--
Our quick and dirty workaround is to provide a "shim" which bridges the gap between this es6-closure "hybrid" module (which cannot be used in forwardDeclare like this) and a "real" closure module. First, the declareModuleId needs to be different - I renamed it above to have the suffix .es6. Then, a new closure module is created:
// Declare a "full" closure module, so we can reference it with requireType+module.get
goog.module('some.dependency.DependencyClass');
// Depend on the "hybrid" module
const hybrid = goog.require('some.dependency.DependencyClass.es6');
// Re-export the module that was imported
exports = hybrid;
With this extra file in the project, it seems possible to use the forwardDeclare/module.get pattern, though a new file is needed for each es6 module that will be depended on in this way, so it isn't ideal.