[玩转electron系列]纯 ts 从零完成 electron 的搭建和构建

最近公司想搞 electron,我来之前其实有搞过,不过也就做得应付了事。现在有时间了,就想让我规范化起来。

electron 简介

官方描述:

Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。

从官方的描述当中,总结出来一些做 electron 之前需要熟悉的基本知识

  1. node.js
  2. javascript
  3. html
  4. css

以上只是基本要求,若是在公司里面做项目开发,以下基本前端知识还是要熟悉

  1. 前端框架,angular/react/vue,根据具体项目选定
  2. typescript,这年头还有做前端不会 ts 的吗?
  3. sass/less/scss的一种,一般less比较多
  4. material design / ant-design,基本各厂会根据设计师要求制作自己的组件库
  5. npm/yarn
  6. git

对 electron 有了大概的了解,且一些基本工作准备就绪,就可以开始了

纯 ts 搭建 electron

首先声明一下我的环境:

  • 系统:windows
  • node: v16.15.0
  • yarn: 1.22.18
创建 package.json
yarn init

注意

  • authordescription 两个字段必须写一些东西,空字符串也不行。这是因为在后续的构建会需要这两个字段。虽然构建时的报错写得还算清晰,但连官网都提示了这两个字段的重要性,我们就照着做就好了。
  • main字段需修改为 out/electron-app.js
设置 electron 镜像源,下载 electron 和其他依赖

项目根目录创建 .yarnrc 文件,内容如下:

# default mirror
registry https://registry.npm.taobao.org/

# electron relatives files are downloaded from taobao mirror
electron_mirror "https://npm.taobao.org/mirrors/electron/"
ELECTRON_BUILDER_BINARIES_MIRROR http://npm.taobao.org/mirrors/electron-builder-binaries/

若不指定,electron 下载是从外网下的,比较慢,且可能会出错。包括后续需要的 electron-builder 在下载过程中有一些 binary 是从 github下的,比较慢。换成淘宝的镜像源就快多了。

我用的是 yarn, 所以写的是 .yarnrc,若使用的是 npm, 则写 .npmrc 是一样的。

yarn add electron -D
yarn add @types/electron -D
yarn add typescript -D
yarn add @types/node -D
创建各 electron 所需文件

electron 主进程文件 electron-main.ts

import {BrowserWindow, app, ipcMain, dialog} from 'electron'
import {join} from 'path'
import {ElectronChannel} from './ipc'

export const main = () => {
    onReady('dev')
    appListens()
}

const onReady = (type: 'dev' | 'prod') => {
    app.whenReady().then(() => {
        const mainWindow = createWindow(type)
        mainWindowListens(mainWindow)
    })
}

const mainWindowListens = (mainWindow: BrowserWindow) => {
    ipcMainHandles(mainWindow)
    ipcMainOnS(mainWindow)
}

const ipcMainOnS = (mainWindow: BrowserWindow) => {
}

const ipcMainHandles = (mainWindow: BrowserWindow) => {
    ipcMain.handle(ElectronChannel.openDialog, () => {
        dialog.showOpenDialog(mainWindow).then(v => {
            console.log(v)
        })
    })
}

const createWindow = (type: 'dev' | 'prod' = 'dev') => {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: join(__dirname, 'preload.js')
        }
    })
    if (type === 'dev') {
        win.loadURL('http://localhost:8000')
        win.webContents.openDevTools()
    } else if (type === 'prod') {
        const path = join(__dirname, 'dist', 'index.html')
        win.loadFile(path)
    }
    return win
}

const appListens = () => {
    app.on('window-all-closed', () => {
        if (process.platform !== 'darwin')
            app.quit()
    })
    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0)
            createWindow()
    })
}

electron app 入口文件 electron-app.ts

import {main} from './electron-main'

main()

渲染进程与主进程的沟通文件 preload.ts

import {ipcRenderer, contextBridge} from 'electron'
import {ElectronChannel, electronApi} from './ipc'

const api: IElectionApi = {
    openDialog: () => ipcRenderer.invoke(ElectronChannel.openDialog),
    startDrag: (fileName) => {
        ipcRenderer.invoke(ElectronChannel.onDragStart, fileName)
    }
}

contextBridge.exposeInMainWorld(electronApi, api)

进程间通信的定义文件 ipc.ts

export const electronApi = 'electronApi'
export enum ElectronChannel {
    openDialog = 'openDialog',
    onDragStart = 'onDragStart',
}

为了在前端项目中更方便地使用暴露的 electron api,也为了规范化,定制的文件 renderer.d.ts

export {}
import {electronApi} from './ipc'

declare global {
    interface IElectionApi {
        openDialog: () => Promise<any>
        startDrag: (fileName: string) => void
    }

    interface Window {
        [electronApi]: IElectionApi,
    }
}

创建 ts 配置文件 tsconfig.json

{
    "compilerOptions": {
        "baseUrl": ".",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "module": "commonjs",
        "moduleResolution": "node",
        "noImplicitAny": true,
        "outDir": "out",
        "paths": { },
        "removeComments": false,
        "sourceMap": true,
        "strict": true,
        "suppressImplicitAnyIndexErrors": true,
        "target": "esnext"
    },
    "include": [
        "ipc.ts",
        "electron-app.ts",
        "electron-main.ts",
        "preload.ts",
        "renderer.d.ts",
    ],
    "exclude": [
        "node_modules",
        "umi",
    ]
}
搭建一个前端项目

这块用什么都行,我这里用的是umi。跟着官方教程走一遍
注意:在项目中新建一个目录(我这里新建的目录叫 umi ),在该目录里面搭建 umi 的前端项目

所有文件创建完毕,开始将 electron 跑起来

把 umi 项目跑起来

cd umi
yarn && yarn start

修改根目录 package.jsonscript 字段新增字段 electron:dev

"scripts": {
    "electron:dev": "tsc && electron out/electron-app.js"
  },

把 electron 跑起来

yarn && yarn run electron:dev

过一会就能打开一个客户端,内容是 umi 的界面。

构建 – electron-builder

下载 electron-builder

yarn add electron-builder -D

根目录下创建构建的配置文件 electron-builder.yml

更多配置文件参考官方文档

appId: "haha.app"
asar: false
win:
  target: portable
electronDownload:
  # version: 0.0.2
  # isVerifyChecksum: false
  platform: win32

package.json 文件 script 字段新增字段 electron:build

"scripts": {
    "electron:dev": "tsc && electron out/electron-app.js",
    "electron:build": "tsc && electron-builder",
    "electron:build:debug": "DEBUG=electron-builder electron-builder"
  },

进入 umi 项目,将该项目打包构建,生成文件夹 umi/dist/

cd umi
yarn build

返回项目根目录,构建 electron 客户端

yarn run electron:build

过一会就能在项目根目录 dist 文件夹看到文件 my-electron 1.0.0.exe,windows下双击即可打开

展望未来 – auto update

electron 实际的更新场景应该是两个。

  1. 每次都把最新的客户端生成,然后发送给用户。
  2. 客户端自行发现有更新,提醒用户下载更新。

这两种场景适用不同场合。我认为第一种场景适用于用户的环境比较封闭,甚至处于离线的状态。对于外来的软件,都是由网管统一安装,这样更新虽然麻烦一些,但是胜在稳定。第二种场景适用于用户量很大,而且可能很分散,没有特殊要求的话让用户自行更新其实效率会更高。

暂时我还没走通自动更新的流程,看了一下网上大概思路有两个

  1. exe全量更新
  2. 局部热更新

而更新的方案及使用的库大概有几种

  1. 官方推荐的方案,看这里
  2. electron-updater

待我走通之后,找到最佳实践,再来更新一篇吧

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值