Preload.ts
- electron-builder version: 25.1.7
- Node version: 20
- Electron version: 32.1.2
- Target: Windows
I have an Angular app in Electron. When I add a preload.js file for inter process communication (IPC) the production build of the app is stuck on the index.html and the electron app is stuck and doesn't start up. For the development build I serve the electron app with a URL, localhost:4200 and it works without issues.
File structure (simplified for conciseness)
|-app
|-main.ts
|-preload.ts
|-src
|-app
|-main.ts
|-index.html
|-package.json
|-dist
|-index.html
I have an electron app that is wrapping a Angular app and I use electron-build to build the app
package.json
{
"version": "2.2.10",
"keywords": [
"angular",
"dotnet",
"electron",
"eslint",
"kestrel",
"scss",
"typescript"
],
"main": "app/main.js",
"private": true,
"scripts": {
"start:mac": "npm-run-all -p server:serve:mac electron:serve web:serve",
"start:win": "npm-run-all -p server:serve:win electron:serve web:serve",
"start:test:win": "npm-run-all -p server:serve:win web:serve",
"start:test:mac": "npm-run-all -p server:serve:mac web:serve",
"start:electron": "npm-run-all -p electron:serve web:serve",
"web:serve": "ng serve -c web",
"web:build": "npm run build -- -c web-production",
"build": "npm run electron:serve-tsc && ng build --base-href ./",
"build:dev": "npm run build -- -c dev",
"build:prod": "npm run build -- -c production",
"electron:serve-tsc": "tsc -p tsconfig.serve.json",
"electron:serve": "wait-on tcp:4200 && npm run electron:serve-tsc && electron . --serve",
"electron:local": "npm run build:prod && electron .",
"electron:build": "npm run build:prod && electron-builder build --publish=never",
"win": "electron-builder --win --config ./electron-builder.json",
"postinstall": "electron-builder install-app-deps",
"post-build": "copyfiles -f ./src/assets/* ./dist/assets",
"test": "ng test --watch=false",
"test:e2e": "npx playwright test",
"test:watch": "ng test",
"lint": "ng lint",
},
"dependencies": {
"@angular/animations": "^16.2.11",
"@angular/cdk": "^16.2.10",
"@angular/common": "^16.2.11",
"@angular/compiler": "^16.2.11",
"@angular/core": "^16.2.11",
"@angular/forms": "16.2.11",
"@angular/language-service": "16.2.11",
"@angular/material": "16.2.10",
"@angular/platform-browser": "^16.2.11",
"@angular/platform-browser-dynamic": "16.2.11",
"@angular/router": "16.2.11",
"@ngbracket/ngx-layout": "16.1.3",
"ag-grid-angular": "29.0.0",
"ag-grid-community": "29.0.0",
"dotenv": "16.3.1",
"electron-log": "5.2.0",
"ngx-translate-testing": "6.1.0",
"rxjs": "7.8.0",
"three": "0.137.5",
"tslib": "2.5.3",
"zone.js": "0.13.3"
},
"devDependencies": {
"@angular-builders/custom-webpack": "16.0.1",
"@angular-devkit/build-angular": "16.2.8",
"@angular-eslint/builder": "16.2.0",
"@angular-eslint/eslint-plugin": "^16.2.0",
"@angular-eslint/eslint-plugin-template": "^16.2.0",
"@angular-eslint/schematics": "16.2.0",
"@angular-eslint/template-parser": "16.2.0",
"@angular/cli": "16.2.8",
"@angular/compiler-cli": "16.2.11",
"@ngx-translate/core": "14.0.0",
"@ngx-translate/http-loader": "7.0.0",
"@playwright/test": "1.38.1",
"@types/jasmine": "4.0.3",
"@types/jasminewd2": "2.0.10",
"@types/node": "18.16.18",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/parser": "^5.59.2",
"concurrently": "8.2.1",
"conventional-changelog-cli": "2.2.2",
"electron": "32.1.2",
"electron-builder": "23.6.0",
"electron-debug": "3.2.0",
"electron-reloader": "1.2.3",
"eslint": "^8.39.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jsdoc": "39.3.25",
"eslint-plugin-prefer-arrow": "1.2.3",
"eslint-plugin-prettier": "4.2.1",
"jasmine-core": "4.2.0",
"jasmine-spec-reporter": "7.0.0",
"karma": "6.4.2",
"karma-coverage-istanbul-reporter": "3.0.3",
"karma-electron": "7.2.0",
"karma-jasmine": "5.1.0",
"karma-jasmine-html-reporter": "2.0.0",
"ng-mocks": "14.11.0",
"node-polyfill-webpack-plugin": "2.0.1",
"npm-run-all": "4.1.5",
"playwright": "1.38.1",
"prettier": "2.8.8",
"prettier-eslint": "15.0.1",
"ts-node": "10.9.1",
"typescript": "4.9.5",
"wait-on": "6.0.1",
"webdriver-manager": "12.1.9"
},
"engines": {
"node": ">= 20.16.0"
}
}
electron-builder.json
{
"directories": {
"output": "../output"
},
"files": [
"**/*",
"!**/*.ts",
"!**/.vscode",
"!*.map",
"!package.json",
"!package-lock.json",
"!tsconfig.json",
"!tslint.json",
{
"from": "../dist",
"filter": ["**/*"]
}
],
"extraFiles": {
"from": "../bin/dist/",
"to": "bin/dist/",
"filter": ["**/*"]
},
"win": {
"icon": "dist/assets/icons/icon.ico",
"target": ["nsis"],
"forceCodeSigning": true,
"sign": "../CodeSigning/customSign.js"
},
"portable": {
"splashImage": "dist/assets/icons/icon.ico"
},
"nsis": {
"deleteAppDataOnUninstall": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "App",
"artifactName": "App.Setup.${version}.${ext}",
"uninstallDisplayName": "Uninstall App (${version})",
"oneClick": false,
"runAfterFinish": false
}
}
Have you tried running your app with --inspect or --inspect-brk command line args and debugging breakpoints from there? I'd imagine some error is being thrown in the packaged app as this sounds like a local environment setup issue.
@mmaietta yes, when I run the production executable with devtools enabled I get an error in the console saying Cannot find module 'mypath\win-unpacked\resources\app.asar\preload.js
I probably have to use some electron-builder configuration to properly use the preload.js, but I don't know how.
My win-unpacked folder does have a folder resources and a file app.asar, but since this is a file it cannot contain preload.js
Can you share a minimum reproducible repo for this? Sounds like the wrong path is being passed to a require/import
Additional note: app.asar is an archive that can be extracted with npx asar e <asar path> <extract folder> to check the resources. preload.js should be in there and the asar is the root from which to require the preload.js from.
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days.
This issue was closed because it has been stalled for 30 days with no activity.
@mmaietta Really appreciate you' re follow ups on many other issues over here.. This one was closed due to being stale but I have a similar issue, But would like to reopen and get to the bottom of it.
I have a Next.js ts project.
src-electron /
-index.ts (is electron app)
-preload.mjs (colocated and works in dev)
build yaml:
directories:
output: dist
buildResources: assets
asarUnpack:
- '.next/standalone/.next/cache/**/*'
asar: true
files:
- build
- '.next/standalone/**/*'
- '.next/standalone/**/node_modules/**'
mac:
category: public.app-category.developer-tools
target:
target: dir
arch:
- x64
index.ts:
webPreferences: {
preload: path.join(appPath,'./src-electron/preload.mjs'), <-- using mjs works when and loaded in dev
sandbox: false,
nodeIntegration: true,
contextIsolation: true,
devTools: false,
},
I can also use a preload.ts if needed but really need help on where yaml config file.
Thank You 🙏🏼.
Can you share a minimum reproducible repo for this? Sounds like the wrong path is being passed to a require/import
@mmaietta I've got it correctly loaded and your tips on unpacking asar and seeing if the path mached really helped. Apologies repo is not up and shareable yet but I will eventually do so.
I added below to my yaml which basically copied the folder in a directory above the asar.app .
extraResources:
- from: './src-electron'
to: src-electron
filter:
- '**/*'
in my index.ts:
webPreferences: {
preload: path.join(appPath,'../src-electron/preload.mjs'),
sandbox: false,
nodeIntegration: true,
contextIsolation: true, // protect against prototype pollution
devTools: false,
},
I do have a question I noticed a build folder in my asar with the index.js and preload.js
app.asar/build
- index.js
- preload.js
which I assume is my ts compiler, picking up the preload.ts and compiling correctly into a preload.js into the build dir.
but when I tried
preload: path.join(appPath,'./build/preload.js'),
I get the following error: "Error [ERR_REQUIRE_ESM]: require() of ES Module .../Next Electron RSC.app/Contents/Resources/app.asar/build/preload.js not supported. Instead change the require of preload.js in null to a dynamic import() which is available in all CommonJS modules."
I' de rather have this correctly working with a .ts file as opposed to using a .mjs file.
preload.ts
import { contextBridge, ipcRenderer } from "electron";
contextBridge.exposeInMainWorld('electronAPI', {
toggleTrafficLights: (state) => {
ipcRenderer.send('toggle-traffic-lights', state)
}
})
ESM, Commons js , ts configs .... Perfecting your tooling is a losing game... Kid yourself not it will eventually brake.
Loading the preload.mjs works... Sticking with that.
My module resolutions are "node" for the tsconfig.json and "bundler" for "tsconfig-electron.json" For anyone who does find the poorly documented and unsupported starter I've been building off and gets to this stage... and finds this thread my comments should help.
@mmaietta FYI I have decided not to spend effort to get the preload.ts working. I do think this should stay open as electron.js site points to the preload.ts but they are using electron forge.
My comments and errors are going to help anyone who does want to fix it.
So you're preload is in a different folder structure when packaged? Can probably try something simple like this
preload: app.isPackaged ? path.join(appPath, "build/preload.js") : path.join(appPath,'../src-electron/preload.mjs'),
No it’s not a matter of directory pointing it’s an issue with esm and commonjs bundling.