tsc-esm-fix
Make TS projects compatible with esm/mjs requirements
Problem
This workaround is aimed to bypass a pair of tsc and ts-jest issues right here and right now.
Solutions
- Post-process tsc-compiled outputs everytime after the build.
- Patch project sources once as Sindre recommends in ESM migration guide
This lib may be applied in both cases.
Features
- Injects extensions to imports/re-exports statements.
- Follows
outDir
found in tsconfig.json. - Searches and replaces
__dirname
and __filename
refs with import.meta
. - Fills blank files with
export {}
(esbuild issue) - Changes file extensions (applied to local deps only).
- Supports Windows-based runtimes.
Getting started
Requirements
Node.js ^12.20.0 || ^14.13.1 || >=16.0.0
Install
yarn add -D tsc-esm-fix
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 --target='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';
import * as e1def from 'e1/a/b/c';
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';
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';
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 |
--unlink | Remove original files if ext changes | true |
--fillBlank | Fill blank files with export {} | false |
--cwd | cwd | process.cwd() |
--out | Output dir. Defaults to cwd , so files would be overwritten | process.cwd() |
--debug | Prints debug notes | |
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
ext: boolean | string
unlink?: boolean,
debug?: boolean | IFunction
}
Alternatives
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