Skip to content

Babel Modules

Anton edited this page Jul 30, 2019 · 12 revisions

Since Compilerv20190709, the modules imports from Babel have been working semi-correctly, because the default import is not compatible with the way that the default object is exported.

  • Can import named exports.
  • Can import default export.

The following source code is used in the example on this page.

Source (@a-la/fixture-babel)
/**
 * A function that returns `erte`.
 */
const erte = () => {
  return 'erte'
}

/**
 * A function that returns `c`.
 * @param {string} input
 */
export const c = (input) => {
  return 'c' + (input ? `-${input}` : '')
}

/**
 * A function that returns `b`.
 * @param {number} times
 */
export const b = (times) => {
  return 'b' + (times ? `-${times}` : '')
}

export default erte
Babel-compiled
Show Code
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.b = exports.c = void 0;

/**
 * A function that returns `erte`.
 */
const erte = () => {
  return 'erte';
};
/**
 * A function that returns `c`.
 * @param {string} input
 */


const c = input => {
  return 'c' + (input ? `-${input}` : '');
};
/**
 * A function that returns `b`.
 * @param {number} times
 */


exports.c = c;

const b = times => {
  return 'b' + (times ? `-${times}` : '');
};

exports.b = b;
var _default = erte;
exports.default = _default;
The script to import Babel-compiled modules in Closure Compiler is now:
import erte from 'babel-module'

console.log(erte.default())
console.log(erte.c(''))
console.log(erte.b(''))
  • ✅ Do import a single default object.
  • ⛔️ Do NOT import named exports.

Although it's impossible to use such code with Babel runtime, the code above can be compiled using Google Closure Compiler.

Command & Warnings
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 --package_json_entry_names module,main \
--entry_point e/b.js --externs ../externs/v8/global.js --externs \
../externs/v8/global/buffer.js --externs ../externs/v8/nodejs.js
Modules: b/i.js
b/i.js:6: WARNING - [JSC_TYPE_MISMATCH] assignment to property b of module$b$i.default
found   : undefined
required: function(?): ?
exports.default = exports.b = exports.c = void 0;
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

b/i.js:6: WARNING - [JSC_TYPE_MISMATCH] assignment to property c of module$b$i.default
found   : undefined
required: function(string): ?
exports.default = exports.b = exports.c = void 0;
                              ^^^^^^^^^^^^^^^^^^

0 error(s), 2 warning(s), 94.4% typed
The command generates some warnings, but no errors.
The generated code and output
'use strict';
var a = {};
Object.defineProperty(a, "__esModule", {value:!0});
a.default = a.a = a.b = void 0;
a.b = b => "c" + (b ? `-${b}` : "");
a.a = b => "b" + (b ? `-${b}` : "");
a.default = () => "erte";
console.log(a.default());
console.log(a.b(""));
console.log(a.a(""));
erte
c
b
Trying to execute the output produces the correct result. OK, but what happens when we actually try to execute such program with @babel/register? This is needed for testing and development.
MacBook:fixture-babel zavr$ node erte
erte/erte.js:7
console.log(_build.default.default());
                                  ^

TypeError: _build.default.default is not a function
    at Object.<anonymous> (erte/erte.js:3:13)
    at Module._compile (module.js:653:30)
    at Module._compile (pirates/index.js:99:24)
    at Module._extensions..js (module.js:664:10)
    at Object.newLoader [as .js] (pirates/index.js:104:7)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)

Conclusion

  • no ide support
  • no development environment
  • default.default
Because of referring to the default import as .default, the compatibility with Babel is broken. It's better to use ÀLaMode which is compatible with Closure Compiler.

Importing { named } modules on Babel-compiled modules is not supported because they are still require.js modules! The example below demonstrates what happens:

import erte, { c, b } from '@fixture/babel'

console.log(erte())
console.log(c())
console.log(b())
Command & Generated JS
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 --package_json_entry_names module,main \
--entry_point e/1.js --externs ../externs/v8/global.js --externs \
../externs/v8/global/buffer.js --externs ../externs/v8/nodejs.js
Dependencies: @a-la/fixture-babel
Running Google Closure Compiler 20190709..          
depack e/1 -c -a -p --process_common_js_modules stderr
Exit code 2
e/1.js:1: ERROR - [JSC_DOES_NOT_HAVE_EXPORT] Requested module does not have an export "b".
import erte, { c, b } from '@a-la/fixture-babel'
^

e/1.js:1: ERROR - [JSC_DOES_NOT_HAVE_EXPORT] Requested module does not have an export "c".
import erte, { c, b } from '@a-la/fixture-babel'
^

2 error(s), 0 warning(s)
stdout

The named import syntax on CommonJS modules is not supported unless there is an ECMA6 version of the script which will be detected by static analysis in the module field of the package.json file. Therefore it's good idea to publish the module also with the build for the compiler to include the source code of the package in another package being built.

Clone this wiki locally