Add basic rendering to report generator v2#1933
Add basic rendering to report generator v2#1933dgozman wants to merge 3 commits intoGoogleChrome:masterfrom
Conversation
Supports categories, audits, scores, lists, blocks and text. Changed is-on-https audit to show list of urls as an example. Clearly needs some design love.
| }; | ||
|
|
||
| // /** @typedef {{type: string, text: string|undefined, header: DetailsJSON|undefined, items: Array<DetailsJSON>|undefined}} */ | ||
| // var DetailsJSON; |
There was a problem hiding this comment.
Linter doesn't like var here, but using let will pollute the scope. Is there a known way for typedefs?
There was a problem hiding this comment.
Linter doesn't like var here, but using let will pollute the scope. Is there a known way for typedefs?
yeah, I was thinking about this when looking at enabling closure compilation of the project again. If we do more typedefs in files just meant for node/browserification, the nice thing is that those will be limited in scope to the file. For stuff in the browser it's harder. A few ideas:
- we could add an .eslintrc to this directory to modify the rules, since in theory this js file will only ever run in a browser context and not in node (never say never, though :)
- NTI doesn't support typedefs as namespaces, but would doing
ReportRenderer.DetailsJSONwork here since the namespace would be a real object? - we live with the pollution and in the future add something to
report-generator.jsthat strips it out - We live with the pollution and pick names that will (probably) only ever be used for typedefs
There was a problem hiding this comment.
My vote is for 4. The pollution seems very manageable, for the limited number of typedefs we have.
There was a problem hiding this comment.
My vote is for 4
SGTM2.
We were also just talking and realized it doesn't matter if this is var or let here anyways, since even if we use var here if somewhere else a global with the same name is declared with let or const it will throw an error. So I'm good with let and global pollution.
|
|
||
| /* Text */ | ||
|
|
||
| .lighthouse-text { |
There was a problem hiding this comment.
We tried to follow BEM in the previous report, do we have any opinions about it in the new world?
I'm personally not a huge fan, but I like the idea of having some convention to standardize around.
There was a problem hiding this comment.
shadow dom is the solution :)
There was a problem hiding this comment.
Agree with having a convention. That said, I don't love any of the options. But I think we need to pick one regardless
Honestly BEM probably has the most tooling support of any CSS convention, so I favor that.
Should we migrate to it in this PR? I could go either way.
| element.appendChild(pre); | ||
| renderReport(report) { | ||
| try { | ||
| var element = this._renderReport(report); |
There was a problem hiding this comment.
might have to make a decision if we follow devtools style and conventions or lighthouse (or drift the rest of lighthouse to devtools?). use of const, let vs. var, object shorthand, etc
| */ | ||
| _renderException(e) { | ||
| var element = this._createElement('div', 'lighthouse-exception'); | ||
| element.textContent = '' + e; |
There was a problem hiding this comment.
thoughts on e.stack instead for a little more info?
| */ | ||
| _renderException(e) { | ||
| const element = this._createElement('div', 'lighthouse-exception'); | ||
| element.textContent = String(e); |
There was a problem hiding this comment.
String(e.stack)so we can get the message and callstack.
| }; | ||
|
|
||
| /** @typedef {{type: string, text: string|undefined, header: DetailsJSON|undefined, items: Array<DetailsJSON>|undefined}} */ | ||
| let DetailsJSON; |
There was a problem hiding this comment.
can do let DetailsJSON; // eslint-disable-line no-unused-vars for each of these to disable the lint failure on just these lines
| * @param {string} text | ||
| * @return {Node} | ||
| */ | ||
| _createTextChild(parent, text) { |
There was a problem hiding this comment.
Nope. I'll remove it. Thanks!
| generateReportHtml(reportAsJson) { | ||
| const sanitizedJson = JSON.stringify(reportAsJson).replace(/</g, '\\u003c'); | ||
| const sanitizedJavascript = REPORT_JAVASCRIPT.replace(/<\//g, '\\u003c/'); | ||
| const sanitizedCss = REPORT_CSS.replace(/<\//g, '\\u003c/'); |
There was a problem hiding this comment.
I think @brendankenny mentioned this in another PR, but sanitizedJavascript and sanitizedCss aren't necessary b/c we control both files. Might be a good time to just remove.
There was a problem hiding this comment.
Can rename to escaped or something if we want to make that clearer
There was a problem hiding this comment.
We'd know right away if the whole report was broken :) The current _escapeScriptTags does the same as your sanitizedJson, which sanitizes user input in the json results. But our own stuff should be safe (REPORT_JAVASCRIPT and REPORT_CSS).
|
|
||
| /* Text */ | ||
|
|
||
| .lighthouse-text { |
There was a problem hiding this comment.
shadow dom is the solution :)
| * @param {string=} className | ||
| * @returns {Element} | ||
| */ | ||
| _createElement(name, className) { |
There was a problem hiding this comment.
Shall we support attributes too? There are a couple of places we use them in the current report.
_createElement(name, className, attrs = []) {
...
for (const [key, val] of Object.entries(attrs)) {
element.setAttribute(key, val);
}
There was a problem hiding this comment.
Let's do it when we need it?
There was a problem hiding this comment.
We can wait if you want. But we'll need it for at least two places:
https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-core/report/partials/cards.html#L5
https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-core/report/partials/critical-request-chains.html#L2
I started playing with porting some of the html formatters today and ran into this.
| const element = this._createElement('div', 'lighthouse-score'); | ||
| const value = this._createChild(element, 'div', 'lighthouse-score-value'); | ||
| value.textContent = score.toLocaleString(undefined, {maximumFractionDigits: 1}); | ||
| if (score <= 50) |
There was a problem hiding this comment.
fore scoring you can use this (taken from the existing report):
const RATINGS = {
GOOD: {label: 'good', minScore: 75},
AVERAGE: {label: 'average', minScore: 45},
POOR: {label: 'poor'}
};
There was a problem hiding this comment.
Sorry for the double comments. Github was being weird today.
| const element = this._createElement('div', 'lighthouse-score'); | ||
| const value = this._createChild(element, 'div', 'lighthouse-score__value'); | ||
| value.textContent = score.toLocaleString(undefined, {maximumFractionDigits: 1}); | ||
| if (score <= 50) |
There was a problem hiding this comment.
For scoring, you can use this from the existing report:
const RATINGS = {
GOOD: {label: 'good', minScore: 75},
AVERAGE: {label: 'average', minScore: 45},
POOR: {label: 'poor'}
};
| */ | ||
| _renderScore(score, title, description) { | ||
| const element = this._createElement('div', 'lighthouse-score'); | ||
| const value = this._createChild(element, 'div', 'lighthouse-score__value'); |
There was a problem hiding this comment.
could easily get away without having a _createChild:
element.appendChild(this._createElement('div', 'lighthouse-score__value'));
There was a problem hiding this comment.
_createChild returns an element for further manipulations.
| const renderer = new ReportRenderer(window.__LIGHTHOUSE_JSON__); | ||
| renderer.render(document.body); | ||
| const renderer = new ReportRenderer(document); | ||
| document.body.appendChild(renderer.renderReport(window.__LIGHTHOUSE_JSON__)); |
There was a problem hiding this comment.
Hopefully in the near future, we can move some of the UI into static HTML that gets populated. Is there a plan for that? I'm still very concerned about the maintainability and scalability of a pure dom-based approach.
There was a problem hiding this comment.
This is against the idea of report being embeddable and template-free.
Regarding maintainability: we plan to implement some basic primitives like list/table/url/etc, so that on average nobody has to touch report generator at all.
There was a problem hiding this comment.
I don't think those goals are at odds with a declarative approach. For example, we could declare <template> partials in the page:
<template id="template-audit">
<div class="lighthouse-audit">
<div class="lighthouse-score">
<div class="lighthouse-score__value"><!--score--></div>
<div class="lighthouse-score__text">
<div class="lighthouse-score__title"><!--title--></div>
<div class="lighthouse-score__description"><!--detail--></div>
</div>
</div>
</div>
</template>
http://jsbin.com/bojinipecu/edit?html,output
And various embedders could instantiate slightly different <template>s based on their needs. Alternatively, override a render method and add their extra functionality. It's still 100% DOM, but it would be easier to reason about app structure and make modifications to the UI.
This would also lend itself nicely to creating reusable chunks of markup+functionality in the form of web components. Each component would be responsible for its own css/html/js. DevTools could extend a given component if it needs something different.
const categories = __LIGHTHOUSE_JSON__.reportCategories;
const container = document.querySelector('lighthouse-category');
categories.forEach(audit => {
const auditEl = document.createElement('lighthouse-audit');
auditEl.audit = audit;
container.appendChild(auditEl);
});
might produce something like:
<lighthouse-category>
<lighthouse-audit id="critical-request-chains">
#shadow-root
<div class="lighthouse-score">...</div>
...
<card-fortmatter></card-fortmatter>
</lighthouse-audit>
<lighthouse-audit>...</lighthouse-audit>
</lighthouse-category>
| <meta charset="utf-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"> | ||
| <title>Lighthouse Report</title> | ||
| <style>%%LIGHTHOUSE_CSS%%</style> |
There was a problem hiding this comment.
This one causes vscode's syntax highlighting to blow up. WDYT about making this replace str a css comment: <style>/*%%LIGHTHOUSE_CSS%%*/</style>?
|
There's not too much left here. |
|
Closing down for #1951 |

Supports categories, audits, scores, lists, blocks and text.
Changed is-on-https audit to show list of urls as an example.
Clearly needs some design love.
Ref #1887