I have a Node.js project that I want to compile with Closure Compiler. I do not want it to run in the browser/use browserify. I mainly want the utility of type checking. I originally got the compiler to work correctly using the following:
java -jar compiler.jar -W VERBOSE
--language_in ECMASCRIPT5_STRICT
--externs closure-externs.js
--js="lib/**.js"
Where closure-externs.js
manually defined variables and functions which I was using from Node.js in a rather crude way:
// closure-externs.js
/** @constructor */function Buffer(something){}
function require(path){}
var process = {};
[...]
It turns out that this worked only through sheer luck. There is no dependency tracking between files, so you can have cases where you return a type {Foo}
and the compiler will complain that it doesn't exist (depending on the machine, depending on the compile order). I then found out I was doing it all wrong and should be using --process_common_js_modules
so the compiler will do dependency tracking where I require("foo")
. I am currently invoking the compiler like so:
java -jar compiler.jar -W VERBOSE
--language_in ECMASCRIPT5_STRICT
--externs externs/fs.js
--js="lib/**.js"
--process_common_js_modules
--common_js_entry_module app.js
But this is failing with:
ERROR - required entry point "module$crypto" never provided
ERROR - required entry point "module$dgram" never provided
ERROR - required entry point "module$extend" never provided
ERROR - required entry point "module$fs" never provided
ERROR - required entry point "module$net" never provided
ERROR - required entry point "module$q" never provided
Some of these modules are native to Node.js (e.g. fs
) whereas others are contained in node_modules
like q
. I don't want to run these external modules through the compiler, so I know I need to set up externs
file(s) for them. I know there is https://github.com/dcodeIO/node.js-closure-compiler-externs for common Node.js externs, and I know how to invoke them on the compiler, but for some reason when I do something like --externs externs/fs.js
the error for module$fs
remains. What am I doing wrong?
I know there's other flags like --module
and --common_js_module_path_prefix
but I'm not sure if I need to use them to get this to work or not. My Google-fu has failed to come up with any answers on the correct incantation here. :(
The issue is that you wish for the compiler to somehow recognize that certain require
calls are internal, namely that the required module should be processed by the compiler as source, and others are external so should be left alone. There isn't a good way to handle this situation currently.
In this scenario you would completely omit any require
statements to external modules. The compiler would only process code with internal require statements and modules. After compilation, you would prepend the external require statements:
var crypto = require('crypto');
console.log(crypto);
Because crypto
is declared in an extern, the compiler will correctly recognize the type and symbol name.
When the --process_common_js_modules
is specified, the compiler recognizes require
statements and expands them in a similar fashion to the way macros work in other languages. By aliasing the require
statements that should remain external, the compiler will not recognize them and thus not expand them.
var externalRequire = require;
/** @suppress {duplicate} this is already defined in externs */
var crypto = externalRequire('crypto');
console.log(crypto)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With