diff --git a/bin/build-utils.js b/bin/build-utils.js index 41ccbc0071..fb491fdcd7 100644 --- a/bin/build-utils.js +++ b/bin/build-utils.js @@ -29,8 +29,11 @@ function writeFile(filename, contents) { } function doUglify(pkgName, code, prepend, fileOut) { - var miniCode = prepend + terser.minify(code, { output: { ascii_only: true }}).code; - return writeFile(addPath(pkgName, fileOut), miniCode); + const filename = fileOut.replace(/.*\//, ''); + const sourceMap = { filename, url: filename + '.map' }; + const minified = terser.minify(code, { output: { ascii_only: true }, sourceMap }); + return writeFile(addPath(pkgName, fileOut), prepend + minified.code) + .then(() => writeFile(addPath(pkgName, fileOut) + '.map', minified.map)); } var browserifyCache = {}; diff --git a/bin/test-browser.js b/bin/test-browser.js index aba5ea572b..ca4726e06c 100755 --- a/bin/test-browser.js +++ b/bin/test-browser.js @@ -1,9 +1,11 @@ #!/usr/bin/env node 'use strict'; +const fs = require('node:fs'); const playwright = require('playwright'); - const { identity, pickBy } = require('lodash'); +const { SourceMapConsumer } = require('source-map'); +const stacktraceParser = require('stacktrace-parser'); var MochaSpecReporter = require('mocha').reporters.Spec; const createMochaStatsCollector = require('mocha/lib/stats-collector'); @@ -61,6 +63,8 @@ const qs = { testUrl += '?'; testUrl += new URLSearchParams(pickBy(qs, identity)); +let stackConsumer; + class ArrayMap extends Map { get(key) { if (!this.has(key)) { @@ -108,6 +112,35 @@ class RemoteRunner { this.triggerHandlers(event.name, [ obj, event.err ]); + if (event.err && stackConsumer) { + let stackMapped; + const mappedStack = stacktraceParser + .parse(event.err.stack) + .map(v => { + if (v.file === 'http://127.0.0.1:8000/packages/node_modules/pouchdb/dist/pouchdb.min.js') { + const NON_UGLIFIED_HEADER_LENGTH = 6; // number of lines of header added in build-pouchdb.js + const target = { line:v.lineNumber-NON_UGLIFIED_HEADER_LENGTH, column:v.column-1 }; + const mapped = stackConsumer.originalPositionFor(target); + v.file = 'packages/node_modules/pouchdb/dist/pouchdb.js'; + v.lineNumber = mapped.line; + v.column = mapped.column+1; + if (mapped.name !== null) { + v.methodName = mapped.name; + } + stackMapped = true; + } + return v; + }) + // NodeJS stack frame format: https://nodejs.org/docs/latest/api/errors.html#errorstack + .map(v => `at ${v.methodName} (${v.file}:${v.lineNumber}:${v.column})`) + .join('\n '); + if (stackMapped) { + console.log(` [${obj.title}] Minified error stacktrace mapped to:`); + console.log(` ${event.err.name||'Error'}: ${event.err.message}`); + console.log(` ${mappedStack}`); + } + } + switch (event.name) { case 'fail': this.handleFailed(); break; case 'end': this.handleEnd(); break; @@ -152,19 +185,24 @@ function BenchmarkJsonReporter(runner) { if (runner.failed) { console.log('Runner failed; JSON will not be writted.'); } else { - const { mkdirSync, writeFileSync } = require('fs'); - const resultsDir = 'perf-test-results'; - mkdirSync(resultsDir, { recursive: true }); + fs.mkdirSync(resultsDir, { recursive: true }); const jsonPath = `${resultsDir}/${new Date().toISOString()}.json`; - writeFileSync(jsonPath, JSON.stringify(results, null, 2)); + fs.writeFileSync(jsonPath, JSON.stringify(results, null, 2)); console.log('Wrote JSON results to:', jsonPath); } }); } async function startTest() { + if (qs.src === '../../packages/node_modules/pouchdb/dist/pouchdb.min.js') { + const mapPath = './packages/node_modules/pouchdb/dist/pouchdb.min.js.map'; + const rawMap = fs.readFileSync(mapPath, { encoding:'utf8' }); + const jsonMap = JSON.parse(rawMap); + stackConsumer = await new SourceMapConsumer(jsonMap); + } + try { console.log('Starting', browserName, 'on', testUrl); diff --git a/package.json b/package.json index 1c6cbf3259..0b3f7d5188 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,8 @@ "rollup-plugin-node-resolve": "4.2.4", "rollup-plugin-replace": "1.2.1", "seedrandom": "3.0.5", + "source-map": "0.7.4", + "stacktrace-parser": "0.1.10", "stream-to-promise": "1.1.1", "tape": "4.13.0", "terser": "4.8.0",