electron-react-boilerplate
electron-react-boilerplate copied to clipboard
Electron 28 breaks build: ERR_UNKNOWN_FILE_EXTENSION – Unknown file extension ".ts" for …
Prerequisites
- [x] Using npm
- [x] Using an up-to-date
mainbranch - [x] Using latest version of devtools. Check the docs for how to update
- [x] Tried solutions mentioned in #400
- [x] For issue in production release, add devtools output of
DEBUG_PROD=true npm run build && npm start
Expected Behavior
Updating electron should make the app start.
Current Behavior
I updated Electron to 28.0.0, then ran npm install. Now:
➜ npm start
> start
> ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer
> start:renderer
> cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts
Starting preload.js builder...
Starting Main Process...
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:1212/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.0.119:1212/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::1]:1212/
<i> [webpack-dev-server] Content not from webpack is served from '/Users/werner/Documents/Software/electron-react-boilerplate/public' directory
<i> [webpack-dev-server] 404s will fallback to '/index.html'
> start:main
> cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only .
> start:preload
> cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts
[electronmon] waiting for a change to restart it
App threw an error during load
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/werner/Documents/Software/electron-react-boilerplate/src/main/main.ts
at new NodeError (node:internal/errors:405:5)
at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:80:11)
at defaultGetFormat (node:internal/modules/esm/get_format:125:36)
at defaultLoad (node:internal/modules/esm/load:89:20)
at nextLoad (node:internal/modules/esm/loader:163:28)
at ESMLoader.load (node:internal/modules/esm/loader:603:26)
at ESMLoader.moduleProvider (node:internal/modules/esm/loader:457:22)
at new ModuleJob (node:internal/modules/esm/module_job:64:26)
at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:480:17)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:434:34)
[electronmon] uncaught exception occured
[electronmon] waiting for any change to restart the app
Steps to Reproduce
See above.
Possible Solution (Not obligatory)
Not sure what the issue is. I know that Node v18.19.0 broke ts-node with a similar error message, see https://github.com/TypeStrong/ts-node/issues/1997
Latest known good version for Electron is 27.1.3.
Context
N/A
Your Environment
- Node version : v18.19.0
- electron-react-boilerplate version or branch : main
- Operating System and version : macOS
- Link to your project : N/A
@slhck same here. Did you find a solution meanwhile?
No, I don't know enough about the internals... I will post a solution should I find one, but in the meantime I'll stay on the last 27 release.
So the only thing I know is that the error comes from Electron itself, but I can't find any issue with the Electron package referencing that error. It's as if it wasn't passed a compiled JS file, instead trying to load a TS file, and, obviously, failing. So perhaps it's the webpack step that doesn't finish properly? I would think that this is due to the underlying ts-node bug.
@amilajack Any ideas?
Hope this will help somebody until the fix is released, because I've spent more time on this than I expected... This is how I managed to configure the boilerplate with Electron 28
Prerequisites:
Node.js: v18.16.0
Dependencies: "electron": "^28.1.1", "electron-builder": "^24.6.4", "@electron/rebuild": "^3.3.0"
Steps:
-
Remove
ts-nodedependency -npm uninstall ts-node -
Install
tsxpackage -npm i --save tsxPackage for TS and ESM compilation, supports both: https://www.npmjs.com/package/tsx
-
In every script defined in "scripts" section of package.json make replace
ts-nodewithnode --loader tsxFor example, my "start" scriptbefore:
"start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer",after:"start": "node --loader tsx ./.erb/scripts/check-port-in-use.js && npm run start:renderer",For the parts where cross-env is used, you may use NODE_OPTIONS like this:
"start:main": "cross-env NODE_ENV=development NODE_OPTIONS=\"--loader tsx\" electronmon .", -
Repeat step 3 for
release/app/package.json -
Not sure about this step, but I think this issue appeared after version upgrade. If you see
Could not detect abi for version...error, installnode-abiversion (I have v3.54.0) and add this topackage.jsonresolutions:"resolutions": { "node-abi": "^3.54.0" }
Thanks for providing these steps. When I apply them to this repo, I get:
➜ npm start
> start
> node --loader tsx ./.erb/scripts/check-port-in-use.js && npm run start:renderer
node:internal/process/esm_loader:40
internalBinding('errors').triggerUncaughtException(
^
Error: tsx must be loaded with --import instead of --loader
The --loader flag was deprecated in Node v20.6.0 and v18.19.0
Maybe you are running on an older version of Node?
That said, applying your suggested changes I still get:
➜ npm start
> start
> node --import tsx ./.erb/scripts/check-port-in-use.js && npm run start:renderer
> start:renderer
> cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts
Starting preload.js builder...
Starting Main Process...
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:1212/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.0.119:1212/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::1]:1212/
<i> [webpack-dev-server] Content not from webpack is served from '/Users/werner/Documents/Software/electron-react-boilerplate/public' directory
<i> [webpack-dev-server] 404s will fallback to '/index.html'
> start:main
> cross-env NODE_ENV=development NODE_OPTIONS="--import tsx" electronmon .
> start:preload
> cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts
[electronmon] waiting for a change to restart it
App threw an error during load
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/werner/Documents/Software/electron-react-boilerplate/src/main/main.ts
at __node_internal_captureLargerStackTrace (node:internal/errors:496:5)
at new NodeError (node:internal/errors:405:5)
at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:80:11)
at defaultGetFormat (node:internal/modules/esm/get_format:125:36)
at defaultLoad (node:internal/modules/esm/load:89:20)
at nextLoad (node:internal/modules/esm/loader:163:28)
at ESMLoader.load (node:internal/modules/esm/loader:603:26)
at ESMLoader.moduleProvider (node:internal/modules/esm/loader:457:22)
at new ModuleJob (node:internal/modules/esm/module_job:64:26)
at #createModuleJob (node:internal/modules/esm/loader:480:17)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:434:34)
[electronmon] uncaught exception occured
[electronmon] waiting for any change to restart the app
Yes, as I specified before, I'm using older version of Node.js - v18.16.0
I guess you may try to make it work with newer version, but steps will be different.
Also I noticed that your start:renderer script is not using NODE_OPTIONS I mentioned in the step 3 (same for start:preload)
I can confirm that your suggestions work with older versions of Node, where one has to use --loader. It breaks with v18.18 onwards, which also makes tsx ask for the --import option instead of --loader.
And once I use --import, it no longer works. Specifically, the error only affects npm run start:main. I feel like the loader part does not get forwarded properly to electron itself when using these newer Node versions.
Curiously, when I switch to Node v18.19.0, and use the old Electron version (v26.2.1) as shipped with this repo, and I try to use the --import option with tsx, I get:
➜ npm run start:main
> start:main
> cross-env NODE_ENV=development NODE_OPTIONS="--import tsx" electronmon .
[electronmon] waiting for a change to restart it
electron: --import is not allowed in NODE_OPTIONS
[electronmon] app exited with code 9, waiting for change to restart it
I am a bit lost here; I don't know enough about Node's internals, e.g. how hooks work.
Same issue here. Have to stay at v27 for now
@slhck, it looks like esbuild-register works as an alternative to ts-node in my quick testing, here's a branch that makes the necessary changes: https://github.com/dsanders11/electron-react-boilerplate/tree/esbuild
If you want to test it and let me know if that resolves your issues, I could open a PR on this repo with the changes.
@dsanders11 Awesome, that works great! I didn't know about esbuild-register. Tested and working with Node v18.19.0.
I should add that it prints a warning:
(node:86715) ExperimentalWarning:
--experimental-loadermay be removed in the future; instead useregister(): --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("esbuild-register/loader", pathToFileURL("./"));'
Would be great if you could open a PR!
The fix with esbuild-register is not working for me. I am using typeorm and there is an error with decorators not being supported yet. I am stuck with electron 27 for now.
Following the great contribution of dsanders11 I had to change more things in the scripts section of the "package.json" file to get everything to work correctly:
"scripts": {
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\"",
"build:dll": "cross-env NODE_ENV=development NODE_OPTIONS=\"--loader esbuild-register/loader -r esbuild-register\" webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
"build:main": "cross-env NODE_ENV=production NODE_OPTIONS=\"--loader esbuild-register/loader -r esbuild-register\" webpack --config ./.erb/configs/webpack.config.main.prod.ts",
"build:renderer": "cross-env NODE_ENV=production NODE_OPTIONS=\"--loader esbuild-register/loader -r esbuild-register\" webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
"postinstall": "node -r esbuild-register .erb/scripts/check-native-dep.js && electron-builder install-app-deps && npm run build:dll",
"lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx",
"package": "node -r esbuild-register ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never && npm run build:dll",
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
"start": "node -r esbuild-register ./.erb/scripts/check-port-in-use.js && npm run start:renderer",
"start:main": "cross-env NODE_ENV=development NODE_OPTIONS=\"--loader esbuild-register/loader -r esbuild-register\" electronmon .",
"start:preload": "cross-env NODE_ENV=development NODE_OPTIONS=\"--loader esbuild-register/loader -r esbuild-register\" webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
"start:renderer": "cross-env NODE_ENV=development NODE_OPTIONS=\"--loader esbuild-register/loader -r esbuild-register\" webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
"test": "jest"
},
Be aware that I found some inconsistencies with how esbuild-register treats TypeScript code that is working/transpiled without issues using tools like ts-node, tsx, and tsc. This is a minimal reproducible example: https://github.com/slhck/esbuild-register-test
So, at the moment I cannot recommend using esbuild-register because it does not error while transpiling, instead producing code that silently breaks during runtime, outputting undefined in places where your local tsc check would not flag any errors.
Note that this only applies to library versions before ES2022. So the change made here a few months ago should make tsc throw errors for this in your project. My fork of electron-react-boilerplate is older so it wasn't catching that.
at the moment I cannot recommend using
esbuild-registerbecause it does not error while transpiling
That was an oversight by me - esbuild does not do typechecking, so it needs to be used in combination with tsc -noEmit if you want that.
Be aware that I found some inconsistencies with how
esbuild-registertreats TypeScript code that is working/transpiled without issues using tools likets-node,tsx, andtsc.
That sounds like a potential issue to open upstream on esbuild, since you have a minimal repro case for ES2021., although I don't know how likely that particular case is to be fixed there. The esbuild site lists a handful of caveats around its TypeScript support, so there are various other differences from ts-node/tsc which might bite folks.
Given that, not sure switching to esbuild is a good idea in practice. Since this repo only really needs the ts-node/register functionality for the main process, and Webpack is already used (and for the prod output for the main process), it should probably be refactored to use Webpack for the main process during dev as well and tweak electronmon to trigger on the Webpack output for the main process (and use Webpack in watch mode to rebuild on changes).
I don't have time to look into the above, but that might be a better long-term solution for the ESM issue starting with E28 since it would sidestep the upstream ts-node issue.
Thanks for the reference. Indeed the breakage I am observing has to do with the class field semantics. So it's not a bug.
I agree that simply using webpack to trigger transpilation would be the best way going forward.
Hi,
First, thanks all for sharing your experience for setuping this repository with the new electron version. I'm not an expert in the build chain and I'm a bit lost on whether or not you finally found a way to migrate safely to v28+?
Is there any plan to merge/PR something on the main branch on this project so everyone can have a stable, battle tested config up to date? Thanks,
No, there is no reliable solution. esbuild-register works, but requires a few adaptations in package.json. Even then it prints warnings. I wouldn't recommend it for now.
The best path forward, it seems, would be this:
ts-nodehas to be removed entirely from this repo.webpackis triggered for compiling themainpart during development upon save, which would make Electron load a.jsfile rather than relying upon a Node loader.
I am not sure when I will have time to look into this. Unfortunately no word from the maintainer yet, either. (I am a bit tired of providing PRs without an indication of them being merged … the last commit to this repo was 5 months ago.)
Thanks for the insight.
I hope you will be able to find some time to share a solution. Are there any other repo that provide end to end integration like this one?
I hope the maintainer will react on this topic quickly as the 26 version will be unsupported soon and 27 in few months. We need to find solutions. If I can help in any way, I will. but clearly all those stuffs are out of my current knowledge, I able to tweak a ready config but not to create a new one :(
@slhck I did dig into Electron-Forge and the setup for a blanck project is straight forward and works with the latest Electron version out of the box. The setup is not as complete as this one, but it might a good start to fix this repo? Or didn't they use the same approach? Thanks
I ran into this issue yesterday and I was able to get it working with the following changes:
- In the
startscript, replacets-nodewithtsx. - In the
start:mainscript, add NODE_OPTION flag and minor changes to the electronmon arguments.
Here is what the updated version of these scripts look like:
"start": "tsx ./.erb/scripts/check-port-in-use.js && npm run start:renderer"
"start:main": "cross-env NODE_ENV=development NODE_OPTIONS=\"--loader tsx\" electronmon ."
I haven't exhaustively checked for the side-effects but the development environment is working fine i.e. the files are getting transpiled and on code change, the latest changes are loaded automatically.
A few points to note:
- My postinstall script still uses ts-node. Will get around to this soon.
- My package script still uses ts-node. Will get around to this soon.
- I had to install
tsxas a dev dependency.
My Environment
Node version : v20.5.0 Electron: 28.2.3 electron-react-boilerplate version or branch : main Operating System and version : macOS
I hope this helps developers who stumble onto this thread in future.
Hey, I managed to get it working with Electron 28 using esbuild-register. However, after updating to Electron 29.0.1, I encountered an Cannot find module error. 🫠
Does anyone else have encountered this issue and managed to resolve it?
"scripts": {
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\"",
"build:dll": "cross-env NODE_ENV=development webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
"build:main": "cross-env NODE_ENV=production webpack --config ./.erb/configs/webpack.config.main.prod.ts",
"build:renderer": "cross-env NODE_ENV=production webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
"postinstall": "node -r esbuild-register .erb/scripts/check-native-dep.js && electron-builder install-app-deps && npm run build:dll",
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
"lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx",
"package": "node -r esbuild-register ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never && npm run build:dll",
"start": "node -r esbuild-register ./.erb/scripts/check-port-in-use.js && npm run start:renderer",
"start:main": "cross-env NODE_ENV=development NODE_OPTIONS=\"--loader esbuild-register/loader -r esbuild-register\" electronmon .",
"start:preload": "cross-env NODE_ENV=development webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
"start:renderer": "cross-env NODE_ENV=development webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
"test": "jest",
"publish": "npm run build && electron-builder -c.win.certificateSha1=842a817a51e2a1d360fcd62f54bf5f9193e919e1 --publish always --win --x64"
},
I ran into this issue yesterday and I was able to get it working with the following changes:
- In the
startscript, replacets-nodewithtsx.- In the
start:mainscript, add NODE_OPTION flag and minor changes to the electronmon arguments.Here is what the updated version of these scripts look like:
"start": "tsx ./.erb/scripts/check-port-in-use.js && npm run start:renderer""start:main": "cross-env NODE_ENV=development NODE_OPTIONS=\"--loader tsx\" electronmon ."I haven't exhaustively checked for the side-effects but the development environment is working fine i.e. the files are getting transpiled and on code change, the latest changes are loaded automatically.
A few points to note:
- My postinstall script still uses ts-node. Will get around to this soon.
- My package script still uses ts-node. Will get around to this soon.
- I had to install
tsxas a dev dependency.My Environment
Node version : v20.5.0 Electron: 28.2.3 electron-react-boilerplate version or branch : main Operating System and version : macOS
I hope this helps developers who stumble onto this thread in future.
Because webpack needs to use ts-node when using typescript as the configuration language: webpack-configuration-languages. And currently it does not support ESModule, this will be a hindrance when we move fully to ESModule.
One more thing, it seems that node will no longer support the use of custom ESM Loader(you will get this warning):
ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
Well it doesn't "load" typescript sources at runtime, it resolves them in typescript, stores them somewhere and then redirects require() calls to them, most likely achieved by monkey-patching require(). Which is of course not possible in ESM since import is a keyword and not a symbol. The solution is to explicitly have a ts -> js transformation step in your build pipeline and drop ts-node from runtime dependencies.
As mentioned here, after electron v28.0.0 switches to esmodule we will no longer be able to use ts-node to compile ts -> js at runtime. Instead, ts should be compiled into js before running. The simplest way is that we can use webpack or tsc to compile ts into js in advance and write it to a disk file, and then execute electron. to start the service (as far as I know electron-forge uses this method).
- Write a
webpack.config.main.dev.tsfor the main process code (the output path must be consistent with themainattribute ofpackage.json - Change
start:maincommand
"start:main": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.dev.ts && electronmon .",
(If you care about the time-consuming compilation, you can use swc-loader to speed up the compilation process.)
I've tried this solution myself and everything works fine. But when I fully migrated to esmodule, webpack started to complain: The webpack.config.ts file could not be recognized. Because webpack does not yet support esmodule when using typescript as the configuration language.
So eventually I started to give up ts-node & webpack and turned to vite and esbuild for a good development experience. At the same time, I also retained the advantages of electron-react-boilerplate. If you are interested you can view the current complete project code: https://github.com/1111mp/nvm-desktop. Currently everything is working fine.
(This comment does not in any way imply that electron-react-boilerplate is obsolete. In fact, all this has nothing to do with electron-react-boilerplate itself, because the problem that causes incompatibility with electron v28.0.0 and above is caused by the tools that its upstream depends on. The design of electron-react-boilerplate is still very good.)
Thanks for your comment!
Write a webpack.config.main.dev.ts for the main process code
That sounds reasonable, although it was far from obvious to me how that would look like. I played around a little, and what I did was the following. Create a file ./erb/configs/webpack.config.main.dev.ts:
/**
* Webpack config for production electron main process
*/
import path from 'path';
import webpack from 'webpack';
import { merge } from 'webpack-merge';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import baseConfig from './webpack.config.base';
import webpackPaths from './webpack.paths';
import checkNodeEnv from '../scripts/check-node-env';
import { getContentScriptEntries } from './getContentScriptEntries';
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
// at the dev webpack config is not accidentally run in a production environment
if (process.env.NODE_ENV === 'production') {
checkNodeEnv('development');
}
const configuration: webpack.Configuration = {
devtool: 'inline-source-map',
mode: 'development',
target: 'electron-main',
entry: {
...getContentScriptEntries(),
main: path.join(webpackPaths.srcMainPath, 'main.ts'),
// preload: path.join(webpackPaths.srcMainPath, 'preload.ts'),
// TODO merge this with the preload-file ...
},
output: {
path: webpackPaths.dllPath,
filename: '[name].bundle.dev.js',
library: {
type: 'umd',
},
},
plugins: [
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
new BundleAnalyzerPlugin({
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
analyzerPort: 8888,
}),
new webpack.DefinePlugin({
'process.type': '"browser"',
}),
],
/**
* Disables webpack processing of __dirname and __filename.
* If you run the bundle in node.js it falls back to these values of node.js.
* https://github.com/webpack/webpack/issues/2010
*/
node: {
__dirname: false,
__filename: false,
},
};
export default merge(baseConfig, configuration);
Now change package.json to point to the newly generated bundle JS file:
diff --git a/package.json b/package.json
index 893ca68..d3dbe0f 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"version": "0.9.0",
- "main": "./src/main/main.ts",
+ "main": "./.erb/dll/main.bundle.dev.js",
"private": true,
"scripts": {
"build": "concurrently \"yarn run build:main\" \"yarn run build:renderer\"",
@@ -24,7 +24,7 @@
"package:all": "yarn run prepackage && yarn run package:linux && yarn run package:mac && yarn run package:win",
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
"start": "ts-node ./.erb/scripts/check-port-in-use.js && yarn run start:renderer",
- "start:main": "cross-env NODE_ENV=development electronmon --inspect=5858 -r ts-node/register/transpile-only .",
+ "start:main": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.dev.ts && electronmon .",
"start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
"start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
"test": "yarn run test:unit && yarn run test:e2e",
I also had to change a few places in my application that looked like this — due to outputting the bundle in .erb/dll now:
diff --git a/src/main/helpers/paths.ts b/src/main/helpers/paths.ts
index 80b9b34..db33e96 100644
--- a/src/main/helpers/paths.ts
+++ b/src/main/helpers/paths.ts
@@ -3,7 +3,7 @@ import path from 'path';
export const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'assets')
- : path.join(__dirname, '../../../assets');
+ : path.join(__dirname, '../../assets');
export function getAssetPath(...paths: string[]) {
return path.join(RESOURCES_PATH, ...paths);
This works, even with hot-reloading, and I have had no issues launching the app with Electron 29 and Node v18.19.0.
This comment does not in any way imply that electron-react-boilerplate is obsolete
The only thing that irks me is that there is no official comment from the maintainers yet. The package is lagging behind and v27 will be unsupported as of April 16, 2024. Of course, I understand it's free, open-source software and there's no guarantee to receive any support whatsoever. But given the various solutions proposed here, an official comment regarding what would be the recommended solution would be good.
@slhck first, thanks for working on this.
I tried your solution in your last post, but it's not working for me because of a native dependency (keytar) of my Electron app.
At start I get :
App threw an error during load
Error: Cannot find module 'keytar'
Require stack:
- C:\Users\user\Projets\myproject\app\.erb\dll\main.bundle.dev.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1084:15)
at s._resolveFilename (node:electron/js2c/browser_init:2:114421)
at Module._load (C:\Users\user\Projets\myproject\app\node_modules\runtime-required\runtime-required.js:28:44)
at Module.require (node:internal/modules/cjs/loader:1150:19)
at require (node:internal/modules/cjs/helpers:119:18)
at webpackUniversalModuleDefinition (C:\Users\user\Projets\myproject\app\.erb\dll\main.bundle.dev.js:3:28)
at Object.<anonymous> (C:\Users\user\Projets\myproject\app\.erb\dll\main.bundle.dev.js:10:3)
at Module._compile (node:internal/modules/cjs/loader:1271:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1326:10)
at Module.load (node:internal/modules/cjs/loader:1126:32)
And it cannot be installed in main package, the dependency is only installed in the release/app/package.json
I am thinking about making the jump to electron's new official tool for a lot of this electron-forge. There is a webpack + typescript template which works with a react + typescript front-end that should be easiest to convert to at first. Although, they have a vite + typescript plugin and it might be worth it long-term to also switch to vite.
Does anyone see potential issues with converting to a electron-forge + webpackge + typescript setup? If not, I will probably give it a try soon.
For what is worth, I did that migration recently, to the electron-forge boilerplate with the vite-typescript template, and the transition was surprisingly smooth. I hardly had to change anything serious in my code, other than to specify in the configuration that I wanted different directories for main and renderer. I'm not an expert in webpack, but I found the vite configuration much easier to understand and modify, which I was never able to do reliably with webpack.
For what is worth, I did that migration recently, to the
electron-forgeboilerplate with thevite-typescripttemplate, and the transition was surprisingly smooth. I hardly had to change anything serious in my code, other than to specify in the configuration that I wanted different directories formainandrenderer. I'm not an expert inwebpack, but I found theviteconfiguration much easier to understand and modify, which I was never able to do reliably withwebpack.
thanks for the push! I used your repo to help get things working... thanks. Also my dev environment feels much quickier and more snappy. For everyone else, I'll tag my PR here so y'all can see the file changes
That sounds reasonable, although it was far from obvious to me how that would look like. I played around a little, and what I did was the following. Create a file
./erb/configs/webpack.config.main.dev.ts:
Your solution worked for me too. The only thing I want to adopt is to make a hot reload of electronmon work. Currently, if any changes happen in src/main/main.ts (and all imports tree), it requires a manual restart of the npm start command.
I tried your solution in your last post, but it's not working for me because of a native dependency (keytar) of my Electron app.
I also have a native dependency (better-sqlite3).
To make it work, you need to create a symlink of release/app/node_modules into .erb/dll/node_modules or at least to .erb/node_modules.
As you see, the boilerplate already has a script: https://github.com/electron-react-boilerplate/electron-react-boilerplate/blob/main/.erb/scripts/link-modules.ts that links release/app/node_modules into src/node_modules to make native dependencies reachable. Since within the proposed changes the entry point moved from the src/main/main.ts to .erb/dll/main.bundle.dev.js, you might need to put your native dependencies somewhere in the hierarchy before reaching the root path of the project.
So, the following changes worked for me:
.erb/scripts/link-modules.ts:
import fs from 'fs';
import webpackPaths from '../configs/webpack.paths';
const { srcNodeModulesPath, appNodeModulesPath, erbNodeModulesPath } = webpackPaths;
if (!fs.existsSync(srcNodeModulesPath) && fs.existsSync(appNodeModulesPath)) {
fs.symlinkSync(appNodeModulesPath, srcNodeModulesPath, 'junction');
}
if (!fs.existsSync(erbNodeModulesPath) && fs.existsSync(appNodeModulesPath)) {
fs.symlinkSync(appNodeModulesPath, erbNodeModulesPath, 'junction');
}
.erb/configs/webpack.paths.ts:
const path = require('path');
const rootPath = path.join(__dirname, '../..');
const erbPath = path.join(__dirname, '..');
const erbNodeModulesPath = path.join(erbPath, 'node_modules');
const dllPath = path.join(__dirname, '../dll');
const srcPath = path.join(rootPath, 'src');
const srcMainPath = path.join(srcPath, 'main');
const srcRendererPath = path.join(srcPath, 'renderer');
const releasePath = path.join(rootPath, 'release');
const appPath = path.join(releasePath, 'app');
const appPackagePath = path.join(appPath, 'package.json');
const appNodeModulesPath = path.join(appPath, 'node_modules');
const srcNodeModulesPath = path.join(srcPath, 'node_modules');
const distPath = path.join(appPath, 'dist');
const distMainPath = path.join(distPath, 'main');
const distRendererPath = path.join(distPath, 'renderer');
const buildPath = path.join(releasePath, 'build');
export default {
rootPath,
erbNodeModulesPath,
dllPath,
srcPath,
srcMainPath,
srcRendererPath,
releasePath,
appPath,
appPackagePath,
appNodeModulesPath,
srcNodeModulesPath,
distPath,
distMainPath,
distRendererPath,
buildPath,
};
I tried to play around with electron-forge, but for me, it requires too much work to move the codebase to match their configuration. I'm deeply using electron-builder, its publishers, configured signing & notarizing of macOS builds, assembling via NSIS the app for Windows, configured unit tests, etc. I might need weeks to migrate it 😆
Will try to stay with the existing boilerplate.
Also tried to play around with electron-vite, but the main pitfall is that it does not support typescript decorators, but I'm using typeorm together with better-sqlite3.
The bad thing is that there's no good solution at the moment, it is time to invent your own wheels! 🚴
fyi, if it helps, here is my PR https://github.com/NiceNode/nice-node/pull/536
Changes:
electron-buildersuite -> electron-forge
webpack -> vite
eslint, babel & prettier -> biome,
jest -> vitest
I agree, it does take a week+ to fully migrate. I suggest wait as long as you can until you have to switch.