npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

tsc-esm-fix

v3.1.2

Published

Make tsc-compiled `es2020/esnext` bundles compatible with esm/mjs requirements

Downloads

77,955

Readme

tsc-esm-fix

Make TS projects compatible with esm/mjs requirements

CI Maintainability Test Coverage npm (tag)

Problem

This workaround is aimed to bypass a bunch of tsc, ts-jest and esbuild issues right here and right now.

moduleResolution: nodenext

Nightly build TypeScript 4.7 provides experimental esm support. But it still forces to add extensions by hand (tested on 4.7.0-dev.20220408).

src/main/ts/q/u/x/index.ts:1:21 - error TS2835: Relative import paths need explicit file extensions in EcmaScript imports when '--moduleResolution' is 'node12' or 'nodenext'. Did you mean '../../../foo.js'?

1 import { foo } from '../../../foo'

Moreover, if understand TS/49271 correctly, nodenext + pkg.json type: module requires .js extension to be added to all .d.ts files of external ESM packages too. Well, good luck with that.

Solutions

  1. Post-process tsc-compiled outputs each time after build.
  2. Patch project sources once as Sindre recommends in the ESM migration guide
  3. Use ttypescript with transformer-append-js-ext plugin

This lib covers options 1 and 2.

Features

  • Injects extensions to imports/re-exports statements.
    • import {foo} from './foo'import {foo} from './foo.js'
    • import {baz} from 'external/baz'import {baz} from 'external/baz.js'
    • Note, including the file extension is only necessary for packages without an "exports" field. So in this case all the external refs remain as are.
    • Pays attention to index files: import {bar} from './bar'import {bar} from './bar/index.js'
    • Handles . and .. shortcuts
      • export * from '.'export * from './index.js'
      • export * from '..'export * from '../index.js'
    • Injects .js extensions into .d.ts libdef files
    • Does not affect string literals and comments: depseek
  • Handles conditional exports (https://nodejs.org/api/packages.html#conditional-exports)
  • Follows outDir found in tsconfig.json.
  • Searches and replaces __dirname and __filename refs with import.meta.
  • Fills blank files with export {} (esbuild issue 1043)
  • Patches source map files to point to the updated files.
  • Patches require statements with new file refs if ext changes (hybrid/dual pkg)
  • Changes file extensions (applied to local deps only).
  • Supports Windows-based runtimes.

Getting started

Requirements

Node.js >=16.0.0

Install

npm i -dev tsc-esm-fix
yarn add -D tsc-esm-fix

# or w/o saving to package.json
npx tsc-esm-fix [options]

Usage examples

tsc-esm-fix [options]

# to post-process outputs each time
tsc-esm-fix --target='target/es6'

# to patch ts sources once
tsc-esm-fix --src='src/main/ts' --ext='.js'
import { fix } from 'tsc-esm-fix'
await fix({
  dirnameVar: true,
  filenameVar: true,
  ext: true
})

Input
code ref

import { foo } from './foo';
import './bar';

// external cjs module
import * as e1def from 'e1/a/b/c';
import * as e1root from 'e1';
const { e1 } = e1def;
const { e1: e1x } = e1root;
export { e1, e1x };

// external esm module with `main` in pkg.json
export { m1 } from 'm1';
export { m1 as m1x } from 'm1/index';

// external esm module with `exports` in pkg.json
export { e2 } from 'e2';
export { e2 as es3 } from 'e2/index';
export { e2 as es4 } from 'e2/alias';
export { e2foo } from 'e2/foo';
export { e2bar } from 'e2/bar-bundle';

export * from './foo';
export * from './baz';
export * from './q/u/x';
export const foobaz = foo + 'baz';
export { foo as foo1 } from './foo.js';

// Dir with index.js file inside: ./qux.js/index.js
export { qux } from './qux.js';

export const dirname = __dirname;
export const filename = __filename;

console.log(foobaz);

Output

import { foo } from './foo.js';
import './bar.js';

import * as e1def from 'e1/a/b/c/index.js';
import * as e1root from 'e1';
const { e1 } = e1def;
const { e1: e1x } = e1root;
export { e1, e1x };

export { m1 } from 'm1';
export { m1 as m1x } from 'm1/index.js';

export { e2 } from 'e2';
export { e2 as es3 } from 'e2/index';
export { e2 as es4 } from 'e2/alias';
export { e2foo } from 'e2/foo';
export { e2bar } from 'e2/bar-bundle';

export * from './foo.js';
export * from './baz/index.js';
export * from './q/u/x/index.js';
export const foobaz = foo + 'baz';
export { foo as foo1 } from './foo.js';

export { qux } from './qux.js/index.js';

export const dirname = /file:\\\\/\\\\/(.+)\\\\/[^/]/.exec(import.meta.url)[1];
export const filename = /file:\\\\/\\\\/(.+)/.exec(import.meta.url)[1];

CLI

tsc-esm-fix [opts]

| Option | Description | Default | |------------------------|------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| | --tsconfig | Path to project's ts-config(s) | tsconfig.json | | --src | Entry points where the ts-source files are placed. If defined src option suppresses target | | | --target | tsc-compiled output directory | If not specified inherited from tsconfig.json compilerOptions.outDir | | --dirnameVar | Replace __dirname usages with import.meta | true | | --filenameVar | Replace __filename var references with import.meta statements | true | | --ext | Append extension to relative imports/re-exports | .js | | --ts-ext | Known TS extensions | .ts,.tsx,.mts,.mtsx,.cts,.ctsx | | --js-ext | Known JS extensions | .js,.jsx,.mjs,.mjsx,.cjs,.cjsx | | --unlink | Remove original files if ext changes | true | | --fillBlank | Fill blank files with export {} | false | | --forceDefaultExport | Injects export default undefined if not present | false | | --sourceMap | Patch source map files to point to the updated files. | false | | --cwd | cwd | process.cwd() | | --out | Output dir. Defaults to cwd, so files would be overwritten | process.cwd() | | --debug | Prints debug notes | |

--target vs --src

When --src option is used, the util just modifies file contents in place. --target also renames files to change their extension. You may prevent deletion original of files by using --no-unlink.

glob patterns

By default, the util looks for ts/tsx files in src directory and js/d.ts files in target. But you can specify custom patterns via corresponding options. For example: --src='src/main/ts/**/*.ts'.

const patterns =
  sources.length > 0
    ? sources.map((src) => src.includes('*') ? src : `${src}/**/*.{ts,tsx}`)
    : targets.map((target) => target.includes('*') ? target : `${target}/**/*.{js,d.ts}`)

JS/TS API

import { fix, IFixOptions } from 'tsc-esm-fix'

const fixOptions: IFixOptions = {
  tsconfig: 'tsconfig.build.json',
  dirnameVar: true,
  filenameVar: true,
  ext: true
}

await fix(fixOptions)
export interface IFixOptions {
  cwd: string
  src?: string | string[]
  target?: string | string[]
  out?: string
  tsconfig?: string | string[]
  dirnameVar: boolean
  filenameVar: boolean
  fillBlank?: boolean
  forceDefaultExport?: boolean
  sourceMap?: boolean
  ext: boolean | string
  tsExt: string | string[]
  jsExt: string | string[]
  unlink?: boolean,
  debug?: boolean | IFunction
}

Alternatives

  • https://github.com/mothepro/tsc-esm
  • https://github.com/digital-loukoum/tsc-esm
  • https://github.com/beenotung/fix-esm-import-path

Contributing

Feel free to open any issues: bug reports, feature requests or questions. You're always welcome to suggest a PR. Just fork this repo, write some code, add some tests and push your changes. Any feedback is appreciated.

References

License

MIT