/
terser.ts
85 lines (76 loc) · 2.52 KB
/
terser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { Worker } from 'okie'
import type { Terser } from 'types/terser'
import type { Plugin } from '../plugin'
import type { ResolvedConfig } from '..'
import { requireResolveFromRootWithFallback } from '../utils'
let terserPath: string | undefined
const loadTerserPath = (root: string) => {
if (terserPath) return terserPath
try {
terserPath = requireResolveFromRootWithFallback(root, 'terser')
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
throw new Error(
'terser not found. Since Vite v3, terser has become an optional dependency. You need to install it.'
)
} else {
const message = new Error(`terser failed to load:\n${e.message}`)
message.stack = e.stack + '\n' + message.stack
throw message
}
}
return terserPath
}
export function terserPlugin(config: ResolvedConfig): Plugin {
const makeWorker = () =>
new Worker(
async (
terserPath: string,
code: string,
options: Terser.MinifyOptions
) => {
// test fails when using `import`. maybe related: https://github.com/nodejs/node/issues/43205
// eslint-disable-next-line no-restricted-globals -- this function runs inside cjs
const terser = require(terserPath)
return terser.minify(code, options) as Terser.MinifyOutput
}
)
let worker: ReturnType<typeof makeWorker>
return {
name: 'vite:terser',
async renderChunk(code, _chunk, outputOptions) {
// This plugin is included for any non-false value of config.build.minify,
// so that normal chunks can use the preferred minifier, and legacy chunks
// can use terser.
if (
config.build.minify !== 'terser' &&
// @ts-ignore injected by @vitejs/plugin-legacy
!outputOptions.__vite_force_terser__
) {
return null
}
// Do not minify ES lib output since that would remove pure annotations
// and break tree-shaking.
if (config.build.lib && outputOptions.format === 'es') {
return null
}
// Lazy load worker.
worker ||= makeWorker()
const terserPath = loadTerserPath(config.root)
const res = await worker.run(terserPath, code, {
safari10: true,
...config.build.terserOptions,
sourceMap: !!outputOptions.sourcemap,
module: outputOptions.format.startsWith('es'),
toplevel: outputOptions.format === 'cjs'
})
return {
code: res.code!,
map: res.map as any
}
},
closeBundle() {
worker?.stop()
}
}
}