Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to parse webpack source URLs, how to work around around? #500

Open
lancejpollard opened this issue Feb 20, 2024 · 3 comments
Open

Comments

@lancejpollard
Copy link

lancejpollard commented Feb 20, 2024

It looks like it's failing right here:

const url = new URL(input, base);

I have this code for parsing the string sourcemap from a JS file, but it's not working:

const CACHE: Record<string, SourceMapConsumer> = {}

async function loadFile(
  line: string,
): Promise<SourceMapConsumer | void> {
  const link = CACHE[`${line}`]
  if (link) {
    return link
  }

  const res = await fetch(line)
  const text = await res.text()
  const last = text.trim().split('\n').pop() ?? ''
  console.log(text)
  console.log(last)
  if (
    last.match(
      /(\/\/# sourceMappingURL=data:application\/json;charset=utf-8;base64,)/,
    )
  ) {
    console.log(last.slice(RegExp.$1.length))
    const json = JSON.parse(
      atob(last.slice(RegExp.$1.length)),
    ) as RawSourceMap
    json.sources.forEach((source, i) => {
      json.sources[i] = source.replace(/^webpack:\/\//g, 'http://')
    })
    console.log(json)

    const sm = await new SourceMapConsumer(json)
    CACHE[`${line}`] = sm
    return sm
  }
}

async function readFileLocation(
  file: string,
  line: number,
  rise: number,
): Promise<[string, number | undefined, number | undefined]> {
  const link = await loadFile(file)

  const trace = {
    column: rise,
    filename: file,
    line: line,
  }

  if (link) {
    const token = link.originalPositionFor(trace)
    if (token.source) {
      return [
        token.source,
        token.line == null ? undefined : token.line,
        token.column == null ? undefined : token.column,
      ]
    } else {
      return [file, line, rise]
    }
  } else {
    return [file, line, rise]
  }
}

export async function testSourceMaps(error: Error): Promise<string> {
  const stack = getFileLineColumn(error.stack?.split('\n') ?? [])
  const list: Array<string> = []

  for (const data of stack) {
    const [file, line, column] = await readFileLocation(
      data.file,
      data.line ?? 0,
      data.column ?? 0,
    )

    console.log(file, line, column)
  }
}

As you can see in the example, I tried to replace webpack:// with http:// but it didn't seem to help:

json.sources[i] = source.replace(/^webpack:\/\//g, 'http://')

How do I get this working, any suggestions? The error I'm getting is:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'decode')
    at new URLStateMachine (url-state-machine.js:546:1)
    at module.exports.basicURLParse (url-state-machine.js:1264:1)
    at new URLImpl (URL-impl.js:13:1)
    at Object.setup (URL.js:317:1)
    at new URL (URL.js:26:1)
    at util.js:179:1
    at Object.computeSourceURL (util.js:431:1)
    at source-map-consumer.js:207:1
    at Array.map (<anonymous>)
    at source-map-consumer.js:206:1

The JSON looks liek this when I parse the sourcemap in this fashion:

Screenshot 2024-02-20 at 11 58 14 AM

Any help would be greatly appreciated. Thank you.

@martypdx
Copy link

@lancejpollard I would test the URL creation in isolation. That seems to be your probably moreso any sourcemap issue. Given the stack track, it looks like this is the URL implementation being used.

If you can make sure your url string works in the constructor, then you just need to validate your replace algorithm produces the exact right string.

Also, be aware that URL will remove the extraneous dot file path: http://task/./node_modules becomes http://task/node_modules.

@jkrems
Copy link
Collaborator

jkrems commented Feb 24, 2024

URL shouldn't touch the path for unknown schemes (like webpack://) which also means it's somewhat important to not change the scheme. Example:

> new URL('webpack://task/./node_modules/foo/bar.js').href
'webpack://task/./node_modules/foo/bar.js'
> new URL('https://task/./node_modules/foo/bar.js').href
'https://task/node_modules/foo/bar.js'

@martypdx
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants