-
Notifications
You must be signed in to change notification settings - Fork 0
Babel Modules
Since Compilerv20190709
, the modules imports from Babel have been working semi-correctly, because although it is possible to compile a Babel-transpiled module with Closure Compiler, the compatibility between the two is not ensured for default exports.
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; |
Because of how CommonJS Compatibility is implemented, all RequireJS modules will only make accessible a single default object, without named exports.
The script to import Babel-compiled modules in ES6 Code is now: | |
---|---|
import erte from '@fixture/babel'
console.log(erte.default())
console.log(erte.c(''))
console.log(erte.b('')) |
|
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
|
Because of referring to the default import as .default , the compatibility with Babel is broken for default imports. Therefore, it's better to use ÀLaMode for transpilation which is compatible with Closure Compiler. |
To see what happens when trying to import { named }
exports, refer to the example below.
import erte, { c, b } from '@fixture/babel'
console.log(erte())
console.log(c())
console.log(b())
Command & Generated JS |
---|
|
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 '../b/i'
^
e/1.js:1: ERROR - [JSC_DOES_NOT_HAVE_EXPORT] Requested module does not have an export "c".
import erte, { c, b } from '../b/i'
^
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. Thus it's a 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.