Electron — 初體驗

Conrad
Conrad KU
Published in
5 min readApr 13, 2023

Build cross-platform desktop apps with JavaScript, HTML, and CSS

前言

本來試著想學 Windows Forms 但在排版時遇到問題,本身是前端工程師就想說有沒有能直接把網頁變桌面應用程式就找到了 Electron 😁

接下來嘗試將在公司最近做的前後端分離 project 包成桌面應用程式

🔖 文章索引

1. 前端 project 設定
2. Prerequisites
3. Create your application
4. Create main.js in root
5. Packaging Your Application
6. Auto Unpack Native Modules Plugin
7. 完成版設定
8. 參考文章

前端 project 設定

使用 Vue Cli ( SPA ) 將 .env.production.local 檔案設定

# Electron 桌面應用程式

VUE_APP_PublicPath=
VUE_APP_ApiBaseUrl=Your Api Domain

將 project 打包出 dist

# generate folder dist

$ yarn build

Prerequisites

建議安裝 nvm 控制 node 版本

# node 版本需要 14.17.5 以上

$ node -v

Create your application

mkdir my-electron-app && cd my-electron-app
npm init

There are a few rules to follow for the purposes of this tutorial:

  • entry point should be main.js.
  • author and description can be any value, but are necessary for app packaging.

Your package.json file should look something like this:

{
"name": "Your project name",
"version": "1.0.0",
"description": "Your project description",
"main": "main.js",
"author": "Project author name",
"license": "MIT"
}

Then, install the electron package into your app's devDependencies.

$ npm install --save-dev electron

OR

$ npm i -D electron

Finally, you want to be able to execute Electron. In the scripts field of your package.json config, add a start command like so:

{
"name": "Your project name",
"version": "1.0.0",
"description": "Your project description",
"main": "main.js",
"author": "Project author name",
"license": "MIT",
"scripts": {
"start": "electron ."
}
}

This start command will let you open your app in development mode.

$ npm start

dist 資料夾移到這專案根目錄中

Create main.js in root

// Modules to control application life and create native browser window
const {app, BrowserWindow, Menu} = require('electron')
const path = require('path')

function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1440,
height: 900,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

// remove menu
Menu.setApplicationMenu(null);

// and load the index.html of the app.
mainWindow.loadFile('./dist/index.html')

// Open the DevTools.
mainWindow.webContents.openDevTools()
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
})

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

Packaging Your Application

You can install Electron Forge’s CLI in your project’s devDependencies and import your existing project with a handy conversion script.

$ npm install --save-dev @electron-forge/cli
$ npx electron-forge import

Once the conversion script is done, Forge should have added a few scripts to your package.json file.

// package.json

{
...

"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
},

...
}
# Make sure you have git installed and Node.js version >= 14.17.5

$ npm run make

Auto Unpack Native Modules Plugin

...\out\xxx\resources\ 資料夾中的程式碼打包成 app.asar

完成版設定

// 目錄結構

- dist ( your front-end production )
- node_modules
- .gitignore
- forge.config.js
- main.js
- package-lock.json
- package.json
// package.json

{
"name": "Your project name",
"version": "1.0.0",
"description": "your project description",
"main": "main.js",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
},
"author": "Project author name",
"license": "MIT",
"devDependencies": {
"@electron-forge/cli": "6.1.1",
"@electron-forge/maker-deb": "6.1.1",
"@electron-forge/maker-rpm": "6.1.1",
"@electron-forge/maker-squirrel": "6.1.1",
"@electron-forge/maker-zip": "6.1.1",
"@electron-forge/plugin-auto-unpack-natives": "6.1.1",
"electron": "24.0.0"
},
"dependencies": {
"electron-squirrel-startup": "1.0.0"
}
}
// forge.config.js

module.exports = {
packagerConfig: {
asar: true
},
plugins: [
{
name: '@electron-forge/plugin-auto-unpack-natives',
config: {}
}
],
rebuildConfig: {},
makers: [
{
name: '@electron-forge/maker-squirrel',
config: {},
},
{
name: '@electron-forge/maker-zip',
platforms: ['darwin'],
},
{
name: '@electron-forge/maker-deb',
config: {},
},
{
name: '@electron-forge/maker-rpm',
config: {},
},
],
};
// main.js

// Modules to control application life and create native browser window
const {app, BrowserWindow, Menu} = require('electron')
const path = require('path')

function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1440,
height: 900,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

// remove menu
Menu.setApplicationMenu(null);

// and load the index.html of the app.
mainWindow.loadFile('./dist/index.html')

// Open the DevTools.
// mainWindow.webContents.openDevTools()
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
})

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
// .gitignore

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

參考文章

--

--

Conrad
Conrad KU

Remember, happiness is a choice, so choose to be happy.