@jsenv/lighthouse-impact 2.0.0 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,4 @@
1
- # Lighthouse impact
2
-
3
- Report pull request impacts on lighthouse score.
4
-
5
- [![npm package](https://img.shields.io/npm/v/@jsenv/lighthouse-impact.svg?logo=npm&label=package)](https://www.npmjs.com/package/@jsenv/lighthouse-impact)
6
- [![github main](https://github.com/jsenv/lighthouse-impact/workflows/main/badge.svg)](https://github.com/jsenv/lighthouse-impact/actions?workflow=main)
7
- [![codecov coverage](https://codecov.io/gh/jsenv/lighthouse-impact/branch/main/graph/badge.svg)](https://codecov.io/gh/jsenv/lighthouse-impact)
8
-
9
- # Presentation
1
+ # Lighthouse impact [![npm package](https://img.shields.io/npm/v/@jsenv/lighthouse-impact.svg?logo=npm&label=package)](https://www.npmjs.com/package/@jsenv/lighthouse-impact)
10
2
 
11
3
  `@jsenv/lighthouse-impact` analyses a pull request impact on lighthouse score. This analysis is posted in a comment of the pull request on GitHub.
12
4
 
@@ -32,7 +24,7 @@ The first thing you need is a script capable to generate a lighthouse report.
32
24
  npm install --save-dev @jsenv/lighthouse-impact
33
25
  ```
34
26
 
35
- _generate_lighthouse_report.mjs_
27
+ _lighthouse.mjs_
36
28
 
37
29
  ```js
38
30
  /*
@@ -77,7 +69,7 @@ _index.html_
77
69
  </html>
78
70
  ```
79
71
 
80
- At this stage, you could generate a lighthouse report on your machine. For an example, see [package.json#L36](./package.json#L36) and [script/lighthouse/generate_lighthouse_report.mjs#L37](./script/lighthouse/generate_lighthouse_report.mjs#L37).
72
+ At this stage, you could generate a lighthouse report on your machine. For an example, see [package.json#L37](./package.json#L37) and [script/lighthouse/lighthouse.mjs#L19](./script/lighthouse/lighthouse.mjs#L19).
81
73
 
82
74
  Now it's time to configure a workflow to compare lighthouse reports before and after merging a pull request.
83
75
 
@@ -107,10 +99,10 @@ jobs:
107
99
  - name: Setup git
108
100
  uses: actions/checkout@v2
109
101
  - name: Setup node
110
- uses: actions/setup-node@v1
102
+ uses: actions/setup-node@v2
111
103
  with:
112
- node-version: "16.x"
113
- - name: Setup npm
104
+ node-version: "16.13.0"
105
+ - name: Install node modules
114
106
  run: npm install
115
107
  - name: Report lighthouse impact
116
108
  run: node ./report_lighthouse_impact.mjs
@@ -131,9 +123,9 @@ import {
131
123
  readGitHubWorkflowEnv,
132
124
  } from "@jsenv/lighthouse-impact"
133
125
 
134
- reportLighthouseImpact({
126
+ await reportLighthouseImpact({
135
127
  ...readGitHubWorkflowEnv(),
136
- lighthouseReportPath: "./generate_lighthouse_report.mjs#lighthouseReport",
128
+ lighthouseReportPath: "./lighthouse.mjs#lighthouseReport",
137
129
  })
138
130
  ```
139
131
 
@@ -175,7 +167,7 @@ reportLighthouseImpact({
175
167
  + repositoryName: process.env.TRAVIS_REPO_SLUG.split("/")[1],
176
168
  + pullRequestNumber: process.env.TRAVIS_PULL_REQUEST,
177
169
  + githubToken: process.env.GITHUB_TOKEN, // see next step
178
- lighthouseReportPath: "./generate_lighthouse_report.mjs#lighthouseReport",
170
+ lighthouseReportPath: "./lighthouse.mjs#lighthouseReport",
179
171
  })
180
172
  ```
181
173
 
File without changes
package/main.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export { generateLighthouseReport } from "./src/generateLighthouseReport.js"
2
- export { logLighthouseReport } from "./src/logLighthouseReport.js"
3
2
 
4
3
  export { readGitHubWorkflowEnv } from "@jsenv/github-pull-request-impact"
5
4
  export { reportLighthouseImpact } from "./src/reportLighthouseImpact.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/lighthouse-impact",
3
- "version": "2.0.0",
3
+ "version": "2.1.3",
4
4
  "description": "Package description",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -10,10 +10,11 @@
10
10
  },
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "https://github.com/jsenv/lighthouse-impact"
13
+ "url": "https://github.com/jsenv/workflow",
14
+ "directory": "packages/jsenv-lighthouse-impact"
14
15
  },
15
16
  "engines": {
16
- "node": ">=14.17.0"
17
+ "node": ">=16.13.0"
17
18
  },
18
19
  "publishConfig": {
19
20
  "access": "public",
@@ -26,50 +27,36 @@
26
27
  },
27
28
  "./*": "./*"
28
29
  },
30
+ "main": "./main.js",
29
31
  "files": [
30
32
  "/src/",
31
33
  "/main.js"
32
34
  ],
33
35
  "scripts": {
34
- "eslint-check": "node ./node_modules/eslint/bin/eslint.js . --ext=.js,.mjs",
35
- "generate-importmap": "node ./script/importmap/generate_importmap.mjs",
36
- "measure-performances": "node --expose-gc ./script/performance/generate_performance_report.mjs --log",
37
- "generate-lighthouse-report": "node ./script/lighthouse/generate_lighthouse_report.mjs --local",
38
- "generate-comment-snapshot-file": "node ./test/comment/generate_comment_snapshot_file.mjs",
36
+ "eslint": "npx eslint . --ext=.js,.mjs",
37
+ "importmap": "node ./script/importmap/importmap.mjs",
38
+ "snapshot": "node ./test/comment/generate_comment_snapshot_file.mjs",
39
39
  "test": "node ./script/test/test.mjs",
40
40
  "test-with-coverage": "npm run test -- --coverage",
41
- "prettier-format": "node ./script/prettier/prettier_format.mjs",
42
- "prettier-format-stage": "npm run prettier-format -- --staged",
43
- "prettier-check": "npm run prettier-format -- --dry-run",
44
- "prepublishOnly": "node ./script/publish/remove_postinstall.mjs",
45
- "postpublish": "node ./script/publish/restore_postinstall.mjs"
41
+ "prettier": "prettier --write ."
46
42
  },
47
43
  "dependencies": {
48
- "@jsenv/cancellation": "3.0.0",
44
+ "@jsenv/abort": "4.1.2",
49
45
  "@jsenv/dynamic-import-worker": "1.0.0",
50
- "@jsenv/filesystem": "2.3.1",
51
- "@jsenv/github-pull-request-impact": "1.6.4",
46
+ "@jsenv/filesystem": "2.7.1",
47
+ "@jsenv/github-pull-request-impact": "1.6.6",
52
48
  "@jsenv/logger": "4.0.1",
53
- "chrome-launcher": "0.14.0",
54
- "lighthouse": "8.2.0"
49
+ "chrome-launcher": "0.15.0",
50
+ "lighthouse": "9.2.0"
55
51
  },
56
52
  "devDependencies": {
57
- "@babel/core": "7.15.8",
58
- "@babel/eslint-parser": "7.15.8",
59
- "@jsenv/assert": "2.3.2",
60
- "@jsenv/codecov-upload": "3.5.0",
61
- "@jsenv/core": "23.0.5",
62
- "@jsenv/eslint-config": "16.0.8",
63
- "@jsenv/github-release-package": "1.2.3",
64
- "@jsenv/importmap-eslint-resolver": "5.1.2",
65
- "@jsenv/importmap-node-module": "2.4.1",
66
- "@jsenv/package-publish": "1.6.2",
67
- "@jsenv/performance-impact": "2.0.2",
68
- "@jsenv/prettier-check-project": "5.6.1",
69
- "@jsenv/server": "7.2.0",
70
- "eslint": "7.32.0",
71
- "eslint-plugin-html": "6.2.0",
72
- "eslint-plugin-import": "2.25.2",
73
- "prettier": "2.4.1"
53
+ "@jsenv/assert": "2.4.1",
54
+ "@jsenv/core": "25.3.0",
55
+ "@jsenv/eslint-config": "16.0.9",
56
+ "@jsenv/importmap-eslint-resolver": "5.2.5",
57
+ "@jsenv/importmap-node-module": "5.1.3",
58
+ "eslint": "8.7.0",
59
+ "eslint-plugin-import": "2.25.4",
60
+ "prettier": "2.5.1"
74
61
  }
75
62
  }
@@ -2,27 +2,23 @@
2
2
 
3
3
  import { createRequire } from "node:module"
4
4
 
5
- import { createLogger } from "@jsenv/logger"
6
- import {
7
- createCancellationToken,
8
- createCancellationSource,
9
- composeCancellationToken,
10
- createOperation,
11
- executeAsyncFunction,
12
- } from "@jsenv/cancellation"
13
5
  import {
14
6
  writeFile,
15
7
  resolveUrl,
16
8
  assertAndNormalizeDirectoryUrl,
17
9
  } from "@jsenv/filesystem"
10
+ import { createLogger } from "@jsenv/logger"
11
+ import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
12
+
13
+ import { formatLighthouseReportForLog } from "./internal/formatLighthouseReportForLog.js"
18
14
 
19
15
  const require = createRequire(import.meta.url)
20
16
 
21
17
  export const generateLighthouseReport = async (
22
18
  url,
23
19
  {
24
- cancellationToken = createCancellationToken(),
25
- cancelOnSIGINT = true,
20
+ signal = new AbortController().signal,
21
+ handleSIGINT = true,
26
22
  logLevel,
27
23
 
28
24
  headless = true,
@@ -36,6 +32,7 @@ export const generateLighthouseReport = async (
36
32
  delayBetweenEachRunInSeconds = 1,
37
33
 
38
34
  projectDirectoryUrl, // required only when jsonFile or htmlFile is passed
35
+ log = false,
39
36
  jsonFile = false,
40
37
  jsonFileRelativeUrl = "./lighthouse/lighthouse_report.json",
41
38
  jsonFileLog = true,
@@ -44,31 +41,23 @@ export const generateLighthouseReport = async (
44
41
  htmlFileLog = true,
45
42
  } = {},
46
43
  ) => {
47
- // eslint-disable-next-line import/no-unresolved
48
- const ReportGenerator = require("lighthouse/report/report-generator")
44
+ const ReportGenerator = require("lighthouse/report/generator/report-generator.js")
49
45
  const {
50
46
  computeMedianRun,
51
47
  } = require("lighthouse/lighthouse-core/lib/median-run.js")
52
48
  const chromeLauncher = require("chrome-launcher")
53
49
 
54
- let cleanup = () => {}
55
-
56
- if (cancelOnSIGINT) {
57
- const processCancellationSource = createCancellationSource()
58
- const processCancellationToken = processCancellationSource.token
59
- cancellationToken = composeCancellationToken(
60
- cancellationToken,
61
- processCancellationToken,
62
- )
63
- const SIGINTCallback = () => {
64
- processCancellationSource.cancel("process SIGINT")
65
- }
66
- process.once("SIGINT", SIGINTCallback)
67
- // beware if someday something do things on cleanup
68
- // to call the old cleanup function
69
- cleanup = () => {
70
- process.removeListener("SIGINT", SIGINTCallback)
71
- }
50
+ const generateReportOperation = Abort.startOperation()
51
+ generateReportOperation.addAbortSignal(signal)
52
+ if (handleSIGINT) {
53
+ generateReportOperation.addAbortSource((abort) => {
54
+ return raceProcessTeardownEvents(
55
+ {
56
+ SIGINT: true,
57
+ },
58
+ abort,
59
+ )
60
+ })
72
61
  }
73
62
 
74
63
  const jsenvGenerateLighthouseReport = async () => {
@@ -83,34 +72,49 @@ export const generateLighthouseReport = async (
83
72
  "--disk-cache-size=1",
84
73
  // "--disk-cache-dir=/dev/null",
85
74
  ]
86
- const chrome = await createOperation({
87
- cancellationToken,
88
- start: () => chromeLauncher.launch({ chromeFlags }),
89
- })
75
+ const chrome = await chromeLauncher.launch({ chromeFlags })
76
+ if (generateReportOperation.signal.aborted) {
77
+ return { aborted: true }
78
+ }
79
+
90
80
  const lighthouseOptions = {
91
81
  chromeFlags,
92
82
  port: chrome.port,
93
83
  }
94
84
 
95
85
  const reports = []
96
- await Array(runCount)
97
- .fill()
98
- .reduce(async (previous, _, index) => {
99
- await previous
100
- if (index > 0 && delayBetweenEachRunInSeconds) {
101
- await new Promise((resolve) =>
102
- setTimeout(resolve, delayBetweenEachRunInSeconds * 1000),
103
- )
104
- }
105
- const report = await generateOneLighthouseReport(url, {
106
- cancellationToken,
107
- lighthouseOptions,
108
- config,
109
- })
110
- reports.push(report)
111
- }, Promise.resolve())
86
+ try {
87
+ await Array(runCount)
88
+ .fill()
89
+ .reduce(async (previous, _, index) => {
90
+ generateReportOperation.throwIfAborted()
91
+ await previous
92
+
93
+ if (index > 0 && delayBetweenEachRunInSeconds) {
94
+ await new Promise((resolve) =>
95
+ setTimeout(resolve, delayBetweenEachRunInSeconds * 1000),
96
+ )
97
+ }
98
+ generateReportOperation.throwIfAborted()
99
+ const report = await generateOneLighthouseReport(url, {
100
+ lighthouseOptions,
101
+ config,
102
+ })
103
+ reports.push(report)
104
+ }, Promise.resolve())
105
+ } catch (e) {
106
+ if (Abort.isAbortError(e)) {
107
+ return { aborted: true }
108
+ }
109
+ throw e
110
+ }
112
111
 
113
112
  const lighthouseReport = computeMedianRun(reports)
113
+
114
+ if (log) {
115
+ logger.info(formatLighthouseReportForLog(lighthouseReport))
116
+ }
117
+
114
118
  await chrome.kill()
115
119
 
116
120
  if (jsonFile || htmlFile) {
@@ -153,30 +157,19 @@ export const generateLighthouseReport = async (
153
157
  return lighthouseReport
154
158
  }
155
159
 
156
- return executeAsyncFunction(
157
- async () => {
158
- try {
159
- return await jsenvGenerateLighthouseReport()
160
- } finally {
161
- cleanup()
162
- }
163
- },
164
- {
165
- catchCancellation: true,
166
- considerUnhandledRejectionsAsExceptions: true,
167
- },
168
- )
160
+ try {
161
+ return await jsenvGenerateLighthouseReport()
162
+ } finally {
163
+ await generateReportOperation.end()
164
+ }
169
165
  }
170
166
 
171
167
  const generateOneLighthouseReport = async (
172
168
  url,
173
- { cancellationToken, lighthouseOptions, config },
169
+ { lighthouseOptions, config },
174
170
  ) => {
175
171
  const lighthouse = require("lighthouse")
176
- const results = await createOperation({
177
- cancellationToken,
178
- start: () => lighthouse(url, lighthouseOptions, config),
179
- })
172
+ const results = await lighthouse(url, lighthouseOptions, config)
180
173
 
181
174
  // use results.lhr for the JS-consumeable output
182
175
  // https://github.com/GoogleChrome/lighthouse/blob/master/types/lhr.d.ts
@@ -1,7 +1,7 @@
1
- export const logLighthouseReport = (lighthouseReport) => {
1
+ export const formatLighthouseReportForLog = (lighthouseReport) => {
2
2
  const scores = {}
3
3
  Object.keys(lighthouseReport.categories).forEach((name) => {
4
4
  scores[name] = lighthouseReport.categories[name].score
5
5
  })
6
- console.log(JSON.stringify(scores, null, " "))
6
+ return JSON.stringify(scores, null, " ")
7
7
  }
@@ -1,15 +1,9 @@
1
- /* eslint-disable new-cap */
1
+ import * as githubRESTAPI from "@jsenv/github-pull-request-impact/src/internal/github_rest_api.js"
2
2
  import { createDetailedMessage } from "@jsenv/logger"
3
- import {
4
- GET,
5
- POST,
6
- PATCH,
7
- } from "@jsenv/github-pull-request-impact/src/internal/git_hub_api.js"
8
3
 
9
4
  // https://developer.github.com/v3/gists/#create-a-gist
10
5
 
11
6
  export const patchOrPostGists = async ({
12
- cancellationToken,
13
7
  logger,
14
8
 
15
9
  githubToken,
@@ -45,14 +39,14 @@ export const patchOrPostGists = async ({
45
39
  logger.debug(`update or create both gists.`)
46
40
  let [beforeMergeGist, afterMergeGist] = await Promise.all([
47
41
  beforeMergeGistId
48
- ? GET(`https://api.github.com/gists/${beforeMergeGistId}`, {
49
- cancellationToken,
42
+ ? githubRESTAPI.GET({
43
+ url: `https://api.github.com/gists/${beforeMergeGistId}`,
50
44
  githubToken,
51
45
  })
52
46
  : null,
53
47
  afterMergeGistId
54
- ? GET(`https://api.github.com/gists/${afterMergeGistId}`, {
55
- cancellationToken,
48
+ ? githubRESTAPI.GET({
49
+ url: `https://api.github.com/gists/${afterMergeGistId}`,
56
50
  githubToken,
57
51
  })
58
52
  : null,
@@ -66,25 +60,19 @@ export const patchOrPostGists = async ({
66
60
  })
67
61
  if (beforeMergeGist) {
68
62
  logger.info(`updating base gist at ${gistIdToUrl(beforeMergeGist.id)}`)
69
- beforeMergeGist = await PATCH(
70
- `https://api.github.com/gists/${beforeMergeGist.id}`,
71
- beforeMergeGistBody,
72
- {
73
- cancellationToken,
74
- githubToken,
75
- },
76
- )
63
+ beforeMergeGist = await githubRESTAPI.PATCH({
64
+ url: `https://api.github.com/gists/${beforeMergeGist.id}`,
65
+ githubToken,
66
+ body: beforeMergeGistBody,
67
+ })
77
68
  logger.info(`base gist updated`)
78
69
  } else {
79
70
  logger.info(`creating base gist`)
80
- beforeMergeGist = await POST(
81
- `https://api.github.com/gists`,
82
- beforeMergeGistBody,
83
- {
84
- cancellationToken,
85
- githubToken,
86
- },
87
- )
71
+ beforeMergeGist = await githubRESTAPI.POST({
72
+ url: `https://api.github.com/gists`,
73
+ githubToken,
74
+ body: beforeMergeGistBody,
75
+ })
88
76
  logger.info(`base gist created at ${gistIdToUrl(beforeMergeGist.id)}`)
89
77
  }
90
78
 
@@ -98,25 +86,19 @@ export const patchOrPostGists = async ({
98
86
  logger.info(
99
87
  `updating after merge gist at ${gistIdToUrl(afterMergeGist.id)}`,
100
88
  )
101
- afterMergeGist = await PATCH(
102
- `https://api.github.com/gists/${afterMergeGist.id}`,
103
- afterMergeGistBody,
104
- {
105
- cancellationToken,
106
- githubToken,
107
- },
108
- )
89
+ afterMergeGist = await githubRESTAPI.PATCH({
90
+ url: `https://api.github.com/gists/${afterMergeGist.id}`,
91
+ githubToken,
92
+ body: afterMergeGistBody,
93
+ })
109
94
  logger.info(`after merge gist updated`)
110
95
  } else {
111
96
  logger.info(`creating after merge gist`)
112
- afterMergeGist = await POST(
113
- `https://api.github.com/gists`,
114
- afterMergeGistBody,
115
- {
116
- cancellationToken,
117
- githubToken,
118
- },
119
- )
97
+ afterMergeGist = await githubRESTAPI.POST({
98
+ url: `https://api.github.com/gists`,
99
+ githubToken,
100
+ body: afterMergeGistBody,
101
+ })
120
102
  logger.info(`after merge gist created at ${gistIdToUrl(afterMergeGist.id)}`)
121
103
  }
122
104
 
@@ -1,5 +1,5 @@
1
- import { commentGitHubPullRequestImpact } from "@jsenv/github-pull-request-impact"
2
1
  import { assertAndNormalizeDirectoryUrl, resolveUrl } from "@jsenv/filesystem"
2
+ import { commentGitHubPullRequestImpact } from "@jsenv/github-pull-request-impact"
3
3
  import { importOneExportFromFile } from "@jsenv/dynamic-import-worker"
4
4
 
5
5
  import { patchOrPostGists } from "./internal/patchOrPostGists.js"
@@ -8,7 +8,6 @@ import { createLighthouseImpactComment } from "./internal/createLighthouseImpact
8
8
  export const reportLighthouseImpact = async ({
9
9
  logLevel,
10
10
  commandLogs = false,
11
- cancellationToken,
12
11
  cancelOnSIGINT,
13
12
  projectDirectoryUrl,
14
13
 
@@ -41,7 +40,6 @@ export const reportLighthouseImpact = async ({
41
40
  commandLogs,
42
41
  // lighthouse report are super verbose, do not log them
43
42
  infoLogs: false,
44
- cancellationToken,
45
43
  cancelOnSIGINT,
46
44
  projectDirectoryUrl,
47
45
 
@@ -59,7 +57,6 @@ export const reportLighthouseImpact = async ({
59
57
  },
60
58
  commentIdentifier: `<!-- Generated by @jsenv/lighthouse-impact -->`,
61
59
  createCommentForComparison: async ({
62
- cancellationToken,
63
60
  logger,
64
61
 
65
62
  pullRequestBase,
@@ -74,7 +71,6 @@ export const reportLighthouseImpact = async ({
74
71
  let afterMergeGist
75
72
  try {
76
73
  const gistResult = await patchOrPostGists({
77
- cancellationToken,
78
74
  logger,
79
75
 
80
76
  githubToken,