Skip to content

Commit

Permalink
fix(gatsby): fix codeframe generation for html errors (#33255)
Browse files Browse the repository at this point in the history
  • Loading branch information
pieh authored Sep 20, 2021
1 parent 06ed2a0 commit 4221f54
Showing 1 changed file with 39 additions and 12 deletions.
51 changes: 39 additions & 12 deletions packages/gatsby-cli/src/reporter/prepare-stack-trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* https://github.com/evanw/node-source-map-support/blob/master/source-map-support.js
*/

import { readFileSync } from "fs"
import { readFileSync, readdirSync } from "fs"
import { codeFrameColumns } from "@babel/code-frame"
import stackTrace from "stack-trace"
import {
Expand All @@ -11,6 +11,7 @@ import {
IndexedSourceMapConsumer,
NullableMappedPosition,
} from "source-map"
import * as path from "path"

export class ErrorWithCodeFrame extends Error {
codeFrame?: string = ``
Expand All @@ -28,13 +29,25 @@ export class ErrorWithCodeFrame extends Error {

export async function prepareStackTrace(
error: Error,
source: string
sourceOfMainMap: string
): Promise<ErrorWithCodeFrame> {
const newError = new ErrorWithCodeFrame(error)
const map = await new SourceMapConsumer(readFileSync(source, `utf8`))
// source point to single map, but with code splitting for build-html we need to handle more maps
// we use fact that all .map files will be in same dir as main one here
const bundleDir = path.dirname(sourceOfMainMap)
const bundleDirMapFiles = readdirSync(bundleDir)
.filter(fileName => fileName.endsWith(`.js.map`))
.map(fileName => path.join(bundleDir, fileName))

const maps = await Promise.all(
bundleDirMapFiles.map(
async source => await new SourceMapConsumer(readFileSync(source, `utf8`))
)
)

const stack = stackTrace
.parse(newError)
.map(frame => wrapCallSite(map, frame))
.map(frame => wrapCallSite(maps, frame))
.filter(
frame =>
`wasConverted` in frame &&
Expand All @@ -44,7 +57,7 @@ export async function prepareStackTrace(
.match(/^webpack:\/+(lib\/)?(webpack\/|\.cache\/)/))
)

newError.codeFrame = getErrorSource(map, stack[0])
newError.codeFrame = getErrorSource(maps, stack[0])
newError.stack =
`${newError.name}: ${newError.message}\n` +
stack.map(frame => ` at ${frame}`).join(`\n`)
Expand All @@ -53,10 +66,17 @@ export async function prepareStackTrace(
}

function getErrorSource(
map: BasicSourceMapConsumer | IndexedSourceMapConsumer,
maps: Array<BasicSourceMapConsumer | IndexedSourceMapConsumer>,
topFrame: stackTrace.StackFrame | IWrappedStackFrame
): string {
const source = map.sourceContentFor(topFrame.getFileName(), true)
let source
for (const map of maps) {
source = map.sourceContentFor(topFrame.getFileName(), true)
if (source) {
break
}
}

return source
? codeFrameColumns(
source,
Expand All @@ -83,13 +103,13 @@ interface IWrappedStackFrame {
}

function wrapCallSite(
map: BasicSourceMapConsumer | IndexedSourceMapConsumer,
maps: Array<BasicSourceMapConsumer | IndexedSourceMapConsumer>,
frame: stackTrace.StackFrame
): IWrappedStackFrame | stackTrace.StackFrame {
const source = frame.getFileName()
if (!source) return frame

const position = getPosition({ map, frame })
const position = getPosition({ maps, frame })
if (!position.source) return frame

return {
Expand All @@ -103,10 +123,10 @@ function wrapCallSite(
}

function getPosition({
map,
maps,
frame,
}: {
map: BasicSourceMapConsumer | IndexedSourceMapConsumer
maps: Array<BasicSourceMapConsumer | IndexedSourceMapConsumer>
frame: stackTrace.StackFrame
}): NullableMappedPosition {
if (frame.getFileName().includes(`webpack:`)) {
Expand All @@ -124,7 +144,14 @@ function getPosition({

const line = frame.getLineNumber()
const column = frame.getColumnNumber()
return map.originalPositionFor({ line, column })
for (const map of maps) {
const test = map.originalPositionFor({ line, column })
if (test.source) {
return test
}
}

return { source: null, column: null, line: null, name: null }
}

// This is copied almost verbatim from the V8 source code at
Expand Down

0 comments on commit 4221f54

Please sign in to comment.