Skip to content

Commit a9ba017

Browse files
sapphi-redbluwy
andauthored
feat: generate code frame for parse errors thrown by terser (#20642)
Co-authored-by: Bjorn Lu <[email protected]>
1 parent 530687a commit a9ba017

File tree

1 file changed

+33
-13
lines changed

1 file changed

+33
-13
lines changed

packages/vite/src/node/plugins/terser.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
import { WorkerWithFallback } from 'artichokie'
77
import type { Plugin } from '../plugin'
88
import type { ResolvedConfig } from '..'
9-
import { requireResolveFromRootWithFallback } from '../utils'
9+
import { generateCodeFrame, requireResolveFromRootWithFallback } from '../utils'
1010

1111
export interface TerserOptions extends TerserMinifyOptions {
1212
/**
@@ -50,7 +50,13 @@ export function terserPlugin(config: ResolvedConfig): Plugin {
5050
) => {
5151
const terser: typeof import('terser') = (await import(terserPath))
5252
.default
53-
return terser.minify(code, options) as TerserMinifyOutput
53+
try {
54+
return (await terser.minify(code, options)) as TerserMinifyOutput
55+
} catch (e) {
56+
// convert to a plain object as additional properties of Error instances are not
57+
// sent back to the main thread
58+
throw { stack: e.stack /* stack is non-enumerable */, ...e }
59+
}
5460
},
5561
{
5662
shouldUseFake(_terserPath, _code, options) {
@@ -78,7 +84,7 @@ export function terserPlugin(config: ResolvedConfig): Plugin {
7884
return !!environment.config.build.minify
7985
},
8086

81-
async renderChunk(code, _chunk, outputOptions) {
87+
async renderChunk(code, chunk, outputOptions) {
8288
// This plugin is included for any non-false value of config.build.minify,
8389
// so that normal chunks can use the preferred minifier, and legacy chunks
8490
// can use terser.
@@ -100,16 +106,30 @@ export function terserPlugin(config: ResolvedConfig): Plugin {
100106
worker ||= makeWorker()
101107

102108
const terserPath = pathToFileURL(loadTerserPath(config.root)).href
103-
const res = await worker.run(terserPath, code, {
104-
safari10: true,
105-
...terserOptions,
106-
sourceMap: !!outputOptions.sourcemap,
107-
module: outputOptions.format.startsWith('es'),
108-
toplevel: outputOptions.format === 'cjs',
109-
})
110-
return {
111-
code: res.code!,
112-
map: res.map as any,
109+
try {
110+
const res = await worker.run(terserPath, code, {
111+
safari10: true,
112+
...terserOptions,
113+
sourceMap: !!outputOptions.sourcemap,
114+
module: outputOptions.format.startsWith('es'),
115+
toplevel: outputOptions.format === 'cjs',
116+
})
117+
return {
118+
code: res.code!,
119+
map: res.map as any,
120+
}
121+
} catch (e) {
122+
if (e.line !== undefined && e.col !== undefined) {
123+
e.loc = {
124+
file: chunk.fileName,
125+
line: e.line,
126+
column: e.col,
127+
}
128+
}
129+
if (e.pos !== undefined) {
130+
e.frame = generateCodeFrame(code, e.pos)
131+
}
132+
throw e
113133
}
114134
},
115135

0 commit comments

Comments
 (0)