2.27.3 β€’ Published 1 year ago

to-esm v2.27.3

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

Test workflow nycrc Coverage Version workflow npm version


Description

A tool to convert Commonjs files into ESM files. To-esm can be used for generating hybrid modules. Do all of your coding using CommonJs, then convert your code into ESM at build or packaging times.


Notes

πŸͺ› "to-esm" allows generating ESM code from your existing CommonJs code in the least destructive way possible.

As the generated ESM code will still resemble the original code, you can still keep using cjs without worry. You can generate a new ESM version whenever your system needs a build or set up a watcher.

🚫 CommonJs offers many advantages by its dynamic nature as it seems very back-end oriented. On the other hand, ESM is more designed for a front-end approach and module bundling (which often hides the differences between the two systems) .

V8 is likely developed around the idea that Chrome should not touch the OS file system for evident security matters. Therefore, even though switching to ESM seems ideal, many "hiccups" still exist.

Hybrid modules make things easier. Note that to-esm can help with this.


Installation

npm install to-esm -g

Usage

to-esm <filepath> [--output=<dirpath>] [--html=<filepath>] [--noheader] [--target=< browser|esm|package >] 
[--prefixpath=<dirpath>] [--bundle=<filepath>] [--watch] [--update-all] [--minify] [--no-bundle-minify]

Examples

πŸ“‹

Generate ESM code

To generate an .mjs(ES module) file from a .js file do:


# πŸ’» < Command
$> to-esm  example/cjs/input.js

🚫 NOTE: to-esm should run from the project root folder.


Click on the arrow to expand or collapse
πŸ“project                 ⇽ Ran from here
β”‚
β””β”€β”€β”€πŸ“example
β”‚   β”‚
β”‚   β””β”€β”€β”€πŸ“code
β”‚       β”‚   πŸ“ library.js
β”‚       β”‚   πŸ“ demo.js   ⇽
β”‚       β”‚   ...
β”‚

πŸ“ library.js ↴

function hi()
{
    console.log(`I wanted to say hi!`)
}

module.exports = hi;

πŸ“ demo.js ↴

const hi = require("./library.js");
hi();

./demo.js => ./demo.mjs πŸ“

πŸ“project
β”‚
β””β”€β”€β”€πŸ“example
β”‚   β”‚
β”‚   β””β”€β”€β”€πŸ“code
β”‚       β”‚   πŸ“„ library.js
β”‚       β”‚   πŸ“„ demo.js
β”‚       β”‚   πŸ“ library.mjs   ⇽
β”‚       β”‚   ...
β”‚
β”” πŸ“ demo.mjs     ⇽

πŸ“ library.js ↴

function hi()
{
    console.log(`I wanted to say hi!`)
}

export default hi;

πŸ“ demo.js ↴

import hi from "./example/code/library.mjs";

hi();

to-esm will convert the entry point inside the working directory. The others will depend on the source location.


πŸ“‹

Generate code into a dedicated directory

--output < folder >

# πŸ’» < Command
$> to-esm  example/cjs/input.cjs --output generated/esm

Click on the arrow to expand or collapse
πŸ“project                 ⇽ Ran from here
β”‚
β””β”€β”€β”€πŸ“example
β”‚   β”‚
β”‚   β””β”€β”€β”€πŸ“code
β”‚       β”‚   πŸ“ library.js
β”‚       β”‚   πŸ“ demo.js   ⇽ 🚩
β”‚       β”‚   ...
πŸ“project                 
β”‚
β””β”€β”€β”€πŸ“example
β”‚   β”‚
β”‚   β””β”€β”€β”€πŸ“code
β”‚       β”‚   πŸ“ library.js
β”‚       β”‚   πŸ“ demo.js   
β”‚       β”‚   ...
β”‚
β””β”€β”€β”€πŸ“generated                   ⇽ 🚩
β”‚   β””β”€β”€β”€πŸ“esm
β”‚       β””β”€β”€β”€πŸ“example   
β”‚           β””β”€β”€β”€πŸ“code
β”‚                  πŸ“ library.mjs ⇽ 🚩
β”‚                  πŸ“ demo.mjs    ⇽ 
β”‚                   ...
Checking the conversion has succeeded
node generated/esm/example/code/demo.mjs

πŸ“‹

Remove automatically generated header

--noheader

# πŸ’» < Command
$> to-esm  example/cjs/input.cjs --output generated --noheader

⏳ - Without the --noheader option

/**
 * DO NOT EDIT THIS FILE DIRECTLY.
 * This file is generated following the conversion of
 * [./example/code/demo.js]{@link ./example/code/demo.js}
 *
 **/
import hi from "./example/code/library.mjs";

hi();

βŒ› With the --noheader option

import hi from "./example/code/library.mjs";

hi();

πŸ“‹

Generate code for the browser

--target < browser | esm | package >

# Command < πŸ’»
$> to-esm  example/cjs/input.cjs --output generated --target browser

Click on the arrow to expand or collapse

1- When generating code for the browser, **

to-esm** will display a warning when the code uses a native Node library.

πŸ“ demo.js ↴

const path = require("path");                   // See directives below to see how to remove this call
function hi()
{
    console.log(`I wanted to say hi!`)
}

module.exports = hi;
During conversion:
πŸ’» >
to-esm: (1130) ================================================================
to-esm: (1132) Processing: ./example/code/demo.js
to-esm: (1134) ----------------------------------------------------------------
to-esm: (1060) βœ” SUCCESS: Converted [./example/code/demo.js] to [generated-browser\demo.mjs]
to-esm: (1150) 
to-esm: (1130) ================================================================
to-esm: (1132) Processing: ./example/code/library.js
to-esm: (1134) ----------------------------------------------------------------
to-esm: (1017) path is a built-in NodeJs module. ⇽ 🚩
to-esm: (1060) βœ” SUCCESS: Converted [./example/code/library.js] to [generated-browser\example\code\library.mjs]
to-esm: (1150) 

2- To load your files in the HTML code, you only point to the entry file (demo.js).

The browser will automatically load the other files.

img.png

demo.mjs is the entrypoint.

The browser automatically loads all the related files.


Click on the arrow to expand or collapse

When there is a requirement to load libraries from the node_modules folder, to-esm will generate a converted copy of the files to the output directory.

πŸ“ demo.js ↴

const toAnsi = require("to-ansi");
const rgbHex = require("rgb-hex-cjs");
const {COLOR_TABLE, SYSTEM} = require("./some-lib.js");
// ...
πŸ“project  
└─── πŸ“ original  
     │─── πŸ“ index.html
     │─── πŸ“ demo.js
     │─── πŸ“ some-lib.js
     β”‚
     └─── πŸ“ generated  
           │─── πŸ“ demo.mjs             β¬… 🚩
           │─── πŸ“ some-lib.mjs         β¬… 🚩
           β”‚
           └─── πŸ“ node_modules         β¬… 🚩
               β”‚
               β””β”€β”€β”€πŸ“ rgb-hex
               β”‚   └── πŸ“ index.cjs
               β”‚     
               β””β”€β”€β”€πŸ“ to-ansi
                   └── πŸ“ index.cjs 
                         

The two libraries used will be easily accessible by the system and ease the bundling in production. See the importmap section to have a more modular approach.


πŸ“‹

Generate importMaps within html files

--html < pattern | html >

# Generates => πŸ“ ./demo.mjs & update index.html
$> to-esm example/cjs/demo.cjs --html index.html

🚫 NOTE: When this option is used, the target is always "browser". --target.


An import map will allow writing imports like this
import rgbhex from "rgb-hex"
instead of
import rgbhex from "../../../path/to/rgb-hex.mjs"

Click on the arrow to expand or collapse
Before

πŸ“ index.html ↴

<!DOCTYPE html>
<html lang="en">
    <head></head>
    <body>
        <script type="module" src="actual/demo-test.mjs"></script>
    </body>
</html>
After
<!DOCTYPE html>
<html lang="en">
    <head>
        <script type="importmap">
        {
          "imports": {
            "rgb-hex": "./node_modules/rgb-hex/index.cjs"
          }
        }
    
        </script>
    </head>
    <body>
        <script type="module" src="actual/demo-test.mjs"></script>
    </body>
</html>

importmap allows some more elaborated setups where third party caching will be entirely handled by the browser.


πŸ“‹

Convert files with patterns

You can have multiple files converted in one go. It can be helpful if some files are not connected.

$> to-esm  --input="example/cjs/*.?(c)js" --output=example/esm/


Options to generate code for npm packages --target package

🚫 NOTE: This option is experimental

To generate a non-bundled package code for npm, use this option. It will add an extra prefix ../../ to all relative path to third party modules.


Options to correct relative paths to third party modules

If your code point to a npm module with the option --target browser, the system will convert the import to the module location entrypoint.

For instance:

πŸ“ source.cjs ↴

const toAnsi = require("to-ansi");

Will be converted to this path (or similar):

πŸ“ source.mjs ↴

import toAnsi from "../../node_modules/to-ansi/index.mjs";

The path will be okay at conversion time. However, if the generated file (source.mjs) is required inside a browser, the path may no longer be valid. It will depend on your server configuration.

The option --prefixpath allows correcting the issue by prepending some value to the target path. This way, you can redirect the converted path to point to the correct location on your server.

# πŸ’» < Command
to-esm source.cjs --output out/ --prefixpath ../somewhere/

πŸ“ source.mjs ↴

import toAnsi from "../somewhere/../../node_modules/to-ansi/index.mjs";

πŸͺ›

Options (via command line)

OptionsDescriptionExpectdefault
filepathFile or pattern to convertfile path
--bundleGenerate minified bundle for esm environmentfile path
--bundle-browserGenerate minified bundle for browser environmentfile path
--bundle-cjsGenerate minified bundle for cjs environmentfile path
--bundle-esmSame as abovefile path
--entrypointExplicitely set entry point (otherwise use the first file set in cli)file path
--extensionSet generated files extensionstring.mjs
--force-lfReplace CLRF with LF
--htmlhtml files to receive importmapsglob
--keep-externalDo not try to copy files from absolute paths into generated folderbooleanfalse
--keepExistingOptions to skip already converted files
--minifyOptions to minify converted filesboolean
--nmBrowserImportedDestination folder name for imported third parties when target is "browser"directory path
--no-commentsOptions to remove comments from converted filesbooleanfalse
--no-bundle-minifyOptions to not minify bundled filesbooleanfalse
--noHeaderOptions to not generate automatic headerbooleanfalse
--outputOutput directorydirectory path
--prefixpathAdd a path to paths targeting third party modulesdirectory path
--resolve-absoluteExtra folders to look for when trying to solve absolute imported pathsstring
--skipEsmResolutionDo not try to resolve third party librariesbooleanfalse
--skipLinksDon't follow links (It will not convert linked files, but resulting links will need manual updates)booleanfalse
--targetSetting the targeted environmentesm / browser / packageesm
--update-allAutomatically update package.json to set entry points
--use-bundleWhen updating package.json use bundled/minified code
--watchWatch mode to automatically apply conversions when changes detecteddirectory path
--subRootDirAllow to retarget the output sub-directorytrue

πŸ’Ž

Advanced Options (via config file)

To apply advanced options, create a config file (.to-esm, .to-esm.json or .to-esm.cjs) and it will be automatically loaded. Otherwise, you can create a file with a custom name and explicitly tell the system to load it.

to-esm --config=.my-to-esm-config.cjs

Keys within the config file are case sensitive.

Options to replace strings before and after every conversion

replaceStart, replaceEnd

πŸ“ .toesm.cjs ↴

module.exports = {
    replaceStart: [
        {
            search : "const chalk = require(\"chalk\");",
            replace: "// ***"
        },
        {
            search : /const\s+colors\s*=\s*require\(.colors.\);/g,
            replace: "// ***"
        }
    ],
    replaceEnd  : [
        {
            search : `// ***`,
            replace: "// --------- chalk and colors were replaced ----------------"
        }
    ]
}
PropertiesDescription
replaceStartwill perform a replacement **_before** doing the conversion to ESM_
replaceEndwill perform a replacement **_after** doing the conversion to ESM_
replaceStart.searchThe regex pattern or string to replace
replaceStart.replaceThe replacement sentence

Options to use two different modules of the same library.

"replaceModules": ...

Sometimes, you may find libraries where only ESM is available when CJS was available on older versions.

This option allows setting a different version depending on the environment used.

For instance, the module "chalk" uses ESM for its Export on its latest version (5.0.0) and CJS for the older version (4.

1.2).

You can setup toesm to use the appropriate version:

πŸ“ .toesm.cjs ↴

module.exports = {
    replaceModules:
        {
            "rgb-hex":
                {
                    cjs: {
                        name: "rgb-hex-cjs",             // β¬… 🚩 .cjs files will use 
                                                         // ... = require("rgb-hex-cjs")  
                                                         // to load the module (v3.0.0)
                        version: "@^3.0.0"
                    },
                    esm: {
                        version: "@latest"                  // β¬… 🚩 .mjs files will use
                                                            // import ... from "rgb-hex"
                                                            // to load the module
                    }
                }
        },
}        

In the .cjs file to convert, you would write:

const rgbhex = require("rgb-hex-cjs");

Which is going to be transformed to:

import rgbhex from "rgb-hex";

PropertiesDescription
replaceModules\The module we want to use two different versions with
replaceModules\.cjsThe module version to use with CommonJs files
replaceModules\.mjsThe module version to use with converted files

Options to set HTML sources and manipulate importmaps.

"html": ...

module.exports =
    {
        html:
            {
                pattern         : "/index.html",
                importmap       :
                    {
                        "my-project": "../node_modules/my-project/src/esm/add.mjs",
                        "lodash"    : "https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"
                    },
                importmapReplace: [
                    {
                        search : "./node_modules",
                        replace: `/node_modules`,
                    }
                ],
            }
    }
PropertiesDescription
patternHTML file pattern where importmap needs updating
importmapvalue to add to HTML files
importmapReplaceApply replacements on the importmap list

The options above will be deployed as below:
<script type="importmap">
        {
          "imports": {
            "my-project": "../node_modules/my-project/src/esm/add.mjs",
            "lodash": "https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"  // ← Example 
          }
        }
    
</script>

Allowing to write this:

import {add} from "my-project"

NOTE: You can imagine improved caching offered by browsers soon


πŸ’‰

Directives

Directives allow more control over the generated code.


Directives to replace code directly from the source.

You can, if you want, also use some to-esm directives within the code. For instance, the code below will not appear when the target is a browser.

/** to-esm-browser: remove **/
const path = require("path");
const fs = require("fs");
const os = require("os");
/** to-esm-browser: end-remove **/

Directives to add code to the source.

It is also possible to add code.

πŸ“ code.cjs ↴

/** to-esm-browser: add
 this.realConsoleLog("LogToFile is not supported in this environment. ")
 **/

In this example, after conversion, the above code will become this:

πŸ“ code.mjs (with target browser) ↴

this.realConsoleLog("LogToFile is not supported in this environment. ")

Directives to ignore code during the parsing so that it won't be converted by mistake.

/** to-esm-all: skip **/
console.log("Skip this");
/** to-esm-all: end-skip **/

Directives to keep the target file as it is.

/** to-esm-all: do-not-overwrite **/

If the .mjs file already exists and contains this directive, it will not be overwritten.


Remove comments from generated code

--no-comments

The example below will remove all comments from the scanned .cjs files.

# πŸ’» < Command
$> to-esm example/**/*.cjs --output generated --target cjs


πŸ’‘

Working with both CJS and ESM

You may want to work with both CommonJs and ESM together. So, you benefit from both worlds.

The CommonJs approach is a dynamic one. So, for example, you can do things like:

if (a)
{
    // load module a
    require(a);
}
else
{
    // load module b
    require(b)
}

With ESM and its static approach, loading both modules is necessary.

    // load module a
import "a";
// load module b
import "b";

πŸ’‘

Some conventions to write code for both CommonJs and ES Modules

Here are a few guides to writing code easily convertible.

Use named exports

For having the best compatibility between the two systems, it is best to use named exports.

Replace structures like:

module.exports = {
    TABLE1  : ...,
    TABLE2  : ...,
    otherKey: ...
}

with:

module.exports.TABLE1 =
...
;
module.exports.TABLE2 =
...
;
module.exports.otherKey =
...
;

Or, if you want to provide a default export too:

// Default export
module.exports = {
    TABLE1, TABLE2, ...
}

// Named export
module.exports.TABLE1 =
...
;
module.exports.TABLE2 =
...
;
module.exports.otherKey =
...
;

Use simple "require"

Rather than using "requires" like below forms (or more complex ones)

🀏 ↴

const Something = require("electron-data-exchanger").myThing;
const anything = require("electron-data-exchanger")(...);

Which may introduce temporary variables (_toesmTemp1)

import _toesmTemp1 from "electron-data-exchanger";

const Something = _toesmTemp1.myThing;

It is best to have them uncomplicated, so the conversion is straightforward.

πŸ‘ ↴

const MySomething = require("electron-data-exchanger");
const myAnything = require("electron-data-exchanger");

// ... The code that uses what was required

Assignment during declaration

to-esm will not convert the below code as it would require some refactoring that would make the generated code not resemble the original code.

Ambiguous form for to-esm
let myVar = "something";

// ...

myVar = require("my-module")
Expected form:
let myVar = require("my-module");

Use directives to solve issues with environments

Library targeting both Node and the Browser

If it needs to do an import in an ESM environment but not in the Browser, you can use directives to solve the issue.

/** to-esm-browser: add
 let myMod = () => { return "somethings"; };
 **/

/** to-esm-browser: remove **/
let myMod = require("my-mod");
/** to-esm-browser: end-remove **/
The code above will convert to:

Node

import myMod from "my-mod";

Browser

let myMod = () =>
{
    return "somethings";
};

πŸ’‘

Create a Hybrid Library with to.esm

1- Use the .cjs extension instead of .js

πŸ“project  
└─── πŸ“ index.cjs                β¬… 🚩
└─── πŸ“ package.json
└─── πŸ“example
β”‚    β”‚
β”‚    β””β”€β”€β”€πŸ“code
β”‚        └───   πŸ“ library.cjs   ⇽ 🚩
β”‚               ...
β”‚
└─── πŸ“ node_modules
β”‚    └── ...
         

2- Run to-esm against the entry point and update package.json

$> to-esm index.cjs --update-all

🚫 The option --update-all will modify your package.json to make it point to your entrypoint.

// Will point to .index.cjs
require("your-module-name")
 
// Will point to .index.mjs
import("your-module-name") 

Click on the arrow to expand or collapse

πŸ“ ./package.json ↴

{
  "name": "my-project",
  "main": "./index.cjs",
  "scripts": {
    "build": "to-esm index.cjs"
  },
  "devDependencies": {
    "to-esm": "file:.."
  }
}

πŸ“ ./index.cjs ↴

const hi = require("./example/code/library.cjs");
hi();

πŸ“ ././example/code/library.cjs ↴

function hi()
{
    console.log(`I wanted to say hi!`)
}

module.exports = hi;

πŸ“ ./package.json ↴

{
  "name": "my-project",
  "main": "./index.cjs",
  "scripts": {
    "build": "to-esm index.cjs"
  },
  "devDependencies": {
    "to-esm": "file:.."
  },
  "module": "./index.mjs",
  β¬…
  🚩
  "type": "module",
  β¬…
  🚩
  // (Change to commonjs if you don't want to use .cjs extension)
  "exports": {
    ".": {
      "require": "./index.cjs",
      β¬…
      🚩
      "import": "./index.mjs"
      β¬…
      🚩
    }
  }
}

πŸ“ ./index.mjs ↴

/**
 * DO NOT EDIT THIS FILE DIRECTLY.
 * This file is generated following the conversion of
 * [./index.cjs]{@link ./index.cjs}
 *
 **/
import hi from "./example/code/library.mjs";

hi();

πŸ“ ././example/code/library.mjs ↴

/**
 * DO NOT EDIT THIS FILE DIRECTLY.
 * This file is generated following the conversion of
 * [./example/code/library.cjs]{@link ./example/code/library.cjs}
 *
 **/
function hi()
{
    console.log(`I wanted to say hi!`)
}

export default hi;

3- Your code is generated.

To test it in NodeJs.

node index.mjs


πŸ’‘

Create a Hybrid Library with to.esm supporting the browser

1- Use .cjs extensions instead of .js

πŸ“project  
└─── πŸ“ index.cjs                β¬… 🚩
└─── πŸ“ package.json
└─── πŸ“example
β”‚    β”‚
β”‚    β””β”€β”€β”€πŸ“code
β”‚        └───   πŸ“ library.cjs   ⇽ 🚩
β”‚               ...
β”‚
└─── πŸ“ node_modules
β”‚    └── ...
         

2- Run to-esm against en entry point

For the browser
$> to-esm index.cjs --output ./generated --target browser --bundle-browser dist/index.min.js

Click on the arrow to expand or collapse

πŸ“ ./index.cjs ↴

const hi = require("./example/code/library.cjs");
hi();

πŸ“ ././example/code/library.cjs ↴

function hi()
{
    console.log(`I wanted to say hi!`)
}

module.exports = hi;

πŸ“ ./index.mjs ↴

/**
 * DO NOT EDIT THIS FILE DIRECTLY.
 * This file is generated following the conversion of
 * [./index.cjs]{@link ./index.cjs}
 *
 **/
import hi from "./example/code/library.mjs";

hi();

πŸ“ ././example/code/library.mjs ↴

/**
 * DO NOT EDIT THIS FILE DIRECTLY.
 * This file is generated following the conversion of
 * [./example/code/library.cjs]{@link ./example/code/library.cjs}
 *
 **/
function hi()
{
    console.log(`I wanted to say hi!`)
}

export default hi;

πŸ“ ./dist/index.min.js ↴ (Generated because of the --bundle option)

const c = {"95c93": {}};
c["95c93"].default = function ()
{
    console.log("I wanted to say hi!")
};
{
    c.bbc7e = {};
    let b = c["95c93"].default;
    b()
}

3- Your code is generated.

πŸ“project  
└─── πŸ“ index.cjs                
└─── πŸ“ package.json
└─── πŸ“generated                 
β”‚    β”‚
β”‚    └─── πŸ“ index.mjs          β¬… 🚩
β”‚    β”‚     
β”‚    └─── πŸ“ ...
β”‚
└─── πŸ“ dist         
β”‚    └── index.min.js           β¬… 🚩
         
Insert the JavaScript browser version
...
<body>
    <script type="module" src="generated/index.mjs"></script>
</body>...
Usage for the ESM version
import "..."

from
"index.mjs" 

πŸ’‘

Make your CJS module ESM compatible in one go.

Start by creating a .cjs file (or migrate your code) to have this structure.

πŸ“project  
└─── πŸ“ package.json
└─── πŸ“ cjs
β”‚    └── πŸ“ index.cjs
         

Run to-esm against en entry point

$> to-esm cjs/index.cjs --output esm/ --bundle-esm bundle/mycode.min.mjs --bundle-cjs bundle/mycode.min.cjs 
--bundle-browser dist/mycode-browser.min.js --update-all --use-bundle --watch
πŸ“project  
└─── πŸ“ package.json
└─── πŸ“ cjs
β”‚    └── πŸ“ index.cjs                       β¬… 🚩 Original code
└─── πŸ“ mjs
β”‚    └── πŸ“ mycode.mjs                      β¬… ESM Converted code                     (--output esm/)
└─── πŸ“ bundle
β”‚    └── πŸ“ mycode.min.mjs                  β¬… Bundled and minified code for ESM      (--bundle-esm bundle/mycode.min.mjs)
β”‚    └── πŸ“ mycode.min.cjs                  β¬… Bundled and minified code for CommonJs (--bundle-cjs bundle/mycode.min.mjs)
└─── πŸ“ dist
β”‚    └── πŸ“ mycode-browser.min.mjs          β¬… Bundled and minified code for browsers (--bundle-browser bundle/mycode.min.
mjs)   
         
  • The option --update-all will automatically modify your package.json to make your module load the correct file depending on the environment

  • The option --use-bundle will make --update-all configure the module to use minified and bundled versions ("mycode.min.mjs", "mycode.min.cjs") when a "require" or "import" is done against your module (Otherwise, it loads " index. cjs" and "mycode.mjs")

  • The option --watch will automatically regenerate files when a change happens to the original cjs file (. /cjs/index.cjs)

This is it. Your module is fully hybrid, and you can keep working with CommonJs while not worrying about ESM.


Click on the arrow to expand or collapse

πŸ“ ./index.cjs ↴

const hi = require("./example/code/library.cjs");
hi();

πŸ“ ././example/code/library.cjs ↴

function hi()
{
    console.log(`I wanted to say hi!`)
}

module.exports = hi;

πŸ“ ./index.mjs ↴

/**
 * DO NOT EDIT THIS FILE DIRECTLY.
 * This file is generated following the conversion of
 * [./index.cjs]{@link ./index.cjs}
 *
 **/
import hi from "./example/code/library.mjs";

hi();

πŸ“ ././example/code/library.mjs ↴

/**
 * DO NOT EDIT THIS FILE DIRECTLY.
 * This file is generated following the conversion of
 * [./example/code/library.cjs]{@link ./example/code/library.cjs}
 *
 **/
function hi()
{
    console.log(`I wanted to say hi!`)
}

export default hi;

πŸ“ ./dist/index.min.js ↴ (Generated because of the --bundle option)

const c = {"95c93": {}};
c["95c93"].default = function ()
{
    console.log("I wanted to say hi!")
};
{
    c.bbc7e = {};
    let b = c["95c93"].default;
    b()
}

3- Your code is generated.

πŸ“project  
└─── πŸ“ index.cjs                
└─── πŸ“ package.json
└─── πŸ“generated                 
β”‚    β”‚
β”‚    └─── πŸ“ index.mjs          β¬… 🚩
β”‚    β”‚     
β”‚    └─── πŸ“ ...
β”‚
└─── πŸ“ dist         
β”‚    └── index.min.js           β¬… 🚩
         
Insert the JavaScript browser version
...
<body>
    <script type="module" src="generated/index.mjs"></script>
</body>...
Usage for the ESM version
import "..."

from
"index.mjs" 


πŸ’‘

Some thoughts

When you bundle your code, you usually introduce code from other third parties. Therefore, it may create implicit code repetition.

Tree shaking eliminates unnecessary code; however, it is done at "compile" time. It means it can not detect what has been repeated (Even though Tree shaking technics seem to go beyond simple dead code elimination).

Also, most IDEs detect the use of dead code, which also mitigates tree shaking greatness.

For instance, let's say you use two libraries. Lib1.js and Lib2.js.

Lib1 uses lodash and has been minified into lib1.min.js Lib2 also uses lodash and has been minified into lib2.min.js.

When you bundle your code containing lib1.js and lib2.js, you add lodash two times (or some functions of it).

Therefore, there are advantages to not systematically using bundled code.

  • 1- Letting the browser cache all shared libraries is one of them; therefore, having the best caching system (Chrome or Firefox would surely know the best way to cache files coming from a common ground).
  • 2- Avoiding automated code repetition
  • 3- Less painful and lengthy wait when the codebase becomes enormous.
  • 4- Make Hot Reloading obsolete. Instead, use Cold Reloading (you reload when you save, when not, the bundler has finished its compilation).
  • 5- Working directly on the "original code" rather than an unmaintainable one (even using source maps sometimes does not solve all the issues).


πŸ’ŠπŸ”₯

Why use to-esm?

  • You can keep on working with CommonJs as usual and generates your ESM code when necessary
  • If CommonJs ever becomes obsolete, you can remove your CommonJs code and use the generated one directly
  • The generated ESM code (non-bundled) looks close to the original CommonJs one.

πŸ”₯πŸ’₯

Plus

Benefits:

  • You do not need a source map when working in development mode.
  • You do not need to bundle your code in development.
  • You benefit directly from your browser caching ability (No more bundling of shared libraries)
  • The generated code looks like the original code.
  • ...

Changelog

current:
  • Fix aliases conversion
  • Fix conversion when an exported name does not match a function name
  • Fix options --skipLinks
2.27.0:
  • Allow changing extension of generated files
2.26.5:
  • Fix error 3109 when scripts start with a shell bang symbol
2.26.4:
  • Fix comments disappearance
  • Fix to-esm add directive applied too soon
2.26.3:
  • Keep line breaks in package.json on update-all
2.26.2:
  • Add support for some Uglify options on non-bundled generated files --beautify, --braces, --comments, --dead_code, --drop_debugger, --drop_console, --inline, --indent_level, --indent_start, --keep_fargs, --keep_fnames, --keep_quoted, --max_line_len, --preserve_line, --quote_keys, --quote_style, --v8, --expression, --reserved, --ie, --annotations, --module, --nameCache, --semicolons, --sourcemap, --toplevel, --warnings, --webkit, --width, --wrap_iife
  • Add option --no-bundle-minify to not minify generated bundled files
  • Add --minify option to minify non-bundled generated files
  • Add --no-comments option to remove comments from generated code
  • Add --force-lf option to replace CLRF with LF
2.24.1:
  • Remove duplicate export on the same line
  • Add options --skipLinks to avoid following linked files
2.24.0:
  • Add options --skipLinks to avoid following linked files
2.23.1:
  • Fix an undefined source variable error during some parsing
  • Fix undefined options errors
  • Fix async functions exported incorrectly
  • Allow skipping third-party module resolution with the skipEsmResolution option
  • Fix no displayed output
  • Set length for displayed log ids to 4
  • Display help with the PageTerm module
  • Fix --version and --help not displaying correctly
  • Fix cjs minification not generated when conversion is not browser compatible
  • Fix wrong path calculations for third-party browser modules
  • Fix modules detected as installed
  • Fix a broken directive
  • Reduce output directories' depth
  • Update documentation
  • Add option --nmBrowserImported to rename imported node_modules

2.27.2

1 year ago

2.27.1

1 year ago

2.27.3

1 year ago

2.27.0

1 year ago

2.26.3

1 year ago

2.26.2

1 year ago

2.26.5

1 year ago

2.26.4

1 year ago

2.26.1

1 year ago

2.26.0

1 year ago

2.25.0

1 year ago

2.23.2

2 years ago

2.23.1

2 years ago

2.22.1

2 years ago

2.22.0

2 years ago

2.22.3

2 years ago

2.22.2

2 years ago

2.21.0

2 years ago

2.20.2

2 years ago

2.20.3

2 years ago

2.20.0

2 years ago

2.20.1

2 years ago

2.24.1

2 years ago

2.24.0

2 years ago

2.23.0

2 years ago

2.11.0

2 years ago

2.11.1

2 years ago

2.19.0

2 years ago

2.17.0

2 years ago

2.15.0

2 years ago

2.13.0

2 years ago

2.11.2

2 years ago

2.13.1

2 years ago

2.11.3

2 years ago

2.12.0

2 years ago

2.18.0

2 years ago

2.14.1

2 years ago

2.16.0

2 years ago

2.12.1

2 years ago

2.14.0

2 years ago

2.9.2

2 years ago

2.9.4

2 years ago

2.9.3

2 years ago

2.10.0

2 years ago

2.9.1

2 years ago

2.6.0

2 years ago

2.8.0

2 years ago

2.7.0

2 years ago

2.9.0

2 years ago

2.7.2

2 years ago

2.7.1

2 years ago

2.5.1

2 years ago

2.5.0

2 years ago

2.4.8

2 years ago

2.4.7

2 years ago

2.4.6

2 years ago

2.4.5

2 years ago

2.4.4

2 years ago

2.4.3

2 years ago

2.4.2

2 years ago

2.4.1

2 years ago

2.4.0

2 years ago

2.3.0

2 years ago

2.2.0

2 years ago

2.1.1

2 years ago

2.1.0

2 years ago

2.0.2

2 years ago

2.0.1

2 years ago

2.0.0

2 years ago

1.8.0

2 years ago

1.7.1

2 years ago

1.7.0

2 years ago

1.6.7

2 years ago

1.6.6

2 years ago

1.6.8

2 years ago

1.6.5

2 years ago

1.6.4

2 years ago

1.6.3

2 years ago

1.6.2

2 years ago

1.6.1

2 years ago

1.5.0

2 years ago

1.4.2

2 years ago

1.4.1

2 years ago

1.3.7

2 years ago

1.3.6

2 years ago

1.3.5

2 years ago

1.3.4

2 years ago

1.3.3

2 years ago

1.3.2

2 years ago

1.3.1

2 years ago

1.3.0

2 years ago

1.2.0

2 years ago

1.1.11

2 years ago

1.1.9

2 years ago

1.1.8

2 years ago

1.1.7

2 years ago

1.1.6

2 years ago

1.1.5

2 years ago

1.1.4

2 years ago

1.1.3

2 years ago

1.1.2

2 years ago

1.1.1

2 years ago

1.1.0

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago