UNPKG

wps-website-performance-scores

Version:

Website Performance Scores (WPS) is a Puppeteer-based library developed in order to measure the performance of a website using WebVitals scores (like Lighthouse).

161 lines (138 loc) 5.74 kB
import { Args, FormattedReport, InitialReport } from "./models/types.model" import puppeteer, { Browser, Viewport } from 'puppeteer' import fs from 'fs' import { Flags } from 'lighthouse/types/externs' const lighthouse = require('lighthouse'); class WPS { targetWebsite: string logFilePath: string screenshotFilePath: string fullDate: boolean viewport: Viewport imageType: string constructor(config: any) { this.targetWebsite = config.targetWebsite this.logFilePath = config.logFilePath || './logs/scoreLogs.json' this.screenshotFilePath = config.screenshotFilePath || './screenshots/' this.fullDate = config.fullDate || true this.viewport = config.viewport this.imageType = config.imageType } /** Runs WPS with the given arguments. */ async run(): Promise<void> { const args = this.processArgs() this.setArgs(args) if (!this.targetWebsite) throw new Error('Please specify a target website in ./config.json') const browser = await this.startBrowser() const initialReport: InitialReport = await this.getTargetScore(browser) const formattedReport: FormattedReport = await this.formatReport(initialReport) this.saveToFolder(formattedReport, this.logFilePath) if (args.screenshot) await this.takeScreenshot(browser) console.log( '\n===== YOUR LIGHTHOUSE SCORES =====\n', formattedReport, '\n==================================' ) await browser.close() } /** Sets the data as defined in the `config.json` */ setArgs(args: Args) { if (args.target) this.targetWebsite = (args.target as string) if (args.fullDate) this.fullDate = (args.fullDate as boolean) } /** Takes screenshot and saves it to the `screenshots/` folder */ async takeScreenshot(browser: Browser) { const page = await browser.newPage() await page.goto(this.targetWebsite) let domain: string = new URL(this.targetWebsite).host domain = domain.includes('www.') ? domain.split('www.')[1].split('.')[0] : domain.split('.')[0] await page.screenshot({ path: `${this.screenshotFilePath}${this.getCurrentFormattedDate()}_${domain}.${this.imageType}` // './screenshots/YYYY.MM.DD-HH:mm:ss_google.png' }) } /** Gets the args (if any) and formats them into an object. */ processArgs(): Args { const argsArray = process.argv.slice(2) const argsObj: { [key: string]: any } = {}; if (argsArray) { argsArray.map((value: string) => { const separator = value.includes('=') ? '=' : ':' const [key, ...val] = value.split(separator) if (val.length) argsObj[key] = val.join(separator) else argsObj[key] = true }) } return argsObj } /** * Use Puppeteer to launch headful Chrome and use the default viewport set in `config.json`. */ async startBrowser(): Promise<Browser> { return await puppeteer.launch({ headless: false, defaultViewport: this.viewport }) } /** * Lighthouse will open the URL. * Puppeteer will observe `targetWebsite` and return the report. * * @param browser * @returns */ async getTargetScore(browser: Browser): Promise<InitialReport> { // Adapted from original at: https://github.com/GoogleChrome/lighthouse/blob/master/docs/puppeteer.md#option-1-launch-chrome-with-puppeteer-and-handoff-to-lighthouse const flags: Flags = { port: +(new URL(browser.wsEndpoint())).port, output: 'json', logLevel: 'info', screenEmulation: { disabled: true } } const { lhr } = await lighthouse(this.targetWebsite, flags) const report: InitialReport = lhr.categories return report } /** Returns the current date formatted as `YYYY.MM.DD-HH:mm:ss` */ getCurrentFormattedDate(full = this.fullDate): string { const today = new Date() const day = today.getDate().toString().length === 2 ? today.getDate() : `0${today.getDate()}` const month = today.getMonth().toString().length === 2 ? today.getMonth() : `0${today.getMonth()}` const year = today.getFullYear() const hour = today.getHours() const minutes = today.getMinutes() const seconds = today.getSeconds() const baseDate = `${year}.${month}.${day}` return full ? `${baseDate}-${hour}:${minutes}:${seconds}` : baseDate } /** Transforms/filters the `initialReport` type into `FormattedReport` */ async formatReport(initialReport: InitialReport): Promise<FormattedReport> { const formattedReport: any = { website: this.targetWebsite, scoreDate: this.getCurrentFormattedDate() } for (const category in initialReport) { if (Object.hasOwnProperty.call(initialReport, category)) { const { id, score }: { id: string, score: number } = (initialReport as any)[category] formattedReport[id.replace(/-/g, '_')] = score } } const finalReport: FormattedReport = formattedReport return finalReport } /** Saves file to folder */ saveToFolder(file: FormattedReport, folder: string): void { try { fs.appendFileSync( folder, `${JSON.stringify(file)},\n`, ) } catch (error) { console.log(error) } } } module.exports = WPS