MISC: Add source map to transformed scripts (#1812)

* MISC: Add source map to transformed scripts

* Print error to console
This commit is contained in:
catloversg
2025-01-20 04:50:50 +07:00
committed by GitHub
parent 7b009991e5
commit 9920b6ae4d
5 changed files with 52 additions and 11 deletions

11
package-lock.json generated
View File

@@ -29,6 +29,7 @@
"bcryptjs": "^2.4.3",
"better-react-mathjax": "^2.0.3",
"clsx": "^1.2.1",
"convert-source-map": "^2.0.0",
"date-fns": "^2.30.0",
"escodegen": "^2.1.0",
"jszip": "^3.10.1",
@@ -60,6 +61,7 @@
"@swc/core": "^1.9.3",
"@types/babel__standalone": "^7.1.7",
"@types/bcryptjs": "^2.4.4",
"@types/convert-source-map": "^2.0.3",
"@types/escodegen": "^0.0.7",
"@types/file-saver": "^2.0.5",
"@types/jest": "^29.5.5",
@@ -4856,6 +4858,13 @@
"@types/node": "*"
}
},
"node_modules/@types/convert-source-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/convert-source-map/-/convert-source-map-2.0.3.tgz",
"integrity": "sha512-ag0BfJLZf6CQz8VIuRIEYQ5Ggwk/82uvTQf27RcpyDNbY0Vw49LIPqAxk5tqYfrCs9xDaIMvl4aj7ZopnYL8bA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/debug": {
"version": "4.1.9",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.9.tgz",
@@ -7230,7 +7239,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
"license": "MIT"
},
"node_modules/cookie": {
"version": "0.7.1",

View File

@@ -29,6 +29,7 @@
"bcryptjs": "^2.4.3",
"better-react-mathjax": "^2.0.3",
"clsx": "^1.2.1",
"convert-source-map": "^2.0.0",
"date-fns": "^2.30.0",
"escodegen": "^2.1.0",
"jszip": "^3.10.1",
@@ -61,6 +62,7 @@
"@swc/core": "^1.9.3",
"@types/babel__standalone": "^7.1.7",
"@types/bcryptjs": "^2.4.4",
"@types/convert-source-map": "^2.0.3",
"@types/escodegen": "^0.0.7",
"@types/file-saver": "^2.0.5",
"@types/jest": "^29.5.5",

View File

@@ -5,6 +5,7 @@
import * as walk from "acorn-walk";
import { parse } from "acorn";
import type * as acorn from "acorn";
import { fromObject } from "convert-source-map";
import { LoadedModule, type ScriptURL, type ScriptModule } from "./Script/LoadedModule";
import type { Script } from "./Script/Script";
@@ -85,6 +86,7 @@ function generateLoadedModule(script: Script, scripts: Map<ScriptFilePath, Scrip
throw new Error(`Script content is an empty string. Filename: ${script.filename}, server: ${script.server}.`);
}
let scriptCode;
let sourceMap;
const fileType = getFileType(script.filename);
switch (fileType) {
case FileType.JS:
@@ -93,7 +95,7 @@ function generateLoadedModule(script: Script, scripts: Map<ScriptFilePath, Scrip
case FileType.JSX:
case FileType.TS:
case FileType.TSX:
scriptCode = transformScript(script.code, fileType);
({ scriptCode, sourceMap } = transformScript(script.code, fileType));
break;
default:
throw new Error(`Invalid file type: ${fileType}. Filename: ${script.filename}, server: ${script.server}.`);
@@ -179,7 +181,19 @@ function generateLoadedModule(script: Script, scripts: Map<ScriptFilePath, Scrip
// servers; it will be listed under the first server it was compiled for.
// We don't include this in the cache key, so that other instances of the
// script dedupe properly.
const adjustedCode = newCode + `\n//# sourceURL=${script.server}/${script.filename}`;
const sourceURL = `${script.server}/${script.filename}`;
let adjustedCode = newCode + `\n//# sourceURL=${sourceURL}`;
if (sourceMap) {
let inlineSourceMap;
try {
inlineSourceMap = fromObject({ ...JSON.parse(sourceMap), sources: [sourceURL], sourceRoot: "/" }).toComment();
} catch (error) {
console.warn(`Cannot generate inline source map for ${script.filename} in ${script.server}`, error);
}
if (inlineSourceMap) {
adjustedCode += `\n${inlineSourceMap}`;
}
}
// At this point we have the full code and can construct a new blob / assign the URL.
const url = URL.createObjectURL(makeScriptBlob(adjustedCode)) as ScriptURL;

View File

@@ -18,7 +18,19 @@ export function handleUnknownError(e: unknown, ws: WorkerScript | null = null, i
e = ws ? basicErrorMessage(ws, msg, "SYNTAX") : `SYNTAX ERROR:\n\n${msg}`;
} else if (e instanceof Error) {
// Ignore any cancellation errors from Monaco that get here
if (e.name === "Canceled" && e.message === "Canceled") return;
if (e.name === "Canceled" && e.message === "Canceled") {
return;
}
if (ws) {
console.error(`An error was thrown in your script. Hostname: ${ws.hostname}, script name: ${ws.name}.`);
}
/**
* If e is an instance of Error, we print it to the console. This is especially useful when debugging a TypeScript
* script. The stack trace in the error popup contains only the trace of the transpiled code. Even with a source
* map, parsing it to get the relevant info from the original TypeScript file is complicated. The built-in developer
* tool of browsers will do that for us if we print the error to the console.
*/
console.error(e);
const msg = getErrorMessageWithStackAndCause(e);
e = ws ? basicErrorMessage(ws, msg) : `RUNTIME ERROR:\n\n${msg}`;
}

View File

@@ -123,12 +123,11 @@ export function getModuleScript(
/**
* This function must be synchronous to avoid race conditions. Check https://github.com/bitburner-official/bitburner-src/pull/1173#issuecomment-2026940461
* for more information.
*
* @param code
* @param fileType
* @returns
*/
export function transformScript(code: string, fileType: FileType): string | null | undefined {
export function transformScript(
code: string,
fileType: FileType,
): { scriptCode: string; sourceMap: string | undefined } {
if (supportedFileTypes.every((v) => v !== fileType)) {
throw new Error(`Invalid file type: ${fileType}`);
}
@@ -149,11 +148,16 @@ export function transformScript(code: string, fileType: FileType): string | null
parserConfig.jsx = true;
}
}
return transformSync(code, {
const result = transformSync(code, {
jsc: {
parser: parserConfig,
// @ts-expect-error -- jsc supports "esnext" target, but the definition in wasm-web.d.ts is outdated. Ref: https://github.com/swc-project/swc/issues/9495
target: "esnext",
},
}).code;
sourceMaps: true,
});
return {
scriptCode: result.code,
sourceMap: result.map,
};
}