The ToDesktop CLI allows you to build and deploy your electron app with native installers, auto-updates and code signing included.
For more information, visit the project landing page.
- Installation
- Get started
- CLI commands
- Automating your builds (CI)
- Project configuration (todesktop.json)
- Build lifecycle hooks (package.json scripts)
- App package.json requirements
- FAQs
- Changelog
Install the package with:
npm install --location=global @todesktop/cli
# or
yarn global add @todesktop/cli
Once installed, you can enable JSON validation and IntelliSense for your configuration files. To do so, please add the following to your VSCode/Cursor workspace settings:
{
"json.schemas": [
{
"fileMatch": ["todesktop.json", "todesktop.*.json"],
"url": "./node_modules/@todesktop/cli/schemas/schema.json"
}
]
}
You can use the ToDesktop CLI to work with an Electron application in 4 steps:
Create a ToDesktop application to link to your Electron application. This is currently done via the web interface. Copy the ToDesktop application ID to your clipboard:
Create a todesktop.json
file in the root of your Electron project.
{
"id": "your-todesktop-id",
"icon": "./desktop-icon.png",
"schemaVersion": 1
}
See Project configuration for the full list of configuration options.
The ToDesktop runtime package takes care of auto-updating, crash reporting, and more.
npm install @todesktop/runtime
# or
yarn add @todesktop/runtime
In your main (background process) script, require the package and call the init
function. The key is to call it right at the beginning.
const { app, BrowserWindow } = require("electron");
const todesktop = require("@todesktop/runtime");
todesktop.init();
function createWindow() {
// Create the browser window.
let win = new BrowserWindow({
width: 800,
height: 600,
});
// and load the index.html of the app.
win.loadFile("index.html");
}
app.whenReady().then(createWindow);
To build your app, run the following command inside the root of your Electron project:
todesktop build
When prompted to login, use your email address and the accessToken from our dashboard. You can retrieve your access token by clicking on your name in the top right corner of the dashboard and selecting "Manage Access Token".
Once built, your app can then be downloaded and tested.
To release that build (i.e. publish new downloads and an auto-update), run:
todesktop release
To test whether that build works fine and can be successfully updated, run:
todesktop smoke-test
See the next section for more information on the available commands.
The main command:
todesktop build
This builds your Electron app with native installers, code signing, and so on baked-in. Once the build has succeeded, you should see the following output in your terminal. These are links to the download binaries for each platform:
> ✅ ToDesktop Quick Start v1.0.0
> Build complete!
> https://dl.todesktop.com/200301s7gg0kd5i/builds/sdsdf23
>See web UI for more information:
>https://app.todesktop.com/apps/200301s7gg0kd5i/builds/sdsdf23
We also support:
-
todesktop build --code-sign=false
. Run a build with code-signing and notarization disabled. This is handy for testing builds quickly. -
todesktop build --config=<path.to.another.todesktop.json>
. Run a build with a different configuration file. -
todesktop build --async
. Run a build in the background. This is handy for CI environments. -
todesktop build --webhook URL
. Send a POST request to the webhook URL when the build is finished. It's especially useful together with the--async
flag. -
todesktop build --ignore-extends-errors
. Ignoreid
andappId
validation errors when extending another todesktop.json file. -
todesktop release
. Release a build. This will publish a new download and an auto-update for existing users. By default it shows a list of builds for you to choose from.- Use
todesktop release <id>
to release a specific build by ID. -
todesktop release --latest
will release the latest build. - Append
--force
to skip the interactive confirmation step. - Append
--config=<path.to.another.todesktop.json>
to use a different configuration file.
- Use
-
todesktop builds
. View your recent builds.- Use
todesktop builds <id>
to view a specific build and its progress. -
todesktop builds --latest
will show the latest build and it's progress. -
todesktop builds --count=<number>
will show the last<number>
builds. -
todesktop builds --format=json
will output build data in JSON format. - Append
--config=<path.to.another.todesktop.json>
to use a different configuration file. - Append
--exit
to disable dynamic pagination and exit the process once the build data has been displayed.
- Use
-
todesktop logout
. Logs you out. -
todesktop smoke-test
Check whether the build works and can be successfully updated.- Use
todesktop smoke-test <id>
to test a specific build by ID. -
todesktop smoke-test --latest
will test the latest build. - Append
--config=<path.to.another.todesktop.json>
to use a different configuration file.
- Use
-
todesktop whoami
. Prints the email of the account you're signed into. -
todesktop --help
. Shows the help documentation. -
todesktop --version
. Shows the current version of the CLI.
You may want to automate builds with your Continuous Integration (CI) provider. To achieve this, simply set up environment variables for TODESKTOP_ACCESS_TOKEN
and TODESKTOP_EMAIL
within your CI project.
TODESKTOP_ACCESS_TOKEN=accessToken
TODESKTOP_EMAIL=email
To build and release in one step, you can execute:
todesktop build && todesktop release --latest --force
If you need to run a build in the background, you can use the --async
flag. To
get notified when the build is finished you can optionally specify a webhook URL
which will receive a POST request with the build data:
todesktop build --async --webhook https://example.com/build-finished-webhook
The webhook receives a POST request with the following JSON body:
// POST https://example.com/build-finished-webhook
{
appId: string;
accountUserEmail: string;
accountUserId: string;
artifacts: {
linux?: LinuxArtifactDownloads;
mac?: MacArtifactDownloads;
windows?: WindowsArtifactDownloads;
};
buildId: string;
endedAt: string; // 2023-01-01T00:00:00Z
errorMessage?: string;
requesterUserEmail: string;
requesterUserId: string; // The same as accountUserId or `contextUserId`
schemaVersion: number; // Currently always `1`
startedAt: string; // 2023-01-01T00:00:00Z
status: 'queued' | 'failed' | 'building' | 'preparation' | 'succeeded' | 'cancelled';
}
This describes all of the possible configuration options ín your todesktop.json
.
To avoid confusion, the following terms will be used throughout this file:
- "Project root": this is the parent directory of your
todesktop.json
.
Default: ["**"]
Example: ["dist/**", "!static/**"]
This option allows you to decide which files get uploaded to be built on the ToDesktop servers. By default, all files in your app path are included in your app, except for node_modules
and .git
. Dependencies are installed on our build servers as there could be platform-specific postinstall steps.
If you wish to include files for the build process but exclude them in the distribution version of your app then you should use the filesForDistribution
property
The files must be within your appPath
.
The following are always included if they exist:
/package.json
/package-lock.json
/yarn.lock
/pnpm-lock.yaml
/shrinkwrap.yaml
- Asterisk (
*
) — matches everything except slashes (path separators). - A double star or globstar (
**
) — matches zero or more directories. - Question mark (
?
) – matches any single character except slashes (path separators). - Exclamation mark (
!
) — a glob that starts with an exclamation mark will result in any matched files being excluded.
Examples:
-
src/**/*.js
— matches all files in the src directory (any level of nesting) that have the.js
extension. -
src/*.??
— matches all files in the src directory (only first level of nesting) that have a two-character extension.
We use the fast-glob library under the hood.
Default: auto-generated.
Example: com.microsoft.word
.
Your application ID. Omit this unless you know what you're doing. It's used as the CFBundleIdentifier for MacOS and as the Application User Model ID for Windows.
WARNING: if you have deployed an application with ToDesktop and would like to change this ID, talk to us first.
Default: .
.
Example: ./dist
.
This is the path to your Electron application directory. Omit this unless your project setup is complicated. This is the directory that the CLI uploads.
The path can be absolute or a relative path from the project root. The directory it points to must be a valid Electron application directory; i.e.:
- It could be ran with the
electron
command; i.e.npx electron {{appPath}}
. - It needs to contain a valid
package.json
. - The
package.json
must either have amain
property pointing to a file in the directory or there must be anindex.js
at the root of the directory.
Side note: if your package.json
contains a postinstall
script which references scripts, these must be accessible within the appPath
directory as only the appPath
is uploaded to our servers.
Default: no protocol scheme is registered.
Example: word
or [word, ...]
.
If you want to register a protocol for your application (e.g. example://
) and or support deeplinking, you will need to use this option. If your desired protocol is example://
, you would set "appProtocolScheme": "example"
. NOTE: these features also require additional application logic.
Default: true
Whether to package your application's source code within an asar archive. You should only turn this off if you have a good reason to.
Default: [**/*.node
]
This option allows you to decide which files get unpacked from the asar archive. By default we unpack all native *.node
files.
If you want to unpack only files that are required to be unpacked, you can set this property to false
.
You can also specify a list of glob patterns to unpack.
Default: auto-generated from build id
The build version. Maps to the CFBundleVersion on macOS, and FileVersion metadata property on Windows.
Default: The package.json
productName / name
.
Example: Copyright © 1995 Walt Disney
.
The human-readable copyright line for the app.
Example: ./mac-dmg-background.tiff
.
Default: undefined
(if undefined
then we use this template).
The path to the DMG installer's background image. It must be a .tiff
file. The resolution of this file determines the resolution of the installer window. Typically, backgrounds are 540x380.
You can generate a retina tiff background from png files using the following command:
tiffutil -cathidpicheck background.png background@2x.png -out background.tiff
The background color (accepts css colors). Defaults to "#ffffff
" (white) if no background image.
The size of all the icons inside the DMG. Defaults to 80
.
The size of all the icon texts inside the DMG. Defaults to 12
.
The title of the produced DMG, which will be shown when mounted (volume name). Macro ${productName}
, ${version}
and ${name}
are supported.
Defaults to "${productName} ${version}
".
Customize icon locations. The x and y coordinates refer to the position of the center of the icon (at 1x scale), and do not take the label into account.
-
x
number - The device-independent pixel offset from the left of the window to the center of the icon. -
y
number - The device-independent pixel offset from the top of the window to the center of the icon.
[
{
// Your app icon
"x": 100,
"y": 100
},
{
// Applications directory icon
"x": 300,
"y": 100,
}
]
The DMG windows position and size. In most cases, you will only want to specify a height
and width
value but not x
and y
.
-
x
number - The X position relative to left of the screen. -
y
number - The Y position relative to top of the screen. -
width
number - The width. Defaults to background image width or 540. -
height
number - The height. Defaults to background image height or 380.
{
"width": 400,
"height": 300
}
Default: null
.
Example: ./todesktop.staging.json
.
This is the path to a base configuration file. This is especially useful for configuration sharing between staging and production builds. The base configuration file can be a relative path from the project root or an absolute path.
For more information about how to create a staging version of your app see: How do I create a staging version of my app?.
Default: []
.
This option allows you specify files to be copied into the application's content directory (Contents
for MacOS, root directory for Linux and Windows).
Each item in the array must be an object, containing a from
property which is a path to a file or directory. The path can be absolute or a relative path from the project root. The files specified must be inside your project root. A directory's contents are copied, not the directory itself (see example below).
The to
property is optional. Use it to specify a directory inside the content directory to copy the file to.
Example:
[
{ "from": "./static/image.png" },
{ "from": "./static/other/anotherImage.png", "to": "images" },
{ "from": "./static", "to": "assets" }
]
In the example above, image.png
would be copied to the root of the content directory, whereas anotherImage.png
would be copied to an images
directory at the root of the content directory. The contents of the ./static
directory would be copied to assets
in the content directory (i.e. ./static/example.txt
would be copied to assets/example.txt
).
Default: Electron is downloaded from the main official source.
Example: https://cdn.npm.taobao.org/dist/electron/
The base URL of the mirror to download Electron from. This may be a mirror geographically closer to you or even your own mirror which contains custom Electron builds. The version downloaded is the Electron version specified in devDependencies
in your app's package.json
. Alternatively you can explicitly specify an electronVersion
in todesktop.json
as described below.
Default: Electron version specified in devDependencies
in your app's package.json
Example: 12.0.7-beta.17
The version of Electron to use. In most cases you should not specify an electronVersion
property. Only specify this option if you wish to override the version that is specified in package.json
.
Default: []
.
Example:
[
{ "from": "./static/image.png" },
{ "from": "./static/other/anotherImage.png", "to": "images" },
{ "from": "./static", "to": "assets" }
]
This option allows you to specify files to be copied into the application's resources directory (Contents/Resources
for MacOS, resources
for Linux and Windows). It works just like the extraContentFiles
option, except the files go to a different directory.
Associate a file type with your Electron app.
Example:
[
{
"ext": "ics",
"name": "Calendar"
}
]
-
ext
String | String[] - The extension (minus the leading period). e.g. png. -
name
String - The name. e.g. PNG. Defaults to value ofext
. -
description
String - windows-only. The description. -
icon
String - macOS and windows. Icon file name without extension. It points to ico file for Windows and icns for macOS. For example, if theicon
value is"icons/py"
then it will look for both"icons/py.ico"
and"icons/py.icns"
in your project directory. -
mimeType
String - linux-only. The mime-type. -
role
=Editor
String - macOS-only. The app’s role with respect to the type. The value can beEditor
,Viewer
,Shell
, orNone
. Corresponds toCFBundleTypeRole
. -
isPackage
Boolean - macOS-only. Whether the document is distributed as a bundle. If set to true, the bundle directory is treated as a file. Corresponds toLSTypeIsPackage
. -
rank
=Default
String macOS-only. Determines how Launch Services ranks this app among the apps that declare themselves editors or viewers of files of this type. The possible values are:Owner
(this app is the primary creator of files of this type),Default
(this app is an opener of files of this type; this value is also used if no rank is specified),Alternate
(this app is a secondary viewer of files of this type), andNone
(this app is never selected to open files of this type, but it accepts drops of files of this type).
Example: ["!**/node_modules/realm/android/**", "!**/design/**"]
This option allows you to explicitly exclude or include certain files in the packaged version of your app. These files are filtered after the build step which happens on the ToDesktop servers.
This is often useful for excluding large files which are installed during the build step but are not needed at runtime by your applcation.
The following are always excluded if they exist:
!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}
!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}
!**/node_modules/*.d.ts
!**/node_modules/.bin
!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}
!.editorconfig
!**/._*
!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}
!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}
!**/{appveyor.yml,.travis.yml,circle.yml}
!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}
Example: ./appIcon.png
.
The path to your application's desktop icon. It must be an ICNS or PNG.
Note: to ensure the icon is never missing (e.g. this happens sometimes in Ubuntu), set the icon
option when creating your BrowserWindow
s.
Example: 2005223bd1nqpl7
Your ToDesktop application ID. This is used to identify your app. This would have been generated when you first created your ToDesktop application via the web interface:
Default: We have good default settings for Linux.
Example: { "category": "Utility"
.
This object contains some options that only apply to the building & releasing for Linux.
Default: undefined
Example: Utility
.
The application category.
Example: ./linux-icon.png
.
Default: The root icon
is used.
The path to your application's Linux desktop icon. It must be an ICNS or PNG.
Note: to ensure the icon is never missing (e.g. this happens sometimes in Ubuntu), set the icon
option when creating your BrowserWindow
s.
Example: 0.1.0
Default: 0.0.11
The version of the Linux image that ToDesktop should use to build your app.
Linux Changelog:
-
0.1.0
: Updated g++ → g++10, gcc → gcc10. WARNING: This compiler has been updated to a newer version that is not compatible with older versions of Linux like Ubuntu 20.04. You should probably only use this version if you know what you're doing. -
0.0.11
: Updated git 2.25.1 → 2.47.1 node 18.18.2 → 18.20.5
Default: true
This option allows you to configure whether your app should run in a sandboxed environment.
We default this to true
for compatibility reasons because some Linux distributions do not support unprivileged user namespaces.
Default: false
Whether to include all of the submodules node_modules directories
Default: We have good default settings for Mac.
Example: { "entitlements": "./entitlements.mac.plist" }
.
This object contains some options that only apply to the building & releasing for MacOS.
Default: []
Example: ["./node_modules/example-package/example-file"]
.
Paths of any extra binaries that need to be signed. These could be files in your own app code or node_modules
.
Default: undefined
Example: public.app-category.productivity
.
The application category type, as shown in the Finder via View -> Arrange by Application Category when viewing the Applications directory.
For example, public.app-category.developer-tools
will set the application category to "Developer Tools".
Valid values are listed in Apple’s documentation.
Default: A sane minimal entitlements file we've put together.
Example: ./entitlements.mac.plist
.
The path to an entitlements file for signing your application. It must be a plist file.
Default: No entitlements file is provided by default.
Example: ./entitlementsInherit.mac.plist
.
The path to a child entitlements file for signing your application. It must be a plist file.
Default: {}
.
Example: { "NSUserNotificationAlertStyle": "alert" }
.
Extra entries for Info.plist
.
Example: ./mac-icon.png
.
Default: The root icon
is used.
The path to your application's Mac desktop icon. It must be an ICNS or PNG.
Example: ./requirements.txt
.
Default: No requirements file is used by default.
The path to the requirements file used when signing your application.
Default: We use default development settings for Mac App Store.
Example: { "type": "development" }
.
This object contains options that only apply to building the application for Mac App Store.
Default: No entitlements file is provided by default.
Example: ./entitlements.mas.plist
.
The path to an entitlements file for signing your application. It must be a plist file.
Default: No entitlements file is provided by default.
Example: ./entitlementsInherit.mas.plist
.
The path to a child entitlements file for signing your application. It must be a plist file.
Default: No provisioning profile is used by default.
Example: ./mas.provisionprofile
.
The path to a provisioning profile for authorizing your application.
Default: "development"
Example: "distribution"
.
Whether to sign app for development or for distribution.
Default: not defined
Example: "Contents/Resources/foobar/**"
Minimatch pattern of paths that are allowed to be x64 binaries in both ASAR files.
Example: 18.12.1
.
The version of Node.js that ToDesktop should use to build your app.
Example: 9.8.1
.
The version of NPM that ToDesktop should use for installation.
Default: {}
Example:
"packageJson": {
"extends": "package.json",
"name": "example-app-canary",
"productName": "Example App Canary",
"dependencies": {
"electron": "21.0.1"
}
}
If you want to override the default package.json
configuration, use the packageJson
property. For example, you can use this to override the productName
or version
properties.
You can also set the version of a dependency
(or devDependency
), such as Electron Builder, to null
. This will remove Electron Builder from the effective package.json
that ToDesktop will use.
"packageJson": {
"extends": "package.json",
"devDependencies": {
"electron-builder": null
}
}
Default: If yarn.lock
exists, yarn
is used. If pnpm-lock.yaml
or shrinkwrap.yaml
exists, pnpm
is used. Otherwise, npm
is used.
Example: yarn
The package manager to use when installing dependencies. Valid values are npm
, yarn
or pnpm
.
Example: 8.10.5
.
The version of pnpm that ToDesktop should use for installation.
Default: app-builder
.
The library that ToDesktop should use for rebuilding native modules. Valid values are app-builder
or @electron/rebuild
.
Example: 1
.
This is the todesktop.json
schema version. This must be 1
.
Example: { "confinement": "classic", "grade": "devel" }
.
This object contains some options that only apply to the building for the Snap Store.
Default: ["desktop-gtk2"]
.
Example: ["launch-scripts"]
.
Ensures that all the part names listed are staged before the app part begins its lifecycle.
Default: See snap.ts.
Example: ["-usr/lib/python*"]
.
Specifies which files from the app part to stage and which to exclude. Individual files, directories, wildcards, globstars, and exclusions are accepted. See Snapcraft filesets to learn more about the format.
Default: undefined
.
Example: snapd2.38
.
The list of features that must be supported by the core in order for this snap to install. To learn more, see the Snapcraft docs.
Default: false
.
Example: true
.
Whether or not the snap should automatically start on login.
Default: core18
.
Example: core20
.
The base snap to use for building this snap.
Default: []
.
Example: ["libssl-dev", "libssh-dev", "libncursesw5-dev"]
.
The list of debian packages needs to be installed for building this snap.
Default: strict
.
Example: classic
.
The type of confinement supported by the snap. devmode
, strict
, or classic
.
Default: {"TMPDIR": "$XDG_RUNTIME_DIR"}
.
Example: {"TMPDIR": "$XDG_RUNTIME_DIR"}
.
The custom environment. If you set this, it will be merged with the default.
Default: stable
.
Example: devel
.
The quality grade of the snap. It can be either devel
(i.e. a development version of the snap, so not to be published to the “stable” or “candidate” channels) or stable
(i.e. a stable release or release candidate, which can be released to all channels).
Default: undefined
.
Example: { "/var/lib/foo": { bind: "$SNAP_DATA/var/lib/foo" } }
.
Specifies any files to make accessible from locations such as /usr
, /var
, and /etc
. See snap layouts to learn more.
Default: ["desktop", "desktop-legacy", "home", "x11", "unity7", "browser-support", "network", "gsettings", "pulseaudio", "opengl"]
.
Example: [ "default", { "browser-sandbox": { "interface": "browser-support", "allow-sandbox": true } }, "another-simple-plug-name" ]
.
The list of plugs. If list contains default
, it will be replaced with the default list, so, ["default", "foo"]
can be used to add a custom plug foo
in addition to the default list.
Additional attributes can be specified using object instead of just name of plug:
[
{
"browser-sandbox": {
"interface": "browser-support",
"allow-sandbox": true
}
},
"another-simple-plug-name"
]
Default: ["libasound2", "libgconf2-4", "libnotify4", "libnspr4", "libnss3", "libpcre3", "libpulse0", "libxss1", "libxtst6"]
.
Example: ["default", "depends"]
.
The list of Ubuntu packages to use that are needed to support the app part creation. Like depends
for deb. If list contains default
, it will be replaced with the default list, so, ["default", "foo"]
can be used to add custom package foo
in addition to the defaults.
Default: The productName.
Example: The super cat generator
.
A sentence summarising the snap. Max len. 78 characters, describing the snap in short and simple terms.
Default: true
if stagePackages
is not specified.
Example: false
.
Whether to use a template snap.
Default: 20
.
Example: 35
.
The max upload size (in MB). Before uploading your files to our servers, we check that the total file size is less than this number. If you are accidentally including unneccesary files in your app, check out the appPath
and appFiles
options.
Default: We have good default settings for Windows.
Example: { "icon": "./icon.ico" }
.
This object contains some options that only apply to the building & releasing for Windows.
Example: ./icon.ico
.
Default: The root icon
is used.
The path to your application's Windows desktop icon. It must be an ICO, ICNS, or PNG.
Example:
{
"debugLogging": true,
"url": "https://download.todesktop.com/nsis/nsis-3.06.1-log.7z",
"checksum": "pB4LJ5s+bIjK6X+IrY4oyq1knpI1YNcykawJR1+ax9XqDULohiS6J7/Imin22rBBX6uoEDY2gvsaCcvqKkWAtA=="
}
Default: undefined
.
Allows you to provide your own makensis, such as one with support for debug logging via LogSet and LogText. (Logging also requires option debugLogging = true). It's not recommended to use it for production build.
Example of NSIS script which enables install logging:
!macro customInit
SetOutPath $INSTDIR
LogSet on
!macroend
Example: build/installer.nsh
.
Default: undefined
.
The path to NSIS script to customize installer.
Example: ["ABC Limited"]
.
Default: Default to the common name from your code signing certificate.
The publisher name, exactly as in your code signing certificate. Several names can be provided. Defaults to common name from your code signing certificate. You should typically not include this property in your configuration unless you wish to transition to a new certificate in the future.
Sometimes you want to do something before or during the build process. For example, you might want to run a script before the build starts, or you might want to run a script after the files have been packaged. Our lifecycle hooks provide a way to do this.
To specify a script, add a scripts
property to your package.json
file. The key is the name of the script (prefixed by todesktop:
), and the value is the path to the script.
{
"scripts": {
"todesktop:beforeInstall": "./scripts/beforeInstall.js",
"todesktop:beforeBuild": "./scripts/beforeBuild.js",
"todesktop:afterPack": "./scripts/afterPack.js"
}
}
When writing your script, you can follow this template:
module.exports = async ({ pkgJsonPath, pkgJson, appDir, hookName }) => {
/**
* pkgJsonPath - string - path to the package.json file
* pkgJson - object - the parsed package.json file
* appDir - string - the path to the app directory
* hookName - string - the name of the hook ("todesktop:beforeInstall" or "todesktop:afterPack")
*/
};
Example: ./scripts/beforeBuild.js
.
The path to a script that will run before dependencies are rebuilt for target architectures.
Example script:
// Set environment variable depending on the architecture
module.exports = async ({
pkgJsonPath,
pkgJson,
appDir,
electronVersion,
platform,
arch,
hookName,
}) => {
if (arch === "arm64") {
process.env.VARIABLE = "value";
} else {
process.env.VARIABLE = "alternative-value";
}
};
Example: ./scripts/beforeInstall.js
.
The path to a script that will be run before the build starts.
Example script:
const { writeFile } = require("fs/promises");
// Delete `internal` dependency from package.json
module.exports = async ({ pkgJsonPath, pkgJson, appDir, hookName }) => {
delete pkgJson.dependencies["internal"];
await writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
};
Example: ./scripts/afterPack.js
.
The path to a script that will be run after the app has been packed (but before it has been transformed into a distributable installer format and signed).
The afterPack
function also has the following arguments added to it's signature:
- appPkgName - string - the name of the app package
- appId - string - the app id
- shouldCodeSign - boolean - whether the app will be code signed or not
- outDir - string - the path to the output directory
- appOutDir - string - the path to the app output directory
- packager - object - the packager object
- arch - number - the architecture of the app.
ia32 = 0
,x64 = 1
,armv7l = 2
,arm64 = 3
,universal = 4
.
Example script:
const { writeFile } = require("fs/promises");
// Add a copyright file inside of the app directory on Mac only
module.exports = async ({ appOutDir, packager }) => {
if (os.platform() === "darwin") {
const appName = packager.appInfo.productFilename;
const appPath = path.join(`${appOutDir}`, `${appName}.app`);
await writeFile(
path.join(appPath, "copyright.txt"),
`Copyright © ${new Date().getFullYear()} ${appName}`
);
}
};
- Electron must be in your
devDependencies
and it must be a fixed version. I.e. it doesn't start with^
or~
. - You must set the
author
property.
- You should set the
productName
property. Otherwise, your app name will default to the value of thename
property.
ToDesktop CLI is similar to Continuous Integration service so you can use the guide from here: https://docs.npmjs.com/using-private-packages-in-a-ci-cd-workflow/
To summarize:
- Create a token using npm:
npm token create --read-only
. - In ToDesktop's web UI go to Settings -> Build and Deploy.
- Enter an environment variable key of
NPM_TOKEN
and value should be the token entered above. - Create an
.npmrc
file in the root of your project with the following contents:
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
Note: Do not put a token in this file. You are specifying a literal value of ${NPM_TOKEN}
. NPM will replace the value for you. 5. Add .npmrc
to your appFiles
array [".npmrc"]
in todesktop.json
.
By default, ToDesktop uses version 1.x.x
of Yarn
if a yarn.lock
file is present in your project. You can override this by creating a .yarnrc.yml
file in your project directory and specifying the yarnPath
property to point to your specified version of yarn:
yarnPath: .yarn/releases/yarn-3.1.1.cjs
This can be done automatically by running yarn set version x.x.x
from within your project directory. This will create a .yarnrc.yml
file and a corresponding .yarn/releases/yarn-x.x.x.cjs
that the yarnPath
property points to. This will also add a packageManager
field in your package.json
with a value of yarn@x.x.x
It's important to ensure that the .yarn
folder is included in your build. If you had previously changed your todesktop.json
's appFiles
property from its default glob implementation of **
, then please ensure that it includes the .yarn
directory:
Example: [".yarn/**", ".yarnrc.yml", "...include your other changes here..."]
You will want to exclude the .yarn
directory in the distribution version of your app. You can use the filesForDistribution
property to achieve this:
Example: ["!.yarn/**", "!.yarnrc.yml"]
ToDesktop CLI supports the concept of a staging version of your app. This is useful if you want to test your app before releasing it to the public. To create a staging version of your app, you need to do the following:
-
Create a new app in ToDesktop's web UI.
-
Create a new todesktop configuration file named
todesktop.staging.json
-
Add the following to your
todesktop.staging.json
file:
{
"extends": "./todesktop.json",
"id": "<ID_OF_YOUR_STAGING_APP>",
"appId": "myapp.staging.app",
"icon": "./resources/staging.png",
"packageJson": {
"name": "myapp-staging",
"productName": "My App (Staging)"
}
}
- Then in your package.json, you could do something like this:
{
"name": "myapp",
// ...
"scripts": {
"todesktop-build": "todesktop build",
"todesktop-staging-build": "todesktop build --config=./todesktop.staging.json",
},
}
Now you can run npm run todesktop-build
to build the production app. Or you can run npm run todesktop-staging-build
to build the staging app.
No problem, this can be achieved with a postInstall
script in combination with ToDesktop's TODESKTOP_CI
and TODESKTOP_INITIAL_INSTALL_PHASE
environment variables.
Name | Description |
---|---|
TODESKTOP_CI |
Set to true when running on ToDesktop build servers |
TODESKTOP_INITIAL_INSTALL_PHASE |
Set to true when running the first npm/yarn/pnpm install on ToDesktop build servers |
First, let's create a file called todesktop-postinstall.js
or something similar in the root of your app (alongside pkckage.json
). This file is going to run a script to compile typescript after your dependencies have been installed. It could look something like this
const { exec } = require("child_process");
const { promisify } = require("util");
const execAsync = promisify(exec);
async function postInstall() {
const firstInstallOnToDesktopServers =
process.env.TODESKTOP_CI && process.env.TODESKTOP_INITIAL_INSTALL_PHASE;
if (firstInstallOnToDesktopServers) {
console.log("➔ Building typescript on ToDesktop servers");
await execAsync("npm run build", {
stdio: "inherit",
});
} else {
console.log("➔ Not on ToDesktop servers... Do nothing.");
}
}
postInstall();
Next, add the following to your package.json
:
{
// ...
"scripts": {
// This is our existing typescript build script
"build": "tsc -p .",
// Our new postinstall script will run the script above when on ToDesktop servers
"postinstall": "node todesktop-postinstall.js"
}
}
Now, when we build your app on ToDesktop servers, it will also run your custom build
script after all dependencies have been installed.
- The build ID is now logged on the CLI when in CI mode
- Add support for
beforeBuild
hook.
- Fix:
linux.imageVersion
now supports any string, not just semver.
- Stop erroring in cases where
appId
is not defined in an extendedtodesktop.json
.
- You can now specify
linux.imageVersion
to explicitly set the version of the Linux image that ToDesktop should use to build your app.
- Add additional
id
andappId
validation when extending anothertodesktop.json
file. Can be disabled with the--ignore-extends-errors
flag.
- Add support for
snap.base
in snap configuration - Fix required JSON validation when extending another json file
- Add support for additional token verification when cancelling smoke test
- Update Readme to include instructions on
todesktop.json
VSCode/Cursor validation
- Add support for JSON validation and Intellisense of todesktop.json files
- Fix: format error properly when attempting log in with enviornment variables
- Fix: add JSON schema for missing
todesktop.json
properties
- Throw error if unsupported properties are provided in
todesktop.json
- Chore: bump dependencies
- Add support for
windows.publisherName
- Add support for additional token verification
- Add support for
mas.x64ArchFiles
in config. - Fix: Build is only recognised as ongoing if it was created in the last 24 hours.
- Add support for
mac.entitlementsInherit
in config.
- Fix: Mac URL download links are now formatted correctly.
- Add support for
mas.entitlements
in config. - Add support for
mas.entitlementsInherit
in config. - Add support for
mas.provisioningProfile
in config. Removedmac.provisioningProfile
as a result.
- Add support for
mas.type
in config. - Add support for
mac.provisioningProfile
in config. - Add support for specifying
buildVersion
in config.
- Add support for
includeSubNodeModules
in config.
- You can now specify
@electron/rebuild
as a customrebuildLibrary
in yourtodesktop.json
file.
- Revert support for
yarnVersion
in config. Instead use.yarnrc.yml
file to specify yarn version.
- Add support for
--webhook
flag fortodesktop build
command - Add support for
--async
flag to run a build in the in the background - Add support for specifying custom
yarnVersion
in config - Add support for specifying custom
pnpmVersion
in config
- Report errors when S3 upload fails and retry 3 times
- Add support for multiple app protocol schemes
- Add support for specifying custom
npmVersion
in config - Add support for bundling a requirements file for Mac
- Fix: Linux/Windows platform links no longer have mac/zip/[arch] added to the end of the download URL
- Add asar configuration support
- Add support for specifying custom
appBuilderLibVersion
in config - Show suggestion to run a Smoke Test when releasing an untested build
- Add
todesktop smoke-test
command
- Add support for specifying custom
windows.nsisCustomBinary
in config
- Add support for specifying custom
nodeVersion
in config
- Add support for specifying
windows.nsisInclude
in config
- Codebase refactored and converted to typescript
- Add support for
--exit
flag fortodesktop builds
.
- Add support for
todesktop builds --format=json
. - Add support for
todesktop builds --count=<number>
.
- Fix for uploading correct package.json when using the
packageJson
override.
- Allow setting dependencies in
packageJson
to null.
- Add stage support to
release
andbuilds
commands.
- Adds
extends
andpackageJson
field totodesktop.json
file. - Added
--config
option to pass a different configuration file.
- Added support for delegated users and teams.
- Fix: When the build is finished the download link is now an Apple Silicon link if you are on an Apple Silicon Mac.
- Add support for
linux.noSandbox
configuration option. - Fix Resolutions for Yarn 2+.
- Add support for
asarUnpack
configuration option.
- Add support for
beforeInstall
andafterPack
hooks.
- Feature: Support multiple concurrent builds
- Enhancement: Switched to presigned uploads (removes AWS dependency)
- Fix: Fixed package resolution for Ink
- Add PNPM support