Transform CommonJS module into ES module.
const foo = require("foo")
-> import * as foo from "foo";
.require
/exports
statement that is not top-level.Promise.resolve(require("foo"))
-> import("foo")
.There are more examples under test/cases
folder.
const {parse} = require("acorn");
const {transform} = require("cjs-es");
const code = `
function foo() {}
function bar() {}
module.exports = {foo, bar};
`;
transform({code, ast: parse(code, {ecmaVersion: "latest"})})
.then(result => {
console.log(result.code);
/* ->
function foo() {}
function bar() {}
export {foo};
export {bar};
*/
});
When binding the module into one identifier:
const foo = require("foo");
The transformer imports all members from the module by default:
import * as foo from "foo";
To import the default member, mark require()
as // default
:
const foo = require("foo"); // default
Result:
import foo from "foo";
Note that if the identifier is used as the callee of a function/new expression, it would be considered as the default member since the namespace is not callable.
If the module.exports
is assigned with an object pattern:
const foo = "foo";
const bar = "bar";
module.exports = {
foo,
bar
};
The transformer converts it into named exports:
const foo = "foo";
const bar = "bar";
export {foo};
export {bar};
To export the entire object as the default member, mark module.exports
as // default
:
const foo = "foo";
const bar = "bar";
module.exports = { // default
foo,
bar
};
Result:
const foo = "foo";
const bar = "bar";
export default {
foo,
bar
};
Also note that if you set exportStyle
to default
, all named exports would be merged into a namespace object:
const foo = "foo";
const bar = "bar";
exports.foo = foo;
exports.bar = bar;
Result:
const foo = "foo";
const bar = "bar";
const _module_exports_ = {};
export {_module_exports_ as default};
_module_exports_.foo = foo;
_module_exports_.bar = bar;
If the require
/module
/exports
statement are nested, they would be hoisted.
if (foo) {
require("foo").foo();
}
Result:
import * as _require_foo_ from "foo";
if (foo) {
_require_foo_.foo();
}
if (foo) {
module.exports = () => "foo";
} else {
module.exports = () => "bar";
}
Result:
let _module_exports_;
export {_module_exports_ as default};
if (foo) {
_module_exports_ = () => "foo";
} else {
_module_exports_ = () => "bar";
}
if (foo) {
exports.foo = () => "foo";
}
function test() {
exports.foo = () => "bar";
}
Result:
let _export_foo_;
export {_export_foo_ as foo};
if (foo) {
_export_foo_ = () => "foo";
}
function test() {
_export_foo_ = () => "bar";
}
ES6 lazy load import("...")
is async and return a promise. It is interchangeable with Promise.resolve(require("..."))
in CommonJS:
module.exports = () => {
return Promise.resolve(require("foo"));
};
Result:
export default () => {
return import("foo");
};
module.exports
/exports
at the same timeIt is not a good idea to put exports
everywhere, but it is a common pattern:
if (foo) {
exports = module.exports = () => "foo";
} else {
module.exports = exports = () => "bar";
}
exports.OK = "OK";
console.log(module.exports);
All module.export
and exports
would be converted into a single reference:
let _module_exports_;
export {_module_exports_ as default};
if (foo) {
_module_exports_ = () => "foo";
} else {
_module_exports_ = () => "bar";
}
_module_exports_.OK = "OK";
console.log(_module_exports_);
module
aroundIt will generate a module wrapper in this case:
var define = require('amdefine')(module);
define(() => {});
Result:
const _module_ = {exports: {}};
import _require_amdefine_ from "amdefine";
var define = _require_amdefine_(_module_);
define(() => {});
export default _module_.exports;
This module exports following members.
transform
: A function which can convert CJS module synax into ES module syntax.async transform({
parse?: (code: String) => ESTree,
code: String,
ast?: ESTree,
sourceMap?: Boolean = false,
importStyle?: String | async (moduleId) => String,
exportStyle?: String | async () => String,
nested?: Boolean = false,
warn?: (message: String, pos: Number) => void
})
=> TransformResult
parse
is a parser function which can parse JavaScript code into AST. The module will use this function to parse code
. You don't have to provide the parse
function if ast
is set.
code
is the JavaScript source code.
ast
- if you already have the AST of the code, you can set it as ast
so the module don't have to parse the code again.
sourceMap
- if true
then generate the source map.
importStyle
and exportStyle
are used to decide how to transform import/export statements. The value or the value returned by the function must be "named"
or "default"
. By default, the transformer always prefer to use named exports for import/export statements.
If importStyle
is a function, it will only be called once for each moduleId
if needed.
If exportStyle
is a function, it will only be called once if needed.
nested
- By default, only top-level nodes are analyzed and transformed. To analyze the entire tree, set this to true.
warn
- the transformer uses warn
function to emit a warning. If warn
is not set then the transformer will print the message to the console using console.error
.
If an error is thrown during walking the AST, the error has a property pos
which points to the index of the current node.
{
code: String,
isTouched: Boolean,
map: Object | null
}
code
- the result ES source code.
isTouched
- if true
then the code is changed.
map
is the source map object generated by magicString.generateMap
. Only available if isTouched
and the sourceMap
option are both true
.
0.9.2 (Aug 8, 2022)
0.9.1 (Aug 8, 2022)
0.9.0 (Aug 8, 2022)
0.8.2 (Jul 2, 2019)
0.8.1 (Jun 18, 2019)
0.8.0 (Jun 13, 2019)
context.finalImportType
.0.7.0 (Jun 13, 2019)
0.6.4 (Jun 6, 2019)
this
.0.6.3 (Jun 6, 2019)
typeof exports
exists.0.6.2 (Sep 19, 2018)
0.6.1 (Sep 19, 2018)
0.6.0 (Sep 19, 2018)
[, foo]
.exports
and module.exports
to a single reference.0.5.0 (Jul 19, 2018)
0.4.9 (Jun 29, 2018)
0.4.8 (Jun 22, 2018)
0.4.7 (May 15, 2018)
0.4.6 (May 13, 2018)
0.4.5 (May 1, 2018)
0.4.4 (May 1, 2018)
0.4.3 (May 1, 2018)
options.warn
.require
.const foo = module.exports = ...
.0.4.2 (Apr 30, 2018)
0.4.1 (Apr 30, 2018)
0.4.0 (Apr 30, 2018)
options.importStyle
and options.exportStyle
are async now.transform
function is async now.options.hoist
, options.dynamicImport
.options.nested
.0.3.3 (Apr 29, 2018)
options.ast
.0.3.2 (Apr 28, 2018)
.node
property for tree-walk error.0.3.1 (Apr 28, 2018)
0.3.0 (Apr 27, 2018)
hoist
option.dynamicImport
option.0.2.2 (Apr 26, 2018)
isTouched
property.0.2.1 (Apr 26, 2018)
0.2.0 (Apr 26, 2018)
// all
comment.// default
to change import/export style.0.1.0 (Apr 25, 2018)