diff options
author | Kristóf Marussy <kristof@marussy.com> | 2021-12-30 21:47:46 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2021-12-30 21:47:46 +0100 |
commit | 1383dde6aa0d25b5fa23d7a7b64ba7de21ec5b99 (patch) | |
tree | 94739ff48121a1d69358acf5f2c60124d1b1cdec /packages | |
parent | build: Only use vite typings in renderer (diff) | |
download | sophie-1383dde6aa0d25b5fa23d7a7b64ba7de21ec5b99.tar.gz sophie-1383dde6aa0d25b5fa23d7a7b64ba7de21ec5b99.tar.zst sophie-1383dde6aa0d25b5fa23d7a7b64ba7de21ec5b99.zip |
build: Fully switch over to ESM
Now we can run with ESM at build and test time and transpile into
commonjs for electron. This greatly simplifies testing, since we treat
everything as ESM during build with esbuild anyways. Now the test
environment and the build scripts match the apparent (but not the actual
for the main, preload, and inject modules) runtime environment.
Caveats:
- We may use top-level async expressions in tests and script, but not in
code that gets transpiled into commonjs or scripts that get imported
by vite. The limitation w.r.t. commonjs seems fundamental.
- Jest only experimentally supports ESM and there are some limitations
with mocking. Most limitations (except the lack of automatic mocks)
can be worked around by async importing code that uses mocks.
- There are packages marked as modules (so that node reads any scripts
in them as ESM) that nevertheless get transpiled into commonjs
modules. However, these should be clearly marked by using a .cjs
extension as their bundle. The worst offender is the root package,
which has a .cjs as its main entry point that gets read by electron,
but is in fact marked as a module. This doesn't seem to bother electron
at all. The service-inject package is an IIFE with a .js extension,
but it outputs a fully self-contained bundle, so the choice of module
format should be irrelevant.
Diffstat (limited to 'packages')
-rw-r--r-- | packages/main/esbuild.config.js | 10 | ||||
-rw-r--r-- | packages/main/package.json | 2 | ||||
-rw-r--r-- | packages/main/src/devTools.ts | 6 | ||||
-rw-r--r-- | packages/preload/esbuild.config.js | 10 | ||||
-rw-r--r-- | packages/preload/jest.config.js | 6 | ||||
-rw-r--r-- | packages/preload/package.json | 4 | ||||
-rw-r--r-- | packages/preload/src/__mocks__/electron.ts | 25 | ||||
-rw-r--r-- | packages/preload/src/contextBridge/__tests__/SophieRendererImpl.spec.ts | 14 | ||||
-rw-r--r-- | packages/preload/tsconfig.json | 3 | ||||
-rw-r--r-- | packages/renderer/package.json | 2 | ||||
-rw-r--r-- | packages/renderer/vite.config.js | 10 | ||||
-rw-r--r-- | packages/service-inject/esbuild.config.js | 10 | ||||
-rw-r--r-- | packages/service-inject/package.json | 2 | ||||
-rw-r--r-- | packages/service-preload/esbuild.config.js | 10 | ||||
-rw-r--r-- | packages/service-preload/package.json | 2 | ||||
-rw-r--r-- | packages/service-shared/esbuild.config.js | 10 | ||||
-rw-r--r-- | packages/service-shared/package.json | 3 | ||||
-rw-r--r-- | packages/shared/esbuild.config.js | 10 | ||||
-rw-r--r-- | packages/shared/package.json | 3 |
19 files changed, 54 insertions, 88 deletions
diff --git a/packages/main/esbuild.config.js b/packages/main/esbuild.config.js index 7653078..a39534d 100644 --- a/packages/main/esbuild.config.js +++ b/packages/main/esbuild.config.js | |||
@@ -1,7 +1,5 @@ | |||
1 | // @ts-check | 1 | import { node, fileURLToDirname } from '../../config/build-common.js'; |
2 | 2 | import { getConfig } from '../../config/esbuild-config.js'; | |
3 | const { node } = require('../../config/build-common'); | ||
4 | const { getConfig } = require('../../config/esbuild-config'); | ||
5 | 3 | ||
6 | const externalPackages = ['electron']; | 4 | const externalPackages = ['electron']; |
7 | 5 | ||
@@ -9,8 +7,8 @@ if (process.env.MODE !== 'development') { | |||
9 | externalPackages.push('electron-devtools-installer'); | 7 | externalPackages.push('electron-devtools-installer'); |
10 | } | 8 | } |
11 | 9 | ||
12 | module.exports = getConfig({ | 10 | export default getConfig({ |
13 | absWorkingDir: __dirname, | 11 | absWorkingDir: fileURLToDirname(import.meta.url), |
14 | entryPoints: [ | 12 | entryPoints: [ |
15 | 'src/index.ts', | 13 | 'src/index.ts', |
16 | ], | 14 | ], |
diff --git a/packages/main/package.json b/packages/main/package.json index c118d2b..99451bd 100644 --- a/packages/main/package.json +++ b/packages/main/package.json | |||
@@ -2,7 +2,7 @@ | |||
2 | "name": "@sophie/main", | 2 | "name": "@sophie/main", |
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "main": "dist/index.cjs", | 5 | "type": "module", |
6 | "types": "dist-types/index.d.ts", | 6 | "types": "dist-types/index.d.ts", |
7 | "scripts": { | 7 | "scripts": { |
8 | "typecheck": "tsc" | 8 | "typecheck": "tsc" |
diff --git a/packages/main/src/devTools.ts b/packages/main/src/devTools.ts index 6c25b3e..7c7c86a 100644 --- a/packages/main/src/devTools.ts +++ b/packages/main/src/devTools.ts | |||
@@ -27,14 +27,12 @@ import type { BrowserWindow } from 'electron'; | |||
27 | * because the mobx-state-tree devtools are currently unmaintained. | 27 | * because the mobx-state-tree devtools are currently unmaintained. |
28 | */ | 28 | */ |
29 | export async function installDevToolsExtensions(): Promise<void> { | 29 | export async function installDevToolsExtensions(): Promise<void> { |
30 | const installerPackage = await import('electron-devtools-installer'); | 30 | // Hack to lazily require a CJS module from an ES module transpiled into a CJS module. |
31 | const { | 31 | const { |
32 | default: installExtension, | 32 | default: installExtension, |
33 | REACT_DEVELOPER_TOOLS, | 33 | REACT_DEVELOPER_TOOLS, |
34 | REDUX_DEVTOOLS, | 34 | REDUX_DEVTOOLS, |
35 | } = installerPackage.default instanceof Function | 35 | } = require('electron-devtools-installer'); |
36 | ? installerPackage | ||
37 | : installerPackage.default as unknown as typeof import('electron-devtools-installer'); | ||
38 | await installExtension( | 36 | await installExtension( |
39 | [ | 37 | [ |
40 | REACT_DEVELOPER_TOOLS, | 38 | REACT_DEVELOPER_TOOLS, |
diff --git a/packages/preload/esbuild.config.js b/packages/preload/esbuild.config.js index 76ac33f..de51fc5 100644 --- a/packages/preload/esbuild.config.js +++ b/packages/preload/esbuild.config.js | |||
@@ -1,10 +1,8 @@ | |||
1 | // @ts-check | 1 | import { chrome, fileURLToDirname } from '../../config/build-common.js'; |
2 | import { getConfig } from '../../config/esbuild-config.js'; | ||
2 | 3 | ||
3 | const { chrome } = require('../../config/build-common'); | 4 | export default getConfig({ |
4 | const { getConfig } = require('../../config/esbuild-config'); | 5 | absWorkingDir: fileURLToDirname(import.meta.url), |
5 | |||
6 | module.exports = getConfig({ | ||
7 | absWorkingDir: __dirname, | ||
8 | entryPoints: [ | 6 | entryPoints: [ |
9 | 'src/index.ts', | 7 | 'src/index.ts', |
10 | ], | 8 | ], |
diff --git a/packages/preload/jest.config.js b/packages/preload/jest.config.js index 5334b14..faecf9a 100644 --- a/packages/preload/jest.config.js +++ b/packages/preload/jest.config.js | |||
@@ -1,9 +1,7 @@ | |||
1 | // @ts-check | 1 | import rootConfig from '../../jest.config.js'; |
2 | |||
3 | const rootConfig = require('../../jest.config.js'); | ||
4 | 2 | ||
5 | /** @type {import('ts-jest').InitialOptionsTsJest} */ | 3 | /** @type {import('ts-jest').InitialOptionsTsJest} */ |
6 | module.exports = { | 4 | export default { |
7 | ...rootConfig, | 5 | ...rootConfig, |
8 | testEnvironment: 'jsdom', | 6 | testEnvironment: 'jsdom', |
9 | }; | 7 | }; |
diff --git a/packages/preload/package.json b/packages/preload/package.json index ac21618..e6dd0ee 100644 --- a/packages/preload/package.json +++ b/packages/preload/package.json | |||
@@ -3,10 +3,10 @@ | |||
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "sideEffects": false, | 5 | "sideEffects": false, |
6 | "main": "dist/index.cjs", | 6 | "type": "module", |
7 | "types": "dist-types/index.d.ts", | 7 | "types": "dist-types/index.d.ts", |
8 | "scripts": { | 8 | "scripts": { |
9 | "test": "jest", | 9 | "test": "node --experimental-vm-modules ../../node_modules/jest/bin/jest.js", |
10 | "typecheck": "tsc" | 10 | "typecheck": "tsc" |
11 | }, | 11 | }, |
12 | "dependencies": { | 12 | "dependencies": { |
diff --git a/packages/preload/src/__mocks__/electron.ts b/packages/preload/src/__mocks__/electron.ts deleted file mode 100644 index 52cddf9..0000000 --- a/packages/preload/src/__mocks__/electron.ts +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2021-2022 Kristóf Marussy <kristof@marussy.com> | ||
3 | * | ||
4 | * This file is part of Sophie. | ||
5 | * | ||
6 | * Sophie is free software: you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU Affero General Public License as | ||
8 | * published by the Free Software Foundation, version 3. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Affero General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Affero General Public License | ||
16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * SPDX-License-Identifier: AGPL-3.0-only | ||
19 | */ | ||
20 | |||
21 | export const ipcRenderer = { | ||
22 | invoke: jest.fn(), | ||
23 | on: jest.fn(), | ||
24 | send: jest.fn(), | ||
25 | }; | ||
diff --git a/packages/preload/src/contextBridge/__tests__/SophieRendererImpl.spec.ts b/packages/preload/src/contextBridge/__tests__/SophieRendererImpl.spec.ts index 71ac2a1..e40dcf5 100644 --- a/packages/preload/src/contextBridge/__tests__/SophieRendererImpl.spec.ts +++ b/packages/preload/src/contextBridge/__tests__/SophieRendererImpl.spec.ts | |||
@@ -18,8 +18,8 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { describe, it, jest } from '@jest/globals'; | ||
21 | import { mocked } from 'jest-mock'; | 22 | import { mocked } from 'jest-mock'; |
22 | import { ipcRenderer } from 'electron'; | ||
23 | import type { IJsonPatch } from 'mobx-state-tree'; | 23 | import type { IJsonPatch } from 'mobx-state-tree'; |
24 | import { | 24 | import { |
25 | Action, | 25 | Action, |
@@ -29,9 +29,17 @@ import { | |||
29 | SophieRenderer, | 29 | SophieRenderer, |
30 | } from '@sophie/shared'; | 30 | } from '@sophie/shared'; |
31 | 31 | ||
32 | import { createSophieRenderer } from '../SophieRendererImpl'; | 32 | jest.unstable_mockModule('electron', () => ({ |
33 | ipcRenderer: { | ||
34 | invoke: jest.fn(), | ||
35 | on: jest.fn(), | ||
36 | send: jest.fn(), | ||
37 | }, | ||
38 | })); | ||
33 | 39 | ||
34 | jest.mock('electron'); | 40 | const { ipcRenderer } = await import('electron'); |
41 | |||
42 | const { createSophieRenderer } = await import('../SophieRendererImpl'); | ||
35 | 43 | ||
36 | const event: Electron.IpcRendererEvent = null as unknown as Electron.IpcRendererEvent; | 44 | const event: Electron.IpcRendererEvent = null as unknown as Electron.IpcRendererEvent; |
37 | 45 | ||
diff --git a/packages/preload/tsconfig.json b/packages/preload/tsconfig.json index 741d435..0f27305 100644 --- a/packages/preload/tsconfig.json +++ b/packages/preload/tsconfig.json | |||
@@ -6,9 +6,6 @@ | |||
6 | "dom", | 6 | "dom", |
7 | "dom.iterable", | 7 | "dom.iterable", |
8 | "esnext" | 8 | "esnext" |
9 | ], | ||
10 | "types": [ | ||
11 | "@types/jest" | ||
12 | ] | 9 | ] |
13 | }, | 10 | }, |
14 | "references": [ | 11 | "references": [ |
diff --git a/packages/renderer/package.json b/packages/renderer/package.json index fb13129..2a26b2b 100644 --- a/packages/renderer/package.json +++ b/packages/renderer/package.json | |||
@@ -2,7 +2,7 @@ | |||
2 | "name": "@sophie/renderer", | 2 | "name": "@sophie/renderer", |
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "main": "dist/index.html", | 5 | "type": "module", |
6 | "types": "dist-types/index.d.ts", | 6 | "types": "dist-types/index.d.ts", |
7 | "scripts": { | 7 | "scripts": { |
8 | "typecheck": "tsc" | 8 | "typecheck": "tsc" |
diff --git a/packages/renderer/vite.config.js b/packages/renderer/vite.config.js index 30729c0..6f3d351 100644 --- a/packages/renderer/vite.config.js +++ b/packages/renderer/vite.config.js | |||
@@ -1,12 +1,12 @@ | |||
1 | // @ts-check | ||
2 | |||
3 | /* eslint-env node */ | 1 | /* eslint-env node */ |
4 | 2 | ||
5 | import { builtinModules } from 'module'; | 3 | import { builtinModules } from 'module'; |
6 | import { join } from 'path'; | 4 | import { join } from 'path'; |
7 | import react from '@vitejs/plugin-react'; | 5 | import react from '@vitejs/plugin-react'; |
8 | 6 | ||
9 | import { banner, chrome } from '../../config/build-common'; | 7 | import { banner, chrome, fileURLToDirname } from '../../config/build-common.js'; |
8 | |||
9 | const thisDir = fileURLToDirname(import.meta.url); | ||
10 | 10 | ||
11 | const mode = process.env.MODE || 'development'; | 11 | const mode = process.env.MODE || 'development'; |
12 | 12 | ||
@@ -20,8 +20,8 @@ export default { | |||
20 | /** @type {import('vite').LogLevel} */ | 20 | /** @type {import('vite').LogLevel} */ |
21 | logLevel: 'info', | 21 | logLevel: 'info', |
22 | mode, | 22 | mode, |
23 | root: __dirname, | 23 | root: thisDir, |
24 | cacheDir: join(__dirname, '../../.vite'), | 24 | cacheDir: join(thisDir, '../../.vite'), |
25 | plugins: [ | 25 | plugins: [ |
26 | react({ | 26 | react({ |
27 | babel: { | 27 | babel: { |
diff --git a/packages/service-inject/esbuild.config.js b/packages/service-inject/esbuild.config.js index 38e5b7d..3f1d6d0 100644 --- a/packages/service-inject/esbuild.config.js +++ b/packages/service-inject/esbuild.config.js | |||
@@ -1,10 +1,8 @@ | |||
1 | // @ts-check | 1 | import { chrome, fileURLToDirname } from '../../config/build-common.js'; |
2 | import { getConfig } from '../../config/esbuild-config.js'; | ||
2 | 3 | ||
3 | const { chrome } = require('../../config/build-common'); | 4 | export default getConfig({ |
4 | const { getConfig } = require('../../config/esbuild-config'); | 5 | absWorkingDir: fileURLToDirname(import.meta.url), |
5 | |||
6 | module.exports = getConfig({ | ||
7 | absWorkingDir: __dirname, | ||
8 | entryPoints: [ | 6 | entryPoints: [ |
9 | 'src/index.ts', | 7 | 'src/index.ts', |
10 | ], | 8 | ], |
diff --git a/packages/service-inject/package.json b/packages/service-inject/package.json index 825de24..7c496fd 100644 --- a/packages/service-inject/package.json +++ b/packages/service-inject/package.json | |||
@@ -3,7 +3,7 @@ | |||
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "sideEffects": false, | 5 | "sideEffects": false, |
6 | "main": "dist/index.cjs", | 6 | "type": "module", |
7 | "types": "dist-types/index.d.ts", | 7 | "types": "dist-types/index.d.ts", |
8 | "scripts": { | 8 | "scripts": { |
9 | "typecheck": "tsc" | 9 | "typecheck": "tsc" |
diff --git a/packages/service-preload/esbuild.config.js b/packages/service-preload/esbuild.config.js index 76ac33f..3c67b31 100644 --- a/packages/service-preload/esbuild.config.js +++ b/packages/service-preload/esbuild.config.js | |||
@@ -1,10 +1,8 @@ | |||
1 | // @ts-check | 1 | import { chrome, fileURLToDirname } from "../../config/build-common.js"; |
2 | import { getConfig } from '../../config/esbuild-config.js'; | ||
2 | 3 | ||
3 | const { chrome } = require('../../config/build-common'); | 4 | export default getConfig({ |
4 | const { getConfig } = require('../../config/esbuild-config'); | 5 | absWorkingDir: fileURLToDirname(import.meta.url), |
5 | |||
6 | module.exports = getConfig({ | ||
7 | absWorkingDir: __dirname, | ||
8 | entryPoints: [ | 6 | entryPoints: [ |
9 | 'src/index.ts', | 7 | 'src/index.ts', |
10 | ], | 8 | ], |
diff --git a/packages/service-preload/package.json b/packages/service-preload/package.json index 7cbdfc8..8da5eb7 100644 --- a/packages/service-preload/package.json +++ b/packages/service-preload/package.json | |||
@@ -2,7 +2,7 @@ | |||
2 | "name": "@sophie/service-preload", | 2 | "name": "@sophie/service-preload", |
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "main": "dist/index.js", | 5 | "type": "module", |
6 | "types": "dist-types/index.d.ts", | 6 | "types": "dist-types/index.d.ts", |
7 | "scripts": { | 7 | "scripts": { |
8 | "typecheck": "tsc" | 8 | "typecheck": "tsc" |
diff --git a/packages/service-shared/esbuild.config.js b/packages/service-shared/esbuild.config.js index ce57cd7..8df2edf 100644 --- a/packages/service-shared/esbuild.config.js +++ b/packages/service-shared/esbuild.config.js | |||
@@ -1,10 +1,8 @@ | |||
1 | // @ts-check | 1 | import { chrome, fileURLToDirname } from '../../config/build-common.js'; |
2 | import { getConfig } from '../../config/esbuild-config.js'; | ||
2 | 3 | ||
3 | const { chrome } = require('../../config/build-common'); | 4 | export default getConfig({ |
4 | const { getConfig } = require('../../config/esbuild-config'); | 5 | absWorkingDir: fileURLToDirname(import.meta.url), |
5 | |||
6 | module.exports = getConfig({ | ||
7 | absWorkingDir: __dirname, | ||
8 | entryPoints: [ | 6 | entryPoints: [ |
9 | 'src/index.ts', | 7 | 'src/index.ts', |
10 | ], | 8 | ], |
diff --git a/packages/service-shared/package.json b/packages/service-shared/package.json index e812e4a..5c8ea79 100644 --- a/packages/service-shared/package.json +++ b/packages/service-shared/package.json | |||
@@ -3,7 +3,8 @@ | |||
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "sideEffects": false, | 5 | "sideEffects": false, |
6 | "module": "dist/index.mjs", | 6 | "type": "module", |
7 | "main": "dist/index.mjs", | ||
7 | "types": "dist/index.d.ts", | 8 | "types": "dist/index.d.ts", |
8 | "scripts": { | 9 | "scripts": { |
9 | "typecheck": "tsc" | 10 | "typecheck": "tsc" |
diff --git a/packages/shared/esbuild.config.js b/packages/shared/esbuild.config.js index f58d776..fbaa6f1 100644 --- a/packages/shared/esbuild.config.js +++ b/packages/shared/esbuild.config.js | |||
@@ -1,10 +1,8 @@ | |||
1 | // @ts-check | 1 | import { chrome, fileURLToDirname } from '../../config/build-common.js'; |
2 | import { getConfig } from '../../config/esbuild-config.js'; | ||
2 | 3 | ||
3 | const { chrome } = require('../../config/build-common'); | 4 | export default getConfig({ |
4 | const { getConfig } = require('../../config/esbuild-config'); | 5 | absWorkingDir: fileURLToDirname(import.meta.url), |
5 | |||
6 | module.exports = getConfig({ | ||
7 | absWorkingDir: __dirname, | ||
8 | entryPoints: [ | 6 | entryPoints: [ |
9 | 'src/index.ts', | 7 | 'src/index.ts', |
10 | ], | 8 | ], |
diff --git a/packages/shared/package.json b/packages/shared/package.json index e4b57b0..428bff3 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json | |||
@@ -3,7 +3,8 @@ | |||
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | "sideEffects": false, | 5 | "sideEffects": false, |
6 | "module": "dist/index.mjs", | 6 | "type": "module", |
7 | "main": "dist/index.mjs", | ||
7 | "types": "dist/index.d.ts", | 8 | "types": "dist/index.d.ts", |
8 | "scripts": { | 9 | "scripts": { |
9 | "typecheck": "tsc" | 10 | "typecheck": "tsc" |