AuditsStatusView.js 9.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. export default class StatusView{constructor(controller){this._controller=controller;this._statusView=null;this._statusHeader=null;this._progressWrapper=null;this._progressBar=null;this._statusText=null;this._cancelButton=null;this._inspectedURL='';this._textChangedAt=0;this._fastFactsQueued=FastFacts.slice();this._currentPhase=null;this._scheduledTextChangeTimeout=null;this._scheduledFastFactTimeout=null;this._dialog=new UI.Dialog();this._dialog.setDimmed(true);this._dialog.setCloseOnEscape(false);this._dialog.setOutsideClickCallback(event=>event.consume(true));this._render();}
  2. _render(){const dialogRoot=UI.createShadowRootWithCoreStyles(this._dialog.contentElement,'audits/auditsDialog.css');const auditsViewElement=dialogRoot.createChild('div','audits-view vbox');const cancelButton=UI.createTextButton(ls`Cancel`,this._cancel.bind(this));const fragment=UI.Fragment.build`
  3. <div class="audits-view vbox">
  4. <h2 $="status-header">Auditing your web page\u2026</h2>
  5. <div class="audits-status vbox" $="status-view">
  6. <div class="audits-progress-wrapper" $="progress-wrapper">
  7. <div class="audits-progress-bar" $="progress-bar"></div>
  8. </div>
  9. <div class="audits-status-text" $="status-text"></div>
  10. </div>
  11. ${cancelButton}
  12. </div>
  13. `;auditsViewElement.appendChild(fragment.element());this._statusView=fragment.$('status-view');this._statusHeader=fragment.$('status-header');this._progressWrapper=fragment.$('progress-wrapper');this._progressBar=fragment.$('progress-bar');this._statusText=fragment.$('status-text');UI.ARIAUtils.markAsProgressBar(this._progressBar,0,Audits.StatusView.StatusPhases.length-1);this._cancelButton=cancelButton;UI.ARIAUtils.markAsStatus(this._statusText);this._dialog.setDefaultFocusedElement(cancelButton);this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeight);this._dialog.setMaxContentSize(new UI.Size(500,400));}
  14. _reset(){this._resetProgressBarClasses();clearTimeout(this._scheduledFastFactTimeout);this._textChangedAt=0;this._fastFactsQueued=FastFacts.slice();this._currentPhase=null;this._scheduledTextChangeTimeout=null;this._scheduledFastFactTimeout=null;}
  15. show(dialogRenderElement){this._reset();this.updateStatus(ls`Loading\u2026`);const parsedURL=this._inspectedURL.asParsedURL();const pageHost=parsedURL&&parsedURL.host;const statusHeader=pageHost?ls`Auditing ${pageHost}`:ls`Auditing your web page`;this._renderStatusHeader(statusHeader);this._dialog.show(dialogRenderElement);}
  16. _renderStatusHeader(statusHeader){this._statusHeader.textContent=`${statusHeader}\u2026`;}
  17. hide(){if(this._dialog.isShowing()){this._dialog.hide();}}
  18. setInspectedURL(url=''){this._inspectedURL=url;}
  19. updateStatus(message){if(!message||!this._statusText){return;}
  20. if(message.startsWith('Cancel')){this._commitTextChange(Common.UIString('Cancelling\u2026'));clearTimeout(this._scheduledFastFactTimeout);return;}
  21. const nextPhase=this._getPhaseForMessage(message);const nextPhaseIndex=Audits.StatusView.StatusPhases.indexOf(nextPhase);const currentPhaseIndex=Audits.StatusView.StatusPhases.indexOf(this._currentPhase);if(!nextPhase&&!this._currentPhase){this._commitTextChange(Common.UIString('Lighthouse is warming up\u2026'));clearTimeout(this._scheduledFastFactTimeout);}else if(nextPhase&&(!this._currentPhase||currentPhaseIndex<nextPhaseIndex)){this._currentPhase=nextPhase;const text=this._getMessageForPhase(nextPhase);this._scheduleTextChange(text);this._scheduleFastFactCheck();this._resetProgressBarClasses();this._progressBar.classList.add(nextPhase.progressBarClass);UI.ARIAUtils.setProgressBarValue(this._progressBar,nextPhaseIndex,text);}}
  22. _cancel(){this._controller.dispatchEventToListeners(Audits.Events.RequestAuditCancel);}
  23. _getMessageForPhase(phase){if(phase.message){return phase.message;}
  24. const deviceType=Audits.RuntimeSettings.find(item=>item.setting.name==='audits.device_type').setting.get();const throttling=Audits.RuntimeSettings.find(item=>item.setting.name==='audits.throttling').setting.get();const match=LoadingMessages.find(item=>{return item.deviceType===deviceType&&item.throttling===throttling;});return match?match.message:ls`Lighthouse is loading your page`;}
  25. _getPhaseForMessage(message){return StatusPhases.find(phase=>message.startsWith(phase.statusMessagePrefix));}
  26. _resetProgressBarClasses(){if(!this._progressBar){return;}
  27. this._progressBar.className='audits-progress-bar';}
  28. _scheduleFastFactCheck(){if(!this._currentPhase||this._scheduledFastFactTimeout){return;}
  29. this._scheduledFastFactTimeout=setTimeout(()=>{this._updateFastFactIfNecessary();this._scheduledFastFactTimeout=null;this._scheduleFastFactCheck();},100);}
  30. _updateFastFactIfNecessary(){const now=performance.now();if(now-this._textChangedAt<fastFactRotationInterval){return;}
  31. if(!this._fastFactsQueued.length){return;}
  32. const fastFactIndex=Math.floor(Math.random()*this._fastFactsQueued.length);this._scheduleTextChange(ls`\ud83d\udca1 ${this._fastFactsQueued[fastFactIndex]}`);this._fastFactsQueued.splice(fastFactIndex,1);}
  33. _commitTextChange(text){if(!this._statusText){return;}
  34. this._textChangedAt=performance.now();this._statusText.textContent=text;}
  35. _scheduleTextChange(text){if(this._scheduledTextChangeTimeout){clearTimeout(this._scheduledTextChangeTimeout);}
  36. const msSinceLastChange=performance.now()-this._textChangedAt;const msToTextChange=minimumTextVisibilityDuration-msSinceLastChange;this._scheduledTextChangeTimeout=setTimeout(()=>{this._commitTextChange(text);},Math.max(msToTextChange,0));}
  37. renderBugReport(err){console.error(err);clearTimeout(this._scheduledFastFactTimeout);clearTimeout(this._scheduledTextChangeTimeout);this._resetProgressBarClasses();this._progressBar.classList.add('errored');this._commitTextChange('');this._statusText.createChild('p').createTextChild(Common.UIString('Ah, sorry! We ran into an error.'));if(KnownBugPatterns.some(pattern=>pattern.test(err.message))){const message=Common.UIString('Try to navigate to the URL in a fresh Chrome profile without any other tabs or extensions open and try again.');this._statusText.createChild('p').createTextChild(message);}else{this._renderBugReportBody(err,this._inspectedURL);}}
  38. renderText(statusHeader,text){this._renderStatusHeader(statusHeader);this._commitTextChange(text);}
  39. toggleCancelButton(show){this._cancelButton.style.visibility=show?'visible':'hidden';}
  40. _renderBugReportBody(err,auditURL){const issueBody=`
  41. ${err.message}
  42. \`\`\`
  43. Channel: DevTools
  44. Initial URL: ${auditURL}
  45. Chrome Version: ${navigator.userAgent.match(/Chrome\/(\S+)/)[1]}
  46. Stack Trace: ${err.stack}
  47. \`\`\`
  48. `;this._statusText.createChild('p').createTextChild(ls`If this issue is reproducible, please report it at the Lighthouse GitHub repo.`);this._statusText.createChild('code','monospace').createTextChild(issueBody.trim());}}
  49. export const fastFactRotationInterval=6000;export const minimumTextVisibilityDuration=3000;const KnownBugPatterns=[/PARSING_PROBLEM/,/DOCUMENT_REQUEST/,/READ_FAILED/,/TRACING_ALREADY_STARTED/,/^You must provide a url to the runner/,/^You probably have multiple tabs open/,];export const StatusPhases=[{id:'loading',progressBarClass:'loading',statusMessagePrefix:'Loading page',},{id:'gathering',progressBarClass:'gathering',message:ls`Lighthouse is gathering information about the page to compute your score.`,statusMessagePrefix:'Gathering',},{id:'auditing',progressBarClass:'auditing',message:ls`Almost there! Lighthouse is now generating your report.`,statusMessagePrefix:'Auditing',}];const LoadingMessages=[{deviceType:'mobile',throttling:'on',message:ls`Lighthouse is loading your page with throttling to measure performance on a mobile device on 3G.`,},{deviceType:'desktop',throttling:'on',message:ls`Lighthouse is loading your page with throttling to measure performance on a slow desktop on 3G.`,},{deviceType:'mobile',throttling:'off',message:ls`Lighthouse is loading your page with mobile emulation.`,},{deviceType:'desktop',throttling:'off',message:ls`Lighthouse is loading your page.`,},];const FastFacts=[ls`1MB takes a minimum of 5 seconds to download on a typical 3G connection [Source: WebPageTest and DevTools 3G definition].`,ls`Rebuilding Pinterest pages for performance increased conversion rates by 15% [Source: WPO Stats]`,ls`BBC has seen a loss of 10% of their users for every extra second of page load [Source: WPO Stats]`,ls`By reducing the response size of JSON needed for displaying comments, Instagram saw increased impressions [Source: WPO Stats]`,ls`Walmart saw a 1% increase in revenue for every 100ms improvement in page load [Source: WPO Stats]`,ls`If a site takes >1 second to become interactive, users lose attention, and their perception of completing the page task is broken [Source: Google Developers Blog]`,ls`75% of global mobile users in 2016 were on 2G or 3G [Source: GSMA Mobile]`,ls`The average user device costs less than 200 USD. [Source: International Data Corporation]`,ls`53% of all site visits are abandoned if page load takes more than 3 seconds [Source: Google DoubleClick blog]`,ls`19 seconds is the average time a mobile web page takes to load on a 3G connection [Source: Google DoubleClick blog]`,ls`14 seconds is the average time a mobile web page takes to load on a 4G connection [Source: Google DoubleClick blog]`,ls`70% of mobile pages take nearly 7 seconds for the visual content above the fold to display on the screen. [Source: Think with Google]`,ls`As page load time increases from one second to seven seconds, the probability of a mobile site visitor bouncing increases 113%. [Source: Think with Google]`,ls`As the number of elements on a page increases from 400 to 6,000, the probability of conversion drops 95%. [Source: Think with Google]`,ls`70% of mobile pages weigh over 1MB, 36% over 2MB, and 12% over 4MB. [Source: Think with Google]`,ls`Lighthouse only simulates mobile performance; to measure performance on a real device, try WebPageTest.org [Source: Lighthouse team]`,];self.Audits=self.Audits||{};Audits=Audits||{};Audits.StatusView=StatusView;Audits.StatusView.StatusPhases=StatusPhases;