Skip to content

Commit

Permalink
feat(lhci-report): add lighthouse ci reports
Browse files Browse the repository at this point in the history
  • Loading branch information
andrepolischuk committed Mar 22, 2024
1 parent 156eaed commit 9c08af1
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Common utils used by Rambler team
- [@rambler-tech/cookie-storage](packages/cookie-storage)
- [@rambler-tech/local-storage](packages/local-storage)
- [@rambler-tech/session-storage](packages/session-storage)
- [@rambler-tech/lhci-report](packages/lhci-report)

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@rambler-tech/eslint-config": "^0.10.4",
"@rambler-tech/licenselint-config": "^0.0.2",
"@rambler-tech/prettier-config": "^0.1.0",
"@rambler-tech/ts-config": "^0.1.0",
"@rambler-tech/ts-config": "^0.1.1",
"@rambler-tech/typedoc-config": "^0.3.0",
"@size-limit/preset-small-lib": "^9.0.0",
"@types/jest": "^29.5.5",
Expand Down
32 changes: 32 additions & 0 deletions packages/lhci-report/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Lighthouse CI report

Print Lighthouse CI report to CLI

## Install

```
npm install -D eslint @rambler-tech/lhci-report
```

or

```
yarn add -D eslint @rambler-tech/lhci-report
```

## Usage

```sh
@rambler-tech/lhci-report <lhci report dir>

Lighthouse report

URL: https://www.rambler.ru/
Number of runs: 3

performance 0.93 0.94 0.94
accessibility 0.87 0.87 0.87
best-practices 0.52 0.56 0.56
seo 0.92 0.92 0.92
pwa 0.71 0.71 0.71
```
24 changes: 24 additions & 0 deletions packages/lhci-report/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env node
import * as path from 'path'
import * as fs from 'fs/promises'
import {formatReport} from './format'
import {getReport, type Manifest} from './report'

async function print(dir: string) {
const manifestFile = path.resolve(dir, 'manifest.json')
// eslint-disable-next-line security/detect-non-literal-fs-filename
const manifestJson = await fs.readFile(manifestFile, 'utf8')
const manifest: Manifest = JSON.parse(manifestJson)
const report = getReport(manifest)

// eslint-disable-next-line no-console
console.log(formatReport(report))
}

const [, , reportDir] = process.argv

if (!reportDir) {
throw new Error('report dir not exists')
}

print(path.resolve(process.cwd(), reportDir))
30 changes: 30 additions & 0 deletions packages/lhci-report/format.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {green, red, yellow} from 'chalk'
import {formatReport} from './format'

test('format the report', () => {
const mock = {
'http://example.com': {
performance: [1, 0.9],
accessibility: [0.5, 0.6],
'best-practices': [0.6, 0.5],
seo: [0.2, 0.3],
pwa: [0.1, 0.4]
}
}

const report = formatReport(mock)

expect(report).toContain('URL: http://example.com')
expect(report).toContain('Number of runs: 2')
expect(report).toContain(
`performance ${green('1.00')} ${green('0.90')}`
)
expect(report).toContain(
`accessibility ${yellow('0.50')} ${yellow('0.60')}`
)
expect(report).toContain(
`best-practices ${yellow('0.60')} ${yellow('0.50')}`
)
expect(report).toContain(`seo ${red('0.20')} ${red('0.30')}`)
expect(report).toContain(`pwa ${red('0.10')} ${red('0.40')}`)
})
43 changes: 43 additions & 0 deletions packages/lhci-report/format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {green, red, yellow, type Chalk} from 'chalk'
import type {Report} from './report'

const METRIC_NAME_LENGTH = 18

const CRITICAL_TRESHOLD = 0.5
const WARN_TRESHOLD = 0.9

const TRESHOLDS: [number, Chalk][] = [
[CRITICAL_TRESHOLD, red],
[WARN_TRESHOLD, yellow],
[Infinity, green]
]

function formatMetricValue(value: number) {
const [, color]: any = TRESHOLDS.find(([treshold]) => value < treshold)

return color(value.toFixed(2))
}

export function formatReport(report: Report) {
let output = '\nLighthouse report\n'

Object.entries(report).forEach(([url, metrics]) => {
output += '\n'
output += `URL: ${url}`
output += '\n'
output += `Number of runs: ${metrics.performance.length}`
output += '\n\n'

Object.entries(metrics).forEach(([metric, values]) => {
const row = [
metric.padEnd(METRIC_NAME_LENGTH, ' '),
...values.map(formatMetricValue)
]

output += row.join(' ')
output += '\n'
})
})

return output
}
18 changes: 18 additions & 0 deletions packages/lhci-report/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@rambler-tech/lhci-report",
"version": "0.0.0",
"cli": "dist/cli.js",
"types": "dist/cli.d.ts",
"license": "MIT",
"sideEffects": false,
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/chalk": "^0.4.31",
"@types/node": "^20.11.30"
},
"dependencies": {
"chalk": "^4"
}
}
38 changes: 38 additions & 0 deletions packages/lhci-report/report.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {getReport} from './report'

test('get the report', () => {
const mock = [
{
url: 'http://example.com',
summary: {
performance: 1,
acccessibility: 0.5,
'best-practices': 0.6,
seo: 0.2,
pwa: 0.1
}
},
{
url: 'http://example.com',
summary: {
performance: 0.9,
acccessibility: 0.6,
'best-practices': 0.5,
seo: 0.3,
pwa: 0.4
}
}
]

const report = getReport(mock)

expect(report).toEqual({
'http://example.com': {
performance: [1, 0.9],
acccessibility: [0.5, 0.6],
'best-practices': [0.6, 0.5],
seo: [0.2, 0.3],
pwa: [0.1, 0.4]
}
})
})
18 changes: 18 additions & 0 deletions packages/lhci-report/report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export type Manifest = {
url: string
summary: Record<string, number>
}[]

export type Report = Record<string, Record<string, number[]>>

export function getReport(manifest: Manifest) {
return manifest.reduce((acc, {url, summary}) => {
Object.entries(summary).forEach(([metric, value]) => {
acc[url] ??= {}
acc[url][metric] ??= []
acc[url][metric].push(value)
})

return acc
}, {} as Report)
}
1 change: 1 addition & 0 deletions packages/lhci-report/tsconfig.json
1 change: 1 addition & 0 deletions tsconfig.package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"baseUrl": ".",
"outDir": "dist"
},
Expand Down
56 changes: 49 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1507,10 +1507,10 @@
resolved "https://registry.yarnpkg.com/@rambler-tech/prettier-config/-/prettier-config-0.1.0.tgz#e80dd5b7ea7f01f3fa30e86d785a68f0656882ff"
integrity sha512-WyJcCAPDe7nsClWdBz3eOguhJJhhZRGjXQYWvB1JPbDpljxmiEwLD9IU1TcLvy/Smt9eq9Y4jh1sIupkKxrfmQ==

"@rambler-tech/ts-config@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@rambler-tech/ts-config/-/ts-config-0.1.0.tgz#fd44b9c3af4b1f9b2aeff2bcefe6a21b5befc067"
integrity sha512-bePQ83MwWsAKgKntDZL9iCMCTo7YEyUFEHDryyEhyIq9nDkAe4G7uhEqQTqntAdQ9fx4n+tDaSagtA+sSk1Viw==
"@rambler-tech/ts-config@^0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@rambler-tech/ts-config/-/ts-config-0.1.1.tgz#02ae41b7909923b341391d8411c708abff2a00c4"
integrity sha512-gQiGU7x3wjdclv9rxgelAlmBNeRJBpxg+nXjmmUzspIOBp4f7u6cOmxKFYlmBJMpk9CyvpHlTG+YFIZ8t6W9Jw==

"@rambler-tech/typedoc-config@^0.3.0":
version "0.3.0"
Expand Down Expand Up @@ -1680,6 +1680,11 @@
dependencies:
"@babel/types" "^7.20.7"

"@types/chalk@^0.4.31":
version "0.4.31"
resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-0.4.31.tgz#a31d74241a6b1edbb973cf36d97a2896834a51f9"
integrity sha512-nF0fisEPYMIyfrFgabFimsz9Lnuu9MwkNrrlATm2E4E46afKDyeelT+8bXfw1VSc7sLBxMxRgT7PxTC2JcqN4Q==

"@types/graceful-fs@^4.1.3":
version "4.1.7"
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.7.tgz#30443a2e64fd51113bc3e2ba0914d47109695e2a"
Expand Down Expand Up @@ -1758,6 +1763,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.7.tgz#74d323a93f1391a63477b27b9aec56669c98b2ab"
integrity sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g==

"@types/node@^20.11.30":
version "20.11.30"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.30.tgz#9c33467fc23167a347e73834f788f4b9f399d66f"
integrity sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==
dependencies:
undici-types "~5.26.4"

"@types/normalize-package-data@^2.4.0":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
Expand Down Expand Up @@ -8041,7 +8053,16 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"

"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -8115,7 +8136,14 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down Expand Up @@ -8577,6 +8605,11 @@ unbox-primitive@^1.0.2:
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"

undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==

unique-filename@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea"
Expand Down Expand Up @@ -8848,7 +8881,7 @@ wordwrap@^1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand All @@ -8866,6 +8899,15 @@ wrap-ansi@^6.0.1:
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
Expand Down

0 comments on commit 9c08af1

Please sign in to comment.