closure-compiler
closure-compiler copied to clipboard
ERROR - [JSC_JS_MODULE_LOAD_WARNING] Failed to load module "util"
Context
I would like to compile a node based project which dependencies include util and other node builtins.
However, the compiler won't load them despite using the --process_common_js_modules and --module_resolution NODE flags. Every other dependencies is loaded properly with --js.
My understanding was that, by using --externs and --output_wrapper (or --output_wrapper_file), the compiler would inject and use them as global variables within the final output. I've used @externs/nodejs to that effect.
Following here is a very basic failing setup:
Setup
Compiler
npm i -D google-closure-compiler
# + [email protected]
I also tried
[email protected]from a year ago in case it would be related to the latest version.
Source
const util = require('util')
console.log('it works...')
module.exports = {}
Command
google-closure-compiler index.js --process_common_js_modules --compilation_level ADVANCED --module_resolution NODE
Error
index.js:1:13: ERROR - [JSC_JS_MODULE_LOAD_WARNING] Failed to load module "util"
1| const util = require('util')
^
1 error(s), 0 warning(s)
Question
Is my initial assumption correct? Or is it not possible to compile with node builtins. If yes, could you help out with the configuration?
I believe this is working as expected; you need to pass every JS source with the --js flag, including sources from node modules.
Ok, I see. It works indeed if I place mock packages of builtins in node_modules and pass them with --js.
Thank you.
@mprobst, util is a Node builtin and does not exist in node_modules/. This does not work as expected, as these cannot be flagged as externs and apparently only work if you spoof them in node_modules/ and pass them in as normal JS (?).
This is entirely unintuitive, see https://github.com/google/closure-compiler/issues/3740.
@mistersomebody, could you please upload your project directory to a repo so that I can replicate the hack? Your creativity is much appreciated.
@ctjlewis
Here's an adaptation of what I ended up doing:
Sample
./index.js
const util = require('util')
console.log('It works:', util.isArray([]))
Mock
./node_modules/util/index.js
module.exports = util
Wrapper
./wrapper.txt
(util => {
%output%
})(require('util'))
Externs
Copy the
utilextern and removemodule.exports = utilat the end
./externs.js
/* LICENCE ... */
/**
* @const
*/
var util = {};
/**
* @param {string} format
* @param {...*} var_args
* @return {string}
* @nosideeffects
*/
util.format;
/**
* @param {string} string
* @return {void}
*/
util.debug;
/**
* @param {...*} var_args
* @return {void}
*/
util.error;
/**
* @param {...*} var_args
* @return {void}
*/
util.puts;
/**
* @param {...*} var_args
* @return {void}
*/
util.print;
/**
* @param {string} string
* @return {void}
*/
util.log;
/**
* @param {*} object
* @param {{showHidden: (boolean|undefined),
* depth: (number|null|undefined),
* colors: (boolean|undefined),
* customInspect: (boolean|undefined)}=} options
* @return {string}
* @nosideeffects
*/
util.inspect;
/**
* @param {*} object
* @return {boolean}
* @nosideeffects
*/
util.isArray;
/**
* @param {*} object
* @return {boolean}
* @nosideeffects
*/
util.isRegExp;
/**
* @param {*} object
* @return {boolean}
* @nosideeffects
*/
util.isDate;
/**
* @param {*} object
* @return {boolean}
* @nosideeffects
*/
util.isError;
/**
* @param {Function} constructor
* @param {Function} superConstructor
* @return {void}
*/
util.inherits;
Command
google-closure-compiler \
--compilation_level ADVANCED \
--js_output_file dist/index.js \
--module_resolution NODE \
--process_common_js_modules \
--export_local_property_definitions \
--generate_exports \
--externs ./externs.js \
--js node_modules/util/index.js \
--output_wrapper_file ./wrapper.txt \
index.js
Output
./dist/index.js
(util => {
'use strict';console.log("It works",util.isArray([]));
})(require('util'))
Cheers