-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
treemap: first pass on Lighthouse Treemap #11545
Changes from all commits
86772a7
b92f793
5d2693d
b91150f
5ab0d0d
cafb2f3
df39217
6682ffb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* @license Copyright 2020 The Lighthouse Authors. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
'use strict'; | ||
|
||
const GhPagesApp = require('./gh-pages-app.js'); | ||
|
||
/** | ||
* Build treemap app, optionally deploying to gh-pages if `--deploy` flag was set. | ||
*/ | ||
async function run() { | ||
const app = new GhPagesApp({ | ||
name: 'treemap', | ||
appDir: `${__dirname}/../lighthouse-treemap/app`, | ||
html: {path: 'index.html'}, | ||
stylesheets: [ | ||
{path: 'styles/*'}, | ||
], | ||
javascripts: [ | ||
{path: 'src/*'}, | ||
], | ||
assets: [ | ||
{path: 'images/**/*'}, | ||
{path: 'debug.json'}, | ||
], | ||
}); | ||
|
||
await app.build(); | ||
|
||
const argv = process.argv.slice(2); | ||
if (argv.includes('--deploy')) { | ||
await app.deploy(); | ||
} | ||
} | ||
|
||
run(); |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -27,6 +27,9 @@ | |||||||
|
||||||||
/** @typedef {import('./dom')} DOM */ | ||||||||
|
||||||||
const VIEWER_ORIGIN = 'http://localhost:8000'; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need a good way to control when to use localhost vs when to use the hosted app. Important for local development. Any ideas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could append |
||||||||
const TREEMAP_URL = `${VIEWER_ORIGIN}/treemap/`; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is only when local though right? when deployed won't it be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seems like the path and origin will be environment dependent |
||||||||
|
||||||||
/** | ||||||||
* @param {HTMLTableElement} tableEl | ||||||||
* @return {Array<HTMLElement>} | ||||||||
|
@@ -457,8 +460,7 @@ class ReportUIFeatures { | |||||||
break; | ||||||||
} | ||||||||
case 'open-viewer': { | ||||||||
const viewerPath = '/lighthouse/viewer/'; | ||||||||
ReportUIFeatures.openTabAndSendJsonReport(this.json, viewerPath); | ||||||||
ReportUIFeatures.openTabAndSendJsonReportToViewer(this.json); | ||||||||
break; | ||||||||
} | ||||||||
case 'save-gist': { | ||||||||
|
@@ -478,6 +480,20 @@ class ReportUIFeatures { | |||||||
self.print(); | ||||||||
} | ||||||||
|
||||||||
_openTreemap() { | ||||||||
const treemapDebugData = /** @type {LH.Audit.Details.DebugData} */ ( | ||||||||
this.json.audits['script-treemap-data'].details); | ||||||||
if (!treemapDebugData) return; | ||||||||
|
||||||||
const windowName = `treemap-${this.json.requestedUrl}`; | ||||||||
// TODO how to use this type ...? | ||||||||
/** @type {import('../../../../lighthouse-treemap/types/treemap').Treemap.Options} */ | ||||||||
const treemapOptions = { | ||||||||
lhr: this.json, | ||||||||
}; | ||||||||
ReportUIFeatures.openTabAndSendData(treemapOptions, TREEMAP_URL, windowName); | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Keyup handler for the document. | ||||||||
* @param {KeyboardEvent} e | ||||||||
|
@@ -492,33 +508,43 @@ class ReportUIFeatures { | |||||||
/** | ||||||||
* Opens a new tab to the online viewer and sends the local page's JSON results | ||||||||
* to the online viewer using postMessage. | ||||||||
* @param {LH.Result} reportJson | ||||||||
* @param {string} viewerPath | ||||||||
* @param {LH.Result} json | ||||||||
* @protected | ||||||||
*/ | ||||||||
static openTabAndSendJsonReportToViewer(json) { | ||||||||
// The popup's window.name is keyed by version+url+fetchTime, so we reuse/select tabs correctly | ||||||||
// @ts-ignore - If this is a v2 LHR, use old `generatedTime`. | ||||||||
const fallbackFetchTime = /** @type {string} */ (json.generatedTime); | ||||||||
const fetchTime = json.fetchTime || fallbackFetchTime; | ||||||||
const windowName = `${json.lighthouseVersion}-${json.requestedUrl}-${fetchTime}`; | ||||||||
ReportUIFeatures.openTabAndSendData(json, `${VIEWER_ORIGIN}/lighthouse/viewer/`, windowName); | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Opens a new tab to an external page and sends data using postMessage. | ||||||||
* @param {Object} data | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
(we should probably update viewer to accept There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Planning to add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Isn't that what viewer uses?
They both require an LHR, there could be some overlap in types if we wanted to.
I'm separately advocating elsewhere in this PR that we do do something with it ;) |
||||||||
* @param {string} url | ||||||||
* @param {string} windowName | ||||||||
* @protected | ||||||||
*/ | ||||||||
static openTabAndSendJsonReport(reportJson, viewerPath) { | ||||||||
const VIEWER_ORIGIN = 'https://googlechrome.github.io'; | ||||||||
static openTabAndSendData(data, url, windowName) { | ||||||||
const origin = new URL(url).origin; | ||||||||
// Chrome doesn't allow us to immediately postMessage to a popup right | ||||||||
// after it's created. Normally, we could also listen for the popup window's | ||||||||
// load event, however it is cross-domain and won't fire. Instead, listen | ||||||||
// for a message from the target app saying "I'm open". | ||||||||
const json = reportJson; | ||||||||
window.addEventListener('message', function msgHandler(messageEvent) { | ||||||||
if (messageEvent.origin !== VIEWER_ORIGIN) { | ||||||||
if (messageEvent.origin !== origin) { | ||||||||
return; | ||||||||
} | ||||||||
if (popup && messageEvent.data.opened) { | ||||||||
popup.postMessage({lhresults: json}, VIEWER_ORIGIN); | ||||||||
popup.postMessage(data, origin); | ||||||||
window.removeEventListener('message', msgHandler); | ||||||||
} | ||||||||
}); | ||||||||
|
||||||||
// The popup's window.name is keyed by version+url+fetchTime, so we reuse/select tabs correctly | ||||||||
// @ts-expect-error - If this is a v2 LHR, use old `generatedTime`. | ||||||||
const fallbackFetchTime = /** @type {string} */ (json.generatedTime); | ||||||||
const fetchTime = json.fetchTime || fallbackFetchTime; | ||||||||
const windowName = `${json.lighthouseVersion}-${json.requestedUrl}-${fetchTime}`; | ||||||||
const popup = window.open(`${VIEWER_ORIGIN}${viewerPath}`, windowName); | ||||||||
const popup = window.open(url, windowName); | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Lighthouse Treemap Viewer | ||
|
||
## Development | ||
|
||
```sh | ||
yarn serve-treemap | ||
|
||
# in separate terminal, start build watch | ||
# dependency: `brew install entr` | ||
find lighthouse-treemap | entr -s 'DEBUG=1 yarn build-treemap' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this a new dependency we need to add to CONTRIBUTING.md? $ which entr
entr not found There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, that doesn't seem important to add there. I'll just add a comment here |
||
open http://localhost:8000/treemap/?debug | ||
``` |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
<!-- | ||
Copyright 2020 The Lighthouse Authors. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
--> | ||
|
||
<!doctype html> | ||
<html> | ||
|
||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"> | ||
<title>Lighthouse Treemap</title> | ||
<link rel="icon" | ||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAEhklEQVR4AWJxL/BhIAesev1U5tcflpncgNrKIsqNIwzC9feMpDUzs70kOczMzMzJJcxwCTMzncPMnOwtzBwzMzPb0vRfeZPp0VhPS5I39V5fdiXV1/VD+9QC7OVn9BsyH1XIoEI1PfmJvLFowVV564+34DFUHudbmfDh4kVXh//7XwE+WjS/YfXZe3yr4j2rqj1AIhSB7hZ8ZtPZu/zw8cK523U4wE1/rvPfWrz4zs0m9ZdC9yUJAlASdBAgocRegfF/f3/h/PuaFsxMdwjAR0vm1+06eMMfIrhLqTWqdH4EumU2SPfMhigJAlRQbZrgrRsl9U+Y2DYDFCz3ILC9kiAiqSrMwbWT0nceEnR+9Kggc2zjOJCASDENkg0a5HfZZgDP81CM3CrQs2Z1+o7DJ6ePr8sK0AOCHv5Jjdt3evyYSaZ351VIStIxPRAUtrBYbxC6w+BZ0ivVSBKkIhJhemSyZpfB00EiPO2VjzYkxhcqXQqCWCShGplvi3y0QxqbuBurMjyJeWnkHZuAEgIQGsUBqwrfjZ+IlBgKyRJzVVYF8O6qFWdh86YzQzMrZigYmxAyfvHgLZQ/LC1CbeniW2Hkqr/PH16SgvGuf2/uzNMBwJA/njxizGPtSyAf7EziJCMGRDRdhoAC4PL1A/SrKQMAAQkEfpJAcRQdrBJ7gNwjSpJsdwK+CANBkqa1LgQB4IicV9nYUct7gaxuDJUErQIiEAiMxLVOFlKzIktPpT0ggpdpC/8YAHnxbgkUY4tAAFSR7AAXNyAAWHJrA/kHGjzg5nleuwFO7Nd/IoDw4Pm58+4jNLmYG0wRA5bErc2Mr3Y+dXTDW1VvwqbJkzMCHQ4S1GTCBOIgUHJrGdEwqzR+jAp/o2qAZelUDoQnruEEdDclJI6576AlNVfc+22XN/+Y1vnJD0Yind6UpEEvn/Hqq15EYjCW7jZCJEpnNvDgkyelDjs106kuux2AAXCSobULOWP8mLhYlpoDMK4qAFXJGk+grtH8YXVz5KJblqaG1+VUdTc0I290bmUQAriGITRbdQnom0aoFj8kx1+wMD2ifncAXUQE4SkDqN1hE0jEophs1SUwZAOhUAiMCLwRtamtTZtbbmZErSAUHbSysaoEmnrsakiMiUAURi283gN6wans9oX8rOCrj7/JP35DFD+iQ7Au/K2KE1jzx6ujjUnXFH9KjEq6ZlhsTBICrNLJf47Pv/pkHzvup1w4dmUbEei0+bcXRqJuh5kVARQ8byyYxOwNGr7A87xh1tp8sGT+uMInrwi++Xj7TQz2d27NvwEkrOflAFQGIDA5khASBCGdO2/Z/MnLPwYfv5TFhjW7QhVKAB6afwe2LpFlFsCnlQEosgQgDsdOG1/LKeNqJS4JCSPJ/i+TakwEARor7gER1Iva5JmPOJK0RUqmoPnnlzFCtmIAhAAQEIQRgDaiYPIauNXcnDlRIrWNFY3hm7PG9YRqr7IV7HrCgAC17befjEvRq2nGhAHtBqDpOuI/I1diUUAMYIxEdyejBJqLnNoszGZtfiX/CztGv2mq+sdaAAAAAElFTkSuQmCC"> | ||
<meta name="theme-color" content="#304ffe"> | ||
<link rel="stylesheet" href="styles/treemap.css"> | ||
</head> | ||
|
||
<body> | ||
<main class="lh-main lh-vars"> | ||
<div class="panel panel--settings"> | ||
<header> | ||
<div class="lh-header--section"> | ||
<style> | ||
.lh-topbar__logo { | ||
width: 24px; | ||
height: 24px; | ||
user-select: none; | ||
flex: none; | ||
} | ||
</style> | ||
|
||
<div> | ||
<!-- Lighthouse logo. Stolen from templates.html --> | ||
<svg class="lh-topbar__logo" viewBox="0 0 24 24"> | ||
<defs> | ||
<linearGradient x1="57.456%" y1="13.086%" x2="18.259%" y2="72.322%" id="lh-topbar__logo--a"> | ||
<stop stop-color="#262626" stop-opacity=".1" offset="0%"/> | ||
<stop stop-color="#262626" stop-opacity="0" offset="100%"/> | ||
</linearGradient> | ||
<linearGradient x1="100%" y1="50%" x2="0%" y2="50%" id="lh-topbar__logo--b"> | ||
<stop stop-color="#262626" stop-opacity=".1" offset="0%"/> | ||
<stop stop-color="#262626" stop-opacity="0" offset="100%"/> | ||
</linearGradient> | ||
<linearGradient x1="58.764%" y1="65.756%" x2="36.939%" y2="50.14%" id="lh-topbar__logo--c"> | ||
<stop stop-color="#262626" stop-opacity=".1" offset="0%"/> | ||
<stop stop-color="#262626" stop-opacity="0" offset="100%"/> | ||
</linearGradient> | ||
<linearGradient x1="41.635%" y1="20.358%" x2="72.863%" y2="85.424%" id="lh-topbar__logo--d"> | ||
<stop stop-color="#FFF" stop-opacity=".1" offset="0%"/> | ||
<stop stop-color="#FFF" stop-opacity="0" offset="100%"/> | ||
</linearGradient> | ||
</defs> | ||
<g fill="none" fill-rule="evenodd"> | ||
<path d="M12 3l4.125 2.625v3.75H18v2.25h-1.688l1.5 9.375H6.188l1.5-9.375H6v-2.25h1.875V5.648L12 3zm2.201 9.938L9.54 14.633 9 18.028l5.625-2.062-.424-3.028zM12.005 5.67l-1.88 1.207v2.498h3.75V6.86l-1.87-1.19z" fill="#F44B21"/> | ||
<path fill="#FFF" d="M14.201 12.938L9.54 14.633 9 18.028l5.625-2.062z"/> | ||
<path d="M6 18c-2.042 0-3.95-.01-5.813 0l1.5-9.375h4.326L6 18z" fill="url(#lh-topbar__logo--a)" fill-rule="nonzero" transform="translate(6 3)"/> | ||
<path fill="#FFF176" fill-rule="nonzero" d="M13.875 9.375v-2.56l-1.87-1.19-1.88 1.207v2.543z"/> | ||
<path fill="url(#lh-topbar__logo--b)" fill-rule="nonzero" d="M0 6.375h6v2.25H0z" transform="translate(6 3)"/> | ||
<path fill="url(#lh-topbar__logo--c)" fill-rule="nonzero" d="M6 6.375H1.875v-3.75L6 0z" transform="translate(6 3)"/> | ||
<path fill="url(#lh-topbar__logo--d)" fill-rule="nonzero" d="M6 0l4.125 2.625v3.75H12v2.25h-1.688l1.5 9.375H.188l1.5-9.375H0v-2.25h1.875V2.648z" transform="translate(6 3)"/> | ||
</g> | ||
</svg> | ||
|
||
<span class="lh-header--title lh-text-dim">Lighthouse Treemap</span> | ||
</div> | ||
</div> | ||
|
||
<div class="lh-header--section"> | ||
<span class="lh-header--url-and-size"> | ||
<span class="lh-header--url"></span> • <span class="lh-header--size lh-text-dim"></span></span> | ||
</span> | ||
<div class="panel panel--modals"> | ||
<!-- View modes go here --> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe use an |
||
</div> | ||
</div> | ||
</header> | ||
</div> | ||
|
||
<div class="panel panel--treemap"> | ||
<!-- treemap goes here --> | ||
</div> | ||
</main> | ||
|
||
<script src="src/treemap.js"></script> | ||
|
||
<script> | ||
(function (i, s, o, g, r, a, m) { | ||
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () { | ||
(i[r].q = i[r].q || []).push(arguments) | ||
}, i[r].l = 1 * new Date(); a = s.createElement(o), | ||
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) | ||
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga'); | ||
|
||
ga('create', 'UA-85519014-2', 'auto'); | ||
ga('send', 'pageview'); | ||
</script> | ||
</body> | ||
|
||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noticed an issue with the duplication stuff. Need to make a separate PR for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean split this fix out into a separate PR with tests or there's another fix not shown here that needs to happen in a different PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First one. This is the fix.