aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-12-30 21:47:46 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2021-12-30 21:47:46 +0100
commit1383dde6aa0d25b5fa23d7a7b64ba7de21ec5b99 (patch)
tree94739ff48121a1d69358acf5f2c60124d1b1cdec
parentbuild: Only use vite typings in renderer (diff)
downloadsophie-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.
-rw-r--r--.electron-builder.config.cjs (renamed from .electron-builder.config.js)0
-rw-r--r--config/build-common.js28
-rw-r--r--config/esbuild-config.js17
-rw-r--r--jest.config.js14
-rw-r--r--package.json3
-rw-r--r--packages/main/esbuild.config.js10
-rw-r--r--packages/main/package.json2
-rw-r--r--packages/main/src/devTools.ts6
-rw-r--r--packages/preload/esbuild.config.js10
-rw-r--r--packages/preload/jest.config.js6
-rw-r--r--packages/preload/package.json4
-rw-r--r--packages/preload/src/__mocks__/electron.ts25
-rw-r--r--packages/preload/src/contextBridge/__tests__/SophieRendererImpl.spec.ts14
-rw-r--r--packages/preload/tsconfig.json3
-rw-r--r--packages/renderer/package.json2
-rw-r--r--packages/renderer/vite.config.js10
-rw-r--r--packages/service-inject/esbuild.config.js10
-rw-r--r--packages/service-inject/package.json2
-rw-r--r--packages/service-preload/esbuild.config.js10
-rw-r--r--packages/service-preload/package.json2
-rw-r--r--packages/service-shared/esbuild.config.js10
-rw-r--r--packages/service-shared/package.json3
-rw-r--r--packages/shared/esbuild.config.js10
-rw-r--r--packages/shared/package.json3
-rw-r--r--scripts/build.js25
-rw-r--r--scripts/update-electron-vendors.js16
-rw-r--r--scripts/watch.js44
-rw-r--r--tsconfig.json5
28 files changed, 150 insertions, 144 deletions
diff --git a/.electron-builder.config.js b/.electron-builder.config.cjs
index 5238c69..5238c69 100644
--- a/.electron-builder.config.js
+++ b/.electron-builder.config.cjs
diff --git a/config/build-common.js b/config/build-common.js
index aea2335..ff5a218 100644
--- a/config/build-common.js
+++ b/config/build-common.js
@@ -1,11 +1,17 @@
1// @ts-check 1import { readFileSync } from 'fs';
2import { dirname, join } from 'path';
3import { fileURLToPath } from 'url';
2 4
3// `resolveJsonModule` is disabled for this package, but vite will load the json nevertheless. 5const thisDir = fileURLToDirname(import.meta.url);
4// @ts-ignore 6
5const { chrome: chromeVersion, node: nodeVersion } = require('../.electron-vendors.cache.json'); 7// We import this from a vite config, where top-level await is not available (es2021),
8// so we have to use the synchronous filesystem API.
9const electronVendorsJson = readFileSync(join(thisDir, '../.electron-vendors.cache.json'), 'utf8');
10
11const { chrome: chromeVersion, node: nodeVersion } = JSON.parse(electronVendorsJson);
6 12
7/** @type {string} */ 13/** @type {string} */
8module.exports.banner = `/*! 14export const banner = `/*!
9 * Copyright (C) 2021-2022 Sophie contributors 15 * Copyright (C) 2021-2022 Sophie contributors
10 * 16 *
11 * This file is part of Sophie. 17 * This file is part of Sophie.
@@ -27,7 +33,15 @@ module.exports.banner = `/*!
27`; 33`;
28 34
29/** @type {string} */ 35/** @type {string} */
30module.exports.chrome = `chrome${chromeVersion}`; 36export const chrome = `chrome${chromeVersion}`;
31 37
32/** @type {string} */ 38/** @type {string} */
33module.exports.node = `node${nodeVersion}`; 39export const node = `node${nodeVersion}`;
40
41/**
42 * @param {string} url
43 * @returns {string}
44 */
45export function fileURLToDirname(url) {
46 return dirname(fileURLToPath(url));
47}
diff --git a/config/esbuild-config.js b/config/esbuild-config.js
index 9140b89..52d1a59 100644
--- a/config/esbuild-config.js
+++ b/config/esbuild-config.js
@@ -1,6 +1,4 @@
1// @ts-check 1import { banner } from './build-common.js';
2
3const { banner } = require('./build-common');
4 2
5/** @type {string} */ 3/** @type {string} */
6const mode = process.env.MODE || 'development'; 4const mode = process.env.MODE || 'development';
@@ -8,8 +6,10 @@ const mode = process.env.MODE || 'development';
8/** @type {boolean} */ 6/** @type {boolean} */
9const isDevelopment = mode === 'development'; 7const isDevelopment = mode === 'development';
10 8
9/** @type {string} */
11const modeString = JSON.stringify(mode); 10const modeString = JSON.stringify(mode);
12 11
12/** @type {Record<string, string>} */
13const defineEnv = { 13const defineEnv = {
14 'import.meta.env.DEV': JSON.stringify(isDevelopment), 14 'import.meta.env.DEV': JSON.stringify(isDevelopment),
15 'import.meta.env.MODE': modeString, 15 'import.meta.env.MODE': modeString,
@@ -20,13 +20,16 @@ const defineEnv = {
20 20
21/** 21/**
22 * @param {import('esbuild').BuildOptions} config 22 * @param {import('esbuild').BuildOptions} config
23 * @param {object | unknown} metaEnvVars 23 * @param {Record<string, string>} [metaEnvVars]
24 * @returns {import('esbuild').BuildOptions} 24 * @returns {import('esbuild').BuildOptions}
25 */ 25 */
26module.exports.getConfig = function(config, metaEnvVars) { 26export function getConfig(config, metaEnvVars) {
27 /** @type {Record<string, string>} */
27 const defineMeta = {}; 28 const defineMeta = {};
28 for (const varName in metaEnvVars) { 29 if (metaEnvVars) {
29 defineMeta[`import.meta.env.${varName}`] = JSON.stringify(metaEnvVars[varName]); 30 for (const varName in metaEnvVars) {
31 defineMeta[`import.meta.env.${varName}`] = JSON.stringify(metaEnvVars[varName]);
32 }
30 } 33 }
31 return { 34 return {
32 logLevel: 'info', 35 logLevel: 'info',
diff --git a/jest.config.js b/jest.config.js
index eda029a..1aa0cbb 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,17 +1,21 @@
1// @ts-check 1import { join } from 'path';
2 2
3const { join } = require('path'); 3import { fileURLToDirname } from './config/build-common.js';
4
5const dirname = fileURLToDirname(import.meta.url);
4 6
5/** @type {import('ts-jest').InitialOptionsTsJest} */ 7/** @type {import('ts-jest').InitialOptionsTsJest} */
6module.exports = { 8export default {
7 preset: 'ts-jest', 9 preset: 'ts-jest/presets/default-esm',
8 globals: { 10 globals: {
9 'ts-jest': { 11 'ts-jest': {
10 isolatedModules: true, 12 isolatedModules: true,
13 useESM: true,
11 }, 14 },
12 }, 15 },
13 moduleNameMapper: { 16 moduleNameMapper: {
14 '@sophie/(.+)': join(__dirname, 'packages/$1/src/index.ts'), 17 '@sophie/(.+)': join(dirname, 'packages/$1/src/index.ts'),
18 '^(\\.{1,2}/.*)\\.js$': '$1',
15 }, 19 },
16 resetMocks: true, 20 resetMocks: true,
17 restoreMocks: true, 21 restoreMocks: true,
diff --git a/package.json b/package.json
index e30d6fd..620c9cc 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
13 "engines": { 13 "engines": {
14 "node": ">=v16.13" 14 "node": ">=v16.13"
15 }, 15 },
16 "type": "module",
16 "main": "packages/main/dist/index.cjs", 17 "main": "packages/main/dist/index.cjs",
17 "scripts": { 18 "scripts": {
18 "clean": "rimraf dist packages/*/dist packages/*/tsconfig.tsbuildinfo .vite", 19 "clean": "rimraf dist packages/*/dist packages/*/tsconfig.tsbuildinfo .vite",
@@ -20,7 +21,7 @@
20 "build": "node scripts/build.js", 21 "build": "node scripts/build.js",
21 "precompile": "cross-env MODE=production yarn run build", 22 "precompile": "cross-env MODE=production yarn run build",
22 "compile": "yarn precompile && yarn compile:electron-builder", 23 "compile": "yarn precompile && yarn compile:electron-builder",
23 "compile:electron-builder": "electron-builder build --config .electron-builder.config.js --dir", 24 "compile:electron-builder": "electron-builder build --config .electron-builder.config.cjs --dir",
24 "watch": "node scripts/watch.js", 25 "watch": "node scripts/watch.js",
25 "typecheck": "yarn workspaces foreach -vpt run typecheck", 26 "typecheck": "yarn workspaces foreach -vpt run typecheck",
26 "update-electron-vendors": "node scripts/update-electron-vendors.js", 27 "update-electron-vendors": "node scripts/update-electron-vendors.js",
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 1import { node, fileURLToDirname } from '../../config/build-common.js';
2 2import { getConfig } from '../../config/esbuild-config.js';
3const { node } = require('../../config/build-common');
4const { getConfig } = require('../../config/esbuild-config');
5 3
6const externalPackages = ['electron']; 4const 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
12module.exports = getConfig({ 10export 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 */
29export async function installDevToolsExtensions(): Promise<void> { 29export 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 1import { chrome, fileURLToDirname } from '../../config/build-common.js';
2import { getConfig } from '../../config/esbuild-config.js';
2 3
3const { chrome } = require('../../config/build-common'); 4export default getConfig({
4const { getConfig } = require('../../config/esbuild-config'); 5 absWorkingDir: fileURLToDirname(import.meta.url),
5
6module.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 1import rootConfig from '../../jest.config.js';
2
3const rootConfig = require('../../jest.config.js');
4 2
5/** @type {import('ts-jest').InitialOptionsTsJest} */ 3/** @type {import('ts-jest').InitialOptionsTsJest} */
6module.exports = { 4export 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
21export 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
21import { describe, it, jest } from '@jest/globals';
21import { mocked } from 'jest-mock'; 22import { mocked } from 'jest-mock';
22import { ipcRenderer } from 'electron';
23import type { IJsonPatch } from 'mobx-state-tree'; 23import type { IJsonPatch } from 'mobx-state-tree';
24import { 24import {
25 Action, 25 Action,
@@ -29,9 +29,17 @@ import {
29 SophieRenderer, 29 SophieRenderer,
30} from '@sophie/shared'; 30} from '@sophie/shared';
31 31
32import { createSophieRenderer } from '../SophieRendererImpl'; 32jest.unstable_mockModule('electron', () => ({
33 ipcRenderer: {
34 invoke: jest.fn(),
35 on: jest.fn(),
36 send: jest.fn(),
37 },
38}));
33 39
34jest.mock('electron'); 40const { ipcRenderer } = await import('electron');
41
42const { createSophieRenderer } = await import('../SophieRendererImpl');
35 43
36const event: Electron.IpcRendererEvent = null as unknown as Electron.IpcRendererEvent; 44const 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
5import { builtinModules } from 'module'; 3import { builtinModules } from 'module';
6import { join } from 'path'; 4import { join } from 'path';
7import react from '@vitejs/plugin-react'; 5import react from '@vitejs/plugin-react';
8 6
9import { banner, chrome } from '../../config/build-common'; 7import { banner, chrome, fileURLToDirname } from '../../config/build-common.js';
8
9const thisDir = fileURLToDirname(import.meta.url);
10 10
11const mode = process.env.MODE || 'development'; 11const 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 1import { chrome, fileURLToDirname } from '../../config/build-common.js';
2import { getConfig } from '../../config/esbuild-config.js';
2 3
3const { chrome } = require('../../config/build-common'); 4export default getConfig({
4const { getConfig } = require('../../config/esbuild-config'); 5 absWorkingDir: fileURLToDirname(import.meta.url),
5
6module.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 1import { chrome, fileURLToDirname } from "../../config/build-common.js";
2import { getConfig } from '../../config/esbuild-config.js';
2 3
3const { chrome } = require('../../config/build-common'); 4export default getConfig({
4const { getConfig } = require('../../config/esbuild-config'); 5 absWorkingDir: fileURLToDirname(import.meta.url),
5
6module.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 1import { chrome, fileURLToDirname } from '../../config/build-common.js';
2import { getConfig } from '../../config/esbuild-config.js';
2 3
3const { chrome } = require('../../config/build-common'); 4export default getConfig({
4const { getConfig } = require('../../config/esbuild-config'); 5 absWorkingDir: fileURLToDirname(import.meta.url),
5
6module.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 1import { chrome, fileURLToDirname } from '../../config/build-common.js';
2import { getConfig } from '../../config/esbuild-config.js';
2 3
3const { chrome } = require('../../config/build-common'); 4export default getConfig({
4const { getConfig } = require('../../config/esbuild-config'); 5 absWorkingDir: fileURLToDirname(import.meta.url),
5
6module.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"
diff --git a/scripts/build.js b/scripts/build.js
index 5abcdab..9b9b26e 100644
--- a/scripts/build.js
+++ b/scripts/build.js
@@ -1,19 +1,28 @@
1const esbuild = require('esbuild'); 1import { build as esbuildBuild } from 'esbuild';
2const { join } = require('path'); 2import { join } from 'path';
3const vite = require('vite'); 3import { build as viteBuild } from 'vite';
4
5import { fileURLToDirname } from '../config/build-common.js';
6
7const thisDir = fileURLToDirname(import.meta.url);
4 8
5/** 9/**
6 * @param {string} packageName 10 * @param {string} packageName
7 * @returns {Promise<import('esbuild').BuildResult>} 11 * @returns {Promise<import('esbuild').BuildResult>}
8 */ 12 */
9function buildPackageEsbuild(packageName) { 13async function buildPackageEsbuild(packageName) {
10 const config = require(`../packages/${packageName}/esbuild.config.js`); 14 /** @type {{ default: import('esbuild').BuildOptions }} */
11 return esbuild.build(config); 15 const { default: config } = await import(`../packages/${packageName}/esbuild.config.js`);
16 return esbuildBuild(config);
12} 17}
13 18
19/**
20 * @param {string} packageName
21 * @returns {Promise<unknown>}
22 */
14function buildPackageVite(packageName) { 23function buildPackageVite(packageName) {
15 return vite.build({ 24 return viteBuild({
16 configFile: join(__dirname, `../packages/${packageName}/vite.config.js`), 25 configFile: join(thisDir, `../packages/${packageName}/vite.config.js`),
17 }); 26 });
18} 27}
19 28
diff --git a/scripts/update-electron-vendors.js b/scripts/update-electron-vendors.js
index 650d394..fea8b9d 100644
--- a/scripts/update-electron-vendors.js
+++ b/scripts/update-electron-vendors.js
@@ -1,11 +1,9 @@
1#!/usr/bin/env node 1import { execSync } from 'child_process';
2import electronPath from 'electron';
3import { writeFile } from 'fs/promises';
4import { join, resolve } from 'path';
2 5
3// @ts-check 6import { fileURLToDirname } from '../config/build-common.js';
4
5const { execSync } = require('child_process');
6const electronPath = require('electron');
7const { writeFile } = require('fs/promises');
8const path = require('path');
9 7
10/** 8/**
11 * Returns versions of electron vendors 9 * Returns versions of electron vendors
@@ -34,11 +32,11 @@ function updateVendors() {
34 const nodeMajorVersion = electronRelease.node.split('.')[0]; 32 const nodeMajorVersion = electronRelease.node.split('.')[0];
35 const chromeMajorVersion = electronRelease.v8.split('.')[0] + electronRelease.v8.split('.')[1]; 33 const chromeMajorVersion = electronRelease.v8.split('.')[0] + electronRelease.v8.split('.')[1];
36 34
37 const browserslistrcPath = path.resolve(process.cwd(), '.browserslistrc'); 35 const browserslistrcPath = resolve(process.cwd(), '.browserslistrc');
38 36
39 return Promise.all([ 37 return Promise.all([
40 writeFile( 38 writeFile(
41 './.electron-vendors.cache.json', 39 join(fileURLToDirname(import.meta.url), '../.electron-vendors.cache.json'),
42 JSON.stringify({ 40 JSON.stringify({
43 chrome: chromeMajorVersion, 41 chrome: chromeMajorVersion,
44 node: nodeMajorVersion, 42 node: nodeMajorVersion,
diff --git a/scripts/watch.js b/scripts/watch.js
index d4229e9..82a8feb 100644
--- a/scripts/watch.js
+++ b/scripts/watch.js
@@ -1,20 +1,20 @@
1// @ts-check 1import { build as esbuildBuild } from 'esbuild';
2import { spawn } from 'child_process';
3import { watch } from 'chokidar';
4import electronPath from 'electron';
5import { join } from 'path';
6import { createServer } from 'vite';
2 7
3const esbuild = require('esbuild'); 8import { fileURLToDirname } from '../config/build-common.js';
4const { spawn } = require('child_process');
5const chokidar = require('chokidar');
6const electronPath = require('electron');
7const { join } = require('path');
8const { createServer } = require('vite');
9 9
10process.env.MODE = 'development'; 10/** @type {string} */
11process.env.NODE_ENV = 'development'; 11const thisDir = fileURLToDirname(import.meta.url);
12 12
13/** @type {string} */ 13/** @type {string} */
14const sharedModule = join(__dirname, '../packages/shared/dist/index.mjs'); 14const sharedModule = join(thisDir, '../packages/shared/dist/index.mjs');
15 15
16/** @type {string} */ 16/** @type {string} */
17const serviceSharedModule = join(__dirname, '../packages/service-shared/dist/index.mjs'); 17const serviceSharedModule = join(thisDir, '../packages/service-shared/dist/index.mjs');
18 18
19/** @type {RegExp[]} */ 19/** @type {RegExp[]} */
20const stderrIgnorePatterns = [ 20const stderrIgnorePatterns = [
@@ -34,15 +34,17 @@ const stderrIgnorePatterns = [
34 * @return {Promise<void>} 34 * @return {Promise<void>}
35 */ 35 */
36async function setupEsbuildWatcher(packageName, extraPaths, callback) { 36async function setupEsbuildWatcher(packageName, extraPaths, callback) {
37 const config = require(`../packages/${packageName}/esbuild.config.js`); 37 /** @type {{ default: import('esbuild').BuildOptions }} */
38 const { default: config } = await import(`../packages/${packageName}/esbuild.config.js`);
38 config.logLevel = 'info'; 39 config.logLevel = 'info';
39 config.incremental = true; 40 config.incremental = true;
40 const incrementalBuild = await esbuild.build(config); 41
42 const incrementalBuild = await esbuildBuild(config);
41 const paths = [ 43 const paths = [
42 join(__dirname, `../packages/${packageName}/src`), 44 join(thisDir, `../packages/${packageName}/src`),
43 ...(extraPaths || []), 45 ...(extraPaths || []),
44 ]; 46 ];
45 const watcher = chokidar.watch(paths, { 47 const watcher = watch(paths, {
46 ignored: /(^|[\/\\])\.|__(tests|mocks)__|\.(spec|test)\.[jt]sx?$/, 48 ignored: /(^|[\/\\])\.|__(tests|mocks)__|\.(spec|test)\.[jt]sx?$/,
47 ignoreInitial: true, 49 ignoreInitial: true,
48 persistent: true, 50 persistent: true,
@@ -51,7 +53,7 @@ async function setupEsbuildWatcher(packageName, extraPaths, callback) {
51 callback(); 53 callback();
52 } 54 }
53 watcher.on('change', () => { 55 watcher.on('change', () => {
54 incrementalBuild.rebuild().then(() => { 56 incrementalBuild.rebuild?.().then(() => {
55 if (callback) { 57 if (callback) {
56 console.log(`\u26a1 Reloading package ${packageName}`); 58 console.log(`\u26a1 Reloading package ${packageName}`);
57 callback(); 59 callback();
@@ -81,7 +83,7 @@ async function setupDevServer(packageName) {
81 clearScreen: false, 83 clearScreen: false,
82 }, 84 },
83 }, 85 },
84 configFile: join(__dirname, `../packages/${packageName}/vite.config.js`), 86 configFile: join(thisDir, `../packages/${packageName}/vite.config.js`),
85 }); 87 });
86 await viteDevServer.listen(); 88 await viteDevServer.listen();
87 return viteDevServer; 89 return viteDevServer;
@@ -158,6 +160,9 @@ function setupMainPackageWatcher(viteDevServer) {
158 * @returns {Promise<void>} 160 * @returns {Promise<void>}
159 */ 161 */
160async function setupDevEnvironment() { 162async function setupDevEnvironment() {
163 process.env.MODE = 'development';
164 process.env.NODE_ENV = 'development';
165
161 /** @type {import('vite').ViteDevServer | null} */ 166 /** @type {import('vite').ViteDevServer | null} */
162 let viteDevServer = null; 167 let viteDevServer = null;
163 /** @type {(event: import('vite').HMRPayload) => void} */ 168 /** @type {(event: import('vite').HMRPayload) => void} */
@@ -182,6 +187,11 @@ async function setupDevEnvironment() {
182 ])), 187 ])),
183 ]); 188 ]);
184 189
190 if (viteDevServer === null) {
191 console.error('Failed to create vite dev server');
192 return;
193 }
194
185 console.log('\ud83c\udf80 Sophie is starting up') 195 console.log('\ud83c\udf80 Sophie is starting up')
186 return setupMainPackageWatcher(viteDevServer); 196 return setupMainPackageWatcher(viteDevServer);
187} 197}
diff --git a/tsconfig.json b/tsconfig.json
index 270616b..dfffc9d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,7 @@
1{ 1{
2 "compilerOptions": { 2 "compilerOptions": {
3 "module": "esnext", 3 "module": "es2022",
4 "target": "esnext", 4 "target": "es2021",
5 "moduleResolution": "node", 5 "moduleResolution": "node",
6 "esModuleInterop": true, 6 "esModuleInterop": true,
7 "allowSyntheticDefaultImports": true, 7 "allowSyntheticDefaultImports": true,
@@ -11,6 +11,7 @@
11 "exactOptionalPropertyTypes": true, 11 "exactOptionalPropertyTypes": true,
12 "isolatedModules": true, 12 "isolatedModules": true,
13 "skipLibCheck": true, 13 "skipLibCheck": true,
14 "checkJs": true,
14 "lib": [ 15 "lib": [
15 "esnext" 16 "esnext"
16 ] 17 ]