Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c908f9e

Browse files
authored
fix: enhance js plugin hook error like rollup (#2767)
### Description - related #2551 As requested in #2551, this automatically injects plugin, hook name, etc.. to errors thrown by js plugin. I also updated error summary formatting to include those details. <details><summary>Example</summary> For the following plugin: ```js plugins: [ { name: 'my-plugin', transform() { this.error("my-error", 2) } } ] ``` Build error now shows this: ``` $ pnpm -C examples/basic-typescript build > @example/typescript@ build /home/hiroshi/code/others/rolldown/examples/basic-typescript > rolldown --config ./rolldown.config.js file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-f-_TEmuT.mjs:168 const wrapper = new Error(summary); ^ Error: Build failed with 1 error: [plugin my-plugin] /home/hiroshi/code/others/rolldown/examples/basic-typescript/index.ts:1:2 RollupError: my-error 1: import { hello } from './hello' ^ 2: 3: console.log(hello()) at error (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-f-_TEmuT.mjs:817:24) at TransformPluginContext.error (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-f-_TEmuT.mjs:1321:11) at TransformPluginContext.transform (file:///home/hiroshi/code/others/rolldown/examples/basic-typescript/rolldown.config.js:17:14) at plugin (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-f-_TEmuT.mjs:1537:25) at handleOutputErrors (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-f-_TEmuT.mjs:168:19) at transformToRollupOutput (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-f-_TEmuT.mjs:152:2) at RolldownBuild.write (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-f-_TEmuT.mjs:2907:10) at async bundleInner (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/esm/cli.mjs:393:23) { errors: [Getter/Setter] } Node.js v20.18.0 ``` which previously was ``` $ pnpm -C examples/basic-typescript build > @example/typescript@ build /home/hiroshi/code/others/rolldown/examples/basic-typescript > rolldown --config ./rolldown.config.js file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-BcFJfRrY.mjs:169 const wrapper = new Error(summary); ^ Error: Build failed with 1 error: RollupError: my-error at error (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-BcFJfRrY.mjs:790:24) at TransformPluginContext.error (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-BcFJfRrY.mjs:1294:11) at TransformPluginContext.transform (file:///home/hiroshi/code/others/rolldown/examples/basic-typescript/rolldown.config.js:17:14) at plugin (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-BcFJfRrY.mjs:1490:30) at handleOutputErrors (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-BcFJfRrY.mjs:169:19) at transformToRollupOutput (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-BcFJfRrY.mjs:152:2) at RolldownBuild.write (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/shared/src_index-BcFJfRrY.mjs:2786:10) at async bundleInner (file:///home/hiroshi/code/others/rolldown/packages/rolldown/dist/esm/cli.mjs:393:23) { errors: [Getter/Setter] } ``` </details>
1 parent 9eb7103 commit c908f9e

8 files changed

Lines changed: 133 additions & 3 deletions

File tree

packages/rolldown/src/plugin/bindingify-plugin.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
bindingifyCloseWatcher,
3232
bindingifyWatchChange,
3333
} from './bindingify-watch-hooks'
34+
import { error, logPluginError } from '../log/logs'
3435

3536
// Note: because napi not catch error, so we need to catch error and print error to debugger in adapter.
3637
export function bindingifyPlugin(
@@ -144,7 +145,7 @@ export function bindingifyPlugin(
144145
const { plugin: closeWatcher, meta: closeWatcherMeta } =
145146
bindingifyCloseWatcher(plugin, options, pluginContextData)
146147

147-
return {
148+
const result: BindingPluginOptions = {
148149
name: plugin.name ?? 'unknown',
149150
buildStart,
150151
buildStartMeta,
@@ -192,4 +193,47 @@ export function bindingifyPlugin(
192193
closeWatcher,
193194
closeWatcherMeta,
194195
}
196+
return wrapHandlers(result)
197+
}
198+
199+
function wrapHandlers(plugin: BindingPluginOptions): BindingPluginOptions {
200+
for (const hookName of [
201+
'buildStart',
202+
'resolveId',
203+
'resolveDynamicImport',
204+
'buildEnd',
205+
'transform',
206+
'moduleParsed',
207+
'load',
208+
'renderChunk',
209+
'augmentChunkHash',
210+
'renderStart',
211+
'renderError',
212+
'generateBundle',
213+
'writeBundle',
214+
'closeBundle',
215+
'banner',
216+
'footer',
217+
'intro',
218+
'outro',
219+
'watchChange',
220+
'closeWatcher',
221+
] as const) {
222+
const handler = plugin[hookName] as any
223+
if (handler) {
224+
plugin[hookName] = async (...args: any[]) => {
225+
try {
226+
return await handler(...args)
227+
} catch (e: any) {
228+
return error(
229+
logPluginError(e, plugin.name, {
230+
hook: hookName,
231+
id: hookName === 'transform' ? args[2] : undefined,
232+
}),
233+
)
234+
}
235+
}
236+
}
237+
}
238+
return plugin
195239
}

packages/rolldown/src/utils/transform-to-rollup-output.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
} from './asset-source'
2020
import { bindingifySourcemap } from '../types/sourcemap'
2121
import { transformToRenderedModule } from './transform-rendered-module'
22+
import { RollupError } from '../rollup'
2223

2324
function transformToRollupOutputChunk(
2425
bindingChunk: BindingOutputChunk,
@@ -134,8 +135,7 @@ export function handleOutputErrors(output: BindingOutputs) {
134135
summary += '\n...'
135136
break
136137
}
137-
const e = errors[i]
138-
summary += (e.stack ?? e.message) + '\n'
138+
summary += getErrorMessage(errors[i]) + '\n'
139139
}
140140
const wrapper = new Error(summary)
141141
// expose individual errors as getters so that
@@ -156,6 +156,38 @@ export function handleOutputErrors(output: BindingOutputs) {
156156
}
157157
}
158158

159+
function getErrorMessage(e: RollupError) {
160+
let s = ''
161+
if (e.plugin) {
162+
s += `[plugin ${e.plugin}]`
163+
}
164+
const id = e.id ?? e.loc?.file
165+
if (id) {
166+
s += ' ' + id
167+
if (e.loc) {
168+
s += `:${e.loc.line}:${e.loc.column}`
169+
}
170+
}
171+
if (s) {
172+
s += '\n'
173+
}
174+
const message = `${e.name ?? 'Error'}: ${e.message}`
175+
s += message
176+
if (e.frame) {
177+
s = joinNewLine(s, e.frame)
178+
}
179+
// copy stack since it's important for js plugin error
180+
if (e.stack) {
181+
s = joinNewLine(s, e.stack.replace(message, ''))
182+
}
183+
return s
184+
}
185+
186+
function joinNewLine(s1: string, s2: string): string {
187+
// ensure single new line in between
188+
return s1.replace(/\n+$/, '') + '\n' + s2.replace(/^\n+/, '')
189+
}
190+
159191
export function transformToOutputBundle(
160192
output: BindingOutputs,
161193
changed: ChangedOutputs,

packages/rolldown/tests/fixtures/misc/error/load/_config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export default defineTest({
2020
expect(e.errors[0]).toMatchObject({
2121
message: 'my-error',
2222
extraProp: 1234,
23+
code: 'PLUGIN_ERROR',
24+
plugin: 'my-plugin',
25+
hook: 'load',
2326
})
2427
},
2528
})
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { defineTest } from '@tests'
2+
import { join } from 'node:path'
3+
import { expect } from 'vitest'
4+
5+
export default defineTest({
6+
config: {
7+
plugins: [
8+
{
9+
name: 'my-plugin',
10+
async transform(_code, id) {
11+
if (id.includes('main.js')) {
12+
return this.error('my-error', 4)
13+
}
14+
},
15+
},
16+
],
17+
},
18+
catchError(e: any) {
19+
const id = join(import.meta.dirname, 'main.js')
20+
expect(e.message).toContain(`\
21+
[plugin my-plugin] ${id}:2:0
22+
RollupError: my-error
23+
1: xxx
24+
2: yyy
25+
^
26+
3: zzz
27+
`)
28+
expect(e.errors[0]).toMatchObject({
29+
message: 'my-error',
30+
code: 'PLUGIN_ERROR',
31+
plugin: 'my-plugin',
32+
hook: 'transform',
33+
id,
34+
})
35+
},
36+
})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
xxx
2+
yyy
3+
zzz

packages/rolldown/tests/fixtures/misc/error/renderChunk/_config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export default defineTest({
2020
expect(e.errors[0]).toMatchObject({
2121
message: 'my-error',
2222
extraProp: 1234,
23+
code: 'PLUGIN_ERROR',
24+
plugin: 'my-plugin',
25+
hook: 'renderChunk',
2326
})
2427
},
2528
})

packages/rolldown/tests/fixtures/misc/error/resolveId/_config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export default defineTest({
1919
expect(e.errors[0]).toMatchObject({
2020
message: 'my-error',
2121
extraProp: 1234,
22+
code: 'PLUGIN_ERROR',
23+
plugin: 'my-plugin',
24+
hook: 'resolveId',
2225
})
2326
},
2427
})

packages/rolldown/tests/fixtures/misc/error/transform/_config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { defineTest } from '@tests'
2+
import { join } from 'node:path'
23
import { expect } from 'vitest'
34

45
export default defineTest({
@@ -13,12 +14,17 @@ export default defineTest({
1314
],
1415
},
1516
catchError(e: any) {
17+
expect(e.message).toContain('[plugin my-plugin]')
1618
expect(e.message).toContain('my-error')
1719
expect(e.message).toContain('at errorFn2')
1820
expect(e.message).toContain('at errorFn1')
1921
expect(e.errors[0]).toMatchObject({
2022
message: 'my-error',
2123
extraProp: 1234,
24+
code: 'PLUGIN_ERROR',
25+
plugin: 'my-plugin',
26+
hook: 'transform',
27+
id: join(import.meta.dirname, './main.js'),
2228
})
2329
},
2430
})

0 commit comments

Comments
 (0)