From 64110b75a67bdb03c73c0428900572c2a7c7838a Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 30 Mar 2026 22:25:23 -0700 Subject: [PATCH 1/4] build: drop redundant npx prefixes - package.json scripts: eslint, tsc, prettier are all devDependencies, npm/yarn already resolve them from node_modules/.bin - mocha-cli.ts: spawn yarn tsx instead of npx tsx (tsx is a devDep) --- package.json | 6 +++--- spec-electron-setup/scripts/mocha-cli.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 964e8e1..16c1f7a 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,9 @@ "build:node": "cross-env NODE_OPTIONS='--import=tsx' webpack --config webpack.node.config.ts", "build": "npm run clean && npm run build:node && npm run build:types && npm run build:browser", "dev": "cross-env NODE_OPTIONS='--import=tsx' webpack serve --config webpack.dev.config.ts", - "lint:eslint": "npx eslint -c eslint.config.mjs", - "lint": "npx tsc --noEmit && prettier . --check --experimental-cli", - "lint:fix": "npx prettier . --write --experimental-cli && npm run lint:eslint --fix", + "lint:eslint": "eslint -c eslint.config.mjs", + "lint": "tsc --noEmit && prettier . --check --experimental-cli", + "lint:fix": "prettier . --write --experimental-cli && npm run lint:eslint --fix", "prepublishOnly": "npm run build", "test": "mocha spec-electron-setup/scripts/mocha-cli.ts" }, diff --git a/spec-electron-setup/scripts/mocha-cli.ts b/spec-electron-setup/scripts/mocha-cli.ts index 9170e25..9c4d20c 100644 --- a/spec-electron-setup/scripts/mocha-cli.ts +++ b/spec-electron-setup/scripts/mocha-cli.ts @@ -16,7 +16,7 @@ describe('Electron Spec Runner', function () { it('should complete Electron tests successfully', (done) => { const runnerPath = path.resolve(__dirname, './spec-runner.ts'); - const child = spawn('npx', ['tsx', `"${runnerPath}"`], { stdio: 'inherit', shell: true }); + const child = spawn('yarn', ['tsx', `"${runnerPath}"`], { stdio: 'inherit', shell: true }); child.on('close', (code) => { expect(code).to.equal(0, 'Electron exited with non-zero status'); From 1215b0ccd009c95d85f32f0f2c35b00deec2761f Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 30 Mar 2026 22:49:41 -0700 Subject: [PATCH 2/4] test: use npx --no instead of yarn for tsx spawn CI uses npm and installs different electron versions per matrix entry, which modifies package.json and leaves yarn.lock stale. yarn tsx then fails its workspace consistency check. npx --no achieves the same thing (no registry fallback, tsx is a devDep) without yarn's lockfile check. --- spec-electron-setup/scripts/mocha-cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec-electron-setup/scripts/mocha-cli.ts b/spec-electron-setup/scripts/mocha-cli.ts index 9c4d20c..bd2a11f 100644 --- a/spec-electron-setup/scripts/mocha-cli.ts +++ b/spec-electron-setup/scripts/mocha-cli.ts @@ -16,7 +16,7 @@ describe('Electron Spec Runner', function () { it('should complete Electron tests successfully', (done) => { const runnerPath = path.resolve(__dirname, './spec-runner.ts'); - const child = spawn('yarn', ['tsx', `"${runnerPath}"`], { stdio: 'inherit', shell: true }); + const child = spawn('npx', ['--no', 'tsx', `"${runnerPath}"`], { stdio: 'inherit', shell: true }); child.on('close', (code) => { expect(code).to.equal(0, 'Electron exited with non-zero status'); From 5c75aa2b411f4989290f5259d0a85e6b1d65092b Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 30 Mar 2026 22:51:24 -0700 Subject: [PATCH 3/4] ci: use --no-save for matrix electron install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit npm install defaults to --save, which rewrites package.json with the matrix electron version. That leaves yarn.lock stale, and yarn 4 checks lockfile consistency on every invocation — including yarn tsx in the spec runner. --no-save installs to node_modules without touching package.json. Reverts the previous npx --no workaround. --- .github/workflows/test.yml | 2 +- spec-electron-setup/scripts/mocha-cli.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 488a77d..42d6a7f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,7 +54,7 @@ jobs: - name: Install dependencies run: yarn install --immutable - name: Install Electron - run: npm install "electron@${{ matrix.electron-version }}" + run: npm install --no-save "electron@${{ matrix.electron-version }}" - name: Lint run: npm run lint - name: Build diff --git a/spec-electron-setup/scripts/mocha-cli.ts b/spec-electron-setup/scripts/mocha-cli.ts index bd2a11f..9c4d20c 100644 --- a/spec-electron-setup/scripts/mocha-cli.ts +++ b/spec-electron-setup/scripts/mocha-cli.ts @@ -16,7 +16,7 @@ describe('Electron Spec Runner', function () { it('should complete Electron tests successfully', (done) => { const runnerPath = path.resolve(__dirname, './spec-runner.ts'); - const child = spawn('npx', ['--no', 'tsx', `"${runnerPath}"`], { stdio: 'inherit', shell: true }); + const child = spawn('yarn', ['tsx', `"${runnerPath}"`], { stdio: 'inherit', shell: true }); child.on('close', (code) => { expect(code).to.equal(0, 'Electron exited with non-zero status'); From ce51a8db4f627a2de64036b3e9e50c4a30bdcde9 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 30 Mar 2026 22:53:38 -0700 Subject: [PATCH 4/4] ci: pin matrix electron versions via npm: aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the CI-time npm install electron@X with lockfile-pinned aliases (electron36 through electron40 as npm:electron@^XX). The spec runner selects which one to use via ELECTRON_PKG env var, defaulting to the base electron devDep for local runs. This reverts the --no-save workaround from the previous commit — the real fix is not fetching electron from the registry at CI time at all. Each alias has a dependenciesMeta.built: true entry so the postinstall binary download runs despite enableScripts: false. The npmPreapprovedPackages entry for 'electron' already covers the aliases (yarn checks the resolved name, not the alias). Also switches setup-node cache from 'npm' to 'yarn'. --- .github/workflows/test.yml | 6 +- package.json | 20 +++++ spec-electron-setup/scripts/spec-runner.ts | 5 +- yarn.lock | 96 ++++++++++++++++++++++ 4 files changed, 122 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 42d6a7f..ac491ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -50,14 +50,14 @@ jobs: uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: node-version: "${{ matrix.node-version }}" - cache: 'npm' + cache: 'yarn' - name: Install dependencies run: yarn install --immutable - - name: Install Electron - run: npm install --no-save "electron@${{ matrix.electron-version }}" - name: Lint run: npm run lint - name: Build run: npm run build - name: Test run: npm run test + env: + ELECTRON_PKG: electron${{ matrix.electron-version }} diff --git a/package.json b/package.json index 16c1f7a..82b4ac2 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,11 @@ "cross-env": "^7.0.3", "css-loader": "^7.1.2", "electron": "^36.5.0", + "electron36": "npm:electron@^36", + "electron37": "npm:electron@^37", + "electron38": "npm:electron@^38", + "electron39": "npm:electron@^39", + "electron40": "npm:electron@^40", "eslint": "^9.28.0", "eslint-plugin-chai-friendly": "^1.1.0", "eslint-plugin-react": "^7.37.5", @@ -116,6 +121,21 @@ "dependenciesMeta": { "electron": { "built": true + }, + "electron36": { + "built": true + }, + "electron37": { + "built": true + }, + "electron38": { + "built": true + }, + "electron39": { + "built": true + }, + "electron40": { + "built": true } } } diff --git a/spec-electron-setup/scripts/spec-runner.ts b/spec-electron-setup/scripts/spec-runner.ts index c155ae5..4a888c1 100644 --- a/spec-electron-setup/scripts/spec-runner.ts +++ b/spec-electron-setup/scripts/spec-runner.ts @@ -1,13 +1,14 @@ import { spawnSync } from 'node:child_process'; import path from 'node:path'; -import electronPath from 'electron'; +// eslint-disable-next-line @typescript-eslint/no-require-imports +const electronPath: string = require(process.env.ELECTRON_PKG || 'electron'); import 'colors'; async function main(): Promise { const runnerArgs = ['spec-electron-setup/electron/main.js']; const cwd = path.resolve(__dirname, '..', '..'); - const { status, signal } = spawnSync(electronPath as unknown as string, runnerArgs, { + const { status, signal } = spawnSync(electronPath, runnerArgs, { cwd, stdio: 'inherit', }); diff --git a/yarn.lock b/yarn.lock index 7479c87..a5b4796 100644 --- a/yarn.lock +++ b/yarn.lock @@ -628,6 +628,11 @@ __metadata: css-loader: "npm:^7.1.2" denque: "npm:^2.1.0" electron: "npm:^36.5.0" + electron36: "npm:electron@^36" + electron37: "npm:electron@^37" + electron38: "npm:electron@^38" + electron39: "npm:electron@^39" + electron40: "npm:electron@^40" eslint: "npm:^9.28.0" eslint-plugin-chai-friendly: "npm:^1.1.0" eslint-plugin-react: "npm:^7.37.5" @@ -657,6 +662,16 @@ __metadata: dependenciesMeta: electron: built: true + electron36: + built: true + electron37: + built: true + electron38: + built: true + electron39: + built: true + electron40: + built: true languageName: unknown linkType: soft @@ -1560,6 +1575,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^24.9.0": + version: 24.12.0 + resolution: "@types/node@npm:24.12.0" + dependencies: + undici-types: "npm:~7.16.0" + checksum: 10c0/8b31c0af5b5474f13048a4e77c57f22cd4f8fe6e58c4b6fde9456b0c13f46a5bfaf5744ff88fd089581de9f0d6e99c584e022681de7acb26a58d258c654c4843 + languageName: node + linkType: hard + "@types/node@npm:~22.10.7": version: 22.10.10 resolution: "@types/node@npm:22.10.10" @@ -3480,6 +3504,71 @@ __metadata: languageName: node linkType: hard +"electron36@npm:electron@^36": + version: 36.9.5 + resolution: "electron@npm:36.9.5" + dependencies: + "@electron/get": "npm:^2.0.0" + "@types/node": "npm:^22.7.7" + extract-zip: "npm:^2.0.1" + bin: + electron: cli.js + checksum: 10c0/85f7239e6912dba8dcab133b51c12e730e3da083877226d8f783d938779023f76b6a1012e8587a21944cd84491b69b376c3ab9d334ee81e4b7e87301ccfa0c44 + languageName: node + linkType: hard + +"electron37@npm:electron@^37": + version: 37.10.3 + resolution: "electron@npm:37.10.3" + dependencies: + "@electron/get": "npm:^2.0.0" + "@types/node": "npm:^22.7.7" + extract-zip: "npm:^2.0.1" + bin: + electron: cli.js + checksum: 10c0/a09c10d76be021a94f6c8b251ef990553fe530a6a1271c22026f06a502e977fac116a88b78e73abf50177386a76d69b1c9a52f62d6de60006cc50ed4cb969f0f + languageName: node + linkType: hard + +"electron38@npm:electron@^38": + version: 38.8.6 + resolution: "electron@npm:38.8.6" + dependencies: + "@electron/get": "npm:^2.0.0" + "@types/node": "npm:^22.7.7" + extract-zip: "npm:^2.0.1" + bin: + electron: cli.js + checksum: 10c0/4e3c02a01b99a77d715a28ec1b1053382860c3100a735adae5784387e38f7cb800313aeb2c9d292297f37237b57b8660bafcf913360a6b68865a45642a495264 + languageName: node + linkType: hard + +"electron39@npm:electron@^39": + version: 39.8.5 + resolution: "electron@npm:39.8.5" + dependencies: + "@electron/get": "npm:^2.0.0" + "@types/node": "npm:^22.7.7" + extract-zip: "npm:^2.0.1" + bin: + electron: cli.js + checksum: 10c0/21448e3d69a5e96912ce84533d39e7258be17879502cfed30bcdd6581b61516a1d1f3b492aad20344367967229bce27018625047f7ee6801257df93bf6b96d97 + languageName: node + linkType: hard + +"electron40@npm:electron@^40": + version: 40.8.5 + resolution: "electron@npm:40.8.5" + dependencies: + "@electron/get": "npm:^2.0.0" + "@types/node": "npm:^24.9.0" + extract-zip: "npm:^2.0.1" + bin: + electron: cli.js + checksum: 10c0/3874115299b101bada7f243afd1e0479c88a11fa534171a3d60d7933f4f0c382ef8e58aeaf91c963a2bb4d087ef3cd68065796b611a1dbaeb4b1205e680a23bd + languageName: node + linkType: hard + "electron@npm:^36.5.0": version: 36.9.4 resolution: "electron@npm:36.9.4" @@ -8729,6 +8818,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~7.16.0": + version: 7.16.0 + resolution: "undici-types@npm:7.16.0" + checksum: 10c0/3033e2f2b5c9f1504bdc5934646cb54e37ecaca0f9249c983f7b1fc2e87c6d18399ebb05dc7fd5419e02b2e915f734d872a65da2e3eeed1813951c427d33cc9a + languageName: node + linkType: hard + "unique-filename@npm:^4.0.0": version: 4.0.0 resolution: "unique-filename@npm:4.0.0"