讲electron之前先说下 B/S、C/S 虽然B/S是目前开发的主流,但是C/S仍然有很大的市场需求
C/S 即Client/Server,客户端/服务器 架构,主要应用于局域网内 是一种典型的两层架构。客户端:用户程序(表示层) 服务器端:一种是数据库服务器,一种是Socket服务器。(数据库层)
B/S 即Browser/Server,浏览器/服务器 架构,主要应用于广域网中 三层:Browser客户端、webapp服务器端和DB(数据库)端。
Electron是一个基于Chromium和 Node.js,使用 HTML、CSS和JavaScript来构建跨平台应用的跨平台开发框架,
技术组成:Electron = Chromium + Node.js + Native API
兼容 Mac、Windows 和 Linux。
目前,Electron已经创建了包括 VScode 和 Atom 在内的大量应用
简单来说就是Electron是构建桌面应用(区别手机应用)的,再直白点比如电脑的酷狗音乐,在windows和mac上都能用
桌面端的开发方式主要有 Native 、 QT 、 Flutter 、 NW 、 Electron 、 Tarui
其各自优劣势如下表格 | 选型 | 性能 | 包体积 | 安全 | 迭代速度 | 跨平台 | 生态和社区 | | :—— | :—— | :—— | :—— | :—— | :—— | :—— | | Native | 高 | 小 | 安全 | 慢 | 不跨 | 强大 | | QT | 高 | 小 | 安全 | 一般 | 跨 | 强大 | | Tarui | 高 | 小 | 安全 | 慢 | 跨 | 小,不成熟 | | Flutter | 暂无 | 暂无 | 暂无 | 暂无 | 跨 | 小 | | NW | 一般 | 大 | 安全 | 快 | 跨 | 强大 | | Electron | 一般 | 大 | 不安全 | 快 | 跨 | 非常强大 |
数据库 lowdb electron 应用数据库有非常多的选择如 lowdb 、 sqlite3 、 electron-store 、 pouchdb 、 dedb 、 rxdb 、 dexie 、 ImmortalDB 等。这些数据库都有一个特性,那就是无服务器
electron 应用数据库技术选型考虑因素主要有以下3点:
生态(使用者数量、维护频率、版本稳定度)
能力
性能
其他(和使用者技术匹配度)
四个最优选择,分别是 lowdb 、 sqlite3 、 nedb 、 electron-store , 理由如下:
lowdb: 生态、能力、性能三方面表现优秀, json 形式的存储结构, 支持 lodash 、 ramda 等 api 操作,利于备份和调用
sqlite3: 生态、能力、性能三方面表现优秀, Nodejs 关系型数据库第一选择方案
nedb: 能力、性能三方面表现优秀,缺点是基本不维护了,但底子还在,尤其操作是 MongoDB 的子集,对于熟悉 MongoDB 的使用者来说是绝佳选择。
electron-store: 生态表现优秀,轻量级持久化方案,简单易用
数据库选型是 lowdb 方案。
PS:提一下 pouchdb ,如果需要将本地数据同步到远端数据库,可以使用 pouchdb ,其和 couchdb 可以轻松完成同步。
环境搭建 创建Electron跨平台应用之前,需要先安装一些常用的工具,如Node、vue和Electron等 node(v16.14.2,高了会报错)、vue都不说了,都知道怎么安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 npm install -g electron electron --version mkdir my-electron-demo && cd my-electron-demo vue init simulatedgreg/electron-vue npm install node-sass@latest vue create myproject cd myproject vue add electron-builder (如果看过我之前写的vue2和vue3共存的文章的话,这里要这么写:vue3 add electron-builder) npm install npm run electron:serve npm run electron:build npm install --save-dev electron npm install --save-dev electron@latest
升级electron最新版(vue-cli安装后electron是13.0.0升级到最新版) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 npm install --save-dev electron@latest DeprecationWarning : Invalid 'main' field in 'C:\Users\BEIBEI\Desktop\my-electron-vue\dist_electron\package.json' of 'background.js' . Please either fix that or report it to the module author解决方法 修改根目录配置文件vue.config.js module .exports = defineConfig({ transpileDependencies : true }) module .exports = defineConfig({ pluginOptions : { electronBuilder : { chainWebpackMainProcess : (config ) => { config.output.filename((file ) => { if (file.chunk.name === "index" ) { return "background.js" ; } else { return "[name].js" ; } }); }, }, }, transpileDependencies : true }) 再次启动 npm run electron:serve 就可以了 Vue Devtools failed to install: Error : net::ERR_CONNECTION_TIMED_OUT 这是因为没有安装vue devtools npm install electron-devtools-installer --save-dev (很久没更新了,不推荐) vue3安装electron vue-tools要装beta版本, 详情参考下面这个地址 (https:
打包 编辑根目录文件package.json,添加描述和作者 1 2 3 4 5 6 7 "name" : "my-electron-vue" ,"name" : "my-electron-vue" ,"description" : "my electron+vue project" ,"author" : "author" ,
添加图标
桌面应用图标: 桌面应用图标大小256*256,且后缀为【.ico】。网页生成ico
在package.json中/vue.config.js中配置图标路径 (package.json中/vue.config.js中,这里配置的是控制打包后的桌面快捷方式的图标) ,如下,这是electron-builder(安装版方式),免安装版配置在执行命令中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 "build" : { "appId" : "com.example.app" , "productName" :"aDemo" , "copyright" : "Copyright © 2019" , "directories" :{ "output" :"./dist" }, "nsis" : { "oneClick" : false , "allowElevation" : true , "allowToChangeInstallationDirectory" : true , "installerIcon" : "./XXX/logo.ico" , "uninstallerIcon" : "./XXX/logo.ico" , "installerHeaderIcon" : "./XXX/logo.ico" , "createDesktopShortcut" : true , "createStartMenuShortcut" : true , "shortcutName" : "idea" , "include" : "build/script/installer.nsh" , "script" : "build/script/installer.nsh" , }, "win" : { "icon" : "public/icons/icon.ico" , "target" : [ { "target" : "nsis" , "arch" : [ "x64" , "ia32" ] } ] }, "mac" : { "icon" : "public/icons/icon.ico" }, "linux" : { "icon" : "public/icons/icon.ico" }, }, vue3-Electron 窗口图标在测试时不变化,打包后改变,目前的现象是如此,配置可以写在vue.config.js中如下: pluginOptions : { electronBuilder : { builderOptions : { appId : "com.example.app" , productName :"aDemo" , copyright : "Copyright © 2019" , directories :{ output :"./dist" }, nsis : { oneClick : false , allowToChangeInstallationDirectory : true , installerIcon : "./public/icon.ico" , installerHeaderIcon : "./public/icon.ico" createDesktopShortcut : true , }, win : { icon : './public/icon.ico' }, "mac" : { "icon" : "./public/icon.ico" }, "linux" : { "icon" : "./public/icon.ico" }, productName : "vfirstss" , } } }
窗口图标 在主进程文件index.js(可能你的主进程文件叫main.js或者别的,我的叫background.js,总之领会精神就好,哈哈哈),这里配置的是窗口图标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 mainWindow = new BrowserWindow({ ...... height : 600 , width : 1020 , webPreferences : { ... nodeIntegration : true }, + icon: path.join(__dirname, './XXX/logo20.ico' ), }) 发现并没有变化?这个其实是正常的,BrowserWindow 对象的 icon 属性只对 windows/Linux 系统生效,对于 Mac OS 需要通过 app.dock.setIcon 进行设置 mainWindow = new BrowserWindow({ ...... height : 600 , width : 1020 , webPreferences : { ... nodeIntegration : true }, ++ icon: path.join(__dirname, 'assets/images/facetime.png' ), }) ++ if (process.platform === 'darwin' ) { ++ app.dock.setIcon(path.join(__dirname, 'assets/images/facetime.png' )); ++ }
设置标识 我们经常会发现图标右上方会有消息通知(Dock badges),比如 App Store 有多少个已安装的软件可以更新,QQ 上有多少条未读的消息等等。这个 Dock 标识在 Electron 中要如何设置呢?
我们可以通过 app.dock.setBadge
API 进行设置。下面我们实现当应用窗口失去焦点时让消息通知的标识加1的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 function createWindow ( ) { mainWindow = new BrowserWindow({ width : 800 , height : 600 , webPreferences : { nodeIntegration : true }, icon : path.join(__dirname, 'assets/images/facetime.png' ) }); if (process.platform === 'darwin' ) { app.dock.setIcon(path.join(__dirname, 'assets/images/facetime.png' )); } mainWindow.loadFile('index.html' ); mainWindow.on('close' , function ( ) { mainWindow = null ; }); ++ mainWindow.on('blur' , () => { ++ const badgeString = app.dock.getBadge(); ++ if (badgeString === '' ) { ++ app.dock.setBadge('1' ); ++ } else { ++ app.dock.setBadge((parseInt (badgeString) + 1 ).toString()); ++ } ++ }); }
在项目中运行以下命令打包项目
等待打包完成 windows安装程序生成位置在 dist_electron\项目名 Setup 0.1.0.exe
windows免安装程序生成位置在 dist_electron\win-unpacked(绿色免安装包)\项目名
mac安装程序生成位置在 dist_electron\项目名-0.1.0.dmg
应用工程目录 使用electron-vue(vue2)模版创建的Electron工程结构如下图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 和前端工程的项目结构类似,Electron项目的目录结构如下所示: electron-vue:Electron模版配置。 build:文件夹,用来存放项目构建脚本。 config:中存放项目的一些基本配置信息,最常用的就是端口转发。 node_modules:这个目录存放的是项目的所有依赖,即 npm install 命令下载下来的文件。 src:这个目录下存放项目的源码,即开发者写的代码放在这里。 static :用来存放静态资源。 index.html:则是项目的首页、入口页,也是整个项目唯一的HTML页面。 package.json:中定义了项目的所有依赖,包括开发时依赖和发布时依赖 对于开发者来说, 90 % 的工作都是在 src 中完成,src 中的文件目录如上图所示 【主进程】 Electron 运行 package.json 的 main 脚本(background.js)的进程被称为主进程。在主进程中运行的脚本通过创建web页面来展示用户界面。一个 Electron 应用总是有且只有一个主进程。 【渲染进程】 由于 Electron 使用了 Chromium 来展示 Web 页面,所以 Chromium 的多进程架构也被使用到。每个 Electron 中的 Web 页面运行在它自己的渲染进程中。在普通的浏览器中,Web页面通常在一个沙盒环境中运行,不被允许去接触原生的资源。然而 Electron 允许用户在 Node.js 的 API 支持下可以在页面中和操作系统进行一些底层交互 【主进程与渲染进程通信】 主进程使用 BrowserWindow 实例创建页面。每个 BrowserWindow 实例都在自己的渲染进程里运行页面。当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。主进程管理所有的Web页面和它们对应的渲染进程。每个渲染进程都是独立的,它只关心它所运行的 Web 页面 src目录结构 在Electron目录中,src会包包含main和renderer两个目录 main目录 main目录会包含index.js和index.dev.js两个文件。 index.js:应用程序的主文件,electron 也从这里启动的,它也被用作 webpack 产品构建的入口文件,所有的 main 进程工作都应该从这里开始。 index.dev.js:此文件专门用于开发阶段,因为它会安装 electron-debug 和 vue-devtools。一般不需要修改此文件,但它可以扩展开发的需求。 渲染进程 renderer是渲染进程目录,平时项目开发源码的存放目录,包含assets、components、router、 store、App.vue和main.js。 assets:assets下的文件如(js、css)都会在dist文件夹下面的项目目录分别合并到一个文件里面去。 components:此文件用于存放应用开发的组件,可以是自定义的组件。 router:如果你了解vue-router,那么Electron项目的路由的使用方式和vue-router的使用方式类似。 modules:electron-vue 利用 vuex 的模块结构创建多个数据存储,并保存在 src/renderer/store/modules 中。
打包并分发应用程序 官网说 最快捷的打包方式是使用 Electron Forge
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 npm install --save-dev @electron-forge/cli npx electron-forge import ✔ Checking your system ✔ Initializing Git Repository ✔ Writing modified package.json file ✔ Installing dependencies ✔ Writing modified package.json file ✔ Fixing .gitignore We have ATTEMPTED to convert your app to be in a format that electron-forge understands. Thanks for using "electron-forge" !!! npm run make > my-electron-app@1.0 .0 make /my-electron-app > electron-forge make ✔ Checking your system ✔ Resolving Forge Config We need to package your application before we can make it ✔ Preparing to Package Application for arch: x64 ✔ Preparing native dependencies ✔ Packaging Application Making for the following targets: zip ✔ Making for target: zip - On platform: darwin - For arch: x64 out/ ├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0 .0 .zip ├── ... └── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app
Electron源码目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 Electron ├──atom - Electron 的源代码 | ├── app - 系统入口代码 | ├── browser - 包含了主窗口、UI 和其他所有与主进程有关的东西,它会告诉渲染进程如何管理页面 | | ├── lib - 主进程初始化代码中 JavaScript 部分的代码 | | ├── ui - 不同平台上 UI 部分的实现 | | | ├── cocoa - Cocoa 部分的源代码 | | | ├── gtk - GTK+ 部分的源代码 | | | └── win - Windows GUI 部分的源代码 | | ├── default_app - 在没有指定 app 的情况下 Electron 启动时默认显示的页面 | | ├── api - 主进程 API 的实现 | | | └── lib - API 实现中 Javascript 部分的代码 | | ├── net - 网络相关的代码 | | ├── mac - 与 Mac 有关的 Objective-C 代码 | | └── resources - 图标,平台相关的文件等 | ├── renderer - 运行在渲染进程中的代码 | | ├── lib - 渲染进程初始化代码中 JavaScript 部分的代码 | | └── api - 渲染进程 API 的实现 | | └── lib - API 实现中 Javascript 部分的代码 | └── common - 同时被主进程和渲染进程用到的代码,包括了一些用来将 node 的事件循环 | | 整合到 Chromium 的事件循环中时用到的工具函数和代码 | ├── lib - 同时被主进程和渲染进程使用到的 Javascript 初始化代码 | └── api - 同时被主进程和渲染进程使用到的 API 的实现以及 Electron 内置模块的基础设施 | └── lib - API 实现中 Javascript 部分的代码 ├── chromium_src - 从 Chromium 项目中拷贝来的代码 ├── docs - 英语版本的文档 ├── docs-translations - 各种语言版本的文档翻译 ├── spec - 自动化测试 ├── atom.gyp - Electron 的构建规则 └── common.gypi - 为诸如 `node` 和 `breakpad` 等其他组件准备的编译设置和构建规则 平时开发时,需要重点关注的就是src、package.json和appveyor.yml目录。除此之外,其他需要注意的目录如下: · script - 用于诸如构建、打包、测试等开发用途的脚本 · tools - 在 gyp 文件中用到的工具脚本,但与 script 目录不同, 该目录中的脚本不应该被用户直接调用 · vendor - 第三方依赖项的源代码,为了防止人们将它与 Chromium 源码中的同名目录相混淆, 在这里我们不使用 third_party 作为目录名 · node_modules - 在构建中用到的第三方 node 模块 · out - ninja 的临时输出目录 · dist - 由脚本 script/create-dist.py 创建的临时发布目录 · external_binaries - 下载的不支持通过 gyp 构建的预编译第三方框架
热更新 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 yarn add --dev electron-reloader const { app, BrowserWindow } = require ('electron' ) const reLoader=require ("electron-reloader" )reLoader(module ) app.on("ready" ,()=> { const mainWindow = new BrowserWindow({ width : 700 , height : 700 }) mainWindow.loadFile('./src/index.html' ).then() })
1
PS APP窗口大小 修改background.js:
1 2 3 4 5 6 7 8 9 10 function createWindow ( ) { win = new BrowserWindow({ + width: 1200 , + height: 620 , webPreferences : { nodeIntegration : true } }) }
取消跨域限制 修改background.js:
1 2 3 4 5 6 7 8 9 10 11 function createWindow ( ) { win = new BrowserWindow({ width : 1200 , height : 620 , webPreferences : { + webSecurity: false , nodeIntegration : true } }) }
取消菜单栏 在我们生成的桌面APP中,我们可以看到默认的菜单栏。
在windows中,菜单栏在APP窗口内的顶部;在macOS中,菜单栏位于电脑屏幕顶部。
为了方便项目将来也能直接生成纯web应用,尽量把APP的全部功能都做到渲染进程里,这里我们取消菜单栏。
由于macOS的特殊性,顶部菜单栏无法删除,所以我们针对macOS特殊处理,把菜单栏只保留“关于”和“退出”。
修改background.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 + import { app, protocol, BrowserWindow, Menu } from 'electron' ... function createWindow ( ) { ... win.on('closed' , () => { win = null }) + createMenu() } + + function createMenu ( ) { + + if (process.platform === 'darwin' ) { + const template = [ + { + label: 'App Demo' , + submenu: [ + { + role: 'about' + }, + { + role: 'quit' + }] + }] + let menu = Menu.buildFromTemplate(template) + Menu.setApplicationMenu(menu) + } else { + + Menu.setApplicationMenu(null ) + } + } macOS菜单栏名称label的“App Demo”会在build版本生效,dev版本会显示“Electron”