// "error-stack-parser": "2.0.1", // "stacktrace-gps": "3.0.2" // additional sources https://github.com/stacktracejs/stacktrace.js/blob/master/stacktrace.js#L102-L116 import fs from 'fs'; import path from 'path'; import { SourceMapConsumer } from 'source-map'; import StackTraceGPS from 'stacktrace-gps'; import ErrorStackParser from 'error-stack-parser'; import mapValues from 'lodash/mapValues'; import update from 'lodash/update'; const blackList = ['/webpack-runtime.js']; function formatFilename(name) { return path.basename(name); } function normalizeAssetNames(assets) { return Object.values(assets) .map(i => i.js) .filter(Boolean) .filter(name => !blackList.includes(name)) .map(formatFilename); } function _getSources(filenames, publicPath) { return filenames.reduce(function collectSources(acc, filename) { const resolvedPath = path.join(publicPath, filename); const sourceFile = fs.readFileSync(resolvedPath, 'utf-8'); acc[filename] = sourceFile; return acc; }, {}); } function getFileSources(filenames, publicPath) { return _getSources(filenames, publicPath); } function getSourceMapSources(filenames, publicPath) { const sourceMapCache = _getSources(filenames, publicPath); return mapValues(sourceMapCache, file => new SourceMapConsumer(file)); } export function createSourceMapsCache(assets, publicPath) { const filenames = normalizeAssetNames(assets); const sourceCache = getFileSources(filenames, publicPath); const filenamesMap = filenames.map(name => `${name}.map`); const sourceMapConsumerCache = getSourceMapSources(filenamesMap, publicPath); const gps = new StackTraceGPS({ offline: true, sourceCache, sourceMapConsumerCache }); return { formatError(errorObject) { return Promise.resolve().then(function formatErrorStack() { const parsedErrorStack = ErrorStackParser.parse(errorObject) .filter(o => o.fileName) .map(obj => update(obj, 'fileName', formatFilename)) .map(s => gps.pinpoint(s)); return Promise.all(parsedErrorStack).then(function formatError(stack) { return { name: errorObject.name, message: errorObject.message, stack: stack.join('\n') }; }); }); } }; }