ClosureCompiler.js icon indicating copy to clipboard operation
ClosureCompiler.js copied to clipboard

Error: Cannot find module './*.js'

Open codinkai opened this issue 12 years ago • 11 comments

Hi,

my project has the following structure:

index.js compile.js lib/ -- Class1.js -- Class2.js package.json

In compile.js the compiler is invoked with index.js and all files in the lib-directory as source files. Compilation works as expected.

But when I invoked the compiled source file, cross-references between Class1.js and Class2.js cannot be found. The following error occurs:

module.js:340 throw err; ^ Error: Cannot find module './Class1.js'

In Class2.js there is a reference to Class1.js with require(''./Class1.js').

I could use absolute paths by setting an environment-variable in index.js and reading this in every require-statement. But I would like to know which is the best-practice solution for this problem.

codinkai avatar Dec 17 '13 16:12 codinkai

In Class2.js, try:

var path = require("path"),
    Class1 = require(path.join(__dirname, "Class1.js"));

dcodeIO avatar Dec 17 '13 17:12 dcodeIO

Unfortunately this does not work. I would expect the require statement to get removed, because the required-file is in the compiler's source directory. If I would use absolute paths uncompiled sources would be loaded, which compiled version might be in the compilation result.

codinkai avatar Dec 19 '13 11:12 codinkai

I am sorry, I do not seem to understand this fully. Of course you can change the require statement to whatever you like, for example: require(path.join(__dirname, "..", "Class1.js")); with __dirname being just a reference to the current directory of the file. If you are using ADVANCED_OPTIMIZATIONS, it might also be required to add externs so that the __dirname variable does not become renamed by CC. Or what am I getting wrong?

dcodeIO avatar Dec 19 '13 12:12 dcodeIO

The closure compiler concatenates the three source files lib/Class1.js, lib/Class2.js and index.js and compiles them into a file, called compiled.js. The compiled.js should not reference to any of the uncompiled files with a require statement.

codinkai avatar Dec 19 '13 14:12 codinkai

I see. In that case, you might want to give Preprocessor a try to bundle your files, possibly leaving stuff out, prior to compilation.

There are also some CC switches for commonjs but I haven't used these, yet.

Just to make this clear: I cannot change the way Closure Compiler works, as ClosureCompiler.js is just a wrapper around it.

dcodeIO avatar Dec 19 '13 15:12 dcodeIO

You are right, but some preprocessing could be added like replacing require-statements to source-files with assignments.

I only want the compiler to make static type check to my sources. I do not care about the result right now. How would you handle the following situtation?

// index.js
var TestClass = require('lib/TestClass.js');

// compiler should throw an error (does concatenation)
console.log(TestClass.add("hello", "world"));
// lib/TestClass.js
var TestClass = function() {};

/**
 * @type {number}
 */ 
TestClass.prototype.attribute = "some initial value";

/**
 * Adds two numbers.
 * 
 * @param {number} a Operand a.
 * @param {number} b Operand b.
 * @return {number} Sum of a and b.
 */
TestClass.prototype.add = function(a, b) {
  return a+b;
}

module.exports = TestClass;

The compilation for these files should fail due to the wrong invocation of "add" with strings instead of numbers AND the wrong type of the attribute. But I do get the following compilation result:

function a() {
}
a.prototype.add = function(b, c) {
  return b + c;
};
module.a = a;
a = require("lib/TestClass.js");
console.log(a.add("hello", "world"));

codinkai avatar Dec 19 '13 16:12 codinkai

What I found on this: http://www.nonblocking.io/2011/12/experimental-support-for-common-js-and.html (CC internal)

Maybe this could be useful, too: http://browserify.org/ (bundles require statements)

Or, like mentioned above, using Preprocessor.js prior to compilation, e.g. by adding conditional blocks

var Class1;

// #ifdef SINGLEFILE
Class1 = (function() {
    var module = {"exports": {}};
    // #include "Class1.js"
    return module.exports;
})();
// #else
Class1 = require("Class1.js");
// #endif

^ This will require the file if run without Preprocessor as the inline function will return {} and not include anything. When run with Preprocessor with SINGLEFILE=true, it will include the file instead, making it safe to be compiled through CC afterwards. ProtoBuf.js uses Preprocessor.js for example for building different versions of the library prior to CC compilation.

dcodeIO avatar Dec 19 '13 16:12 dcodeIO

TypeChecking works, when I invoke the compiler as follows. But I have the same problems as in https://groups.google.com/forum/#!topic/closure-compiler-discuss/1hPmS7EOhj8. Unfortunately I haven't found a solution for it yet.

./node_modules/closurecompiler/bin/ccjs index.js lib/TestClass.js --process_common_js_modules --common_js_entry_module=index.js --compilation_level=ADVANCED_OPTIMIZATIONS --formatting=pretty_print --warning_level=VERBOSE

By the way, how do I pass flag-options to the ClosureCompiler class?

codinkai avatar Dec 27 '13 14:12 codinkai

https://groups.google.com/forum/#!topic/closure-compiler-discuss/acD1bSh3FAQ

codinkai avatar Dec 27 '13 15:12 codinkai

So, I guess CC's CommonJS support is far from being usable.

To pass options (any that closure compiler supports) to ClosureCompiler.js:

  • new ClosureCompiler(options)
  • ClosureCompiler.compile(files, options, callback)
  • Or on the command line to ccjs

Remains browserify and Preprocessor.js. I am sorry that I cannot assist you any further, it's just that I am not a maintainer of closure compiler itself, only of this package.

dcodeIO avatar Dec 27 '13 15:12 dcodeIO

Closure Compiler itself works fine for me with the following command: closure-compiler --process_common_js_modules --common_js_entry_module=./src/index.js --externs=./externs.js --compilation_level=ADVANCED_OPTIMIZATIONS src

However when I try to use ccjs I get the error Illegal source file after options: src.

Then I tried using ccjs like this: ccjs ./src/index.js --process_common_js_modules --common_js_entry_module=./src/index.js --externs=./externs.js --compilation_level=ADVANCED_OPTIMIZATIONS Now it tells me that it can't resolve the module.

nerdbeere avatar Feb 23 '16 13:02 nerdbeere