diff --git a/README.md b/README.md index fe335417..6c749c30 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,25 @@ to make ODIN use your on-premise instance of Nominatim you cat use the environme You are an offline-first user and want to host your own map server (i.e. on your laptop)? GeoWebServer is way to big and uses too many resources? Just fire up [mbtileserver](https://github.com/consbio/mbtileserver), provide a _mbtile_ file that contains all your map tiles and you are done. +## Development + +### Build hygiene + +`npm start` runs the app against the prebuilt `dist/` directory — it does **not** build. +After an interrupted or partial webpack build, `dist/` can contain a bundle and a +source map that do not match each other. Opening the Chrome DevTools against such a +mismatched build freezes the renderer (the inspector blocks while trying to reconcile +bundle and source map). + +If the app freezes when DevTools opens, do a clean build before starting: + +``` +rm -rf dist && npm run webpack && npm start +``` + +`npm run hot` (webpack-dev-server) is unaffected, since it always serves a consistent +in-memory build. + ## License Copyright (c) Syncpoint GmbH. All rights reserved. diff --git a/package-lock.json b/package-lock.json index 3d5c2043..688f7623 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "babel-loader": "^10.0.0", "c8": "^10.1.3", "css-loader": "^7.1.2", - "electron": "^38.8.0", + "electron": "^42.2.0", "electron-builder": "^26.7.0", "electron-updater": "^6.1.4", "eslint-config-standard": "^17.0.0", @@ -1881,25 +1881,50 @@ } }, "node_modules/@electron/get": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.0.0.tgz", + "integrity": "sha512-pjoBpru1KdEtcExBnuHAP1cAc/5faoedw0hzJkL3o4/IJp7HNF1+fbrdxT3gMYRX2oJfvnA/WXeCTVQpYYxyJA==", "dev": true, "license": "MIT", "dependencies": { "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", + "env-paths": "^3.0.0", + "graceful-fs": "^4.2.11", "progress": "^2.0.3", - "semver": "^6.2.0", + "semver": "^7.6.3", "sumchecker": "^3.0.1" }, "engines": { - "node": ">=12" + "node": ">=22.12.0" }, "optionalDependencies": { - "global-agent": "^3.0.0" + "undici": "^7.24.4" + } + }, + "node_modules/@electron/get/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@electron/get/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/@electron/notarize": { @@ -6987,22 +7012,22 @@ } }, "node_modules/electron": { - "version": "38.8.6", - "resolved": "https://registry.npmjs.org/electron/-/electron-38.8.6.tgz", - "integrity": "sha512-lyBhcVi9QYAZL6FO6r5twAWAjWnYomo3iVDvrb5SJZlq928BGemHOKG0tPIq41NOLaCu9f3XdEEjMkjQPjprRg==", + "version": "42.2.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-42.2.0.tgz", + "integrity": "sha512-b2Tc7sIKiZEl0tBVwFM5GJ+FT5KYhmy9QJHjx8BGVZPVW2SctXWEvrE959ElB56qw7H05dBkhlikDA1DmpaAMw==", "dev": true, - "hasInstallScript": true, "license": "MIT", "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^22.7.7", + "@electron/get": "^5.0.0", + "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { - "electron": "cli.js" + "electron": "cli.js", + "install-electron": "install.js" }, "engines": { - "node": ">= 12.20.55" + "node": ">= 22.12.0" } }, "node_modules/electron-builder": { @@ -7251,13 +7276,13 @@ } }, "node_modules/electron/node_modules/@types/node": { - "version": "22.19.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.11.tgz", - "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==", + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.16.0" } }, "node_modules/emoji-regex": { @@ -8776,21 +8801,6 @@ "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", "license": "MIT" }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", @@ -15725,10 +15735,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 15fbe136..20682d67 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "babel-loader": "^10.0.0", "c8": "^10.1.3", "css-loader": "^7.1.2", - "electron": "^38.8.0", + "electron": "^42.2.0", "electron-builder": "^26.7.0", "electron-updater": "^6.1.4", "eslint-config-standard": "^17.0.0", diff --git a/src/main/main.js b/src/main/main.js index 39ca2dc9..7bf122d4 100644 --- a/src/main/main.js +++ b/src/main/main.js @@ -28,13 +28,22 @@ const ready = async () => { // Register app:// protocol handler to serve static files from dist/. const distPath = path.join(app.getAppPath(), 'dist') - protocol.handle('app', (request) => { + protocol.handle('app', async (request) => { const requestURL = new globalThis.URL(request.url) const filePath = path.join(distPath, path.normalize(requestURL.pathname)) if (!filePath.startsWith(distPath)) { return new Response('Forbidden', { status: 403 }) } - return net.fetch('file://' + filePath) + + // The handler must always resolve to a Response. Returning a rejected + // net.fetch() promise (e.g. for a missing file) leaves the request + // unresolved, which freezes the renderer when DevTools requests source + // maps or webpack-virtual source paths that have no file on disk. + try { + return await net.fetch('file://' + filePath) + } catch { + return new Response('Not Found', { status: 404 }) + } }) // Inject Content-Security-Policy and augment CORS headers.