현대 웹 개발에서는 사용자 경험과 성능 최적화가 매우 중요합니다.
개발을 자주 진행하다보면 Lighthouse 측정을 놓치는 경우가 있을 수 있는데 웹 사이트 성능을 지속적으로 모니터링하고 개선하는 것은 사용자들에게 더 나은 경험을 제공하고 검색 엔진 최적화(SEO)에도 도움이 됩니다.
이번에 프로젝트에서 Lighthouse CI와 GitHub Actions를 사용하여 웹 사이트의 성능을 지속적으로 모니터링하고, 성능 문제를 식별하고 해결하기 위한 프로세스를 구현하였는데, 어떻게 진행했는지 같이 살펴봅시다!
본격적으로 도입하기 전 간단하게 Lighthouse와 측정을 도와두는 도구, CWV와 Git Actions, Slack에 대해서 간단하게 정리하겠습니다.
Lighthouse는 Google에서 개발한 오픈 소스 도구로, 웹 앱이나 웹 페이지의 성능, 접근성, SEO 등 다양한 측면을 평가하는 도구입니다.
Lighthouse의 주요 기능
1 . 성능 평가: 웹 페이지의 로딩 속도, 렌더링 시간, 자원 사용 등을 평가하여 성능을 개선하는 데 도움
2 . 접근성 평가: 웹 페이지의 접근성을 평가하여 장애인이나 저시력자를 포함한 모든 사용자가 쉽게 이용할 수 있는지 확인
3 . SEO 평가: 웹 페이지의 검색 엔진 최적화(SEO) 상태를 평가하여 검색 결과에서 노출되는 정도를 개선하는 데 도움
4 . 최적화 제안: 평가 결과를 기반으로 성능을 개선할 수 있는 다양한 제안 사항을 제공
예시
Lighthouse을 측정하기 위해서는 크롬 브라우저의 개발자 도구에서 [Lighthouse] -> Analyze page load 버튼을 클릭함으로써 측정이 가능합니다.
그러나 이러한 방식은 수동으로 진행되며, 코드 변경이나 배포와 관련된 성능 변화를 감지하거나, 성능을 지속적으로 모니터링하기에는 적합하지 않습니다.
이를 해결하기 위해 등장한 것이 바로 Lighthouse CI입니다. Lighthouse CI는 GitHub Actions, GitLab CI 등의 CI/CD 도구와 통합하여 웹 페이지의 성능을 자동화된 방식으로 평가할 수 있게 해줍니다.
Core Web Vitals(CWV)는 Google에서 제공하는 세 가지 핵심 웹 퍼포먼스 지표로, 웹 페이지의 사용자 경험을 측정하는 데 사용됩니다.
대표적인 CI/CD 툴입니다. Github에서 제공하며, 소프트웨어 개발 및 배포 과정을 자동화할 수 있습니다.
사용법은 너무 길어지니 여기서는 생략하도록 하겠습니다.
Slack은 업무 협업 및 커뮤니케이션 도구로 널리 사용되는 플랫폼입니다.
여기서는 Slack Web hooks을 활용하여 PR(Pull Request) 혹은 push 마다 Lighthouse 측정 결과를 슬랙 메시지로 알림을 받아볼 수 있게 하겠습니다.
본격적으로 프로세스를 구현해보도록 해봅시다. 🔥
npm i -E -g @lhci/cli
.lighthouserc.js
파일을 생성하고 다음과 같이 입력합니다. const {paths} = require("./etc/paths.js");
// https://github.com/GoogleChrome/lighthouse-ci/blob/main/docs/configuration.md#target
module.exports = {
ci: {
collect: {
settings: {
emulatedFormFactor: 'desktop',
},
startServerCommand: 'yarn start',
url: paths, // 성능을 측정할 url
numberOfRuns: 1, // Lighthouse가 실행되는 횟수, 점수가 동일한 코드라고 하더라도 네트워크 및 웹 기술 등의 변수에 의해 결과가 다르게 나올 수 있으니 여러번 실행하여 테스트한다.
},
assert: {
assertions: {
'categories:performance': ['warning', { minScore: 0.9 }],
'categories:accessibility': ['warning', { minScore: 0.9 }],
'categories:best-practices': ['warning', { minScore: 0.9 }],
'categories:seo': ['warning', { minScore: 0.9 }],
'categories:pwa': ['warning', { minScore: 0.9 }],
},
},
upload: {
target: 'filesystem',
outputDir: './lhci_reports',
reportFilenamePattern: 'example-%%DATETIME%%-CWV-report.%%EXTENSION%%',
},
server: {},
wizard: {},
},
};
path.js
paths
와 devServer
는 입맛에 맞게 수정하면 됩니다.const devServer = 'http://localhost:3000';
const paths = {
home: '/',
a '/a',
b: '/b',
};
exports.paths = Object.keys(paths).map((key) => `${devServer}${paths[key]}`);
lhci autorun
lhci_reports
와 .lighthouseci
에 각각 측정 결과가 생성된 것을 확인해 볼 수 있습니다.
/.github/workflows/lighthouse.yml
생성한 후 다음과 같이 입력합니다.name: Run Lighthouse CI & Slack Msg When feature Push
on:
push:
branches:
- 'feature/**'
jobs:
create-pr:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Use Node.js 20.9.0
uses: actions/setup-node@v1
with:
node-version: 20.9.0
- name: Set yarn version 1.22.19
run: |
yarn set version classic
- name: Install packages
run: |
yarn install
- name: Build
run: |
yarn build
- name: Run Lighthouse CI
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
run: |
npm install -g @lhci/cli
lhci autorun || echo "Fail to Run Lighthouse CI!"
- name: Format lighthouse score
id: format_lighthouse_score
uses: actions/github-script@v3
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const fs = require('fs');
const results = JSON.parse(fs.readFileSync("/home/runner/work/medipot_front/medipot_front/lhci_reports/manifest.json"));
let comments = "";
results.forEach((result) => {
const { summary, jsonPath } = result;
const details = JSON.parse(fs.readFileSync(jsonPath));
const { audits } = details; // details를 사용하기 전에 정의
const formatResult = (res) => Math.round(res * 100);
Object.keys(summary).forEach(
(key) => (summary[key] = formatResult(summary[key]))
);
const score = (res) => (res >= 90 ? "🟢" : res >= 50 ? "🟠" : "🔴");
const comment = [
`⚡️ Lighthouse report!`,
`| Category | Score |`,
`| --- | --- |`,
`| ${score(summary.performance)} Performance | ${summary.performance} |`,
// Add other categories here
].join("\n");
const detail = [
`| Category | Score |`,
`| --- | --- |`,
`| ${score(
audits["first-contentful-paint"].score * 100
)} First Contentful Paint | ${
audits["first-contentful-paint"].displayValue
} |`,
// Add other details here
].join("\n");
comments += comment + "\n" + detail + "\n";
});
core.setOutput('comments', comments)
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
base: develop
branch: ${{ github.ref }}
title: 'Merge feature branch into develop'
body: |
This Pull Request is automatically generated to merge the feature branch into the develop branch.
- name: comment PR
uses: unsplash/comment-on-pr@v1.3.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
msg: ${{ steps.format_lighthouse_score.outputs.comments}}
feature/
로 시작하는 브랜치가 push 됐을 때 해당 job이 실행됩니다.
LHCI_GITHUB_APP_TOKEN
과GITHUB_TOKEN
을 얻으려면 다음과 같은 단계를 따릅니다.
LHCI_GITHUB_APP_TOKEN
생성하기Generate new token
을 클릭합니다.LHCI_GITHUB_APP_TOKEN
등록하기New repository secret
을 클릭합니다.LHCI_GITHUB_APP_TOKEN
을 입력하고 생성했던 토큰값을 입력합니다.Add secret
을 클릭해서 생성을 완료합니다.GITHUB_TOKEN
얻기GITHUB_TOKEN
은 GitHub Actions
에서 자동으로 제공됩니다.
따라서 별도의 설정이 필요하지 않습니다.
참고로 GitHub Actions
에서 작업을 실행할 때마다 자동으로 생성되며, 해당 작업에서만 사용할 수 있습니다.
코드를 푸시해봅시다.
[Merge pull request]의 테스트를 통과했습니다!
이제 Slack 연동을 해서 pr 요청이 올 때 마다 메시지를 받고 Lighthouse 점수까지 같이 받을 수 있도록 해봅시다.
2편에서 계속 ...
참고:
Running GitHub Actions on Preview Deploys
Lighthouse CI를 알아보고 Github Actions에 적용하기
웹 퍼포먼스 개선을 위한 Lighthouse CI 도입기