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

report: use source maps to show original file name #10930

Merged
merged 15 commits into from
Jan 20, 2021

Conversation

connorjclark
Copy link
Collaborator

@connorjclark connorjclark commented Jun 9, 2020

Demo: https://misc-hoten.surge.sh/source-location-map/report.html (go to legacy javascript)

Before (roughly):
image

After:

image
image

image

Links are blue because renderLink is different than renderTextURL. How do we want to handle this?

@connorjclark connorjclark requested a review from a team as a code owner June 9, 2020 01:26
@connorjclark connorjclark requested review from paulirish and removed request for a team June 9, 2020 01:26
@@ -224,6 +224,11 @@ declare global {
urlProvider: 'network' | 'comment';
line: number;
column: number;
original?: {
file: string;
Copy link
Member

Choose a reason for hiding this comment

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

can we use url instead of file to have consistency with SourceLocationValue?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This would be a misnomer. This value comes from a source maps sources array, and are not urls, but filenames.

I added a comment to note this.

file: string;
line: number;
column: number;
};
Copy link
Member

Choose a reason for hiding this comment

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

also... do you know what's up with this comment?

/** urls from the network are always valid urls. otherwise, urls come from either a comment or header, and may not be well-formed. */

" urls from the network are always valid urls" vs "urls [...] may not be well-formed" 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You can put absolutely anything in a soruceMappingURL comment or the associated header. Treating this user input as a well-formed URL is error prone.

In some cases the protocol hides the true resource (network) url from us, if there is a comment url present. see

const urlProvider = stylesheet.hasSourceURL ? 'comment' : 'network';

so we must have a distinction between these two sources of "url", which is what urlProvider is for.

lighthouse-core/report/html/renderer/details-renderer.js Outdated Show resolved Hide resolved

let element;
// First two cases: url is from network.
Copy link
Member

Choose a reason for hiding this comment

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

it seems like there's gotta be a better way to structure these conditionals.

Copy link
Collaborator Author

@connorjclark connorjclark Aug 21, 2020

Choose a reason for hiding this comment

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

There are certainly different ways to structure this. I went with handling one "provider" at a time. What other way would be simpler?

Copy link
Member

Choose a reason for hiding this comment

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

you have four cases. i figure just an if else handling all those.
plus they all get addDevToolsData so that you can just return once.

diff --git a/lighthouse-core/report/html/renderer/details-renderer.js b/lighthouse-core/report/html/renderer/details-renderer.js
index cef7a8897..e334c4f70 100644
--- a/lighthouse-core/report/html/renderer/details-renderer.js
+++ b/lighthouse-core/report/html/renderer/details-renderer.js
@@ -551,40 +551,32 @@ class DetailsRenderer {
 
     // Lines are shown as one-indexed.
     const generatedLocation = `${item.url}:${item.line + 1}:${item.column}`;
+    let element;
     let originalLocation;
     if (item.original) {
       const file = item.original.file || '<unmapped>';
       originalLocation = `${file}:${item.original.line + 1}:${item.original.column}`;
     }
 
-    // First two cases: url is from network.
-    if (item.urlProvider === 'network') {
-      let element;
-      if (originalLocation) {
-        element = this._renderLink({
-          url: item.url,
-          text: originalLocation,
-        });
-        element.title = `maps to generated location ${generatedLocation}`;
-      } else {
-        element = this.renderTextURL(item.url);
-        this._dom.find('a', element).textContent += `:${item.line + 1}:${item.column}`;
-      }
-
-      return addDevToolsData(element);
-    }
-
-    // Two cases remain:
-    // 1) urlProvider === 'comment' && item.original
-    //    -> Show the source filename in text, source mapped URL in tooltip.
-    // 2) urlProvider === 'comment' && !item.original
-    //    -> Show the source mapped URL.
-
-    let element;
-    if (originalLocation) {
+    // urlProvider reminder:
+    // - 'network' when the url is the actual, observed resource url.
+    // - 'comment' when the url comes from a sourceMapURL comment or X-SourceMap header */
+    if (item.urlProvider === 'network' && originalLocation) {
+      element = this._renderLink({
+        url: item.url,
+        text: originalLocation,
+      });
+      element.title = `Source-mapped from ${generatedLocation}`;
+    } else if (item.urlProvider === 'network' && !originalLocation) {
+      element = this.renderTextURL(item.url);
+      this._dom.find('a', element).textContent += `:${item.line + 1}:${item.column}`;
+    } else if (item.urlProvider === 'comment' && originalLocation) {
+      //  Show the source filename in text, source mapped URL in tooltip.
       element = this._renderText(`${originalLocation} (from source map)`);
       element.title = `${generatedLocation} (from sourceURL)`;
     } else {
+      // The remaining case is urlProvider === 'comment' and doesnt have an originalLocation
+      // Show the source mapped URL.
       element = this._renderText(`${generatedLocation} (from sourceURL)`);
     }
 
diff --git a/types/audit-details.d.ts b/types/audit-details.d.ts
index 4c5ef556b..11ec7b7e9 100644
--- a/types/audit-details.d.ts
+++ b/types/audit-details.d.ts
@@ -218,7 +218,7 @@ declare global {
        */
       export interface SourceLocationValue {
         type: 'source-location';
-        /** urls from the network are always valid urls. otherwise, urls come from either a comment or header, and may not be well-formed. */
+        /** urls from the network are always valid urls. otherwise, urls come from either a comment or header (see urlProvider), and may not be well-formed. */
         url: string;
         /** 'network' when the url is the actual, observed resource url. 'comment' when the url comes from a sourceMapURL comment or X-SourceMap header */
         urlProvider: 'network' | 'comment';

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is much better thx

@connorjclark
Copy link
Collaborator Author

connorjclark commented Aug 21, 2020

(assignee is constant and is the main reviewer as selected by devtools bot. afaiu the current system we're "using" to signal next AI is just swapping labels)

@patrickhulce
Copy link
Collaborator

afaiu the current system we're "using" to signal next AI is just swapping labels

Ya, it means each person needs to keep two links handy for themselves, but it's less effort and much easier to find PRs that are stuck due to mislabeling :)

List of PRs where you are a reviewer:
https://github.com/GoogleChrome/lighthouse/pulls/assigned/<YOUR GITHUB USER>

List of PRs where you are an author:
https://github.com/GoogleChrome/lighthouse/pulls/<YOUR GITHUB USER>

List of PRs that are waiting on your review:
https://github.com/GoogleChrome/lighthouse/pulls?q=is%3Aopen+is%3Apr+assignee%3A<YOUR GITHUB USER>+label%3Awaiting4reviewer

List of PRs that are waiting on your commits:
https://github.com/GoogleChrome/lighthouse/pulls?q=is%3Aopen+is%3Apr+author%3A<YOUR GITHUB USER>+label%3Awaiting4committer

@connorjclark
Copy link
Collaborator Author

afaiu the current system we're "using" to signal next AI is just swapping labels

Ya, it means each person needs to keep two links handy for themselves, but it's less effort and much easier to find PRs that are stuck due to mislabeling :)

List of PRs where you are a reviewer:
https://github.com/GoogleChrome/lighthouse/pulls/assigned/<YOUR GITHUB USER>

List of PRs where you are an author:
https://github.com/GoogleChrome/lighthouse/pulls/<YOUR GITHUB USER>

List of PRs that are waiting on your review:
https://github.com/GoogleChrome/lighthouse/pulls?q=is%3Aopen+is%3Apr+assignee%3A<YOUR GITHUB USER>+label%3Awaiting4reviewer

List of PRs that are waiting on your commits:
https://github.com/GoogleChrome/lighthouse/pulls?q=is%3Aopen+is%3Apr+author%3A<YOUR GITHUB USER>+label%3Awaiting4committer

image

We could add to our docs somewhere what queries to put in the custom dashboard filters.

text: originalLocation,
});
element.title =
`Location ${generatedLocation} maps to original location ${originalLocation}`;
Copy link
Member

Choose a reason for hiding this comment

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

noted about this being too long..

since the text on display is now the originalLocation.. then the title could be

Suggested change
`Location ${generatedLocation} maps to original location ${originalLocation}`;
`Source-mapped from ${generatedLocation}`;

Co-authored-by: Patrick Hulce <patrick.hulce@gmail.com>
@paulirish
Copy link
Member

just capturing the current UX when showing a sourcelocation of a mapped item. note the tooltip:

image

👍

Copy link
Member

@paulirish paulirish left a comment

Choose a reason for hiding this comment

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

great stuff.

small nits only.

let element;
if (item.urlProvider === 'network') {
if (item.urlProvider === 'network' && originalLocation) {
Copy link
Member

Choose a reason for hiding this comment

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

do you mind if we add some comments in here? i always forget what urlProvider is about and wouldn't mind having a lil cheatsheet

Suggested change
if (item.urlProvider === 'network' && originalLocation) {
// Network-served resource w/ sourcemap
if (item.urlProvider === 'network' && originalLocation) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Isn't this why we write jsdocs? hovering over this field in vs code will show this info

Copy link
Collaborator Author

@connorjclark connorjclark Jan 14, 2021

Choose a reason for hiding this comment

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

If originalLocation is aliased to hasSourceMap, plus we consider what I said above, it seems the code would be saying the same as your suggested comments. wdyt?

Copy link
Member

Choose a reason for hiding this comment

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

yeah adding a hasSourceMap var seems nice. That plus the upgraded .d.ts comments sorts this out completely.

text: originalLocation,
});
element.title = `maps to generated location ${generatedLocation}`;
} else if (item.urlProvider === 'network' && !originalLocation) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
} else if (item.urlProvider === 'network' && !originalLocation) {
// Basic case: network-served resource, no sourcemap
} else if (item.urlProvider === 'network' && !originalLocation) {

element = this.renderTextURL(item.url);
this._dom.find('.lh-link', element).textContent += `:${line}:${column}`;
this._dom.find('.lh-link', element).textContent += `:${item.line + 1}:${item.column}`;
} else if (item.urlProvider === 'comment' && originalLocation) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
} else if (item.urlProvider === 'comment' && originalLocation) {
// Resource URL defined by a `sourceURL` and sourcemap also attached
} else if (item.urlProvider === 'comment' && originalLocation) {

} else if (item.urlProvider === 'comment' && originalLocation) {
element = this._renderText(`${originalLocation} (from source map)`);
element.title = `${generatedLocation} (from sourceURL)`;
} else if (item.urlProvider === 'comment' && !originalLocation) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
} else if (item.urlProvider === 'comment' && !originalLocation) {
// Resource URL defined by `sourceURL`, no sourcemap
} else if (item.urlProvider === 'comment' && !originalLocation) {

types/audit-details.d.ts Outdated Show resolved Hide resolved
types/audit-details.d.ts Outdated Show resolved Hide resolved
types/audit-details.d.ts Outdated Show resolved Hide resolved
types/audit-details.d.ts Outdated Show resolved Hide resolved
Comment on lines 233 to 234
/** The relevant file from the map's `sources` array. If missing, could not associate mapping with a specific file ("unmapped" in other tools). */
file?: string;
Copy link
Member

Choose a reason for hiding this comment

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

is this a useless state? Are the line/col numbers still useful if we can't say which file the line/col numbers are in?

@@ -491,6 +491,37 @@ describe('DetailsRenderer', () => {
assert.equal(sourceLocationEl.getAttribute('data-source-column'), `${sourceLocation.column}`);
});

it('renders source-location values using source map data', () => {
Copy link
Member

Choose a reason for hiding this comment

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

may need a few more tests to hit the different cases, e.g. when there's no source map and the title is appended to the title renderTextURL() produces, we'd want to be sure to get an alert if changes to renderTextURL broke the rendering of source-location.

@connorjclark connorjclark changed the title report: use source maps to show original file name for source-location report: use source maps to show original file name Jan 20, 2021
@connorjclark connorjclark merged commit e298b3c into master Jan 20, 2021
@connorjclark connorjclark deleted the source-location-original-map branch January 20, 2021 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants