@@ -545,23 +545,64 @@ export async function build(
545
545
} ,
546
546
}
547
547
548
- const mergeRollupError = ( e : RollupError ) => {
548
+ /**
549
+ * The stack string usually contains a copy of the message at the start of the stack.
550
+ * If the stack starts with the message, we remove it and just return the stack trace
551
+ * portion. Otherwise the original stack trace is used.
552
+ */
553
+ function extractStack ( e : RollupError ) {
554
+ const { stack, name = 'Error' , message } = e
555
+
556
+ // If we don't have a stack, not much we can do.
557
+ if ( ! stack ) {
558
+ return stack
559
+ }
560
+
561
+ const expectedPrefix = `${ name } : ${ message } \n`
562
+ if ( stack . startsWith ( expectedPrefix ) ) {
563
+ return stack . slice ( expectedPrefix . length )
564
+ }
565
+
566
+ return stack
567
+ }
568
+
569
+ /**
570
+ * Esbuild code frames have newlines at the start and end of the frame, rollup doesn't
571
+ * This function normalizes the frame to match the esbuild format which has more pleasing padding
572
+ */
573
+ const normalizeCodeFrame = ( frame : string ) => {
574
+ const trimmedPadding = frame . replace ( / ^ \n | \n $ / g, '' )
575
+ return `\n${ trimmedPadding } \n`
576
+ }
577
+
578
+ const enhanceRollupError = ( e : RollupError ) => {
579
+ const stackOnly = extractStack ( e )
580
+
549
581
let msg = colors . red ( ( e . plugin ? `[${ e . plugin } ] ` : '' ) + e . message )
550
582
if ( e . id ) {
551
583
msg += `\nfile: ${ colors . cyan (
552
584
e . id + ( e . loc ? `:${ e . loc . line } :${ e . loc . column } ` : '' ) ,
553
585
) } `
554
586
}
555
587
if ( e . frame ) {
556
- msg += `\n` + colors . yellow ( e . frame )
588
+ msg += `\n` + colors . yellow ( normalizeCodeFrame ( e . frame ) )
589
+ }
590
+
591
+ e . message = msg
592
+
593
+ // We are rebuilding the stack trace to include the more detailed message at the top.
594
+ // Previously this code was relying on mutating e.message changing the generated stack
595
+ // when it was accessed, but we don't have any guarantees that the error we are working
596
+ // with hasn't already had its stack accessed before we get here.
597
+ if ( stackOnly !== undefined ) {
598
+ e . stack = `${ e . message } \n${ stackOnly } `
557
599
}
558
- return msg
559
600
}
560
601
561
602
const outputBuildError = ( e : RollupError ) => {
562
- const msg = mergeRollupError ( e )
603
+ enhanceRollupError ( e )
563
604
clearLine ( )
564
- config . logger . error ( msg , { error : e } )
605
+ config . logger . error ( e . message , { error : e } )
565
606
}
566
607
567
608
let bundle : RollupBuild | undefined
@@ -727,7 +768,7 @@ export async function build(
727
768
)
728
769
return Array . isArray ( outputs ) ? res : res [ 0 ]
729
770
} catch ( e ) {
730
- e . message = mergeRollupError ( e )
771
+ enhanceRollupError ( e )
731
772
clearLine ( )
732
773
if ( startTime ) {
733
774
config . logger . error (
0 commit comments