Lighthouse CI by Google

Manoj Masakorala
7 min readJan 13, 2020

Whether you are a small startup or a big enterprise or even a freelance developer, wouldn’t it be nice to have a web app which will show the data related to all the projects in a one central location. When I say data I meant data such as performance matrixes, Search engine optimization results, level of accessibility of the projects and PWA level etc.

Many developers are already aware about lighthouse, the automated tool for improving the web page quality. Lighthouse can be used in chrome DevTools, via command line or even as a Node module. You just have to give a url and wait till it run against series of audits against the page. It would give a report at the end of the scan to see how the page has performed against lighthouse audits. The report will highlight the issues web page has and will give resolutions too in fixing those issues.

Lighthouse is an open-source, automated tool for improving the quality of web pages. You can run it against any web page, public or requiring authentication. It has audits for performance, accessibility, progressive web apps, SEO and more.

Lighthose-ci is basically a wrapper around lighthouse CLI. You can run lighthouse in every commit before push to production​. We can use it to reduce or prevent regression testing around web applications. Though lighthouse-ci has been in the market for sometime now the alpha version was released recently (v0.3.0-alpha.0 (2019–11–08)).

LH CI Architecture.

Before you integrate LH CI to your project make sure you meet the following prerequisites.

  1. Source code is managed with git (GitHub, GitLab, Bitbucket, etc).
  2. Branches/pull requests are gated on the results of a continuous integration build process (Travis CI, CircleCI, Jenkins, AppVeyor, GitHub Actions, etc). If you aren’t using a build process yet, Travis CI offers free continuous integration for open-source projects.
  3. Your CI process can build your project into production assets (typically provided as an npm run build command by most JavaScript frameworks).
  4. Your project either: A) has a command that runs a web server with production-like assets. B) is a static site.

Step 1

Create a reactJS/Angular/VueJS/etc project.

I used npm module, “create-react-app” to create a simple reactjs project.

npx create-react-app my-app
cd my-app
npm start

Push the code to Github or other LHCI supported repos hosting service such as bitbucket. I have pushed my code base to Github. If you are using Github you may need to install and check Github status via official Github status check app to differentiate build fails because of LH and other tests. Once you register your repo you would get a token which later you may need to config in Jenkins (LHCI_GITHUB_APP_TOKEN).

Also create .travis.yml file in your root folder and update the file accordingly by looking at the configurations in Github. upload.target can be either a temporary-public-storage or lhci. temporary-public-storage is a google hosted cloud storage. If you use this option you may not need a LHCI server since LH results are pushed to google hosted cloud service and. Also in there the reports are automatically deleted 7 days after upload. In my project Im gonna use lhci.

# dist: xenial (the default) or newer required
language: node_js # Node 10 LTS or later required
addons:
chrome: stable # make Chrome available
before_install:
- npm install -g @lhci/cli@0.3.x # install LHCI
script:
- npm run webpack:prod # build your site
after_success:
- lhci autorun — upload.target=lhci # run lighthouse CI against your static site

You need to create a LHCI configuration file as well. Configs can be setup via following file formats, which are accepted by LHCI.

  1. .lighthouserc.js
  2. lighthouserc.js
  3. .lighthouserc.json
  4. lighthouserc.json
  5. .lighthouserc.yml
  6. lighthouserc.yml
  7. .lighthouserc.yaml
  8. lighthouserc.yaml
lighthouserc.json

Step 2

Setup Jenkins

Normally when you build your project, Jenkins would download the source code into the machine and build the project inside Jenkins machine.The Jenkins machine should have nodeJS and google chrome installed before we run LH-CI. Once you build the project you would have a destination folder as dist, build or with any other name. If you have a different name other than dist or build you may need to config it in LH configuration file. LH would refer the files in dist folder and would start the project in its own server to run assertions. It would run in a headless-chrome browser.

I used following docker image to set up Jenkins. Also I had to install GitHub and nodeJS plugins as Jenkins plugins.

docker pull jenkinsdocker run — name lhci_server -p 8080:8080 -p 50000:50000 -v /var/jenkins_home jenkins

Following bash script will setup the machine. You can install these manually too.

machine-setup.sh

#!/bin/bashset -euxo pipefail# Add Chrome’s apt-keyecho “deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main” | sudo tee -a /etc/apt/sources.list.d/google.listwget -q -O — https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -# Add Node’s apt-keycurl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -# Install NodeJS and Google Chromesudo apt-get updatesudo apt-get install -y nodejs google-chrome-stable

job.sh

#!/bin/bashset -euxo pipefailnpm installnpm run buildexport LHCI_GITHUB_APP_TOKEN=”4HiZunaj:XXXXXXXX:J53MpLyx0eWnZIi6"export CHROME_PATH=$(which google-chrome-stable)export LHCI_BUILD_CONTEXT__EXTERNAL_BUILD_URL=”$BUILD_URL”npm install -g @lhci/cli@0.3.xlhci autorun — upload.target=lhci
Jenkins Job configuration.

Step 3

Install LHCI Server

LHCI server can be run in any node environment. Persistent disk storage or network access to postgres database is needed. LHCI Server is available as a docker image. All you have to do is setup docker and install the container as bellow.

docker image build -t lhci .docker volume create lhci-datadocker container run — publish 9001:9001 — mount=’source=lhci-data,target=/data’ — detach lhciopen http://localhost:9001/app/
Home page LICI Server
Overall statistics
Compare commits.
Descriptive resolutions for web issues.

When you make a commit into Github it would notify Jenkins and hence would start the job execution. Once build is completed LHCI would run LH against series of predefined assertions and give a score accordingly.

Assertion has failed hence build fails.

Running Lighthouse on Authenticated Pages

Some applications do have an authentication layer where they need to enter username and password. If your app is behind a login use following methods to login your page.

Option 1: Script the login with Puppeteer

const emailInput = await page.$('input[type="email"]');
await emailInput.type('admin@example.com');
const passwordInput = await page.$('input[type="password"]');
await passwordInput.type('password');
await Promise.all([
page.$eval('.login-form', form => form.submit()),
page.waitForNavigation(),
]);

An example code

Option 2: Leverage logged-in state with Chrome DevTools

Option 3: Pass custom request headers with Lighthouse CLI

lighthouse http://www.example.com --view --extra-headers="{\"Authorization\":\"...\"}"

Option 4: Open a debug instance of Chrome and manually log in

  1. Globally install lighthouse: npm i -g lighthouse or yarn global add lighthouse. chrome-debug is now in your PATH. This binary launches a standalone Chrome instance with an open debugging port.
  2. Run chrome-debug. This logs the debugging port of your Chrome instance.
  3. Navigate to your site and log in.
  4. In a separate terminal, run lighthouse http://mysite.com --port port-number, using the port number from chrome-debug.

Option 5: Reuse a prepared Chrome User Profile

This option is currently under development. Track or join the discussion here: #8957.

Configure performance budget to your CI

Performance of your web application is critical now a days. App needs to be loaded with in seconds. A performance budget can be a limit for web pages which should not exceed.

“Having a pre-defined ‘budget’ is a clear, tangible way to frame decisions about what can and can’t be included, and at a suitably early stage in the project” — Mark Perkins

  • 1–3 Second Page Load Time — 32% bounce rate increase
  • 1–5 Second Page Load Time — 90% bounce rate increase
  • 1–6 Second Page Load Time — 106% bounce rate increase
  • 1–10 Second Page Load Time — 123% bounce rate increase

This can be JS bundle size, image weight, or load time over network. The file size should be minimal to achieve lower bounce rate. Image optimization, CSS/JS minification is a must. So we may need to take a decision on what is really important to users.

References

https://github.com/GoogleChrome/lighthouse-ci

https://blog.seriesci.com/lighthouse-in-continuous-integration-might-be-easier-than-you-think/

--

--