We’ve chosen to use electron-builder to create the installer because it’s easy to integrate. However, there is a small, mostly-inconsequential buglet concerning how it chooses its install directory.
By default, it’ll use the productName as its leaf install directory. So you get something like %PROGRAMFILES%/${productName}.
This is fine, unless you want to install somewhere else, like %SOMEPLACE%/foo. If that directory doesn’t exist yet, everything works fine. However, on the second install, it’ll install into %SOMEPLACE%/foo/${productName}. This is because electron-builder has an empty-directory check, which will append productName to the requested directory if the latter isn’t empty.
It shouldn’t just do an ‘empty’ check, but also see if this dir is the current install dir.
The reason I stumbled on this is that I’d prefer to have the directory be named “example-project”. This can be done by using productName="example-project", but then that also shows up in the text of the installer. I’d prefer that to be “Example Project”, but then the directories get weird.
For w use “example-project”, but we would like to know how this can be resolved.
Details:
node -v # v16.15.0
yarn -v # 1.22.15
Windows
package.json
{
"name": "example-project",
"description": "Example Project",
"version": "0.0.1",
"license": "MIT",
"scripts": {
"build:start": "node ./scripts/run-script",
"build:clean": "rimraf .dist",
"build:prepare": "node ./build.prepare.js",
"build:main": "webpack --config webpack.config.main.js --mode=production",
"build:renderer": "webpack --config webpack.config.renderer.js --mode=development",
"build:main:dev": "webpack --watch --mode=development --config webpack.config.main.js",
"build:renderer:dev": "webpack serve --port 3000 --mode=development --config webpack.config.renderer.js",
"build:compile": "yarn electron-builder",
"build": "yarn build:clean && npm-run-all --parallel build:prepare build:main build:renderer && yarn build:compile",
"dev": "yarn build:clean && npm-run-all --parallel build:main:dev build:renderer:dev",
"dev:start": "nodemon --watch ./.dist/www/index.js --exec electron ./.dist/www/index.js",
},
"dependencies": {
"axios": "^0.27.2",
"lodash": "^4.17.21",
"mobx": "^6.5.0",
"mobx-react": "^7.4.0",
"mobx-utils": "^6.0.5",
"react": "^17.0.2",
"react-dom": "^17.0.2",
},
"devDependencies": {
"electron": "^18.2.4",
"electron-builder": "^23.0.3",
}
}
electron-build.yml
appId: 'com.example.app'
artifactName: 'ExampleSetup.${ext}'
productName: 'example-project'
copyright: '${author} All rights reserved.'
directories:
output: './.dist/app'
app: './.dist/www'
extraResources:
- ./icons/**/*
icon: './icons/icon.ico'
nsis:
allowToChangeInstallationDirectory: true
include: 'scripts/installer.nsh'
oneClick: false
perMachine: true
runAfterFinish: false
warningsAsErrors: false # off b/c RmTrailingSlash gives a warning
# TODO? name the uninstaller "uninstall.exe", but can't find the option for it.
scripts/installer.nsh
!define ClientRegKey "SOFTWARE\Example\Client"
!define ProductRegKey "SOFTWARE\Example\Cloud GUI"
; SP[0] in/out path
Function RmTrailingSlash
ClearErrors
Exch $R1 ; <path>
Push $R2
StrCpy $R2 "$R1" "" -1 ; R2 gets the last char
StrCmp $R2 "\" 0 NoSlash ; check if last char is '\'
StrCpy $R2 "$R1" -1 ; last char was '\', remove it
Goto Done
NoSlash:
StrCpy $R2 $R1
Done:
Exch
Pop $R1
Exch $R2
FunctionEnd
!macro customHeader
;Default installation folder. May be overwritten by .onInit
InstallDir "$PROGRAMFILES\Example\example-project"
; InstallDirRegKey is overwritten by main electron-builder script
;InstallDirRegKey HKCU "${ProductRegKey}" ""
!macroend
!macro customInit
; If ProductRegKey doesn't exist but ClientRegKey does, use that as install dir.
ReadRegStr $0 HKCU "${ProductRegKey}" ""
${If} "$0" == ""
ReadRegStr $0 HKCU "${ClientRegKey}" ""
${If} "$0" != ""
Push $0
Call RmTrailingSlash
Pop $0
StrCpy $INSTDIR "$0\example-project"
${EndIf}
${EndIf}
!macroend
!macro customInstall
; Write installdir to Example registry. NOTE! This is not the key that the installer uses!
WriteRegStr HKCU "${ProductRegKey}" "" "$INSTDIR"
!macroend
!macro customUninstall
DeleteRegKey HKCU "${ProductRegKey}"
!macroend
We’ve chosen to use electron-builder to create the installer because it’s easy to integrate. However, there is a small, mostly-inconsequential buglet concerning how it chooses its install directory.
By default, it’ll use the productName as its leaf install directory. So you get something like %PROGRAMFILES%/${productName}.
This is fine, unless you want to install somewhere else, like %SOMEPLACE%/foo. If that directory doesn’t exist yet, everything works fine. However, on the second install, it’ll install into %SOMEPLACE%/foo/${productName}. This is because electron-builder has an empty-directory check, which will append productName to the requested directory if the latter isn’t empty.
It shouldn’t just do an ‘empty’ check, but also see if this dir is the current install dir.
The reason I stumbled on this is that I’d prefer to have the directory be named “example-project”. This can be done by using productName="example-project", but then that also shows up in the text of the installer. I’d prefer that to be “Example Project”, but then the directories get weird.
For w use “example-project”, but we would like to know how this can be resolved.
Details:
Windows
package.json
{ "name": "example-project", "description": "Example Project", "version": "0.0.1", "license": "MIT", "scripts": { "build:start": "node ./scripts/run-script", "build:clean": "rimraf .dist", "build:prepare": "node ./build.prepare.js", "build:main": "webpack --config webpack.config.main.js --mode=production", "build:renderer": "webpack --config webpack.config.renderer.js --mode=development", "build:main:dev": "webpack --watch --mode=development --config webpack.config.main.js", "build:renderer:dev": "webpack serve --port 3000 --mode=development --config webpack.config.renderer.js", "build:compile": "yarn electron-builder", "build": "yarn build:clean && npm-run-all --parallel build:prepare build:main build:renderer && yarn build:compile", "dev": "yarn build:clean && npm-run-all --parallel build:main:dev build:renderer:dev", "dev:start": "nodemon --watch ./.dist/www/index.js --exec electron ./.dist/www/index.js", }, "dependencies": { "axios": "^0.27.2", "lodash": "^4.17.21", "mobx": "^6.5.0", "mobx-react": "^7.4.0", "mobx-utils": "^6.0.5", "react": "^17.0.2", "react-dom": "^17.0.2", }, "devDependencies": { "electron": "^18.2.4", "electron-builder": "^23.0.3", } }electron-build.yml
scripts/installer.nsh