Skip to content

Commit b9cd8d5

Browse files
author
EGOIST
committedMay 30, 2022
feat: new option outExtension
1 parent a175339 commit b9cd8d5

File tree

7 files changed

+132
-41
lines changed

7 files changed

+132
-41
lines changed
 

‎docs/README.md

+32-1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,37 @@ dist
224224
└── index.js
225225
```
226226

227+
### Output extension
228+
229+
You can also change the output extension of the files by using `outExtension` option:
230+
231+
```ts
232+
export default defineConfig({
233+
outExtension({ format }) {
234+
return {
235+
js: `.${format}.js`,
236+
}
237+
},
238+
})
239+
```
240+
241+
This will generate your files to `[name].[format].js`.
242+
243+
The signature of `outExtension` is:
244+
245+
```ts
246+
type OutExtension = (ctx: Context) => Result
247+
248+
type Context = {
249+
options: NormalizedOptions
250+
format: Format
251+
/** "type" field in project's package.json */
252+
pkgType?: string
253+
}
254+
255+
type Result = { js?: string }
256+
```
257+
227258
### Code Splitting
228259
229260
Code splitting currently only works with the `esm` output format, and it's enabled by default. If you want code splitting for `cjs` output format as well, try using `--splitting` flag which is an experimental feature to get rid of [the limitation in esbuild](https://esbuild.github.io/api/#splitting).
@@ -319,7 +350,7 @@ export default defineConfig({
319350
})
320351
```
321352

322-
### Tree Shaking
353+
### Tree shaking
323354

324355
esbuild has [tree shaking](https://esbuild.github.io/api/#tree-shaking) enabled by default, but sometimes it's not working very well, see [#1794](https://github.com/evanw/esbuild/issues/1794) [#1435](https://github.com/evanw/esbuild/issues/1435), so tsup offers an additional option to let you use Rollup for tree shaking instead:
325356

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"svelte": "3.46.4",
6464
"ts-essentials": "9.1.2",
6565
"tsconfig-paths": "3.12.0",
66-
"tsup": "5.12.5",
66+
"tsup": "6.0.1",
6767
"typescript": "4.6.3",
6868
"vitest": "0.8.4",
6969
"wait-for-expect": "3.0.2"

‎pnpm-lock.yaml

+14-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/esbuild/index.ts

+31-10
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,44 @@ import { truthy } from '../utils'
1818
import { swcPlugin } from './swc'
1919
import { nativeNodeModulesPlugin } from './native-node-module'
2020
import { PluginContainer } from '../plugin'
21+
import { OutExtensionFactory } from '../options'
2122

22-
const getOutputExtensionMap = (
23-
pkgTypeField: string | undefined,
23+
const defaultOutExtension = ({
24+
format,
25+
pkgType,
26+
}: {
2427
format: Format
25-
) => {
26-
const isModule = pkgTypeField === 'module'
27-
const map: Record<string, string> = {}
28+
pkgType?: string
29+
}): { js: string } => {
30+
let jsExtension = '.js'
31+
const isModule = pkgType === 'module'
2832
if (isModule && format === 'cjs') {
29-
map['.js'] = '.cjs'
33+
jsExtension = '.cjs'
3034
}
3135
if (!isModule && format === 'esm') {
32-
map['.js'] = '.mjs'
36+
jsExtension = '.mjs'
3337
}
3438
if (format === 'iife') {
35-
map['.js'] = '.global.js'
39+
jsExtension = '.global.js'
40+
}
41+
return {
42+
js: jsExtension,
43+
}
44+
}
45+
46+
const getOutputExtensionMap = (
47+
options: NormalizedOptions,
48+
format: Format,
49+
pkgType: string | undefined
50+
) => {
51+
const outExtension: OutExtensionFactory =
52+
options.outExtension || defaultOutExtension
53+
54+
const defaultExtension = defaultOutExtension({ format, pkgType })
55+
const extension = outExtension({ options, format, pkgType })
56+
return {
57+
'.js': extension.js || defaultExtension.js,
3658
}
37-
return map
3859
}
3960

4061
export async function runEsbuild(
@@ -62,7 +83,7 @@ export async function runEsbuild(
6283
]
6384
const outDir = options.outDir
6485

65-
const outExtension = getOutputExtensionMap(pkg.type, format)
86+
const outExtension = getOutputExtensionMap(options, format, pkg.type)
6687
const env: { [k: string]: string } = {
6788
...options.env,
6889
}

‎src/index.ts

+2-11
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import execa from 'execa'
1313
import kill from 'tree-kill'
1414
import { version } from '../package.json'
1515
import { createLogger, setSilent } from './log'
16-
import { DtsConfig, Format, Options } from './options'
16+
import { NormalizedOptions, Format, Options } from './options'
1717
import { runEsbuild } from './esbuild'
1818
import { shebang } from './plugins/shebang'
1919
import { cjsSplitting } from './plugins/cjs-splitting'
@@ -22,16 +22,7 @@ import { es5 } from './plugins/es5'
2222
import { sizeReporter } from './plugins/size-reporter'
2323
import { treeShakingPlugin } from './plugins/tree-shaking'
2424

25-
export type { Format, Options }
26-
27-
export type NormalizedOptions = Omit<
28-
MarkRequired<Options, 'entry' | 'format' | 'outDir'>,
29-
'dts'
30-
> & {
31-
dts?: DtsConfig
32-
tsconfigResolvePaths: Record<string, string[]>
33-
tsconfigDecoratorMetadata?: boolean
34-
}
25+
export type { Format, Options, NormalizedOptions }
3526

3627
export const defineConfig = (
3728
options:

‎src/options.ts

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
import type { BuildOptions, Plugin as EsbuildPlugin, Loader } from 'esbuild'
22
import type { InputOption } from 'rollup'
3-
import { Plugin } from './plugin'
4-
import { TreeshakingStrategy } from './plugins/tree-shaking'
3+
import { MarkRequired } from 'ts-essentials'
4+
import type { Plugin } from './plugin'
5+
import type { TreeshakingStrategy } from './plugins/tree-shaking'
56

67
export type Format = 'cjs' | 'esm' | 'iife'
78

9+
export type ContextForOutPathGeneration = {
10+
options: NormalizedOptions
11+
format: Format
12+
/** "type" field in project's package.json */
13+
pkgType?: string
14+
}
15+
16+
export type OutExtensionObject = { js?: string }
17+
18+
export type OutExtensionFactory = (
19+
ctx: ContextForOutPathGeneration
20+
) => OutExtensionObject
21+
822
export type DtsConfig = {
923
entry?: InputOption
1024
/** Resolve external types used in dts files from node_modules */
@@ -57,6 +71,7 @@ export type Options = {
5771
jsxFactory?: string
5872
jsxFragment?: string
5973
outDir?: string
74+
outExtension?: OutExtensionFactory
6075
format?: Format[]
6176
globalName?: string
6277
env?: {
@@ -158,3 +173,12 @@ export type Options = {
158173
*/
159174
treeshake?: TreeshakingStrategy
160175
}
176+
177+
export type NormalizedOptions = Omit<
178+
MarkRequired<Options, 'entry' | 'format' | 'outDir'>,
179+
'dts'
180+
> & {
181+
dts?: DtsConfig
182+
tsconfigResolvePaths: Record<string, string[]>
183+
tsconfigDecoratorMetadata?: boolean
184+
}

‎test/index.test.ts

+26
Original file line numberDiff line numberDiff line change
@@ -860,3 +860,29 @@ test('use rollup for treeshaking', async () => {
860860
`import { inject } from 'vue'`
861861
)
862862
})
863+
864+
test('custom output extension', async () => {
865+
const { outFiles } = await run(
866+
getTestName(),
867+
{
868+
'input.ts': `export const foo = [1,2,3]`,
869+
'tsup.config.ts': `export default {
870+
outExtension({ format }) {
871+
return {
872+
js: '.' + format + '.js'
873+
}
874+
}
875+
}`,
876+
},
877+
{
878+
entry: ['input.ts'],
879+
flags: ['--format', 'esm,cjs'],
880+
}
881+
)
882+
expect(outFiles).toMatchInlineSnapshot(`
883+
[
884+
"input.cjs.js",
885+
"input.esm.js",
886+
]
887+
`)
888+
})

0 commit comments

Comments
 (0)
Please sign in to comment.