From 1c2dbca93fe2923664e645353089e6baaa234d8c Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 11:42:06 -0700 Subject: [PATCH 01/15] feat: add clean build dir script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index b5c05c9..e330cb1 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "type": "module", "scripts": { "start": "node dist/index.js", - "build": "tsc", + "clean": "rm -rf dist", + "build": "pnpm clean && tsc", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], From 279b45416f3370b0c325dad66830faefe6564dd4 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 11:45:19 -0700 Subject: [PATCH 02/15] feat: add ChromeRunner class This class will be used to run launch Chrome for Lighthouse. It is a very simple class that wraps around the "chrome-launcher" package. --- package.json | 3 +++ pnpm-lock.yaml | 65 ++++++++++++++++++++++++++++++++++++++++++++- src/ChromeRunner.ts | 21 +++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/ChromeRunner.ts diff --git a/package.json b/package.json index e330cb1..0085122 100644 --- a/package.json +++ b/package.json @@ -18,5 +18,8 @@ "@tsconfig/node18": "^18.2.1", "@types/node": "^20.5.9", "typescript": "^5.2.2" + }, + "dependencies": { + "chrome-launcher": "^1.0.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4bfdaa6..3429a39 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +dependencies: + chrome-launcher: + specifier: ^1.0.0 + version: 1.0.0 + devDependencies: '@tsconfig/node18': specifier: ^18.2.1 @@ -23,7 +28,65 @@ packages: /@types/node@20.5.9: resolution: {integrity: sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==} - dev: true + + /chrome-launcher@1.0.0: + resolution: {integrity: sha512-74IMFVfgni/bQ4GotUNJpH2vDR+Sh9cXNPVhPXiedeiB0+5j7/8i8LAqS7WlyNSKqtxJ/CgbOpBDPLkzqDVhlw==} + engines: {node: '>=12.13.0'} + hasBin: true + dependencies: + '@types/node': 20.5.9 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: false + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: false + + /is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: false + + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: false + + /lighthouse-logger@2.0.1: + resolution: {integrity: sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==} + dependencies: + debug: 2.6.9 + marky: 1.2.5 + transitivePeerDependencies: + - supports-color + dev: false + + /marky@1.2.5: + resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} + dev: false + + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: false /typescript@5.2.2: resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} diff --git a/src/ChromeRunner.ts b/src/ChromeRunner.ts new file mode 100644 index 0000000..4f22427 --- /dev/null +++ b/src/ChromeRunner.ts @@ -0,0 +1,21 @@ +import type { LaunchedChrome } from 'chrome-launcher'; +import {launch} from 'chrome-launcher'; + +export default class ChromeRunner { + private flags = ['--disable-gpu']; + chrome!: LaunchedChrome + + constructor(headless: boolean = true) { + if (headless) { + this.flags.push('--headless') + } + } + + async start(): Promise { + this.chrome = await launch({ chromeFlags: this.flags }) + } + + stop() { + this.chrome.kill() + } +} \ No newline at end of file From 657417586f1ed3f66821d9f9267184c015090a4b Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 12:08:53 -0700 Subject: [PATCH 03/15] feat: create a LighthouseRunner class This class will be used to execute the a lighthouse runner using the port of the launched chrome instance. This is mainly a wrapper around the lighthouse node module. --- package.json | 3 +- pnpm-lock.yaml | 938 ++++++++++++++++++++++++++++++++++++++++ src/ChromeRunner.ts | 3 +- src/LighthouseRunner.ts | 19 + 4 files changed, 961 insertions(+), 2 deletions(-) create mode 100644 src/LighthouseRunner.ts diff --git a/package.json b/package.json index 0085122..90200a9 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "typescript": "^5.2.2" }, "dependencies": { - "chrome-launcher": "^1.0.0" + "chrome-launcher": "^1.0.0", + "lighthouse": "^11.1.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3429a39..32c329c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ dependencies: chrome-launcher: specifier: ^1.0.0 version: 1.0.0 + lighthouse: + specifier: ^11.1.0 + version: 11.1.0 devDependencies: '@tsconfig/node18': @@ -22,6 +25,84 @@ devDependencies: packages: + /@puppeteer/browsers@1.7.0: + resolution: {integrity: sha512-sl7zI0IkbQGak/+IE3VEEZab5SSOlI5F6558WvzWGC1n3+C722rfewC1ZIkcF9dsoGSsxhsONoseVlNQG4wWvQ==} + engines: {node: '>=16.3.0'} + hasBin: true + dependencies: + debug: 4.3.4 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.3.0 + tar-fs: 3.0.4 + unbzip2-stream: 1.4.3 + yargs: 17.7.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@sentry/core@6.19.7: + resolution: {integrity: sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==} + engines: {node: '>=6'} + dependencies: + '@sentry/hub': 6.19.7 + '@sentry/minimal': 6.19.7 + '@sentry/types': 6.19.7 + '@sentry/utils': 6.19.7 + tslib: 1.14.1 + dev: false + + /@sentry/hub@6.19.7: + resolution: {integrity: sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==} + engines: {node: '>=6'} + dependencies: + '@sentry/types': 6.19.7 + '@sentry/utils': 6.19.7 + tslib: 1.14.1 + dev: false + + /@sentry/minimal@6.19.7: + resolution: {integrity: sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==} + engines: {node: '>=6'} + dependencies: + '@sentry/hub': 6.19.7 + '@sentry/types': 6.19.7 + tslib: 1.14.1 + dev: false + + /@sentry/node@6.19.7: + resolution: {integrity: sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==} + engines: {node: '>=6'} + dependencies: + '@sentry/core': 6.19.7 + '@sentry/hub': 6.19.7 + '@sentry/types': 6.19.7 + '@sentry/utils': 6.19.7 + cookie: 0.4.2 + https-proxy-agent: 5.0.1 + lru_map: 0.3.3 + tslib: 1.14.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@sentry/types@6.19.7: + resolution: {integrity: sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==} + engines: {node: '>=6'} + dev: false + + /@sentry/utils@6.19.7: + resolution: {integrity: sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==} + engines: {node: '>=6'} + dependencies: + '@sentry/types': 6.19.7 + tslib: 1.14.1 + dev: false + + /@tootallnate/quickjs-emscripten@0.23.0: + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + dev: false + /@tsconfig/node18@18.2.1: resolution: {integrity: sha512-RDDZFuofwkcKpl8Vpj5wFbY+H53xOtqK7ckEL1sXsbPwvKwDdjQf3LkHbtt9sxIHn9nWIEwkmCwBRZ6z5TKU2A==} dev: true @@ -29,6 +110,85 @@ packages: /@types/node@20.5.9: resolution: {integrity: sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==} + /@types/yauzl@2.10.0: + resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} + requiresBuild: true + dependencies: + '@types/node': 20.5.9 + dev: false + optional: true + + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /agent-base@7.1.0: + resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: false + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: false + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: false + + /ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + dependencies: + tslib: 2.6.2 + dev: false + + /axe-core@4.8.1: + resolution: {integrity: sha512-9l850jDDPnKq48nbad8SiEelCv4OrUWrKab/cPj0GScVg6cb6NbCCt/Ulk26QEq5jP9NnGr04Bit1BHyV6r5CQ==} + engines: {node: '>=4'} + dev: false + + /b4a@1.6.4: + resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /basic-ftp@5.0.3: + resolution: {integrity: sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==} + engines: {node: '>=10.0.0'} + dev: false + + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: false + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + /chrome-launcher@1.0.0: resolution: {integrity: sha512-74IMFVfgni/bQ4GotUNJpH2vDR+Sh9cXNPVhPXiedeiB0+5j7/8i8LAqS7WlyNSKqtxJ/CgbOpBDPLkzqDVhlw==} engines: {node: '>=12.13.0'} @@ -42,6 +202,74 @@ packages: - supports-color dev: false + /chromium-bidi@0.4.22(devtools-protocol@0.0.1159816): + resolution: {integrity: sha512-wR7Y9Ioez+cNXT4ZP7VNM1HRTljpNnMSLw4/RnwhhZUP4yCU7kIQND00YiktuHekch68jklGPK1q9Jkb29+fQg==} + peerDependencies: + devtools-protocol: '*' + dependencies: + devtools-protocol: 0.0.1159816 + mitt: 3.0.1 + dev: false + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: false + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: false + + /configstore@5.0.1: + resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==} + engines: {node: '>=8'} + dependencies: + dot-prop: 5.3.0 + graceful-fs: 4.2.11 + make-dir: 3.1.0 + unique-string: 2.0.0 + write-file-atomic: 3.0.3 + xdg-basedir: 4.0.0 + dev: false + + /cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + dev: false + + /cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false + + /crypto-random-string@2.0.0: + resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} + engines: {node: '>=8'} + dev: false + + /csp_evaluator@1.1.1: + resolution: {integrity: sha512-N3ASg0C4kNPUaNxt1XAvzHIVuzdtr8KLgfk1O8WDyimp1GisPAHESupArO2ieHk9QWbrJ/WkQODyh21Ps/xhxw==} + dev: false + + /data-uri-to-buffer@5.0.1: + resolution: {integrity: sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==} + engines: {node: '>= 14'} + dev: false + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -53,17 +281,251 @@ packages: ms: 2.0.0 dev: false + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + + /define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + dev: false + + /degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + dev: false + + /devtools-protocol@0.0.1155343: + resolution: {integrity: sha512-oD9vGBV2wTc7fAzAM6KC0chSgs234V8+qDEeK+mcbRj2UvcuA7lgBztGi/opj/iahcXD3BSj8Ymvib628yy9FA==} + dev: false + + /devtools-protocol@0.0.1159816: + resolution: {integrity: sha512-2cZlHxC5IlgkIWe2pSDmCrDiTzbSJWywjbDDnupOImEBcG31CQgBLV8wWE+5t+C4rimcjHsbzy7CBzf9oFjboA==} + dev: false + + /dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + dependencies: + is-obj: 2.0.0 + dev: false + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: false + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + + /enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + dev: false + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: false + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} dev: false + /escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + dev: false + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: false + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: false + + /extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.4 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.0 + transitivePeerDependencies: + - supports-color + dev: false + + /fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + dev: false + + /fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + dev: false + + /fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: false + + /get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + dev: false + + /get-uri@6.0.1: + resolution: {integrity: sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==} + engines: {node: '>= 14'} + dependencies: + basic-ftp: 5.0.3 + data-uri-to-buffer: 5.0.1 + debug: 4.3.4 + fs-extra: 8.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: false + + /http-link-header@1.1.1: + resolution: {integrity: sha512-mW3N/rTYpCn99s1do0zx6nzFZSwLH9HGfUM4ZqLWJ16ylmYaC2v5eYGqrNTQlByx8AzUgGI+V/32gXPugs1+Sw==} + engines: {node: '>=6.0.0'} + dev: false + + /http-proxy-agent@7.0.0: + resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /https-proxy-agent@7.0.2: + resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /image-ssim@0.2.0: + resolution: {integrity: sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg==} + dev: false + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: false + + /intl-messageformat-parser@1.8.1: + resolution: {integrity: sha512-IMSCKVf0USrM/959vj3xac7s8f87sc+80Y/ipBzdKy4ifBv5Gsj2tZ41EAaURVg01QU71fYr77uA8Meh6kELbg==} + deprecated: We've written a new parser that's 6x faster and is backwards compatible. Please use @formatjs/icu-messageformat-parser + dev: false + + /intl-messageformat@4.4.0: + resolution: {integrity: sha512-z+Bj2rS3LZSYU4+sNitdHrwnBhr0wO80ZJSW8EzKDBowwUe3Q/UsvgCGjrwa+HPzoGCLEb9HAjfJgo4j2Sac8w==} + dependencies: + intl-messageformat-parser: 1.8.1 + dev: false + + /ip@1.1.8: + resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==} + dev: false + + /ip@2.0.0: + resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} + dev: false + /is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} hasBin: true dev: false + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: false + + /is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + dev: false + + /is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + dev: false + /is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -71,6 +533,21 @@ packages: is-docker: 2.2.1 dev: false + /jpeg-js@0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + dev: false + + /js-library-detector@6.7.0: + resolution: {integrity: sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA==} + engines: {node: '>=12'} + dev: false + + /jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.11 + dev: false + /lighthouse-logger@2.0.1: resolution: {integrity: sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==} dependencies: @@ -80,16 +557,477 @@ packages: - supports-color dev: false + /lighthouse-stack-packs@1.12.0: + resolution: {integrity: sha512-tWNKyZg2NbEEKeGM1iqGLWuEEDKwtE6xFAtN4NDXyoXirHQFBcEaMEp4lKK8RjmS3Lw+l3hVONj3SaMzY6FB6w==} + dev: false + + /lighthouse@11.1.0: + resolution: {integrity: sha512-4FzIjuVO9ZQ2sVQtwxVvO2dsJkkpbRjq1LB94+8hH+PvK80cja31H2tCpgig1uxjMXYfGIQzKTsdoUqhrK2Haw==} + engines: {node: '>=18.16'} + hasBin: true + dependencies: + '@sentry/node': 6.19.7 + axe-core: 4.8.1 + chrome-launcher: 1.0.0 + configstore: 5.0.1 + csp_evaluator: 1.1.1 + devtools-protocol: 0.0.1155343 + enquirer: 2.4.1 + http-link-header: 1.1.1 + intl-messageformat: 4.4.0 + jpeg-js: 0.4.4 + js-library-detector: 6.7.0 + lighthouse-logger: 2.0.1 + lighthouse-stack-packs: 1.12.0 + lodash: 4.17.21 + lookup-closest-locale: 6.2.0 + metaviewport-parser: 0.3.0 + open: 8.4.2 + parse-cache-control: 1.0.1 + ps-list: 8.1.1 + puppeteer-core: 21.1.1 + robots-parser: 3.0.1 + semver: 5.7.2 + speedline-core: 1.4.3 + third-party-web: 0.24.0 + ws: 7.5.9 + yargs: 17.7.2 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + + /lookup-closest-locale@6.2.0: + resolution: {integrity: sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==} + dev: false + + /lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + dev: false + + /lru_map@0.3.3: + resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} + dev: false + + /make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.1 + dev: false + /marky@1.2.5: resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} dev: false + /metaviewport-parser@0.3.0: + resolution: {integrity: sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ==} + dev: false + + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + dev: false + + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false + /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} dev: false + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: false + + /netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + dev: false + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: false + + /open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + dev: false + + /pac-proxy-agent@7.0.1: + resolution: {integrity: sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==} + engines: {node: '>= 14'} + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.0 + debug: 4.3.4 + get-uri: 6.0.1 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + pac-resolver: 7.0.0 + socks-proxy-agent: 8.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /pac-resolver@7.0.0: + resolution: {integrity: sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==} + engines: {node: '>= 14'} + dependencies: + degenerator: 5.0.1 + ip: 1.1.8 + netmask: 2.0.2 + dev: false + + /parse-cache-control@1.0.1: + resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} + dev: false + + /pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + dev: false + + /progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: false + + /proxy-agent@6.3.0: + resolution: {integrity: sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.1 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + + /ps-list@8.1.1: + resolution: {integrity: sha512-OPS9kEJYVmiO48u/B9qneqhkMvgCxT+Tm28VCEJpheTpl8cJ0ffZRRNgS5mrQRTrX5yRTpaJ+hRDeefXYmmorQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + + /puppeteer-core@21.1.1: + resolution: {integrity: sha512-Tlcajcf44zwfa9Sbwv3T8BtaNMJ69wtpHIxwl2NOBTyTK3D1wppQovXTjfw0TDOm3a16eCfQ+5BMi3vRQ4kuAQ==} + engines: {node: '>=16.3.0'} + dependencies: + '@puppeteer/browsers': 1.7.0 + chromium-bidi: 0.4.22(devtools-protocol@0.0.1159816) + cross-fetch: 4.0.0 + debug: 4.3.4 + devtools-protocol: 0.0.1159816 + ws: 8.13.0 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + dev: false + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: false + + /robots-parser@3.0.1: + resolution: {integrity: sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==} + engines: {node: '>=10.0.0'} + dev: false + + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + dev: false + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: false + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: false + + /smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + dev: false + + /socks-proxy-agent@8.0.2: + resolution: {integrity: sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + socks: 2.7.1 + transitivePeerDependencies: + - supports-color + dev: false + + /socks@2.7.1: + resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} + engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} + dependencies: + ip: 2.0.0 + smart-buffer: 4.2.0 + dev: false + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + requiresBuild: true + dev: false + optional: true + + /speedline-core@1.4.3: + resolution: {integrity: sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==} + engines: {node: '>=8.0'} + dependencies: + '@types/node': 20.5.9 + image-ssim: 0.2.0 + jpeg-js: 0.4.4 + dev: false + + /streamx@2.15.1: + resolution: {integrity: sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==} + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + dev: false + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: false + + /tar-fs@3.0.4: + resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==} + dependencies: + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 3.1.6 + dev: false + + /tar-stream@3.1.6: + resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==} + dependencies: + b4a: 1.6.4 + fast-fifo: 1.3.2 + streamx: 2.15.1 + dev: false + + /third-party-web@0.24.0: + resolution: {integrity: sha512-mMkV7LE857QCG9DM/mkZoqsEEbJmtimnWBgm/bAmJuRlfVM29OLhPFse1ayrW1xmtJqg7bVU6ZBtjz8vVQGq2g==} + dev: false + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: false + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: false + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: false + + /typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + dev: false + /typescript@5.2.2: resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} hasBin: true dev: true + + /unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + dependencies: + buffer: 5.7.1 + through: 2.3.8 + dev: false + + /unique-string@2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + dependencies: + crypto-random-string: 2.0.0 + dev: false + + /universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: false + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: false + + /write-file-atomic@3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.7 + typedarray-to-buffer: 3.1.5 + dev: false + + /ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /ws@8.13.0: + resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /xdg-basedir@4.0.0: + resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} + engines: {node: '>=8'} + dev: false + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: false + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: false + + /yargs@17.7.1: + resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: false + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: false + + /yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + dev: false diff --git a/src/ChromeRunner.ts b/src/ChromeRunner.ts index 4f22427..69f3810 100644 --- a/src/ChromeRunner.ts +++ b/src/ChromeRunner.ts @@ -11,8 +11,9 @@ export default class ChromeRunner { } } - async start(): Promise { + async start(): Promise { this.chrome = await launch({ chromeFlags: this.flags }) + return this.chrome.port } stop() { diff --git a/src/LighthouseRunner.ts b/src/LighthouseRunner.ts new file mode 100644 index 0000000..b456805 --- /dev/null +++ b/src/LighthouseRunner.ts @@ -0,0 +1,19 @@ +import lighthouse from 'lighthouse'; +import type {Flags, Result} from 'lighthouse'; + +export default class LighthouseRunner { + private lhOptions: Flags = { + output: 'json', + logLevel: 'silent', + } + + async run(url: string, lhOptions: Flags = {}): Promise { + const result = await lighthouse(url, {...this.lhOptions, ...lhOptions}) + + if (result) { + return result.lhr + } + + throw new Error('Lighthouse failed to run') + } +} \ No newline at end of file From c7dfbfe4a9de0ef22e05aa21462c0eb5c3369d98 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 13:43:00 -0700 Subject: [PATCH 04/15] feat: add DatadogClient class This class will be a wrapper around the datadog-api-client package. For the moment, it will only have a method to send metrics to Datadog. That said, we will require some api keys to be able to send metrics, so let's create an .env file and import it via dotenv. --- .env.template | 2 + package.json | 2 + pnpm-lock.yaml | 116 +++++++++++++++++++++++++++++++++++++++++++ src/DatadogClient.ts | 40 +++++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 .env.template create mode 100644 src/DatadogClient.ts diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..84b8d60 --- /dev/null +++ b/.env.template @@ -0,0 +1,2 @@ +DD_API_KEY= +DD_APP_KEY= \ No newline at end of file diff --git a/package.json b/package.json index 90200a9..c955d6b 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,9 @@ "typescript": "^5.2.2" }, "dependencies": { + "@datadog/datadog-api-client": "^1.16.0", "chrome-launcher": "^1.0.0", + "dotenv": "^16.3.1", "lighthouse": "^11.1.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32c329c..e1a9b23 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,15 @@ settings: excludeLinksFromLockfile: false dependencies: + '@datadog/datadog-api-client': + specifier: ^1.16.0 + version: 1.16.0 chrome-launcher: specifier: ^1.0.0 version: 1.0.0 + dotenv: + specifier: ^16.3.1 + version: 16.3.1 lighthouse: specifier: ^11.1.0 version: 11.1.0 @@ -25,6 +31,24 @@ devDependencies: packages: + /@datadog/datadog-api-client@1.16.0: + resolution: {integrity: sha512-PnInPPyw3Ax8xcsAcJDIBUZcLSUWyFSdJc92Ac72+dKuoz79WBYw01naD9NRX0T9Ggv6mUOGILMq8BfpiHYfYA==} + engines: {node: '>=12.0.0'} + dependencies: + '@types/buffer-from': 1.1.0 + '@types/node': 20.5.9 + '@types/pako': 1.0.4 + buffer-from: 1.1.2 + cross-fetch: 3.1.8 + es6-promise: 4.2.8 + form-data: 4.0.0 + loglevel: 1.8.1 + pako: 2.1.0 + url-parse: 1.5.10 + transitivePeerDependencies: + - encoding + dev: false + /@puppeteer/browsers@1.7.0: resolution: {integrity: sha512-sl7zI0IkbQGak/+IE3VEEZab5SSOlI5F6558WvzWGC1n3+C722rfewC1ZIkcF9dsoGSsxhsONoseVlNQG4wWvQ==} engines: {node: '>=16.3.0'} @@ -107,9 +131,19 @@ packages: resolution: {integrity: sha512-RDDZFuofwkcKpl8Vpj5wFbY+H53xOtqK7ckEL1sXsbPwvKwDdjQf3LkHbtt9sxIHn9nWIEwkmCwBRZ6z5TKU2A==} dev: true + /@types/buffer-from@1.1.0: + resolution: {integrity: sha512-BLFpLBcN+RPKUsFxqRkMiwqTOOdi+TrKr5OpLJ9qCnUdSxS6S80+QRX/mIhfR66u0Ykc4QTkReaejOM2ILh+9Q==} + dependencies: + '@types/node': 20.5.9 + dev: false + /@types/node@20.5.9: resolution: {integrity: sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==} + /@types/pako@1.0.4: + resolution: {integrity: sha512-Z+5bJSm28EXBSUJEgx29ioWeEEHUh6TiMkZHDhLwjc9wVFH+ressbkmX6waUZc5R3Gobn4Qu5llGxaoflZ+yhA==} + dev: false + /@types/yauzl@2.10.0: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true @@ -160,6 +194,10 @@ packages: tslib: 2.6.2 dev: false + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + /axe-core@4.8.1: resolution: {integrity: sha512-9l850jDDPnKq48nbad8SiEelCv4OrUWrKab/cPj0GScVg6cb6NbCCt/Ulk26QEq5jP9NnGr04Bit1BHyV6r5CQ==} engines: {node: '>=4'} @@ -182,6 +220,10 @@ packages: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} dev: false + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: false + /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: @@ -231,6 +273,13 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: false + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + /configstore@5.0.1: resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==} engines: {node: '>=8'} @@ -248,6 +297,14 @@ packages: engines: {node: '>= 0.6'} dev: false + /cross-fetch@3.1.8: + resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false + /cross-fetch@4.0.0: resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} dependencies: @@ -307,6 +364,11 @@ packages: esprima: 4.0.1 dev: false + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + /devtools-protocol@0.0.1155343: resolution: {integrity: sha512-oD9vGBV2wTc7fAzAM6KC0chSgs234V8+qDEeK+mcbRj2UvcuA7lgBztGi/opj/iahcXD3BSj8Ymvib628yy9FA==} dev: false @@ -322,6 +384,11 @@ packages: is-obj: 2.0.0 dev: false + /dotenv@16.3.1: + resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} + engines: {node: '>=12'} + dev: false + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: false @@ -340,6 +407,10 @@ packages: strip-ansi: 6.0.1 dev: false + /es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + dev: false + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -402,6 +473,15 @@ packages: pend: 1.2.0 dev: false + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} @@ -604,6 +684,11 @@ packages: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: false + /loglevel@1.8.1: + resolution: {integrity: sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==} + engines: {node: '>= 0.6.0'} + dev: false + /lookup-closest-locale@6.2.0: resolution: {integrity: sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==} dev: false @@ -632,6 +717,18 @@ packages: resolution: {integrity: sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ==} dev: false + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} dev: false @@ -705,6 +802,10 @@ packages: netmask: 2.0.2 dev: false + /pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + dev: false + /parse-cache-control@1.0.1: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} dev: false @@ -767,6 +868,10 @@ packages: - utf-8-validate dev: false + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: false + /queue-tick@1.0.1: resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} dev: false @@ -776,6 +881,10 @@ packages: engines: {node: '>=0.10.0'} dev: false + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: false + /robots-parser@3.0.1: resolution: {integrity: sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==} engines: {node: '>=10.0.0'} @@ -925,6 +1034,13 @@ packages: engines: {node: '>= 4.0.0'} dev: false + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: false + /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: false diff --git a/src/DatadogClient.ts b/src/DatadogClient.ts new file mode 100644 index 0000000..5487ea8 --- /dev/null +++ b/src/DatadogClient.ts @@ -0,0 +1,40 @@ +import { client, v2 } from '@datadog/datadog-api-client'; + + +export default class DatadogClient { + private clientConfiguration: client.Configuration; + + constructor({ api_key, app_key}: { api_key: string, app_key: string }) { + const configurationOpts = { + authMethods: { + apiKeyAuth: api_key, + appKeyAuth: app_key + }, + }; + + this.clientConfiguration = client.createConfiguration(configurationOpts); + } + + async submitMetrics(metricName: string, dataPoints: v2.MetricPoint[], tags: string[] = []): Promise { + const metricsApiInstance = new v2.MetricsApi(this.clientConfiguration); + + const params: v2.MetricsApiSubmitMetricsRequest = { + body: { + series: [ + { + metric: metricName, + type: 3, // gauge + points: dataPoints, + tags: tags + } + ] + } + }; + + const response = await metricsApiInstance.submitMetrics(params); + + if (response.errors && response.errors.length > 0) { + throw new Error(response.errors.join(', ')); + } + } +} \ No newline at end of file From cbd41aa08b1195e8bae8d5bdd8696d0104a786e5 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 14:58:02 -0700 Subject: [PATCH 05/15] feat: integrate classes to run full lighthouse audit The logic in the index file is similar to the logic in the main.py file in the lighthouse-docker repo, https://github.com/iFixit/lighthouse-docker/blob/master/lib/main.py. The only difference is we will use the timestamp of the lighthouse report to timestamp the metrics data sent to Datadog. --- .gitignore | 4 ++ metrics-config.example.json | 13 ++++++ src/index.ts | 79 +++++++++++++++++++++++++++++++++++++ urls.example.json | 3 ++ 4 files changed, 99 insertions(+) create mode 100644 metrics-config.example.json create mode 100644 urls.example.json diff --git a/.gitignore b/.gitignore index c43ad6e..6b169d2 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,7 @@ node_modules/ # VSCode Misc. .vscode + +# Config Files +urls.json +metrics-config.json \ No newline at end of file diff --git a/metrics-config.example.json b/metrics-config.example.json new file mode 100644 index 0000000..892b5ee --- /dev/null +++ b/metrics-config.example.json @@ -0,0 +1,13 @@ +{ + "audits": [ + "largest-contentful-paint", + "first-contentful-paint", + "cumulative-layout-shift", + "total-blocking-time", + "speed-index", + "total-byte-weight", + "server-response-time", + "is-crawlable", + "screenshot-thumbnails" + ] +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e69de29..f9fae7f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -0,0 +1,79 @@ +import ChromeRunner from "./ChromeRunner.js" +import LighthouseRunner from "./LighthouseRunner.js" +import Datadog from "./DatadogClient.js" +import {v2} from '@datadog/datadog-api-client' +import fs from 'node:fs' +import type { Result } from 'lighthouse' +import os from 'node:os' +import dotenv from 'dotenv' +dotenv.config(); + +function getAuditNumericValue(results: Result, audit: string): number { + return results.audits[audit].numericValue || 0 +} + +function getAuditScore(results: Result, audit: string): number { + return results.audits[audit].score || 0 +} + +function getFetchTime(results: Result): number { + return Math.round(new Date(results.fetchTime).getTime() / 1000); +} + +function retrieveDataPointsForAudits(results: Result, audits: string[]) { + const timestamp = getFetchTime(results) + const values: Record> = {} + + for (let audit of audits) { + values[audit] = { + "numericValue": { + timestamp: timestamp, + value: getAuditNumericValue(results, audit) + }, + "score": { + timestamp: timestamp, + value: getAuditScore(results, audit) + } + } + } + + return values +} +(async() => { + const dd = new Datadog({ + api_key: process.env.DD_API_KEY || '', + app_key: process.env.DD_APP_KEY || '' + }) + + const inspectList: Record = JSON.parse(await fs.promises.readFile('urls.json', 'utf8')); + + const coreMetrics: Record = JSON.parse(await fs.promises.readFile('metrics-config.json', 'utf8')); + + for (let [pageType, urls] of Object.entries(inspectList)) { + for (let url of urls) { + const chromeRunner = new ChromeRunner(false) + const lighthouseRunner = new LighthouseRunner() + + const port = await chromeRunner.start() + const results = await lighthouseRunner.run(url, {port: port}) + + chromeRunner.stop() + + const metrics = retrieveDataPointsForAudits(results, coreMetrics['audits']) + + const tags = { + 'url': url, + 'page_type': pageType, + 'lighthouse_version': results.lighthouseVersion, + 'host': os.hostname() + } + + const tagsArray = Object.entries(tags).map(([key, value]) => `${key}:${value}`) + + for (let [audit, dataPoints] of Object.entries(metrics)) { + await dd.submitMetrics(`lighthouse.${audit}.value`, [dataPoints.numericValue], tagsArray) + await dd.submitMetrics(`lighthouse.${audit}.score`, [dataPoints.numericValue], tagsArray) + } + } + } +})() \ No newline at end of file diff --git a/urls.example.json b/urls.example.json new file mode 100644 index 0000000..a3586c1 --- /dev/null +++ b/urls.example.json @@ -0,0 +1,3 @@ +{ + "Test": ["https://www.google.com/", "https://www.youtube.com"] +} \ No newline at end of file From 13e847da95a85e1846a65ac0163a27cfea5b76be Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 15:47:14 -0700 Subject: [PATCH 06/15] fix: add missing behavior to run both form factors In lighthouse-docker we run both form factors, desktop and mobile. To do this we need to import the associated config files for each form factor. We cannot just set the "formFactor" lh option to "desktop" or "mobile" as there are other options that need to be set. For example, the "throttling" option. These additional options were automatically set when we ran lighthouse through the CLI tool in lighthouse-docker. However, when we run lighthouse programmatically, we need to set these options ourselves, or use the config files directly. --- src/LighthouseRunner.ts | 6 ++--- src/index.ts | 58 +++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/LighthouseRunner.ts b/src/LighthouseRunner.ts index b456805..5103fb8 100644 --- a/src/LighthouseRunner.ts +++ b/src/LighthouseRunner.ts @@ -1,5 +1,5 @@ import lighthouse from 'lighthouse'; -import type {Flags, Result} from 'lighthouse'; +import type {Flags, Result, Config} from 'lighthouse'; export default class LighthouseRunner { private lhOptions: Flags = { @@ -7,8 +7,8 @@ export default class LighthouseRunner { logLevel: 'silent', } - async run(url: string, lhOptions: Flags = {}): Promise { - const result = await lighthouse(url, {...this.lhOptions, ...lhOptions}) + async run(url: string, lhOptions: Flags = {}, config: Config = {}): Promise { + const result = await lighthouse(url, {...this.lhOptions, ...lhOptions}, config) if (result) { return result.lhr diff --git a/src/index.ts b/src/index.ts index f9fae7f..c6faa17 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,8 +3,10 @@ import LighthouseRunner from "./LighthouseRunner.js" import Datadog from "./DatadogClient.js" import {v2} from '@datadog/datadog-api-client' import fs from 'node:fs' -import type { Result } from 'lighthouse' import os from 'node:os' +import type { Flags, Result, Config } from 'lighthouse' +import lhDesktopConfig from 'lighthouse/core/config/lr-desktop-config.js' +import lhMobileConfig from 'lighthouse/core/config/lr-mobile-config.js' import dotenv from 'dotenv' dotenv.config(); @@ -39,41 +41,51 @@ function retrieveDataPointsForAudits(results: Result, audits: string[]) { return values } -(async() => { + +async function sendMetricsToDatadog(metricName: string, dataPoints: v2.MetricPoint[], tags: Record) { const dd = new Datadog({ api_key: process.env.DD_API_KEY || '', app_key: process.env.DD_APP_KEY || '' }) + const tagsArray = Object.entries(tags).map(([key, value]) => `${key}:${value}`) - const inspectList: Record = JSON.parse(await fs.promises.readFile('urls.json', 'utf8')); + await dd.submitMetrics(metricName, dataPoints, tagsArray) +} - const coreMetrics: Record = JSON.parse(await fs.promises.readFile('metrics-config.json', 'utf8')); +async function captureLighthouseMetrics(pageType: string, url: string, audits: string[], options: Flags = {}, config: Config = {}) { + const chromeRunner = new ChromeRunner() + const lighthouseRunner = new LighthouseRunner() - for (let [pageType, urls] of Object.entries(inspectList)) { - for (let url of urls) { - const chromeRunner = new ChromeRunner(false) - const lighthouseRunner = new LighthouseRunner() + const port = await chromeRunner.start() + const results = await lighthouseRunner.run(url, {port: port, ...options}, config) - const port = await chromeRunner.start() - const results = await lighthouseRunner.run(url, {port: port}) + chromeRunner.stop() - chromeRunner.stop() + const metrics = retrieveDataPointsForAudits(results, audits) - const metrics = retrieveDataPointsForAudits(results, coreMetrics['audits']) + const tags = { + 'url': url, + 'page_type': pageType, + 'lighthouse_version': results.lighthouseVersion, + 'form_factor': results.configSettings.formFactor, + 'host': os.hostname() + } - const tags = { - 'url': url, - 'page_type': pageType, - 'lighthouse_version': results.lighthouseVersion, - 'host': os.hostname() - } + for (let [audit, dataPoints] of Object.entries(metrics)) { + await sendMetricsToDatadog(`lighthouse.${audit}.value`, [dataPoints.numericValue], tags) + await sendMetricsToDatadog(`lighthouse.${audit}.score`, [dataPoints.score], tags) + } - const tagsArray = Object.entries(tags).map(([key, value]) => `${key}:${value}`) +} +(async() => { + const inspectList: Record = JSON.parse(await fs.promises.readFile('urls.json', 'utf8')); - for (let [audit, dataPoints] of Object.entries(metrics)) { - await dd.submitMetrics(`lighthouse.${audit}.value`, [dataPoints.numericValue], tagsArray) - await dd.submitMetrics(`lighthouse.${audit}.score`, [dataPoints.numericValue], tagsArray) - } + const coreMetrics: Record = JSON.parse(await fs.promises.readFile('metrics-config.json', 'utf8')); + + for (let [pageType, urls] of Object.entries(inspectList)) { + for (let url of urls) { + await captureLighthouseMetrics(pageType, url, coreMetrics.audits, {}, lhDesktopConfig) + await captureLighthouseMetrics(pageType, url, coreMetrics.audits, {}, lhMobileConfig) } } })() \ No newline at end of file From c9f2cc72d5a40e2682f10e48f3ed40e7ac96472d Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 16:05:36 -0700 Subject: [PATCH 07/15] feat: add some logs to communicate progress --- src/index.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/index.ts b/src/index.ts index c6faa17..cca72bd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -56,6 +56,8 @@ async function captureLighthouseMetrics(pageType: string, url: string, audits: s const chromeRunner = new ChromeRunner() const lighthouseRunner = new LighthouseRunner() + const formFactor = config.settings?.formFactor || 'mobile' + console.log(`Running Lighthouse for ${url} with form factor: ${formFactor}`); const port = await chromeRunner.start() const results = await lighthouseRunner.run(url, {port: port, ...options}, config) @@ -71,11 +73,14 @@ async function captureLighthouseMetrics(pageType: string, url: string, audits: s 'host': os.hostname() } + console.log(`Sending metrics to Datadog for ${url}`) for (let [audit, dataPoints] of Object.entries(metrics)) { await sendMetricsToDatadog(`lighthouse.${audit}.value`, [dataPoints.numericValue], tags) await sendMetricsToDatadog(`lighthouse.${audit}.score`, [dataPoints.score], tags) } + console.log(`Done sending metrics to Datadog for ${url}`) + console.log(`Done running Lighthouse for ${url} with form factor: ${formFactor}\n`); } (async() => { const inspectList: Record = JSON.parse(await fs.promises.readFile('urls.json', 'utf8')); @@ -83,9 +88,16 @@ async function captureLighthouseMetrics(pageType: string, url: string, audits: s const coreMetrics: Record = JSON.parse(await fs.promises.readFile('metrics-config.json', 'utf8')); for (let [pageType, urls] of Object.entries(inspectList)) { + console.log(`Capturing metrics for ${pageType} page(s)\n`) + for (let url of urls) { await captureLighthouseMetrics(pageType, url, coreMetrics.audits, {}, lhDesktopConfig) + await captureLighthouseMetrics(pageType, url, coreMetrics.audits, {}, lhMobileConfig) } + + console.log(`Done capturing metrics for ${pageType} page(s)\n`) } + + console.log('Done capturing metrics for all pages') })() \ No newline at end of file From 9dd582c37c9268b45fb00b709b9e3ca26220ea2d Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 16:10:09 -0700 Subject: [PATCH 08/15] chore: add dist to .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6b169d2..842b9bb 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,7 @@ node_modules/ # Config Files urls.json -metrics-config.json \ No newline at end of file +metrics-config.json + +# TSC Output +dist \ No newline at end of file From e2ceee63213773b09c6bfdfc22c52be5106c7e53 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Fri, 8 Sep 2023 16:30:37 -0700 Subject: [PATCH 09/15] chore: update the README --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 84ad791..2dffa85 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,18 @@ -# vigilo +# Vigilo +🚧 Still in development 🚧 + Vigilo is a monitoring tool that automates Lighthouse audits and sends key metrics to Datadog. Designed to keep a vigilant eye on your web application's performance and accessibility. + +### Setup +1. Clone the repo +2. Run `pnpm install` +3. Run `pnpm run build` +4. Run `cp .env.example .env` +5. Add your Datadog API key and Datadog Application key to the `.env` file +6. Run `cp urls.example.json urls.json` +7. Add your URLs to the `urls.json` file +8. Run `cp metrics.example.json metrics.json` +9. Add the metrics you want to send to Datadog to the `metrics.json` file + +### Usage +1. After setup, run `pnpm start` to run vigilo and send metrics to Datadog From 928215261abb1602db41651500720816a04418a1 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Mon, 11 Sep 2023 14:50:03 -0700 Subject: [PATCH 10/15] refactor: simplify truthy checking of response errors --- src/DatadogClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DatadogClient.ts b/src/DatadogClient.ts index 5487ea8..f14304d 100644 --- a/src/DatadogClient.ts +++ b/src/DatadogClient.ts @@ -33,7 +33,7 @@ export default class DatadogClient { const response = await metricsApiInstance.submitMetrics(params); - if (response.errors && response.errors.length > 0) { + if (response.errors?.length) { throw new Error(response.errors.join(', ')); } } From 1f33236635105f40909b9a3a389c62e3ea7a2035 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Tue, 12 Sep 2023 13:41:26 -0700 Subject: [PATCH 11/15] fix(README): use .env.template instead of .env.example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2dffa85..7421285 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Vigilo is a monitoring tool that automates Lighthouse audits and sends key metri 1. Clone the repo 2. Run `pnpm install` 3. Run `pnpm run build` -4. Run `cp .env.example .env` +4. Run `cp .env.template .env` 5. Add your Datadog API key and Datadog Application key to the `.env` file 6. Run `cp urls.example.json urls.json` 7. Add your URLs to the `urls.json` file From 084fb53aa03e5fbc4f4ae4853a5f99f829bbcf27 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Wed, 13 Sep 2023 12:15:46 -0700 Subject: [PATCH 12/15] fix(chrome): use puppeteer instead of chrome-launcher We need to use puppeteer instead of chrome-launcher because at the moment some of the current Devs are having issues with chrome-launcher when running in WSL. We don't have a docker image for vigilo yet, so we need to use puppeteer for now. We will not be passing a "Page" object to the lighthouse runner instead of a "port" option. Aside from that, everything else should be the same. --- package.json | 4 +- pnpm-lock.yaml | 248 +++++++++++++++++++++++++++++++++++++++- src/BrowserRunner.ts | 32 ++++++ src/ChromeRunner.ts | 22 ---- src/LighthouseRunner.ts | 5 +- src/index.ts | 10 +- 6 files changed, 286 insertions(+), 35 deletions(-) create mode 100644 src/BrowserRunner.ts delete mode 100644 src/ChromeRunner.ts diff --git a/package.json b/package.json index c955d6b..a47c95f 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ }, "dependencies": { "@datadog/datadog-api-client": "^1.16.0", - "chrome-launcher": "^1.0.0", "dotenv": "^16.3.1", - "lighthouse": "^11.1.0" + "lighthouse": "^11.1.0", + "puppeteer": "^21.2.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e1a9b23..22fd3c7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,15 +8,15 @@ dependencies: '@datadog/datadog-api-client': specifier: ^1.16.0 version: 1.16.0 - chrome-launcher: - specifier: ^1.0.0 - version: 1.0.0 dotenv: specifier: ^16.3.1 version: 16.3.1 lighthouse: specifier: ^11.1.0 version: 11.1.0 + puppeteer: + specifier: ^21.2.1 + version: 21.2.1(typescript@5.2.2) devDependencies: '@tsconfig/node18': @@ -31,6 +31,28 @@ devDependencies: packages: + /@babel/code-frame@7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.22.13 + chalk: 2.4.2 + dev: false + + /@babel/helper-validator-identifier@7.22.15: + resolution: {integrity: sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/highlight@7.22.13: + resolution: {integrity: sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.15 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: false + /@datadog/datadog-api-client@1.16.0: resolution: {integrity: sha512-PnInPPyw3Ax8xcsAcJDIBUZcLSUWyFSdJc92Ac72+dKuoz79WBYw01naD9NRX0T9Ggv6mUOGILMq8BfpiHYfYA==} engines: {node: '>=12.0.0'} @@ -65,6 +87,22 @@ packages: - supports-color dev: false + /@puppeteer/browsers@1.7.1: + resolution: {integrity: sha512-nIb8SOBgDEMFY2iS2MdnUZOg2ikcYchRrBoF+wtdjieRFKR2uGRipHY/oFLo+2N6anDualyClPzGywTHRGrLfw==} + engines: {node: '>=16.3.0'} + hasBin: true + dependencies: + debug: 4.3.4 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.3.1 + tar-fs: 3.0.4 + unbzip2-stream: 1.4.3 + yargs: 17.7.1 + transitivePeerDependencies: + - supports-color + dev: false + /@sentry/core@6.19.7: resolution: {integrity: sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==} engines: {node: '>=6'} @@ -180,6 +218,13 @@ packages: engines: {node: '>=8'} dev: false + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -187,6 +232,10 @@ packages: color-convert: 2.0.1 dev: false + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: false + /ast-types@0.13.4: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} @@ -231,6 +280,20 @@ packages: ieee754: 1.2.1 dev: false + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: false + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: false + /chrome-launcher@1.0.0: resolution: {integrity: sha512-74IMFVfgni/bQ4GotUNJpH2vDR+Sh9cXNPVhPXiedeiB0+5j7/8i8LAqS7WlyNSKqtxJ/CgbOpBDPLkzqDVhlw==} engines: {node: '>=12.13.0'} @@ -253,6 +316,15 @@ packages: mitt: 3.0.1 dev: false + /chromium-bidi@0.4.26(devtools-protocol@0.0.1159816): + resolution: {integrity: sha512-lukBGfogAI4T0y3acc86RaacqgKQve47/8pV2c+Hr1PjcICj2K4OkL3qfX3qrqxxnd4ddurFC0WBA3VCQqYeUQ==} + peerDependencies: + devtools-protocol: '*' + dependencies: + devtools-protocol: 0.0.1159816 + mitt: 3.0.1 + dev: false + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -262,6 +334,12 @@ packages: wrap-ansi: 7.0.0 dev: false + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -269,6 +347,10 @@ packages: color-name: 1.1.4 dev: false + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: false @@ -297,6 +379,22 @@ packages: engines: {node: '>= 0.6'} dev: false + /cosmiconfig@8.3.5(typescript@5.2.2): + resolution: {integrity: sha512-A5Xry3xfS96wy2qbiLkQLAg4JUrR2wvfybxj6yqLmrUfMAvhS3MZxIP2oQn0grgYIvJqzpeTEWu4vK0t+12NNw==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + typescript: 5.2.2 + dev: false + /cross-fetch@3.1.8: resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} dependencies: @@ -407,6 +505,12 @@ packages: strip-ansi: 6.0.1 dev: false + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: false + /es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} dev: false @@ -416,6 +520,11 @@ packages: engines: {node: '>=6'} dev: false + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: false + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -519,6 +628,11 @@ packages: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: false + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: false + /http-link-header@1.1.1: resolution: {integrity: sha512-mW3N/rTYpCn99s1do0zx6nzFZSwLH9HGfUM4ZqLWJ16ylmYaC2v5eYGqrNTQlByx8AzUgGI+V/32gXPugs1+Sw==} engines: {node: '>=6.0.0'} @@ -562,6 +676,14 @@ packages: resolution: {integrity: sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg==} dev: false + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: false + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -586,6 +708,10 @@ packages: resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} dev: false + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: false + /is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -622,6 +748,21 @@ packages: engines: {node: '>=12'} dev: false + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: false + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: false + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: false + /jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: @@ -680,6 +821,10 @@ packages: - utf-8-validate dev: false + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: false + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: false @@ -806,10 +951,32 @@ packages: resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} dev: false + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: false + /parse-cache-control@1.0.1: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} dev: false + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.22.13 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: false + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: false + /pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: false @@ -835,6 +1002,22 @@ packages: - supports-color dev: false + /proxy-agent@6.3.1: + resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.1 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.2 + transitivePeerDependencies: + - supports-color + dev: false + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: false @@ -868,6 +1051,39 @@ packages: - utf-8-validate dev: false + /puppeteer-core@21.2.1: + resolution: {integrity: sha512-+I8EjpWFeeFKScpQiTEnC4jGve2Wr4eA9qUMoa8S317DJPm9h7wzrT4YednZK2TQZMyPtPQ2Disb/Tg02+4Naw==} + engines: {node: '>=16.3.0'} + dependencies: + '@puppeteer/browsers': 1.7.1 + chromium-bidi: 0.4.26(devtools-protocol@0.0.1159816) + cross-fetch: 4.0.0 + debug: 4.3.4 + devtools-protocol: 0.0.1159816 + ws: 8.14.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /puppeteer@21.2.1(typescript@5.2.2): + resolution: {integrity: sha512-bgY/lYBH3rR+m5EP1FxzY2MRMrau7Pyq+N5YlspA63sF+cBkUiTn5WZXwXm7mEHwkkOSVi5LiS74T5QIgrSklg==} + engines: {node: '>=16.3.0'} + requiresBuild: true + dependencies: + '@puppeteer/browsers': 1.7.1 + cosmiconfig: 8.3.5(typescript@5.2.2) + puppeteer-core: 21.2.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - typescript + - utf-8-validate + dev: false + /querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} dev: false @@ -885,6 +1101,11 @@ packages: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} dev: false + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: false + /robots-parser@3.0.1: resolution: {integrity: sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==} engines: {node: '>=10.0.0'} @@ -967,6 +1188,13 @@ packages: ansi-regex: 5.0.1 dev: false + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: false + /tar-fs@3.0.4: resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==} dependencies: @@ -1013,7 +1241,6 @@ packages: resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} hasBin: true - dev: true /unbzip2-stream@1.4.3: resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} @@ -1100,6 +1327,19 @@ packages: optional: true dev: false + /ws@8.14.1: + resolution: {integrity: sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /xdg-basedir@4.0.0: resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} engines: {node: '>=8'} diff --git a/src/BrowserRunner.ts b/src/BrowserRunner.ts new file mode 100644 index 0000000..c2534bc --- /dev/null +++ b/src/BrowserRunner.ts @@ -0,0 +1,32 @@ +import puppeteer from "puppeteer" +import type {Browser, Page, PuppeteerLaunchOptions} from "puppeteer" + +export default class BrowserRunner { + private launchOptions: PuppeteerLaunchOptions = { + headless: 'new', + // `headless: true` (default) enables old Headless; + // `headless: 'new'` enables new Headless; + // `headless: false` enables “headful” mode. + // See https://developer.chrome.com/articles/new-headless/ for more details. + args: [ + '--disable-gpu' + ] + } + browser!: Browser + + constructor(headless: boolean = true) { + if(!headless) { + this.launchOptions.headless = false + } + } + + async start(): Promise { + this.browser = await puppeteer.launch(this.launchOptions); + const page = await this.browser.newPage(); + return page; + } + + async stop() { + await this.browser.close(); + } +} \ No newline at end of file diff --git a/src/ChromeRunner.ts b/src/ChromeRunner.ts deleted file mode 100644 index 69f3810..0000000 --- a/src/ChromeRunner.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { LaunchedChrome } from 'chrome-launcher'; -import {launch} from 'chrome-launcher'; - -export default class ChromeRunner { - private flags = ['--disable-gpu']; - chrome!: LaunchedChrome - - constructor(headless: boolean = true) { - if (headless) { - this.flags.push('--headless') - } - } - - async start(): Promise { - this.chrome = await launch({ chromeFlags: this.flags }) - return this.chrome.port - } - - stop() { - this.chrome.kill() - } -} \ No newline at end of file diff --git a/src/LighthouseRunner.ts b/src/LighthouseRunner.ts index 5103fb8..a0cdb9a 100644 --- a/src/LighthouseRunner.ts +++ b/src/LighthouseRunner.ts @@ -1,5 +1,6 @@ import lighthouse from 'lighthouse'; import type {Flags, Result, Config} from 'lighthouse'; +import type {Page} from 'puppeteer'; export default class LighthouseRunner { private lhOptions: Flags = { @@ -7,8 +8,8 @@ export default class LighthouseRunner { logLevel: 'silent', } - async run(url: string, lhOptions: Flags = {}, config: Config = {}): Promise { - const result = await lighthouse(url, {...this.lhOptions, ...lhOptions}, config) + async run(url: string, lhOptions: Flags = {}, config: Config = {}, page?: Page): Promise { + const result = await lighthouse(url, {...this.lhOptions, ...lhOptions}, config, page) if (result) { return result.lhr diff --git a/src/index.ts b/src/index.ts index cca72bd..a8baf89 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import ChromeRunner from "./ChromeRunner.js" +import BrowserRunner from "./BrowserRunner.js" import LighthouseRunner from "./LighthouseRunner.js" import Datadog from "./DatadogClient.js" import {v2} from '@datadog/datadog-api-client' @@ -53,15 +53,15 @@ async function sendMetricsToDatadog(metricName: string, dataPoints: v2.MetricPoi } async function captureLighthouseMetrics(pageType: string, url: string, audits: string[], options: Flags = {}, config: Config = {}) { - const chromeRunner = new ChromeRunner() + const browserRunner = new BrowserRunner(false) const lighthouseRunner = new LighthouseRunner() const formFactor = config.settings?.formFactor || 'mobile' console.log(`Running Lighthouse for ${url} with form factor: ${formFactor}`); - const port = await chromeRunner.start() - const results = await lighthouseRunner.run(url, {port: port, ...options}, config) + const page = await browserRunner.start() + const results = await lighthouseRunner.run(url, {...options}, config, page) - chromeRunner.stop() + await browserRunner.stop() const metrics = retrieveDataPointsForAudits(results, audits) From 09a74096699016a38a9dfd144b86cc6f4526d4c8 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Wed, 13 Sep 2023 12:28:12 -0700 Subject: [PATCH 13/15] chore(README): update README to include additional setup instructions for WSL envs --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 7421285..9628c63 100644 --- a/README.md +++ b/README.md @@ -14,5 +14,20 @@ Vigilo is a monitoring tool that automates Lighthouse audits and sends key metri 8. Run `cp metrics.example.json metrics.json` 9. Add the metrics you want to send to Datadog to the `metrics.json` file +⚠️ If you are setting this up on a Windows machine via WSL, then you will need to run the following commands to ensure the correct linux dependencies are installed: +**Make sure dependencies are up to date** +``` +sudo apt update && sudo apt -y upgrade && sudo apt -y autoremove +``` +**Download and Install Chrome** +``` +wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb +sudo apt -y install ./google-chrome-stable_current_amd64.deb +``` +**Check Chrome was Successfully Installed** +``` +google-chrome --version +``` + ### Usage 1. After setup, run `pnpm start` to run vigilo and send metrics to Datadog From 169040a9a74e7a593585f9e029f3f37186b0290a Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Wed, 13 Sep 2023 12:30:44 -0700 Subject: [PATCH 14/15] fix(index): remove headful browser setting I accidentally left this in here when I was debugging. Let's make sure the browser runs in a headless mode --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index a8baf89..a9bb249 100644 --- a/src/index.ts +++ b/src/index.ts @@ -53,7 +53,7 @@ async function sendMetricsToDatadog(metricName: string, dataPoints: v2.MetricPoi } async function captureLighthouseMetrics(pageType: string, url: string, audits: string[], options: Flags = {}, config: Config = {}) { - const browserRunner = new BrowserRunner(false) + const browserRunner = new BrowserRunner() const lighthouseRunner = new LighthouseRunner() const formFactor = config.settings?.formFactor || 'mobile' From e3f1df14365c62a2418101a2b87bbb9724f5bed5 Mon Sep 17 00:00:00 2001 From: Angel de la Torre Date: Wed, 13 Sep 2023 14:50:20 -0700 Subject: [PATCH 15/15] refactor(BrowserRunner): directly return the new page object Co-authored-by: Michael Lahargou --- src/BrowserRunner.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/BrowserRunner.ts b/src/BrowserRunner.ts index c2534bc..1965cd4 100644 --- a/src/BrowserRunner.ts +++ b/src/BrowserRunner.ts @@ -22,8 +22,7 @@ export default class BrowserRunner { async start(): Promise { this.browser = await puppeteer.launch(this.launchOptions); - const page = await this.browser.newPage(); - return page; + return await this.browser.newPage(); } async stop() {