Skip to content

Commit

Permalink
feat: add option for interop default in cjs (#947)
Browse files Browse the repository at this point in the history
  • Loading branch information
sxzz authored Aug 2, 2023
1 parent 692c112 commit d870f4e
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 7 deletions.
16 changes: 10 additions & 6 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,12 @@ Provide the following configuration in your `.vscode/settings.json` (or global)
"json.schemas": [
{
"url": "https://cdn.jsdelivr.net/npm/tsup/schema.json",
"fileMatch": [
"package.json",
"tsup.config.json"
]
"fileMatch": ["package.json", "tsup.config.json"]
}
]
}
```


### Multiple entrypoints

Beside using positional arguments `tsup [...files]` to specify multiple entrypoints, you can also use the cli flag `--entry`:
Expand All @@ -164,7 +160,7 @@ Beside using positional arguments `tsup [...files]` to specify multiple entrypoi
tsup --entry src/a.ts --entry src/b.ts
```

The associated output file names can be defined as follows:
The associated output file names can be defined as follows:

```bash
# Outputs `dist/foo.js` and `dist/bar.js`.
Expand Down Expand Up @@ -350,6 +346,14 @@ tsup src/index.ts --env.NODE_ENV production
When an entry file like `src/cli.ts` contains hashbang like `#!/bin/env node` tsup will automatically make the output file executable, so you don't have to run `chmod +x dist/cli.js`.
### Interop with CommonJS
By default, esbuild will transform `export default x` to `module.exports.default = x` in CommonJS, but you can change this behavior by using the `--cjsInterop` flag: If there are only default exports and no named exports, it will be transformed to `module.exports = x` instead.
```bash
tsup src/index.ts --cjsInterop
```
### Watch mode
```bash
Expand Down
1 change: 1 addition & 0 deletions src/cli-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export async function main(options: Options = {}) {
'--killSignal <signal>',
'Signal to kill child process, "SIGTERM" or "SIGKILL"'
)
.option('--cjsInterop', 'Enable cjs interop')
.action(async (files: string[], flags) => {
const { build } = await import('.')
Object.assign(options, {
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { sizeReporter } from './plugins/size-reporter'
import { treeShakingPlugin } from './plugins/tree-shaking'
import { copyPublicDir, isInPublicDir } from './lib/public-dir'
import { terserPlugin } from './plugins/terser'
import { cjsInterop } from './plugins/cjs-interop'

export type { Format, Options, NormalizedOptions }

Expand Down Expand Up @@ -254,6 +255,7 @@ export async function build(_options: Options) {
silent: options.silent,
}),
cjsSplitting(),
cjsInterop(),
es5(),
sizeReporter(),
terserPlugin({
Expand Down
5 changes: 5 additions & 0 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ export type Options = {
*/
publicDir?: string | boolean
killSignal?: KILL_SIGNAL
/**
* Interop default within `module.exports` in cjs
* @default false
*/
cjsInterop?: boolean
}

export type NormalizedOptions = Omit<
Expand Down
26 changes: 26 additions & 0 deletions src/plugins/cjs-interop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Plugin } from '../plugin'

export const cjsInterop = (): Plugin => {
return {
name: 'cjs-interop',

async renderChunk(code, info) {
if (
!this.options.cjsInterop ||
this.format !== 'cjs' ||
info.type !== 'chunk' ||
!/\.(js|cjs)$/.test(info.path) ||
!info.entryPoint ||
info.exports?.length !== 1 ||
info.exports[0] !== 'default'
) {
return
}

return {
code: code + '\nmodule.exports = exports.default',
map: info.map,
}
},
}
}
24 changes: 23 additions & 1 deletion src/rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,25 @@ const getRollupConfig = async (
},
}

const fixCjsExport: Plugin = {
name: 'tsup:fix-cjs-export',
renderChunk(code, info) {
if (
info.type !== 'chunk' ||
!/\.(ts|cts)$/.test(info.fileName) ||
!info.isEntry ||
info.exports?.length !== 1 ||
info.exports[0] !== 'default'
)
return

return code.replace(
/(?<=(?<=[;}]|^)\s*export\s*){\s*([\w$]+)\s*as\s+default\s*}/,
`= $1`
)
},
}

return {
inputConfig: {
input: dtsOptions.entry,
Expand Down Expand Up @@ -179,7 +198,7 @@ const getRollupConfig = async (
...(options.external || []),
],
},
outputConfig: options.format.map((format) => {
outputConfig: options.format.map((format): OutputOptions => {
const outputExtension =
options.outExtension?.({ format, options, pkgType: pkg.type }).dts ||
defaultOutExtension({ format, pkgType: pkg.type }).dts
Expand All @@ -190,6 +209,9 @@ const getRollupConfig = async (
banner: dtsOptions.banner,
footer: dtsOptions.footer,
entryFileNames: `[name]${outputExtension}`,
plugins: [
format === 'cjs' && options.cjsInterop && fixCjsExport,
].filter(Boolean),
}
}),
}
Expand Down

0 comments on commit d870f4e

Please sign in to comment.