What's the problem?
We're currently using Node.js with "type": "module" and moduleResolution: "node16", which requires explicitly adding .js extensions in all ESM imports. This leads to cluttered and brittle import statements, especially when working in TypeScript where the source files are .ts but get compiled to .js.
Maintaining these extensions manually:
- Hurts developer experience (DX)
- Causes confusion during refactors/renames
- Doesn't align with the clean, extensionless style we're used to in CommonJS or legacy TypeScript setups
What's your solution?
Adopt a bundler like tsup, esbuild or vite in our build pipeline to:
- Allow us to write clean, extensionless imports in
.ts source files
- Automatically rewrite those to proper
.js extensions in the output
- Support modern ESM and fast builds
- Maintain compatibility with
"type": "module" and Node.js ESM requirements
This keeps dev DX clean and avoids runtime errors or path issues after compilation.
Any alternatives?
- Stick with manual
.js extensions
- Functional but error-prone and ugly.
- Switch back to CommonJS (
"module": "CommonJS")
- Avoids the extension issue, but sacrifices ESM features like top-level
await.
- Use
.ts extensions in dev (allowImportingTsExtensions)
- Only works at compile time, breaks at runtime.
Anything else?
Here's an example tsup config we could use:
// tsup.config.ts
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
target: 'es2022',
dts: true,
splitting: false,
sourcemap: true,
clean: true,
outDir: 'dist',
});
What's the problem?
We're currently using Node.js with
"type": "module"andmoduleResolution: "node16", which requires explicitly adding.jsextensions in all ESM imports. This leads to cluttered and brittle import statements, especially when working in TypeScript where the source files are.tsbut get compiled to.js.Maintaining these extensions manually:
What's your solution?
Adopt a bundler like
tsup,esbuildorvitein our build pipeline to:.tssource files.jsextensions in the output"type": "module"and Node.js ESM requirementsThis keeps dev DX clean and avoids runtime errors or path issues after compilation.
Any alternatives?
.jsextensions"module": "CommonJS")await..tsextensions in dev (allowImportingTsExtensions)Anything else?
Here's an example
tsupconfig we could use: