Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: cache source maps in vm sources #52153

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

legendecas
Copy link
Member

Cache source maps found in sources parsed with vm.Script,
vm.compileFunction, and vm.SourceTextModule. Also, retrieve source
url from V8 parsing results.

Not like filenames returned by CallSite.getFileName() in translating
stack traces, when generating source lines prepended to exceptions,
only resource names can be used as an index to find source maps, which
can be source url magic comments instead. Source url magic comments
can be either a file path or a URL. To verify that source urls with
absolute file paths in the source lines are correctly translated,
snapshots should include the full snapshot urls rather than
neutralizing all the path strings in the stack traces.

Fixes: #52102

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/loaders
  • @nodejs/vm

@nodejs-github-bot nodejs-github-bot added lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Mar 19, 2024
@legendecas legendecas added the source maps Issues and PRs related to source map support. label Mar 19, 2024
@GeoffreyBooth
Copy link
Member

Can this let us have V8 produce correct stack traces in the first place so that we don't need to rewrite them?

@legendecas
Copy link
Member Author

V8 doesn't parse JS source maps because it is not necessary to run the code. Source maps are debugging tools that impose runtime performance costs when enabled. In Chrome, only stack traces shown in Chrome DevTools are translated. With the development flag --enable-source-maps, stack traces are translated in Node.js as well.

@GeoffreyBooth are you suggesting that to have V8 translating the stack trace with source maps instead?

@GeoffreyBooth
Copy link
Member

@GeoffreyBooth are you suggesting that to have V8 translating the stack trace with source maps instead?

Yeah. If possible, it would be nice to have V8 handle some or all of the work that we do in lib/internal/source_map/* and the source map-related logic in node_errors.cc. A lot of it is stack trace rewriting per the source map. I don’t know if that’s something that V8 supports as part of its general source map support, but if it is, it would be nice to use that rather than implementing it ourselves.

Not something that needs to be part of this PR, just something that felt like an easy win if you saw the potential for it. Besides reducing our maintenance burden, I’d imagine that V8 source map support would probably be faster than ours.

@@ -151,6 +152,7 @@ function internalCompileFunction(
}

registerImportModuleDynamically(result.function, importModuleDynamically);
maybeCacheSourceMap(filename, code, result.function, false, result.sourceURL, result.sourceMapURL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s the difference between a “source URL” and a “source map URL”? My naïve guess is that a source URL is a file: URL to the module itself, and a source map URL is either a file: URL to a .map file or a data: URL with the source map. I feel like these guesses are probably wrong, though, so these variables should at least get comments or perhaps get better names (since you reuse these names across many files).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your guess is correct. SourceURL is used to specify the URL of the eval-ed source, as described in https://tc39.es/source-map/#linking-evald-code-to-named-generated-code. However, it can be present in sources loaded by CJS/ESM loaders from filesystem as well. V8 will take this magic comment and report errors with it as the script resource name instead:

node/src/node_errors.cc

Lines 62 to 65 in f1949ac

// The ScriptResourceName of the message may be different from the one we use
// to compile the script. V8 replaces it when it detects magic comments in
// the source texts.
Local<Value> script_resource_name = message->GetScriptResourceName();
. So it has to be used as cache key along with its filename.

The name, source url, is taken from the magic comments as:

//# sourceMappingURL=<url>
//# sourceURL=foo.js

Comment on lines +53 to +56
// To reproduce:
// cd test/fixtures/source-map
// npx --package=coffeescript@2.5.1 -- coffee -M --compile tabs.coffee
// sed -i -e "s/$(pwd | sed -e "s/\//\\\\\//g")/\\/synthethized\\/workspace/g" tabs.js
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@legendecas legendecas added the request-ci Add this label to start a Jenkins CI on a PR. label Mar 22, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Mar 22, 2024
@nodejs-github-bot
Copy link
Collaborator

@legendecas
Copy link
Member Author

legendecas commented Mar 22, 2024

Yeah, I can see the potential memory management advantages if v8 translates the source maps. For instance, the script object of eval-ed sources was not exposed through embedder API so it is permanently cached on our side. It is a really good point that if the source map implementation could be moved to V8 and I found that V8 also implemented Wasm source map support.

@legendecas legendecas added the request-ci Add this label to start a Jenkins CI on a PR. label Mar 24, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Mar 24, 2024
@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot
Copy link
Collaborator

@legendecas
Copy link
Member Author

Updated to fix Windows CI failures about the drive letters.

@aduh95
Copy link
Contributor

aduh95 commented May 11, 2024

This needs a rebase.

@eps1lon
Copy link
Contributor

eps1lon commented Nov 15, 2024

What are the next steps to get this merged? This is affecting sourcemaps in bundlers like Webpack and Turbopack that use vm.runInThisContext instead of (0, eval).

@legendecas
Copy link
Member Author

I'm going to rebase to the latest main branch...

Cache source maps found in sources parsed with `vm.Script`,
`vm.compileFunction`, and `vm.SourceTextModule`. Also, retrieve source
url from V8 parsing results.

Not like filenames returned by `CallSite.getFileName()` in translating
stack traces, when generating source lines prepended to exceptions,
only resource names can be used as an index to find source maps, which
can be source url magic comments instead. Source url magic comments
can be either a file path or a URL. To verify that source urls with
absolute file paths in the source lines are correctly translated,
snapshots should include the full snapshot urls rather than
neutralizing all the path strings in the stack traces.
Copy link

codecov bot commented Dec 2, 2024

Codecov Report

Attention: Patch coverage is 74.35897% with 10 lines in your changes missing coverage. Please review.

Project coverage is 88.00%. Comparing base (3bb1d28) to head (ccc60bf).
Report is 254 commits behind head on main.

Files with missing lines Patch % Lines
src/node_contextify.cc 71.42% 2 Missing and 2 partials ⚠️
src/node_errors.cc 62.50% 2 Missing and 1 partial ⚠️
src/module_wrap.cc 60.00% 1 Missing and 1 partial ⚠️
lib/internal/modules/cjs/loader.js 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #52153      +/-   ##
==========================================
+ Coverage   87.95%   88.00%   +0.04%     
==========================================
  Files         656      656              
  Lines      188310   189005     +695     
  Branches    35963    35994      +31     
==========================================
+ Hits       165630   166331     +701     
+ Misses      15854    15837      -17     
- Partials     6826     6837      +11     
Files with missing lines Coverage Δ
lib/internal/modules/esm/translators.js 92.88% <100.00%> (ø)
lib/internal/modules/esm/utils.js 98.88% <100.00%> (ø)
lib/internal/vm.js 100.00% <100.00%> (ø)
lib/internal/vm/module.js 98.47% <100.00%> (+<0.01%) ⬆️
lib/vm.js 99.28% <100.00%> (+<0.01%) ⬆️
lib/internal/modules/cjs/loader.js 94.30% <66.66%> (ø)
src/module_wrap.cc 75.76% <60.00%> (-0.11%) ⬇️
src/node_errors.cc 64.37% <62.50%> (-0.19%) ⬇️
src/node_contextify.cc 81.33% <71.42%> (-0.04%) ⬇️

... and 49 files with indirect coverage changes

@legendecas legendecas added the request-ci Add this label to start a Jenkins CI on a PR. label Dec 2, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Dec 2, 2024
@nodejs-github-bot
Copy link
Collaborator

@eps1lon
Copy link
Contributor

eps1lon commented Dec 3, 2024

Should this have affected vm.runInContext? I can't get vm.runInContext to sourcemap stack traces when I use Node.js built from this branch. Full repro: https://github.com/eps1lon/vm-sourcemaps.

Though tests seem to indicate otherwise. I'd like to check if this fixes the issues we're seeing in Next.js but maybe I'm missing a special command to use Node.js from this branch? node --version is showing v24.0.0-pre so I thought it does use the locally built Node.js.

@legendecas
Copy link
Member Author

legendecas commented Jan 8, 2025

Should this have affected vm.runInContext? I can't get vm.runInContext to sourcemap stack traces when I use Node.js built from this branch. Full repro: https://github.com/eps1lon/vm-sourcemaps.

Though tests seem to indicate otherwise. I'd like to check if this fixes the issues we're seeing in Next.js but maybe I'm missing a special command to use Node.js from this branch? node --version is showing v24.0.0-pre so I thought it does use the locally built Node.js.

@eps1lon https://github.com/eps1lon/vm-sourcemaps specified an external realtive source map url, but vm.runInContext did not specify an absolute URL so vm.runInContext can not resolve the source map. To make such case work, specify an absolute filename in vm.runInContext.

@legendecas legendecas added the request-ci Add this label to start a Jenkins CI on a PR. label Jan 8, 2025
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Jan 8, 2025
@nodejs-github-bot
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. source maps Issues and PRs related to source map support.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Sourcemaps don't work in vm.Script scripts
5 participants