Skip to content
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

SP-668 페이지별 성능 측정 tool(LightHouse) 자동화 환경 구축 #349

Merged
merged 73 commits into from
Aug 20, 2024

Conversation

SungHyun627
Copy link
Collaborator

@SungHyun627 SungHyun627 commented Jul 31, 2024

Closes #348

💡 다음 이슈를 해결했어요.

  • lighthouse CI에 사용되는 상수 정의
  • lighthouse ci configuration 설정
  • lighthouse workflow 작성
    • 환경 설정 및 report 생성
    • 성능 지표 포매팅
    • PR Comment에 반영

💡 이슈를 처리하면서 추가된 코드가 있어요.

🛠 lighthouse CI에 사용되는 상수 정의

lighthouse 성능 측정을 진행할 페이지, 페이지 라우트, 성능 점수 기준 등을 정의하였습니다.

const TEST_RECRUITMENT_ID = 70;
const LH_GREEN_MIN_SCORE = 90;
const LH_ORANGE_MIN_SCORE = 50;
const PAGE_ROUTES = {
MAIN: '/',
AUTH: {
LOGIN: '/login',
},
RECRUITMENT: {
RECRUITMENTS: '/studies',
DETAIL: `/studies/${TEST_RECRUITMENT_ID}/recruitment`,
},
};
module.exports = {
DEV_ORIGIN_URL: `https://local.ludo.study:3000`,
LH_MONITORING_PAGE_NAMES: ['메인', '로그인', '모집공고 모아보기', '모집공고 상세'],
LH_MIN_SCORES: { GREEN: LH_GREEN_MIN_SCORE, ORANGE: LH_ORANGE_MIN_SCORE },
LH_MONITORING_PAGE_ROUTES: {
메인: PAGE_ROUTES.MAIN,
로그인: PAGE_ROUTES.AUTH.LOGIN,
'모집공고 모아보기': PAGE_ROUTES.RECRUITMENT.RECRUITMENTS,
'모집공고 상세': PAGE_ROUTES.RECRUITMENT.DETAIL,
},
};

🛠 lighthouse ci configuration 설정

처음에는 root에 lighthouserc.cjs를 구성하고 lighthouse autorun 명령어를 통해 lighthouse report를 생성하려고 했으나 device가 mobile일 때와 desktop일때를 분리하여 지표를 측정하는 게 필요하다고 생각하여 configuration을 lighthouserc-mobile.cjslighthouserc-desktop.cjs로 나누어서 작성하였습니다.

✔︎ Desktop configuration

const {
LH_MONITORING_PAGE_NAMES,
DEV_ORIGIN_URL,
LH_MONITORING_PAGE_ROUTES,
} = require('./src/Constants/lighthouse.ts');
const urls = LH_MONITORING_PAGE_NAMES.map((pageName) => `${DEV_ORIGIN_URL}${LH_MONITORING_PAGE_ROUTES[pageName]}`);
module.exports = {
ci: {
collect: {
startServerCommand: 'yarn start:mac',
url: urls,
numberOfRuns: 1,
settings: {
chromeFlags: '--ignore-certificate-errors',
preset: 'desktop',
},
},
upload: {
target: 'filesystem',
outputDir: './lhci_reports/desktop',
reportFilenamePattern: '%%PATHNAME%%-%%DATETIME%%-desktop-report.%%EXTENSION%%',
},
},
};

✔︎ Mobile configuration

const {
LH_MONITORING_PAGE_NAMES,
DEV_ORIGIN_URL,
LH_MONITORING_PAGE_ROUTES,
} = require('./src/Constants/lighthouse.ts');
const urls = LH_MONITORING_PAGE_NAMES.map((pageName) => `${DEV_ORIGIN_URL}${LH_MONITORING_PAGE_ROUTES[pageName]}`);
module.exports = {
ci: {
collect: {
startServerCommand: 'yarn start:mac',
url: urls,
numberOfRuns: 1,
settings: {
chromeFlags: '--ignore-certificate-errors',
},
},
upload: {
target: 'filesystem',
outputDir: './lhci_reports/mobile',
reportFilenamePattern: '%%PATHNAME%%-%%DATETIME%%-mobile-report.%%EXTENSION%%',
},
},
};

이를 기반으로 로컬에서 lhci collect --config=lighthouserc-desktop.cjs && lhci upload --config=lighthouserc-desktop.cjs , lhci upload --config=lighthouserc-desktop.cjs && lhci collect --config=lighthouserc-desktop.cjs를 실행하면 아래와 같이 lhci_reports 폴더 하위에 각각의 device에 해당하는 폴더가 만들어지고, 그곳에 report가 생성됩니다.

🛠 lighthouse workflow 작성

생성된 Report와 정의한 상수를 기반으로 lighthouse workflow를 작성하였습니다.

✔︎ 환경 설정 및 report 생성

name: Run lighthouse CI When Push on PR to Dev Branch
on:
pull_request:
branches:
- dev
types: [synchronize, opened]
permissions:
contents: read
pull-requests: write
jobs:
lhci:
name: Lighthouse CI
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Use Node.js 20.10.0
uses: actions/setup-node@v4
with:
node-version: 20.10.0
- name: Install dependencies
run: |
yarn install --immutable --immutable-cache --check-cache
- name: Add host "local.ludo.study"
run: sudo echo "127.0.0.1 local.ludo.study" | sudo tee -a /etc/hosts
- name: Build the project
run: |
yarn build
- name: Run Lighthouse CI - Desktop
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
run: |
yarn global add @lhci/cli
lhci collect --config=lighthouserc-desktop.cjs || echo "Fail to Run Lighthouse CI!"
lhci upload --config=lighthouserc-desktop.cjs || echo "Fail to Run Lighthouse CI!"
- name: Run Lighthouse CI - Mobile
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
run: |
lhci collect --config=lighthouserc-mobile.cjs || echo "Fail to Run Lighthouse CI!"
lhci upload --config=lighthouserc-mobile.cjs || echo "Fail to Run Lighthouse CI!"

  • dev branch에 대한 새로운 PR이 생성되거나 기존 PR에 commit이 추가되거나 변경될 때 workflow가 실행되도록 설정하였습니다.
  • 저장소의 content를 읽고 PR을 수정할 수 있도록 하였습니다
  • PR 코드 checkout, Node 버전 설정, 의존성 설치 등의 step을 설정하였습니다.
  • lighthouse ci를 설치 후, device별로 설정해놓은 configuration 파일을 활용한 명령어를 실행하여 lhci_reports 폴더 하위에 lighthouse report가 생성되도록 하였습니다.

✔︎ 성능 지표 포맷팅

- name: Format Lighthouse Score
id: format_lighthouse_score
uses: actions/github-script@v7
env:
working-directory: ${{ github.workspace }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const {
LH_MONITORING_PAGE_NAMES,
DEV_ORIGIN_URL,
LH_MONITORING_PAGE_ROUTES,
LH_MIN_SCORES,
} = require('./src/Constants/lighthouse.ts');
const desktopLightHouseResults = JSON.parse(fs.readFileSync('lhci_reports/desktop/manifest.json'));
const mobileLightHouseResults = JSON.parse(fs.readFileSync('lhci_reports/mobile/manifest.json'));
let comments = `### 💡 LightHouse Reports\n\n`;
comments += `#### 🟢 90 ~ 100    🟠 50 ~ 89    🔴 0 ~ 49 \n\n`;
const getFormattingScore = (res) => Math.round(res * 100);
const getScoreColor = (score) => (score >= LH_MIN_SCORES.GREEN ? '🟢' : score >= LH_MIN_SCORES.ORANGE ? '🟠' : '🔴');
const getMonitoringPageName = (url) => {
const route = url.replace(DEV_ORIGIN_URL, '');
for (let pageName of LH_MONITORING_PAGE_NAMES) {
if (route === LH_MONITORING_PAGE_ROUTES[pageName]) return pageName;
}
};
const getFormattingResultByPage = (result) => {
const { url, summary, jsonPath } = result;
const { audits } = JSON.parse(fs.readFileSync(jsonPath));
const { performance, accessibility, 'best-practices': bestPractices, seo } = summary;
const {
'first-contentful-paint': firstContentfulPaint,
'largest-contentful-paint': largestContentfulPaint,
'speed-index': speedIndex,
'total-blocking-time': totalBlockingTime,
'cumulative-layout-shift': cumulativeLayoutShift,
} = audits;
const formattingTable = [
`| Category | Score |`,
`| --- | --- |`,
`| ${getScoreColor(getFormattingScore(performance))} Performance | ${getFormattingScore(performance)} |`,
`| ${getScoreColor(getFormattingScore(accessibility))} Accessibility | ${getFormattingScore(accessibility)} |`,
`| ${getScoreColor(getFormattingScore(bestPractices))} Best practices | ${getFormattingScore(bestPractices)} |`,
`| ${getScoreColor(getFormattingScore(seo))} SEO | ${getFormattingScore(seo)} |`,
`| ${getScoreColor(getFormattingScore(firstContentfulPaint.score))} First Contentful Paint | ${firstContentfulPaint.displayValue} |`,
`| ${getScoreColor(getFormattingScore(largestContentfulPaint.score))} Largest Contentful Paint | ${largestContentfulPaint.displayValue} |`,
`| ${getScoreColor(getFormattingScore(speedIndex.score))} Speed Index | ${speedIndex.displayValue} |`,
`| ${getScoreColor(getFormattingScore(totalBlockingTime.score))} Total Blocking Time | ${totalBlockingTime.displayValue} |`,
`| ${getScoreColor(getFormattingScore(cumulativeLayoutShift.score))} Cumulative Layout Shift | ${cumulativeLayoutShift.displayValue} |`,
`\n`,
].join('\n');
return `<details>\n<summary>${`📄 ${getMonitoringPageName(url)}\n`}</summary>\n\n${formattingTable}\n</details>\n\n`;
};
const getLightHouseFormattingResult = (results, type) => {
let comment = type === 'mobile' ? `#### 📱 Mobile\n` : `#### 🖥 Desktop\n`;
results.forEach((result) => (comment += getFormattingResultByPage(result)));
return comment + '\n';
};
comments += getLightHouseFormattingResult(desktopLightHouseResults, 'desktop');
comments += getLightHouseFormattingResult(mobileLightHouseResults, 'mobile');
core.setOutput('comments', comments)

  • lhci_reports 폴더에 있는 report를 가져와 테이블 형식으로 성능 지표를 포맷팅 하였습니다.
  • 주요 지표(Performance, Accessibility, Best Practices, SEO) 및 Performance 하위 지표(FCP, LCP, Speed Index, TBT, CLS) 등을 테이블에 포함하였습니다.
  • 생성된 comments를 Comment PR step에 사용하기 위해, step의 마지막에 core.setOutput('comments', comment)를 작성하였습니다.

✔︎ PR Comment에 반영

- name: Comment PR
id: add_pr_comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { Octokit } = require('@octokit/rest');
const octokit = new Octokit({ auth: `${{ secrets.GITHUB_TOKEN }}` });
const { payload, repo } = context
const newComment = `${{ steps.format_lighthouse_score.outputs.comments }}`
const { data: prevComments } = await octokit.rest.issues.listComments({
owner: repo.owner,
repo: repo.repo,
issue_number : payload.pull_request.number,
})
const prevReportComment = prevComments.find(comment => comment.body.includes(`### 💡 LightHouse Reports\n\n`));
if (prevReportComment) {
await octokit.rest.issues.updateComment({
owner: repo.owner,
repo: repo.repo,
comment_id: prevReportComment.id,
body: newComment,
});
} else {
await octokit.rest.issues.createComment({
owner: repo.owner,
repo: repo.repo,
issue_number: payload.pull_request.number,
body: newComment,
});
}

  • 새로 생성된 comment를 ${{ steps.format_lighthouse_score.outputs.comments }}로 가져와서 PR에 반영하였습니다.
  • @octokit/rest 모듈을 활용하여 기존에 작성한 Comment 리스트를 불러와 기존에 작성한 Lighthouse Report Comment가 있다면 업데이트하고, 없다면 새로 작성하는 방식으로 PR Comment를 반영하였습니다.

🎬 반영된 PR Comment

image

🎬 페이지별 지표

image

💡 필요한 후속작업이 있어요.

구축된 페이지별 성능 측정 자동화 환경을 기반으로, 성능 개선 작업 진행하겠습니다

💡 다음 자료를 참고하면 좋아요.

✅ 셀프 체크리스트

  • 브랜치 전략에 맞는 브랜치에 PR을 올리고 있습니다. (master/main이 아닙니다.)
  • 커밋 메세지를 컨벤션에 맞추었습니다.
  • 변경 후 코드는 컴파일러/브라우저 warning/error 가 발생시키지 않습니다.
  • 변경 후 코드는 기존의 테스트를 통과합니다.
  • 테스트 추가가 필요한지 검토해보았고, 필요한 경우 테스트를 추가했습니다.
  • docs 수정이 필요한지 검토해보았고, 필요한 경우 docs를 수정했습니다.

@SungHyun627 SungHyun627 added this to the 스프린트 18 milestone Jul 31, 2024
@SungHyun627 SungHyun627 self-assigned this Jul 31, 2024
@SungHyun627 SungHyun627 marked this pull request as draft July 31, 2024 04:40
@SungHyun627 SungHyun627 changed the title Feat/sp 668 setup lighthouse ci [SP-668] 페이지별 성능 측정 tool(LightHouse) 자동화 환경 구축 Jul 31, 2024
Copy link

github-actions bot commented Aug 20, 2024

💡 LightHouse Reports

🟢 90 ~ 100    🟠 50 ~ 89    🔴 0 ~ 49

🖥 Desktop

📄 메인
Category Score
🔴 Performance 38
🟠 Accessibility 88
🟢 Best practices 96
🟠 SEO 83
🔴 First Contentful Paint 6.5 s
🔴 Largest Contentful Paint 9.8 s
🔴 Speed Index 6.7 s
🟠 Total Blocking Time 240 ms
🟠 Cumulative Layout Shift 0.183
📄 로그인
Category Score
🔴 Performance 49
🟢 Accessibility 95
🟢 Best practices 96
🟠 SEO 83
🔴 First Contentful Paint 6.3 s
🔴 Largest Contentful Paint 9.7 s
🔴 Speed Index 6.3 s
🟢 Total Blocking Time 10 ms
🟠 Cumulative Layout Shift 0.15
📄 모집공고 모아보기
Category Score
🔴 Performance 41
🟠 Accessibility 77
🟢 Best practices 96
🟠 SEO 75
🔴 First Contentful Paint 6.3 s
🔴 Largest Contentful Paint 9.7 s
🔴 Speed Index 6.3 s
🟢 Total Blocking Time 100 ms
🔴 Cumulative Layout Shift 0.261
📄 모집공고 상세
Category Score
🟠 Performance 55
🟠 Accessibility 87
🟢 Best practices 96
🟠 SEO 75
🔴 First Contentful Paint 5.5 s
🔴 Largest Contentful Paint 8.8 s
🔴 Speed Index 5.5 s
🟢 Total Blocking Time 10 ms
🟢 Cumulative Layout Shift 0.007

📱 Mobile

📄 메인
Category Score
🔴 Performance 37
🟢 Accessibility 95
🟠 Best practices 89
🟠 SEO 83
🔴 First Contentful Paint 21.3 s
🔴 Largest Contentful Paint 60.2 s
🔴 Speed Index 21.3 s
🔴 Total Blocking Time 730 ms
🟢 Cumulative Layout Shift 0.006
📄 로그인
Category Score
🔴 Performance 40
🟢 Accessibility 95
🟢 Best practices 96
🟠 SEO 83
🔴 First Contentful Paint 21.1 s
🔴 Largest Contentful Paint 59.6 s
🔴 Speed Index 21.1 s
🟠 Total Blocking Time 490 ms
🟢 Cumulative Layout Shift 0.093
📄 모집공고 모아보기
Category Score
🔴 Performance 35
🟠 Accessibility 84
🟠 Best practices 89
🟠 SEO 75
🔴 First Contentful Paint 22.2 s
🔴 Largest Contentful Paint 42.9 s
🔴 Speed Index 22.2 s
🔴 Total Blocking Time 860 ms
🟢 Cumulative Layout Shift 0
📄 모집공고 상세
Category Score
🔴 Performance 39
🟠 Accessibility 87
🟢 Best practices 93
🟠 SEO 75
🔴 First Contentful Paint 21.1 s
🔴 Largest Contentful Paint 59.8 s
🔴 Speed Index 21.1 s
🟠 Total Blocking Time 580 ms
🟢 Cumulative Layout Shift 0.069

@SungHyun627 SungHyun627 marked this pull request as ready for review August 20, 2024 08:06
.github/workflows/lighthouse.yml Outdated Show resolved Hide resolved
@SungHyun627 SungHyun627 merged commit 64b50b4 into dev Aug 20, 2024
5 of 6 checks passed
@SungHyun627 SungHyun627 changed the title [SP-668] 페이지별 성능 측정 tool(LightHouse) 자동화 환경 구축 SP-668 페이지별 성능 측정 tool(LightHouse) 자동화 환경 구축 Aug 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SP-668 페이지별 성능 측정 tool(LightHouse) 자동화 환경 구축
2 participants