closure-compiler: CommonJS compatibility does not work as expected

The compiler puts each commonJs module into default property of the imported object.

// ecma
import commonJs from './common-js'

console.log('requiring a common js from ecma:')
console.log(commonJs)
CommonJS From ECMACommonJS From CommonJS
// common-js.js
const commonJs2 = require('./common-js2')

module.exports = () => {
  console.log('default common js export')
}
module.exports['named'] = () => {
  console.log('named common js export')
}

console.log('requiring a ' +
'common js from common js:')
console.log(commonJs2)
// common-js2.js
module.exports = () => {
  console.log('default common js ' 
+ 'export2')
}
module.exports['named'] = () => {
  console.log('named common js ' 
+ 'export2')
}

Run the compiler

java -jar /Users/zavr/node_modules/google-closure-compiler-java/compiler.jar \
--compilation_level ADVANCED --language_out ECMASCRIPT_2017 --formatting PRETTY_PRINT \
--process_common_js_modules --entry_point \
example/commonjs/index.js --module_resolution NODE --js \
example/commonjs/index.js example/commonjs/common-js.js example/commonjs/common-js2.js

Get the output

'use strict';
var a = () => {
  console.log("default common js export2");
};
a.named = () => {
  console.log("named common js export2");
};
var b = {default:() => {
  console.log("default common js export");
}};
b.default.named = () => {
  console.log("named common js export");
};
console.log("requiring a common js from common js:");
console.log(a);
console.log("requiring a common js from ecma:");
console.log(b);

Execute the output

requiring a common js from common js:
{ [Function: a] named: [Function] }
requiring a common js from ecma:
{ default: { [Function: default] named: [Function] } }

This does not make sense. I shouldn’t write .default as confirmed here https://github.com/google/closure-compiler/issues/3308. When it comes to Babel-compiled modules, it’s a nightmare. Babel exports { default: code } itself, so the currently closure-compatible code becomes

import erte from '@a-la/fixture-babel'

console.log(erte.default.default())
console.log(erte.default.c())
console.log(erte.default.b())

And if you actually try to execute in with babel, you get

console.log(_.default.default.default());
                              ^

TypeError: Cannot read property 'default' of undefined

Developers developers developers developers Babel Babel Babel Babel Default Default Default Default

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Comments: 15 (9 by maintainers)

Commits related to this issue

Most upvoted comments

test1.js

module.exports = 'a';

entry.js

import commonJs from './test1.js';
console.log(commonJs); // this should log 'a'

Actual output: java -jar target/closure-compiler-1.0-SNAPSHOT.jar --process_common_js_modules --js test1.js --js entry.js

var module$test1={default:"a"};
console.log(module$test1);
var module$main={};

You’ll notice that the ES Module is referencing the wrong property. That should most certainly be console.log(module$test1.default). It looks like something significant has changed in ES Module rewriting.