decode minified stacktrace
This commit is contained in:
		
							parent
							
								
									7a942881ed
								
							
						
					
					
						commit
						be9b919b60
					
				| @ -6,7 +6,7 @@ import copy from 'clipboard-copy' | ||||
| import { LoggerContext } from './logger' | ||||
| import Button from 'react-bootstrap/Button' | ||||
| import { useToast } from './toast' | ||||
| 
 | ||||
| import { decodeMinifiedStackTrace } from '@/lib/stacktrace' | ||||
| class ErrorBoundary extends Component { | ||||
|   constructor (props) { | ||||
|     super(props) | ||||
| @ -27,7 +27,7 @@ class ErrorBoundary extends Component { | ||||
|   getErrorDetails () { | ||||
|     let details = this.state.error.stack | ||||
|     if (this.state.errorInfo?.componentStack) { | ||||
|       details += `\n\nComponent stack:${this.state.errorInfo.componentStack}` | ||||
|       details += `\n\nComponent stack:\n    ${this.state.errorInfo.componentStack}` | ||||
|     } | ||||
|     return details | ||||
|   } | ||||
| @ -69,7 +69,8 @@ const CopyErrorButton = ({ errorDetails }) => { | ||||
|   const toaster = useToast() | ||||
|   const onClick = async () => { | ||||
|     try { | ||||
|       await copy(errorDetails) | ||||
|       const decodedDetails = await decodeMinifiedStackTrace(errorDetails) | ||||
|       await copy(decodedDetails) | ||||
|       toaster?.success?.('copied') | ||||
|     } catch (err) { | ||||
|       console.error(err) | ||||
|  | ||||
							
								
								
									
										47
									
								
								lib/stacktrace.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								lib/stacktrace.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| import { SourceMapConsumer } from 'source-map' | ||||
| 
 | ||||
| // FUN@FILE:LINE:COLUMN
 | ||||
| const STACK_TRACE_LINE_REGEX = /^([A-Za-z0-9]*)@(.*):([0-9]+):([0-9]+)/ | ||||
| 
 | ||||
| /** | ||||
|  * Decode a minified stack trace using source maps | ||||
|  * @param {string} stack - the minified stack trace | ||||
|  * @param {Object<string, SourceMapConsumer>} [sourceMaps] - an object used to cache source maps | ||||
|  * @returns {Promise<string>} Decoded stack trace | ||||
|  */ | ||||
| export async function decodeMinifiedStackTrace (stack, sourceMaps = {}) { | ||||
|   let decodedStack = '' | ||||
|   for (const line of stack.split('\n')) { | ||||
|     try { | ||||
|       const stackLine = line.trim() | ||||
|       const stackLineParts = stackLine?.match(STACK_TRACE_LINE_REGEX) | ||||
|       if (stackLineParts) { | ||||
|         const [stackFile, stackLine, stackColumn] = stackLineParts.slice(2) | ||||
|         if (!stackFile || !stackLine || !stackColumn) throw new Error('Unsupported stack line ' + JSON.stringify(stackLineParts)) | ||||
|         if ( | ||||
|           ( | ||||
|             !stackFile.startsWith(process.env.NEXT_PUBLIC_ASSET_PREFIX) && | ||||
|         !stackFile.startsWith(process.env.NEXT_PUBLIC_URL) | ||||
|           ) || | ||||
|             !stackFile.endsWith('.js') | ||||
|         ) throw new Error('Unsupported file url ' + stackFile) | ||||
|         const sourceMapUrl = stackFile + '.map' | ||||
|         if (!sourceMaps[sourceMapUrl]) { | ||||
|           sourceMaps[sourceMapUrl] = await new SourceMapConsumer(await fetch(sourceMapUrl).then(res => res.text())) | ||||
|         } | ||||
|         const sourceMapper = sourceMaps[sourceMapUrl] | ||||
|         const map = sourceMapper.originalPositionFor({ | ||||
|           line: parseInt(stackLine), | ||||
|           column: parseInt(stackColumn) | ||||
|         }) | ||||
|         const { source, name, line, column } = map | ||||
|         decodedStack += `${name || ''}@${source}:${line}:${column}\n` | ||||
|         continue | ||||
|       } | ||||
|     } catch (e) { | ||||
|       console.error('Cannot decode stack line', e) | ||||
|     } | ||||
|     decodedStack += `${line}\n` | ||||
|   } | ||||
|   return decodedStack | ||||
| } | ||||
							
								
								
									
										7
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -86,6 +86,7 @@ | ||||
|         "remove-markdown": "^0.5.5", | ||||
|         "sass": "^1.79.5", | ||||
|         "serviceworker-storage": "^0.1.0", | ||||
|         "source-map": "^0.8.0-beta.0", | ||||
|         "textarea-caret": "^3.1.0", | ||||
|         "tldts": "^6.1.51", | ||||
|         "tsx": "^4.19.1", | ||||
| @ -18307,6 +18308,7 @@ | ||||
|       "version": "0.8.0-beta.0", | ||||
|       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", | ||||
|       "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", | ||||
|       "license": "BSD-3-Clause", | ||||
|       "dependencies": { | ||||
|         "whatwg-url": "^7.0.0" | ||||
|       }, | ||||
| @ -18343,6 +18345,7 @@ | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", | ||||
|       "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "punycode": "^2.1.0" | ||||
|       } | ||||
| @ -18350,12 +18353,14 @@ | ||||
|     "node_modules/source-map/node_modules/webidl-conversions": { | ||||
|       "version": "4.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", | ||||
|       "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" | ||||
|       "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", | ||||
|       "license": "BSD-2-Clause" | ||||
|     }, | ||||
|     "node_modules/source-map/node_modules/whatwg-url": { | ||||
|       "version": "7.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", | ||||
|       "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "lodash.sortby": "^4.7.0", | ||||
|         "tr46": "^1.0.1", | ||||
|  | ||||
| @ -91,6 +91,7 @@ | ||||
|     "remove-markdown": "^0.5.5", | ||||
|     "sass": "^1.79.5", | ||||
|     "serviceworker-storage": "^0.1.0", | ||||
|     "source-map": "^0.8.0-beta.0", | ||||
|     "textarea-caret": "^3.1.0", | ||||
|     "tldts": "^6.1.51", | ||||
|     "tsx": "^4.19.1", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user