Skip to content

Commit

Permalink
feat: Minify with terser (#789)
Browse files Browse the repository at this point in the history
closes #742
  • Loading branch information
PuruVJ committed Feb 7, 2023
1 parent 31b2e72 commit fdd4dfa
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 8 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
*.log
dist
.cache
.cache
playground
10 changes: 10 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,16 @@ You can also minify the output, resulting into lower bundle sizes by using the `
tsup src/index.ts --minify
```

To use [Terser](https://github.com/terser/terser) instead of esbuild for minification, pass terser as argument value

```bash
tsup src/index.ts --minify terser
```

> NOTE: You must have terser installed. Install it with `npm install -D terser`
In `tsup.config.js`, you can pass `terserOptions` which will be passed to `terser.minify` as it is.

### Custom loader

Esbuild loader list:
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"rollup-plugin-hashbang": "2.2.2",
"strip-json-comments": "4.0.0",
"svelte": "3.46.4",
"terser": "^5.16.0",
"ts-essentials": "9.1.2",
"tsconfig-paths": "3.12.0",
"tsup": "6.4.0",
Expand Down
85 changes: 81 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/cli-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function main(options: Options = {}) {
.option('--format <format>', 'Bundle format, "cjs", "iife", "esm"', {
default: 'cjs',
})
.option('--minify', 'Minify bundle')
.option('--minify [terser]', 'Minify bundle')
.option('--minify-whitespace', 'Minify whitespace')
.option('--minify-identifiers', 'Minify identifiers')
.option('--minify-syntax', 'Minify syntax')
Expand Down
2 changes: 1 addition & 1 deletion src/esbuild/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ export async function runEsbuild(
write: false,
splitting,
logLevel: 'error',
minify: options.minify,
minify: options.minify === 'terser' ? false : options.minify,
minifyWhitespace: options.minifyWhitespace,
minifyIdentifiers: options.minifyIdentifiers,
minifySyntax: options.minifySyntax,
Expand Down
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { es5 } from './plugins/es5'
import { sizeReporter } from './plugins/size-reporter'
import { treeShakingPlugin } from './plugins/tree-shaking'
import { copyPublicDir, isInPublicDir } from './lib/public-dir'
import { terserPlugin } from './plugins/terser'

export type { Format, Options, NormalizedOptions }

Expand Down Expand Up @@ -260,6 +261,11 @@ export async function build(_options: Options) {
cjsSplitting(),
es5(),
sizeReporter(),
terserPlugin({
minifyOptions: options.minify,
format,
terserOptions: options.terserOptions,
}),
])
await runEsbuild(options, {
pluginContainer,
Expand Down
4 changes: 3 additions & 1 deletion src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { InputOption } from 'rollup'
import { MarkRequired } from 'ts-essentials'
import type { Plugin } from './plugin'
import type { TreeshakingStrategy } from './plugins/tree-shaking'
import type { MinifyOptions } from 'terser'

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

Expand Down Expand Up @@ -65,7 +66,8 @@ export type Options = {
* default to `node14`
*/
target?: string | string[]
minify?: boolean
minify?: boolean | 'terser'
terserOptions?: MinifyOptions
minifyWhitespace?: boolean
minifyIdentifiers?: boolean
minifySyntax?: boolean
Expand Down
67 changes: 67 additions & 0 deletions src/plugins/terser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { MinifyOptions } from 'terser'
import { PrettyError } from '../errors'
import { createLogger } from '../log'
import { Format, Options } from '../options'
import { Plugin } from '../plugin'
import { localRequire } from '../utils'

const logger = createLogger()

export const terserPlugin = ({
minifyOptions,
format,
terserOptions = {},
}: {
minifyOptions: Options['minify']
format: Format
terserOptions?: MinifyOptions
}): Plugin => {
return {
name: 'terser',

async renderChunk(code, info) {
if (minifyOptions !== 'terser' || !/\.(cjs|js|mjs)$/.test(info.path))
return

const terser: typeof import('terser') | undefined = localRequire('terser')

if (!terser) {
throw new PrettyError(
'terser is required for terser minification. Please install it with `npm install terser -D`'
)
}

const { minify } = terser

const defaultOptions: MinifyOptions = {}

if (format === 'esm') {
defaultOptions.module = true
} else {
defaultOptions.toplevel = true
}

try {
const minifiedOutput = await minify(
{ [info.path]: code },
{ ...defaultOptions, ...terserOptions }
)

logger.info('TERSER', 'Minifying with Terser')

if (!minifiedOutput.code) {
logger.error('TERSER', 'Failed to minify with terser')
}

logger.success('TERSER', 'Terser Minification success')

return { code: minifiedOutput.code!, map: minifiedOutput.map }
} catch (e) {
logger.error('TERSER', 'Failed to minify with terser')
logger.error('TERSER', e)
}

return { code, map: info.map }
},
}
}

0 comments on commit fdd4dfa

Please sign in to comment.