goog.provide() code calling into CommonJS module

532 views
Skip to first unread message

Dan Maas

unread,
Mar 4, 2016, 7:24:48 AM3/4/16
to Closure Compiler Discuss
I'm a little confused about the method discussed here to access a CommonJS module from our main goog.provide()/goog.require()-based code that runs in a browser:
https://github.com/google/closure-compiler/issues/1472

If I were 100% CommonJS I'd use:
const pako = require('pako'); // access the Pako CommonJS library

The Github issue suggests I can use the same thing inside a goog.provide() module, but then my compiled code doesn't work because it just inserts a call to require(), which is not available in the browser. (am I supposed to provide my own implementation of require()? I believe it should be a no-op because the entire codebase is getting compiled to a single .js file, CommonJS libraries and all).

I tried the second recommendation:
const pako = goog.require("module$pako$index"); // access the dependency using the mangled module name

but this gives the error

ERROR - Closure dependency methods(goog.provide, goog.require, etc) must be called at file scope.


What DID work for me is this:

goog.provide('MyMainModule');

goog.require('module$pako$index'); // identify the dependency using the mangled module name

MyMainModule.pako = null; // create a local reference to avoid polluting global namespace

if(!MyMainModule.pako) { // necessary to avoid "ERROR - goog.module.get can not be called in global scope."

    MyMain.Module.pako = goog.module.get('module$pako$index');

}

// and now I can use "MyMainModule.pako" the same way as "pako" in the CommonJS example!


This seems awkward for a few reasons:
- needing to use the mangled "module$" name, as mentioned in the Github issue discussion
- the strange if() block to avoid "ERROR - goog.module.get can not be called in global scope.".
- the straightforward attempt to use:

MyMainModule.pako = goog.require('module$pako$index');
causes "ERROR - Closure dependency methods(goog.provide, goog.require, etc) must be called at file scope."

Is there a better "intended" way to do things? The above method actually works, and does seem to carry over type information from annotations in the CommonJS library into my main code, which is very cool! Just wondering about the odd syntax I needed to get it working.

btw this is all with Closure Compiler master as of 20160212. Happy to test again with a newer version if anything's changed.

Many thanks,
Dan Maas

Chad Killingsworth

unread,
Mar 4, 2016, 10:28:27 AM3/4/16
to Closure Compiler Discuss
You pretty much summed up the current state of things. I have 3 PRs queued up that fixes the issues - but they are based on a PR that requires internal changes at Google and so is taking some time. Hopefully things will be moving again soon.

The current rewriting for CommonJS does not happen if the file has a goog.provide call already. However, while we won't support a file having a goog.provide AND a module.exports statement, we should allow a file with goog.require to also have the CommonJS require statement. This is one of the fixes I have ready to go.

If you'd like to look at those changes:

Chad Killingsworth

Dan Maas

unread,
Mar 4, 2016, 10:44:26 AM3/4/16
to closure-comp...@googlegroups.com
Awesome, thanks for the update. Appreciate your work on this. The Closure Compiler has already gone above and beyond my hopes :).

Dan

--

---
You received this message because you are subscribed to a topic in the Google Groups "Closure Compiler Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/closure-compiler-discuss/6H4oNj2pBf4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to closure-compiler-d...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/closure-compiler-discuss/4f993bc5-b7c6-41cf-92a7-b606133596ba%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Dan Maas

unread,
May 20, 2016, 8:54:57 AM5/20/16
to Closure Compiler Discuss
Updating this thread because the 20160517 compiler release affects using CommonJS modules from Google modules (in a good way).

Instead of the above-mentioned work-around involving mangled module names, the Google module can now just say

goog.provide('MyMainModule');

const pako = require('pako');

The above works for Closure compiled code. In practice, we also want to be able to run the raw JavaScript uncompiled, within a browser, during development. In order to do this, we use a little hack where we manually stuff an extra <script> tag into the page that loads the CommonJS module code and attaches it to the global pako symbol. Then our main code accesses it like this:

const my_local_pako = (typeof(pako) === 'undefined' ? require('pako') : pako);
// works both uncompiled (where pako is defined by the browser loading the module externally)
// and compiled (where require('pako') hooks it up to the proper code)

Dan

Chad Killingsworth

unread,
May 20, 2016, 1:15:26 PM5/20/16
to Closure Compiler Discuss

This is unintended and will be removed in the next release. CommonJS module rewriting should not effect goog.module code.

I'll be updating the documentation this next week with examples of module interoperability.

Chad Killingsworth


--

---
You received this message because you are subscribed to the Google Groups "Closure Compiler Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to closure-compiler-d...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/closure-compiler-discuss/d83d17e9-3e0f-45a0-ad4f-96b68b9f01eb%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--

Chad Killingsworth  | Banno | Senior Software Engineer
Jack Henry & Associates, Inc.

Chad Killingsworth

unread,
May 21, 2016, 9:23:39 AM5/21/16
to Closure Compiler Discuss
Actually I mis-read this. This isn't the commonjs rewrite bug.

This is definitely intended. Module systems should freely be able to mix "import" methodologies with this release. It is perfectly valid for a single file to contain an ES6 import, CommonJS require and a goog.require statement.

Documentation has been updated to reflect the lifting of this restriction: https://github.com/google/closure-compiler/wiki/JS-Modules

In addition, the CommonJS "require.ensure" call is recognized and rewritten by the compiler to enable async loading of CommonJS modules. The InjectJS module loader supports this signature.

Chad Killingsworth

Dan Maas

unread,
May 22, 2016, 1:01:20 AM5/22/16
to Closure Compiler Discuss
Awesome, thanks for updating the docs. We're very happy with how it's all working now :).

Dan
Reply all
Reply to author
Forward
0 new messages