Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sidvishnoi/esm-to-cjs

Transform ESM to Common JS for present NodeJS, without any junk wrappers or useless renaming
https://github.com/sidvishnoi/esm-to-cjs

commonjs esm esmodules gulp-plugin nodejs string-manipulation transformer

Last synced: 10 days ago
JSON representation

Transform ESM to Common JS for present NodeJS, without any junk wrappers or useless renaming

Awesome Lists containing this project

README

        

## esm-to-cjs

> Transform ESM to Common JS for present NodeJS, without any junk wrappers or useless renaming.

## Motivation

I was working on a TypeScript project for NodeJS and using ES modules. The transformations to CommonJS by TypeScript (or by Babel + plugins) causes variable renaming (prefixing) and adds some wrapper functions to the transformed code.

I was not happy with this transformation. So I created this tool to convert the ESM import/exports to the kinds that a NodeJS developer would write today.

``` js
// input
import { resolve as resolvePath } from "path";
resolvePath("./hello")

// what i wanted
const { resolve: resolvePath } = require("path");
resolvePath("./hello")

// typescript gave me:
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
path_1.resolve("./hello");
```

``` js
// input
async () => {
const path = await import("path");
}

// what i wanted
async () => {
const path = require("path");
}

// typescript gave me:
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
async () => {
const path = await Promise.resolve().then(() => __importStar(require("path")));
};
```

``` js
// input
export const foo = 5;
console.log(foo);

// what i wanted
const foo = 5;
module.exports = {
foo
}

// typescript gave me:
Object.defineProperty(exports, "__esModule", { value: true });
exports.foo = 5;
console.log(exports.foo);
```

``` js
// input
export { foo as wow, bar } from "baz";
export { baz } from "lorem";

// what i wanted
const { foo: __foo__, bar: __bar__ } = require("baz");
module.exports = {
wow: __foo__,
bar: __bar__,
baz: require("lorem").baz
}

// typescript gave me
Object.defineProperty(exports, "__esModule", { value: true });
var baz_1 = require("baz");
var lorem_1 = require("lorem");
exports.wow = baz_1.foo;
exports.bar = baz_1.bar;
exports.baz = lorem1.baz;
```

So, I created this tool using some simple string manipulations. A lot of sample input/output are [available here](https://github.com/sidvishnoi/esm-to-cjs/blob/main/test/fixtures/supported.md).

## Limitations

- `import * as foo from "bar";` is converted to `const foo = require("bar");`. Not sure if this is what everyone wants. I did it as per my project requirements.
- Also, `import foo from "bar";` is converted to `const foo = require("bar").default;"`.
- No support for `export *` syntax.
- No mixing of default import, named imports and `import *` in same statement.
- See Bug: ["The simpler transform is semantically wrong"](https://github.com/sidvishnoi/esm-to-cjs/issues/4)

## Packages

This tool is available in form of two packages:

- `esm-to-cjs`: the core module.
- `gulp-esm-to-cjs`: as a gulp plugin.

### `esm-to-cjs`

This is the core module. It includes a tokenizer and a transformer. I didn't use some specific JS parser due to overheads and created my own using string manipulation.

**Install:**

```
npm i --save-dev esm-to-cjs
```

**Usage:**

``` js
const { runTransform } = require("esm-to-cjs");

const input = `import { resolve as resolvePath } from "path";`
const options = { quote: "double" }; // see details below
const output = runTransform(input, options);
console.log(output);
// const { resolve: resolvePath } = require("path");
```

**Options:**

``` yaml
quote:
type: string
default: "double"
available: "double" | "single"
description: Tells parser what kind of quotes you use in module names, i.e. like `from "moduleName"`

lenDestructure:
type: number (of characters)
default: 60
description: Used by parser to improve performance. Set to a higher value if your object destruturing statements are longer.

lenModuleName:
type: number (of characters)
default: 20
description: Used by parser to improve performance. Set to a higher value if your module names are longer.

lenIdentifier:
type: number (of characters)
default: 60
description: Used by parser to improve performance. Set to a higher value if your identifier names are longer.

indent:
type: number
default: 2
description: Indentation (spaces) in output code.
```

### `gulp-esm-to-cjs`

Gulp plugin for esm-to-cjs.

**Install**:

```
npm i --save-dev gulp-esm-to-cjs
```

**Usage**:

``` js
// gulpfile.js
const esmToCjs = require("gulp-esm-to-cjs");

function convert() {
return gulp
.src(src)
.pipe(esmToCjs(options))
.pipe(gulp.dest(dest));
}
module.exports.convert = convert;

// use as:
// $ gulp convert
```

## Contributing

- If you've issues regarding the project - documentation, supported features and transformations etc., please file them on [GitHub](https://github.com/sidvishnoi/esm-to-cjs/issues) where we can discuss.
- Pull requests are welcome!
- Please bear in mind that I created this project in a hurry, so the code isn't very impressive. Also, I didn't add all the transformations. See limitations above. Would be nice if we can overcome them!