| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Review requested:
|
Sorry, something went wrong.
Sorry, something went wrong.
Codecov Report
@@ Coverage Diff @@
## master #35725 +/- ##
==========================================
- Coverage 96.40% 96.40% -0.01%
==========================================
Files 222 223 +1
Lines 73682 73713 +31
==========================================
+ Hits 71034 71061 +27
- Misses 2648 2652 +4
Continue to review full report at Codecov.
|
Sorry, something went wrong.
Sorry, something went wrong.
|
This could use some reviews. @nodejs/inspector @nodejs/assert @nodejs/modules-active-members @nodejs/testing @bcoe (source maps) I keep meaning to take a closer look and don't, so I'll ask my question here without having done that (sorry): How does this affect non-inspector output? Will file URLs start showing up in my stack traces at the command line? Or is this inspector-output only? |
Sorry, something went wrong.
Yes, it will affect the console output (stderr/stdout) and the inspector output. Current implementation seems inconsistent, there are already URLs in the output when ESM modules are involved: // error.mjs
export default function test() {
throw new Error();
}// main.js
(function () {
'use strict';
(async () => {
const test = await import('./error.mjs');
test.default();
})().catch(error => {
console.error(error);
});
})();Output:
Error
at Module.test (file:///home/dragiyski/projects/nodejs/test/error.mjs:2:11)
at /home/dragiyski/projects/nodejs/test/main.js:6:21
New Output:
Error
at Module.test (file:///home/dragiyski/projects/nodejs/test/error.mjs:2:11)
at file:///home/dragiyski/projects/nodejs/test/main.js:6:21
There is also URLs even the error is thrown in the CJS module: // main.mjs
import test from './error.js';
test();// error.js
module.exports = function () {
throw new Error();
};Output:
/home/dragiyski/projects/nodejs/test/error.js:2
throw new Error();
^
Error
at module.exports (/home/dragiyski/projects/nodejs/test/error.js:2:11)
at file:///home/dragiyski/projects/nodejs/test/main.mjs:3:1
at ModuleJob.run (node:internal/modules/esm/module_job:146:23)
at async Loader.import (node:internal/modules/esm/loader:165:24)
at async Object.loadESM (node:internal/process/esm_loader:68:5)
New Output:
file:///home/dragiyski/projects/nodejs/test/error.js:2
throw new Error();
^
Error
at module.exports (file:///home/dragiyski/projects/nodejs/test/error.js:2:11)
at file:///home/dragiyski/projects/nodejs/test/main.mjs:3:1
at ModuleJob.run (node:internal/modules/esm/module_job:146:23)
at async Loader.import (node:internal/modules/esm/loader:165:24)
at async Object.loadESM (node:internal/process/esm_loader:68:5)
As it can be seen, ESM modules already report local files as URLs. If any module on NPM examine CallSite object to retrieve a filename and use that filename to fs functions, it would break if it was included from ESM module. This will make the output consistent, so any new module would not need to check if CallSite is an URL (ESM, native node modules, etc) or absolute path (CJS), it would always be an URL. P.S. It might be useful to allow using file: URLs in fs. |
Sorry, something went wrong.
|
It looks like this needs some changes for tests to pass on Windows. 06:53:28 not ok 512 parallel/test-source-map-enable
06:53:28 ---
06:53:28 duration_ms: 0.664
06:53:28 severity: fail
06:53:28 exitcode: 1
06:53:28 stack: |-
06:53:28 node:assert:108
06:53:28 throw new AssertionError(obj);
06:53:28 ^
06:53:28
06:53:28 AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
06:53:29 + actual - expected
06:53:29
06:53:29 + 'file://C:\\workspace\\node-test-binary-windows-js-suites\\node\\test\\fixtures\\source-map'
06:53:29 - 'file:///C:/workspace/node-test-binary-windows-js-suites/node/test/fixtures/source-map'
06:53:29 at Object.<anonymous> (file:///C:/workspace/node-test-binary-windows-js-suites/node/test/parallel/test-source-map-enable.js:90:10)
06:53:29 at Module._compile (node:internal/modules/cjs/loader:1087:30)
06:53:29 at Object.Module._extensions..js (node:internal/modules/cjs/loader:1116:10)
06:53:29 at Module.load (node:internal/modules/cjs/loader:948:32)
06:53:29 at Function.Module._load (node:internal/modules/cjs/loader:789:14)
06:53:29 at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:72:12)
06:53:29 at node:internal/main/run_main_module:17:47 {
06:53:29 generatedMessage: true,
06:53:29 code: 'ERR_ASSERTION',
06:53:29 actual: 'file://C:\\workspace\\node-test-binary-windows-js-suites\\node\\test\\fixtures\\source-map',
06:53:29 expected: 'file:///C:/workspace/node-test-binary-windows-js-suites/node/test/fixtures/source-map',
06:53:29 operator: 'strictEqual'
06:53:29 }
06:53:29 ...
Not entirely sure why those are showing up in Jenkins but not in GitHub Actions CI, but I think it's because we have to skip a bunch of fs tests on GitHub Actions CI on Windows because of something about the underlying file system that is escaping my memory right now. |
Sorry, something went wrong.
We don’t currently run any tests on Windows in GitHub actions. We used to in the workflow for testing building from the source tarball until #34440. |
Sorry, something went wrong.
|
I'm excited to have another person looking at stack traces 😄 A couple initial questions (I'll give a more thorough review in the next couple days).
I will be curious to hear other people's feedback. The addition of the scheme seems a little redundant for the terminal output, but I appreciate that it makes for a better experience in the inspector. |
Sorry, something went wrong.
Yes, when source maps are enabled, the line plugged in into the stack is clickable and links to the source mapped by the source map. The original line is also shown and it leads to the minified file. Chrome's devtools client have some kind of link detection algorithm. You can put in the console any link (including http:// or https://) and it will be clickable even when the link is suffixed with colon (:) and a line number. If it matches registered script exactly it will jump to it, otherwise it will open a new tab in the last focused browser window. However this does not properly detects all URLs in general. For node modules node:internal/url.js will have only /url.js clickable. However, when printing a stack trace the entire part node:internal/url.js would be detected properly and it will be clickable. I have no idea why there would be any difference here. Even worse, when not all call sites are detected as URLs, call sites for node: are shown wrong (URL starts after the first slash), but when all call sites (that have filename) are URLs it works... 😕 It seems having slashes (like node://) helps to detect URL in general, but it does not lead to any registered files. I think that's a bug the devtools devs must fix, but they probably won't because, in websites, all call sites that have filename (they are not native C++) are URLs (scripts in HTML page or remote scripts). Anyway, the idea here is to register all scripts in v8::ScriptCompiler as URL, which is possible since v15.x. Node modules in lib are valid URLs with node: protocol. ESM modules are valid URLs with file:// protocol, even when they are loaded from the local filesystem. The only modules that fail to follow that format are the CJS modules. Because of the ESM modules all facilities to handle path to file URL conversion (or vice versa) are already present and used.
I tried to address that in sourcesToAbsolute, but there is no safe portable way to manually build a file:// URL using string concatenation and I do not see why we need to do that. The final goal is an URL and url module already provides suicient utilities for handling that logic even for more complex cases (detecting if URL is already absolute for any protocol). Originally I tried to apply minimal changes to address sources appended to the call stack, but as it is mentioned in #35903, the source could by absolute pseudo-URL from an external library (i.e. webpack://). |
Sorry, something went wrong.
There was a problem hiding this comment.
It seems having slashes (like node://) helps to detect URL in general, but it does not lead to any registered files. I think that's a bug the devtools devs must fix, but they probably won't because, in websites, all call sites that have filename (they are not native C++) are URLs (scripts in HTML page or remote scripts).
It might be worth talking to some folks who work on inspector, see if they have any thoughts. Where would we want node: to link to? the node.js docs?, the source code on GitHub?
tried to address that in sourcesToAbsolute, but there is no safe portable way to manually build a file:// URL using string concatenation and I do not see why we need to do that.
I'm less concerned about the unit tests passing (I'm sure you'll end up finding the edge cases causing problems).
What I'd like to make sure, is that the inspector UI works as we'd hope on a few testing platforms:
Sorry, something went wrong.
There was a problem hiding this comment.
With the check for file:, under what conditions do we expect this to fail?
If we leave this try/catch, we might want to put a debug in the catch.
Sorry, something went wrong.
There was a problem hiding this comment.
fileURLToPath and normalizeReferrerURL call URL constructor with a single argument. There was a string (I do not remember exactly, but I can try to remove the try/catch and rebuild to find it) like [eval something] that makes URL throws an ERR_INVALID_URL error. Since that is in the unit tests, it might be used in the future. Moreover, users of vm can pass any string for filename or have source map containing any string. The combination of both is possible to make otherwise invalid URL to appear as valid module and in general invalid URLs supplied by the user should not crush for the proper reason: MODULE_NOT_FOUND for example.
Sorry, something went wrong.
There was a problem hiding this comment.
Might be worth getting a unit test around the edge case if possible 👌
Sorry, something went wrong.
There was a problem hiding this comment.
likewise, if we can instead test for filename patterns that would make normalizeReferrerURL throw, it might be better than a catch all try/catch.
Sorry, something went wrong.
There was a problem hiding this comment.
I just ended up undertaking close to this same refactor in #35903
Sorry, something went wrong.
There was a problem hiding this comment.
Yes, that function is affected in both issues. I traced its usage to ensure the first parameter is always a directory path and then converted it to URL. It seems your solution is to first convert it to URL and then call sourcesToAbsolute. Please, make sure it ends with slash /. WHATWG rules for URL will threat the last part as as file otherwise and return one directory upwards. Otherwise both solutions are identical in their core: new URL(source, baseURL).href.
P.S. I am not familiar with the nodejs source, so I try to minimize the amount of dependent changes.
Sorry, something went wrong.
I tested the behavior of devtools on both Windows 10 (Pro June 2020 with Chrome 86.0.4240.111, on VirtualBox) and Ubuntu 20.04, it shows identical behavior:
With both Webstorm (2020.2.3 on Ubuntu 20.04) (Screenshot) and VS Code (configuration above) (Screenshot) the file:// entire URL is visible and:
If someone have the tools and the platform, the following is still not tested:
|
Sorry, something went wrong.
|
module benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/676/ |
Sorry, something went wrong.
|
I think we should probably call this a SemVer major, as upstream libraries tend to assert against error strings (which will change to having a file:// prefix). |
Sorry, something went wrong.
There was a problem hiding this comment.
Thanks for the screen shots, I think this will be a definitely usability improvement for folks using inspectors.
Not for this PR, but two questions I'd like to eventually answer:
Sorry, something went wrong.
There was a problem hiding this comment.
Might be worth getting a unit test around the edge case if possible 👌
Sorry, something went wrong.
Sorry, something went wrong.
|
@nodejs/modules @nodejs/tooling friendly nudge, it would be good to get a few more sets of eyes on this. It will alter stack trace output in a significant way. |
Sorry, something went wrong.
|
@Dragiyski Is this ready for review/landing in your view, or is there still some work you're hoping to do on it first? |
Sorry, something went wrong.
Sorry, something went wrong.
Yes, I think it is ready for review. |
Sorry, something went wrong.
|
I agree with @benjamingr's recommendation, let's benchmark a couple real world modules that are quite large, pulling in the index of googleapis would be a great candidate (its dependency graph is huge, and probably represents a good worst case). Ultimately, I'll trust to @joyeecheung and @benjamingr, as to whether the regression is acceptable. Otherwise, I'm happy with this functionality and am excited that it makes behavior more consistent between ESM and CJS 👍 |
Sorry, something went wrong.
|
@nodejs/tsc (Semver major so needs at least 2 TSC approvals.) |
Sorry, something went wrong.
|
I am still not sure whether making inspector stack traces nicer (a mostly dev-only feature) is worth the cost of the performance regression and potential breakage in the ecosystem. I think we should at least investigate how this would impact real-world packages. |
Sorry, something went wrong.
@joyeecheung @Dragiyski why don't we start with improvement in Error.prepareStackTrace, since it's less controversial? |
Sorry, something went wrong.
|
@bcoe Starting with the Error.prepareStackTrace sounds good, since we are likely to be dealing with errors in those cases |
Sorry, something went wrong.
|
@Dragiyski can you please rebase on top of master to solve the git conflict? |
Sorry, something went wrong.
When the chrome inspector (chrome://inspect) display stack traces, it makes the filename clickable, and developer can easily locate the relevant source with a single click. This only works when filenames are valid URLs. The CJS loader seems to compile sources with absolute path instead of URL, breaking the inspector functionality. This is especially apparent when node_modules contain "at" symbol (@). The loader already presents module to the inspector using file URL, the same URL should be used for compiling the source.
It seems getErrMessage() function uses filename from a CallSite to open a file and extract source code location of the statement. The CallSite now returns file URL, so it must be converted back to path.
Various tests explore the stack trace or CallSite objects' filename. They are modified now to match file URL instead.
Windows path (using backslash) won't be found in stack trace anymore. Use appropriate url.fileURLToPath and url.pathToFileURL when examine the stack trace.
It seems `wrapSafe` filename is always absolute path. Certain aspects for validating paths in `pathToFileURL` can be skipped in favor of better performance of CJS synchrnous loading while keeping the origin.
|
@Dragiyski please let me know when you have something that you'd like folks to take another look at. |
Sorry, something went wrong.
|
@Dragiyski please let me know when you have something that you'd like folks to take another look at. |
Sorry, something went wrong.
|
This needs a rebase. |
Sorry, something went wrong.
|
@Dragiyski would be able to rebase on top of master to solve the git conflict please? |
Sorry, something went wrong.
|
This pull request has been marked as stale due to 90 days of inactivity. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
When the chrome inspector (chrome://inspect) display stack traces, it
makes the filename clickable, and developer can easily locate the
relevant source with a single click. This only works when filenames are
valid URLs. The CJS loader seems to compile sources with absolute path
instead of URL, breaking the inspector functionality. This is especially
apparent when node_modules contain "at" symbol (@). The loader already
presents module to the inspector using file URL, the same URL should be
used for compiling the source.
For example the current stack trace looks like this:
TypeError: (...) at Object.<anonymous> (/home/dragiyski/(...)/@dragiyski/(...)/test.js:19:5)and as shown the link covers only the part after the first slash after the @ directory. The link leads to URL starting with slash (/), which opens an empty (about:blank) tab within the browser. This is an expected behavior, because in URLs @ represents user@host delimiter and the path is not valid absolute URL as it does not have protocol. A properly fixed URL looks like this:
TypeError: (...) at Object.<anonymous> (file:///home/dragiyski/(...)/@dragiyski/(...)/test.js:19:5)and clicking on the link provided in inspector opens the actual location of the source for all call sites, including node_modules containing @ symbol in their path. For the console, the path is printed with file:// in front and clickable in some terminals.
Note: (...) replaces a valid path omitted for security reasons.
Checklist