Skip to content

Instantly share code, notes, and snippets.

@quezo
Forked from khalidx/node-typescript-esm.md
Created November 22, 2023 03:33
Show Gist options
  • Select an option

  • Save quezo/04b74ae60af6b84155cd3b942ea93d2d to your computer and use it in GitHub Desktop.

Select an option

Save quezo/04b74ae60af6b84155cd3b942ea93d2d to your computer and use it in GitHub Desktop.

Revisions

  1. @khalidx khalidx revised this gist Nov 21, 2023. No changes.
  2. @khalidx khalidx revised this gist Nov 21, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion node-typescript-esm.md
    Original file line number Diff line number Diff line change
    @@ -23,7 +23,7 @@ Just add the following files and run `npm run dev`. You'll be good to go!
    "npm": "^10.1.0"
    },
    "scripts": {
    "dev": "node --no-warnings --loader ts-node/esm src/index.ts"
    "dev": "node --no-warnings --enable-source-maps --loader ts-node/esm src/index.ts"
    },
    "dependencies": {},
    "devDependencies": {
  3. @khalidx khalidx revised this gist Nov 21, 2023. 1 changed file with 15 additions and 8 deletions.
    23 changes: 15 additions & 8 deletions node-typescript-esm.md
    Original file line number Diff line number Diff line change
    @@ -63,34 +63,41 @@ Just add the following files and run `npm run dev`. You'll be good to go!

    ### `src/utilities/node.ts`

    Some utilities for getting similar behavior as `__filename`, `__dirname`, and `require.main === module` in Node.JS.
    Some utilities for getting similar behavior as `__filename`, `__dirname`, and `require.main === module` in Node.JS CommonJS.

    This file is optional.

    ```typescript
    import { dirname } from 'node:path'
    import { fileURLToPath } from 'node:url'
    import { dirname } from 'node:path'
    import { argv } from 'node:process'
    import { createRequire } from 'node:module'

    /**
    * This is an ESM replacement for `__filename`.
    *
    * Use it like this: `__filename(import.meta.url)`.
    * Use it like this: `__filename(import.meta)`.
    */
    export const __filename = (url: string) => fileURLToPath(url)
    export const __filename = (meta: ImportMeta): string => fileURLToPath(meta.url)

    /**
    * This is an ESM replacement for `__dirname`.
    *
    * Use it like this: `__dirname(import.meta.url)`.
    * Use it like this: `__dirname(import.meta)`.
    */
    export const __dirname = (url: string) => dirname(__filename(url))
    export const __dirname = (meta: ImportMeta): string => dirname(__filename(meta))

    /**
    * Indicates that the script was run directly.
    * This is an ESM replacement for `require.main === module`.
    *
    * Use it like this: `isMain(import.meta.url)`.
    * Use it like this: `isMain(import.meta)`.
    */
    export const isMain = (url: string) => argv[1] === __filename(url)
    export const isMain = (meta: ImportMeta): boolean => {
    if (!meta || !argv[1]) return false
    const require = createRequire(meta.url)
    const scriptPath = require.resolve(argv[1])
    const modulePath = __filename(meta)
    return scriptPath === modulePath
    }
    ```
  4. @khalidx khalidx revised this gist Nov 21, 2023. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions node-typescript-esm.md
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,11 @@
    The experience of using Node.JS with TypeScript and ESM is horrible.
    The experience of using Node.JS with TypeScript, ts-node, and ESM is horrible.

    There are countless guides of how to integrate the 3, but none of them seem to work.
    There are countless guides of how to integrate them, but none of them seem to work.

    Here's what worked for me.

    Just add the following files and run `npm run dev`. You'll be good to go!

    ### `package.json`

    ```json
  5. @khalidx khalidx created this gist Nov 21, 2023.
    94 changes: 94 additions & 0 deletions node-typescript-esm.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,94 @@
    The experience of using Node.JS with TypeScript and ESM is horrible.

    There are countless guides of how to integrate the 3, but none of them seem to work.

    Here's what worked for me.

    ### `package.json`

    ```json
    {
    "private": true,
    "type": "module",
    "exports": "./dist/index.js",
    "types": "./dist/index.d.ts",
    "sideEffects": false,
    "files": [
    "./dist/"
    ],
    "engines": {
    "node": "^20.9.0",
    "npm": "^10.1.0"
    },
    "scripts": {
    "dev": "node --no-warnings --loader ts-node/esm src/index.ts"
    },
    "dependencies": {},
    "devDependencies": {
    "@sindresorhus/tsconfig": "^5.0.0",
    "ts-node": "^10.9.1",
    "typescript": "^5.2.2"
    }
    }
    ```

    ### `tsconfig.json`

    ```json
    {
    "extends": "@sindresorhus/tsconfig",
    "compilerOptions": {
    "outDir": "./dist/", /* Specify an output folder for all emitted files. */
    "lib": ["ES2022"],
    "target": "ES2022",
    "declarationMap": true, /* Create sourcemaps for d.ts files. */
    "sourceMap": true, /* Create source map files for emitted JavaScript files. */
    "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
    "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
    "esModuleInterop": true
    },
    "include": [
    "./src/**/*.ts"
    ],
    "ts-node": {
    "esm": true,
    "transpileOnly": true,
    "files": true,
    "experimentalResolver": true
    }
    }
    ```

    ### `src/utilities/node.ts`

    Some utilities for getting similar behavior as `__filename`, `__dirname`, and `require.main === module` in Node.JS.

    This file is optional.

    ```typescript
    import { dirname } from 'node:path'
    import { fileURLToPath } from 'node:url'
    import { argv } from 'node:process'

    /**
    * This is an ESM replacement for `__filename`.
    *
    * Use it like this: `__filename(import.meta.url)`.
    */
    export const __filename = (url: string) => fileURLToPath(url)

    /**
    * This is an ESM replacement for `__dirname`.
    *
    * Use it like this: `__dirname(import.meta.url)`.
    */
    export const __dirname = (url: string) => dirname(__filename(url))

    /**
    * Indicates that the script was run directly.
    * This is an ESM replacement for `require.main === module`.
    *
    * Use it like this: `isMain(import.meta.url)`.
    */
    export const isMain = (url: string) => argv[1] === __filename(url)
    ```