cjstoesm

repository·master·Indexed 19 days ago

https://github.com/wessberg/cjstoesm

A tool that transforms CommonJS modules into tree-shakeable ES Modules. It converts exports and module.exports into direct export statements and require() calls into import statements, producing clean, idiomatic code without module wrappers. It can be used via a CLI, a programmatic transform() API, or as a TypeScript custom transformer for integration with bundlers like Rollup and Webpack.

Tokens
9.3K
Snippets
28
Records
36
Agent score
62%

What's inside cjstoesm

  1. Overview of cjstoesm

    master

    cjstoesm is a tool designed to transform CommonJS modules into tree-shakeable ES Modules. This enables CommonJS modules to be bundled for the browser or used with modern tools like Rollup.

    Unlike other solutions that use module wrappers, cjstoesm produces clean, idiomatic, and granular code. It attempts to convert exports and module.exports into direct export statements and converts require() calls into import statements.

    Example Transformations:

    Exports:

    • Input: exports.foo = function foo() {};

    • Output: export function foo() {}

    • Input: module.exports = { foo() { ... }, bar: 3 };

    • Output: export function foo() { ... }; export const bar = 3; export default {foo, bar};

    Imports:

    • Input: const {foo: bar} = require("./my-module");
    • Output: import {foo as bar} from "./my-module.js";

    Import Attributes (e.g., JSON):

    • Input: const pkg = require("./package.json");
    • Output: import pkg from "./package.json" with {type: "json"};
  2. Install cjstoesm

    master

    You can install cjstoesm using your preferred package manager. Note that cjstoesm has typescript as a peer dependency, so you must ensure typescript is installed in your project environment.

    Using npm

    $ npm install cjstoesm

    Using Yarn

    $ yarn add cjstoesm

    Using pnpm

    $ pnpm add cjstoesm

    Running once with npx

    If you don't want to install it permanently, you can run it via npx. You must have typescript available (either as a project dependency or installed globally via npm i -g typescript).

    To run cjstoesm directly:

    $ npx cjstoesm

    To run cjstoesm along with its peer dependencies in one command:

    $ npx -p typescript -p cjstoesm cjstoesm
  3. Configure file extension handling

    master

    By default, cjstoesm adds file extensions to module specifiers to align with Node.js ESM implementation and browser requirements.

    You can change this behavior using:

    • CLI: Use the --preserve-module-specifiers flag.
    • API: Use the preserveModuleSpecifiers option.
  4. Configure command arguments and options in createCommand

    master

    When using createCommand, you define the command's interface via the CreateCommandOptions object.

    Arguments (args)

    Arguments are defined as an object where keys are the argument names. Each entry specifies:

    • type: The expected type (e.g., "string", "string[]").
    • required: A boolean indicating if the argument is mandatory (<arg> syntax) or optional ([arg] syntax).
    • For type: "string[]", the command will use the ... syntax (e.g., <arg...>).

    Options (options)

    Options are defined as an object where keys are the long-hand flag names. Each entry specifies:

    • shortHand: An optional single-character flag (e.g., s for -s).
    • description: The help text for the option.
    • type: The type for coercion ("string", "number", or "boolean").
    • defaultValue: The value used if the option is not provided.
  5. Configure Import Attributes handling

    master

    By default, cjstoesm automatically adds Import Attributes to import declarations when necessary (e.g., when importing JSON files) to align with Node.js and browser standards.

    You can customize this behavior using:

    • CLI: Use the --import-attributes flag.
    • API: Use the importAttributes option.
  6. Integrate cjstoesm with Rollup

    master

    To use cjstoesm with Rollup, integrate it into @rollup/plugin-typescript by providing the transformer in the transformers option.

    import ts from "@rollup/plugin-typescript";
    import {cjsToEsm} from "cjstoesm";
    
    export default {
      input: "...",
      output: [ /* ... */ ],
      plugins: [
        ts({
          transformers: program => cjsToEsm({program})
        })
      ]
    };
  7. Integrate cjstoesm with Webpack

    master

    You can use cjstoesm with popular TypeScript loaders in Webpack by providing the transformer via getCustomTransformers.

    // Using awesome-typescript-loader
    import {cjsToEsm} from "cjstoesm";
    const config = {
      module: {
        rules: [{
          test: /(\.mjs)|(\.[jt]sx?)$/,
          loader: "awesome-typescript-loader",
          options: {
            getCustomTransformers: () => cjsToEsm()
          }
        }]
      }
    };
    
    // Using ts-loader
    import {cjsToEsm} from "cjstoesm";
    const config = {
      module: {
        rules: [{
          test: /(\.mjs)|(\.[jt]sx?)$/,
          loader: "ts-loader",
          options: {
            getCustomTransformers: () => cjsToEsm
          }
        }]
      }
    };
  8. Use the transform() API

    master

    Use the transform function to programmatically convert files from CommonJS to ESM.

    By default, transform writes files to disk. If you want to handle the output yourself (e.g., for a virtual file system or custom writing logic), set write: false. In this mode, the function returns an object containing an array of files, where each file has a fileName and text property.

    import {transform} from "cjstoesm";
    import {writeFileSync} from "fs";
    
    // Standard usage (writes to disk)
    await transform({
      input: "src/**/*.*",
      outDir: "dist"
    });
    
    // Manual usage (no automatic writing)
    const result = await transform({
      input: "src/**/*.*",
      write: false
    });
    
    for (const {fileName, text} of result.files) {
      writeFileSync(fileName, text);
    }
  9. Use cjstoesm as a TypeScript Custom Transformer

    master

    You can integrate cjstoesm directly into the TypeScript compilation pipeline using cjsToEsm() or cjsToEsmTransformerFactory(). This works for both .ts and .js files (ensure allowJs is enabled in compilerOptions).

    • Use cjsToEsm() for simple transpileModule calls.
    • Use cjsToEsmTransformerFactory() when combining with other transformers in a before or after hook.
    • Use cjsToEsm() when emitting from a full TypeScript Program.
    // 1. Simple transpilation
    import {ModuleKind, transpileModule} from "typescript";
    import {cjsToEsm} from "cjstoesm";
    
    const result = transpileModule(`const {join} = require("path");`, {
      transformers: cjsToEsm(),
      compilerOptions: { module: ModuleKind.ESNext }
    });
    
    // 2. Using with other transformers
    import {cjsToEsmTransformerFactory} from "cjstoesm";
    
    transpileModule(`const {join} = require("path");`, {
      transformers: {
        before: [cjsToEsmTransformerFactory(), someOtherTransformerFactory()]
      },
      compilerOptions: { module: ModuleKind.ESNext }
    });
    
    // 3. Using with a full Program
    import {getDefaultCompilerOptions, createProgram, createCompilerHost} from "typescript";
    import {cjsToEsm} from "cjstoesm";
    
    const options = getDefaultCompilerOptions();
    const program = createProgram({
      options,
      rootNames: ["my-file.js"],
      host: createCompilerHost(options)
    });
    program.emit(undefined, undefined, undefined, undefined, cjsToEsm());
  10. Configure ESLint for cjstoesm

    master

    The project uses a shared ESLint configuration provided by @wessberg/ts-config/eslint.config.js. To use this configuration in your own setup or to extend it, import the shared object and spread it into your exported ESLint configuration array. You can then add project-specific rules in subsequent configuration objects within the array.

    import shared from "@wessberg/ts-config/eslint.config.js";
    
    export default [
    	...shared,
    	{
    		rules: {}
    	}
    ];
  11. Configure sandhog with base configuration

    master

    The sandhog.config.js file allows you to define branding and visual assets for the project. It is designed to extend a base configuration imported from @wessberg/ts-config/sandhog.config.js.

    You can override or add the following properties:

    • logo: An object defining the project logo.
      • url: The URL to the logo image.
      • height: The height of the logo in pixels.
    • featureImage: An object defining the feature image used for previews or headers.
      • url: The URL to the feature image.
      • height: The height of the feature image in pixels.
    import baseConfig from "@wessberg/ts-config/sandhog.config.js";
    
    export default {
    	...baseConfig,
    	logo: {
    		url: "https://raw.githubusercontent.com/wessberg/cjstoesm/master/documentation/asset/logo.png",
    		height: 150
    	},
    	featureImage: {
    		height: 500,
    		url: "https://raw.githubusercontent.com/wessberg/cjstoesm/master/documentation/asset/feature.gif"
    	}
    };
  12. Reference: cjstoesm CLI options

    master

    The following options are available for the cjstoesm CLI:

    FlagArgumentDescription
    -d, --debug[arg]Whether to print debug information
    -v, --verbose[arg]Whether to print verbose information
    -s, --silent[arg]Whether to not print anything
    -c, --cwd[arg]Optionally which directory to use as the current working directory
    -p, --preserve-module-specifiers[arg]Determines whether or not module specifiers are preserved. Possible values: external, internal, always, never (default: external)
    -a, --import-attributes[arg]Determines whether or not Import Attributes are included. Possible values: true, false (default: true)
    -m, --dry[arg]If true, no files will be written to disk
    -h, --helpDisplay help for command
    $ cjstoesm --help
    
    Usage: cjstoesm [options] <input> <outDir>
    
    Transforms CJS to ESM modules based on the input glob
    
    Options:
      -d, --debug [arg]                       Whether to print debug information
      -v, --verbose [arg]                     Whether to print verbose information
      -s, --silent [arg]                      Whether to not print anything
      -c, --cwd [arg]                         Optionally which directory to use as the current working directory
      -p, --preserve-module-specifiers [arg]  Determines whether or not module specifiers are preserved. Possible values are: "external", "internal", "always", and "never" (default: "external")
      -a, --import-attributes [arg]           Determines whether or not Import Attributes are included where they are relevant. Possible values are: true and false (default: true)
      -m, --dry [arg]                         If true, no files will be written to disk
      -h, --help                              display help for command