Skip to content

Commit

Permalink
Add source map tracing in error stack traces (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
TooTallNate authored Oct 14, 2023
1 parent fea2edd commit d326b8d
Show file tree
Hide file tree
Showing 35 changed files with 146 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/nervous-tips-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'nxjs-runtime': patch
---

Add source map tracing in error stack traces
1 change: 1 addition & 0 deletions apps/2048/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/2048/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js port of the 2048 game",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.js --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.js --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/ansi/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/ansi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js app with colors and cursor movement using ANSI escapes",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/canvas/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/canvas/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js app using the web `Canvas` API",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/fonts/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/fonts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js app using customs fonts",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
3 changes: 2 additions & 1 deletion apps/hello-world/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js*
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/hello-world/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "Simple 'Hello World' nx.js app",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 --format=esm src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/repl/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/repl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js REPL (read-eval-print-loop) app",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/snake/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/snake/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "Classic 'snake' game using nx.js",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/starwars/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/starwars/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js app that renders the Star Wars ASCII text",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/svg/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/svg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js app that renders an SVG image to the screen",
"scripts": {
"build": "esbuild --bundle --banner:js='globalThis.global = globalThis;' --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --banner:js='globalThis.global = globalThis;' --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"type": "module",
"description": "nx.js API tests",
"scripts": {
"build": "esbuild --bundle --target=es2020 --format=esm src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --target=es2020 --sourcemap --sources-content=false --format=esm src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/touchscreen/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/touchscreen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js app using the touchscreen",
"scripts": {
"build": "esbuild --bundle --main-fields=module,main --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --main-fields=module,main --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/vibrate/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/vibrate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js app demonstrating the `Switch.vibrate()` API",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions apps/wasm/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*.nro
/node_modules
/romfs/main.js
/romfs/main.js.map
2 changes: 1 addition & 1 deletion apps/wasm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"description": "nx.js app that loads a WASM binary",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"build": "esbuild --bundle --sourcemap --sources-content=false --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -euo pipefail
# Build JS runtime
pnpm bundle
mkdir -p romfs
cp -v ./packages/runtime/runtime.js ./romfs/runtime.js
cp -v ./packages/runtime/runtime.* ./romfs/

# Build packages and example apps
pnpm build
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/runtime.js
/runtime.js*
/public
3 changes: 3 additions & 0 deletions packages/runtime/bundle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ await build({
bundle: true,
minify: process.env.MINIFY === '1',
mainFields: ['module', 'main'],
//conditions: ['nxjs', 'import', 'browser', 'require', 'default'],
target: 'es2020',
entryPoints: ['src/index.ts'],
sourcemap: true,
sourcesContent: false,
outfile: 'runtime.js',
});
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"author": "Nathan Rajlich <[email protected]>",
"license": "MIT",
"devDependencies": {
"@jridgewell/trace-mapping": "^0.3.19",
"@types/color-rgba": "^2.1.0",
"@types/to-px": "^1.1.2",
"@ungap/event-target": "^0.2.4",
Expand Down
2 changes: 2 additions & 0 deletions packages/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ import './navigator';
import * as WebAssembly from './wasm';
def('WebAssembly', WebAssembly);

import './source-map';

/**
* The `import.meta` meta-property exposes context-specific metadata to a JavaScript module.
* It contains information about the module, such as the module's URL.
Expand Down
75 changes: 75 additions & 0 deletions packages/runtime/src/source-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { dataUriToBuffer } from 'data-uri-to-buffer';
import {
TraceMap,
originalPositionFor,
type EncodedSourceMap,
} from '@jridgewell/trace-mapping';
import type { SwitchClass } from './switch';

declare const Switch: SwitchClass;

const SOURCE_MAPPING_URL_PREFIX = '//# sourceMappingURL=';
const sourceMapCache = new Map<string, TraceMap | null>();

function filenameToTracer(filename: string) {
let tracer = sourceMapCache.get(filename);
if (typeof tracer !== 'undefined') return tracer;

// `null` means the source map could not be retrieved for this file
tracer = null;

const contentsBuffer = Switch.readFileSync(filename);
const contents = new TextDecoder().decode(contentsBuffer).trimEnd();
const lastNewline = contents.lastIndexOf('\n');
const lastLine = contents.slice(lastNewline + 1);
if (lastLine.startsWith(SOURCE_MAPPING_URL_PREFIX)) {
const sourceMappingURL = lastLine.slice(
SOURCE_MAPPING_URL_PREFIX.length
);
let sourceMapBuffer: ArrayBuffer;
if (sourceMappingURL.startsWith('data:')) {
sourceMapBuffer = dataUriToBuffer(sourceMappingURL).buffer;
} else {
sourceMapBuffer = Switch.readFileSync(
new URL(sourceMappingURL, filename)
);
}
const sourceMap: EncodedSourceMap = JSON.parse(
new TextDecoder().decode(sourceMapBuffer)
);
tracer = new TraceMap(sourceMap);
}
sourceMapCache.set(filename, tracer);
return tracer;
}

(Error as any).prepareStackTrace = (_: Error, stack: string) => {
return stack
.split('\n')
.map((line) => {
try {
const m = line.match(/(\s+at )(.*) \((.*)\:(\d+)\)$/);
if (!m) return line;

const [_, at, name, filename, lineNo] = m;
const tracer = filenameToTracer(filename);
if (!tracer) return line;

const traced = originalPositionFor(tracer, {
line: +lineNo,
// QuickJS doesn't provide column number.
// Unfortunately that means that minification
// doesn't work well with source maps :(
column: 0,
});
if (!traced.source || !traced.line) return line;

const proto = filename === 'romfs:/runtime.js' ? 'nxjs' : 'app';
return `${at}${traced.name || name} (${proto}:${
traced.source
}:${traced.line})`;
} catch (_) {}
return line;
})
.join('\n');
};
19 changes: 19 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions upload.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
#!/bin/bash
#!/usr/bin/env bash
set -euo pipefail
APP="${1-hello-world}"
SWITCH_HOST="${2-192.168.86.115:5000}"
curl --netrc-optional \
--upload-file nxjs.nro "ftp://${SWITCH_HOST}/switch/nxjs.nro" \

ARGS=(
--upload-file nxjs.nro "ftp://${SWITCH_HOST}/switch/nxjs.nro"
--upload-file "./apps/${APP}/romfs/main.js" "ftp://${SWITCH_HOST}/switch/nxjs.js"
)

# Upload source map file, if it exists
if [ -f "./apps/${APP}/romfs/main.js.map" ]; then
ARGS+=(--upload-file "./apps/${APP}/romfs/main.js.map" "ftp://${SWITCH_HOST}/switch/main.js.map")
fi

curl --netrc-optional "${ARGS[@]}"

0 comments on commit d326b8d

Please sign in to comment.