蘑菇街前端团队正式入驻掘金,但愿你们不要吝啬大家手中的赞(比心)!javascript
Electron 咱们会出一个系列,这篇文章主要是介绍 Electron 基础相关的东西,后续会出咱们在实战中更多的技巧以及问题的解决方案,但愿你们持续关注咱们。html
本文主要包括:前端
Electron
是一个赋力前端进行跨平台开发的框架,让开发人员使用 JavaScript, HTML 和 CSS 等前端技术构建跨平台的桌面应用。 Electron
经过将 Chromium
和 Node.js
合并到同一个运行时环境中,并将其打包为 Mac,Windows 和 Linux 系统下的应用,而开发人员只需关注前端代码的开发。java
electron 提供了一个名为 electron-quick-start 的项目,能够 clone 下来当成模版使用,本文仍是使用 create-react-app 来一步一步学习。node
# 安装 create-react-app 命令,若是已将安装请忽略
npm install -g create-react-app
# 建立 electron-react 项目
create-react-app electron-react
# 启动项目
cd electron-react && npm start
复制代码
浏览器打开 localhost:3000 出现下面的画面:react
在 public 文件夹下新建 index.html,随便写点内容:webpack
...
<div>hello world</div>
...
复制代码
接下来建立 electron 主线程文件,public/main.js,建议写在 public 路径下面。git
const {app, BrowserWindow} = require('electron')
// 建立全局变量并在下面引用,避免被GC
let win
function createWindow () {
// 建立浏览器窗口并设置宽高
win = new BrowserWindow({ width: 800, height: 600 })
// 加载页面
win.loadFile('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
// 添加window关闭触发事件
win.on('closed', () => {
win = null // 取消引用
})
}
// 初始化后 调用函数
app.on('ready', createWindow)
// 当所有窗口关闭时退出。
app.on('window-all-closed', () => {
// 在 macOS 上,除非用户用 Cmd + Q 肯定地退出,
// 不然绝大部分应用及其菜单栏会保持激活。
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// 在macOS上,当单击dock图标而且没有其余窗口打开时,
// 一般在应用程序中从新建立一个窗口。
if (win === null) {
createWindow()
}
})
复制代码
最后,修改 package.json 中的 main 字段对应的路径, 并添加 start 命令github
{
...
"main": "main.js",
"scripts": "electron ."
}
复制代码
执行 npm start, 就会弹出以下界面:web
这里我简单写了一个页面,你们也能够写一写本身感兴趣的东西。
因而,一个简单的桌面应用就开发好了,真的 so easy.
electron 的进程分为主进程
和渲染进程
先来看看 electron 项目基本目录结构
app
└─public
└─index.html---------------入口文件
├─main.js----------------------程序启动入口,主进程
├─ipc--------------------------进程间模块
├─appNetwork-------------------应用通讯模块
└─src--------------------------窗口管理,渲染进程
├─components---------------通用组件模块
├─store--------------------数据共享模块
├─statics------------------静态资源模块
└─pages----------------------窗口业务模块
├─窗口A----------------窗口
└─窗口B----------------窗口
复制代码
package.json 中的 main
字段对应的文件的进程是主进程
。Electron集成了Chromium来展现窗口界面,窗口中所看到的内容使用的都是HTML渲染出来的。 Chromium自己是多进程渲染页面的架构(在默认状况下,Chromium的默认策略是对每个tab新开一个进程,以确保每一个页面是独立且互不影响的。避免一个页面的崩溃致使所有页面没法使用),因此Electron在展现窗口时,也会使用到Chromium的多进程架构。而这种多进程渲染架构在Electron中,就被称之为渲染进程(render process)
。
在 electron 中,GUI 相关的模块(如 dialog,menu 等)仅在主进程可用,在渲染进程中不可用。为了在渲染进程中使用它们,须要使用 ipc
模块向主进程发送消息,下面是几种进程间通信的方法。
从主进程到渲染进程的异步通讯,也能够将消息从主进程发送到渲染进程,参考 webContents.send.
发送消息时,事件名称为 channel。
回复同步消息时,须要设置 event.returnValue。
将异步消息发送回发送方,可使用 event.reply(...),这个辅助方法将自动处理来自渲染进程的消息,然而 event.sender.send(...) 这个方法则始终将消息发送给主进程。
下面是在渲染和主进程之间发送和处理消息的一个例子:
// 在主进程中
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg); // 输出 'ping'
event.reply('asynchronous-reply', 'pong');
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // 输出 ‘ping’
event.returnValue = 'pong'
})
复制代码
// 在渲染进程(网页)中
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // 输出 'pong'
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg); // 输出 'pong'
})
ipcRenderer.send('asynchronous-message', 'ping')
复制代码
remote
为渲染进程
和主进程通讯提供了一种简单的方法。你能够调用 main 进程对象的方法,而没必要显式发送进程间消息。例如:从渲染进程建立浏览器窗口
const { BrowserWindow } = require('electron').remote
let win = new BrowserWindow({ width: 800, height: 600 })
win.loadUrl('https://www.mogu.com')
复制代码
注意: 反过来(若是须要从主进程访问渲染进程),可使用 webContents.executeJavascript。
经过
channel
向渲染进程发送异步消息,能够发送任意参数。在内部,参数会被序列化为 JSON,所以参数对象伤的函数和原型链不会被发送
除了以上这些方法,也可使用 localStorage、sessionStorage 等。
开发完成后,还须要将应用打包成可执行文件,这一环节的坑仍是学习 electron 到如今踩的最多的。
目前主流的打包工具备 electron-packager 和 electron-builder
安装依赖:
npm i electron-packager --save-dev
打包:
electron-packager <sourcedir> <appname> --platform=<platform> --arch=<arch> [optional flags...]
也能够直接运行 npm run electron-packager .
打包。
官方解释:
A complete solution to package and build a ready for distribution Electron, Proton Native or Muon app for macOS, Windows and Linux with “auto update” support out of the box.
简单的说,electron-builder 有比 electron-packager 更丰富的功能,支持更多的平台,同时也支持了自动更新。除了这几点外,electron-builder 打出的包更为轻量,而且能够打包出不暴露源码的 setup 安装程序。另外使用下来感受比 electron-packager 的坑要少一点。
安装依赖:
npm i electron-builder --save-dev
复制代码
打包:
package.json
文件中定义 build
字段{
"build": {
"appId": "com.xxx.app",
"extends": null,
"files": [
"build/**/*"
],
"mac": {
"icon": "icons/icon.icns"
},
"win": {
"target": "nsis",
"icon": "icons/icon.png"
}
}
}
复制代码
这是最基础的配置,固然打包过程当中可能会碰到其余的问题须要修改配置。一般 files 配置只写一个 build 文件夹是不够的,要根据项目结构和打包状况添加其余路径。
{
"scripts": {
"pack": "electron-builder"
}
}
复制代码
打包完成后在 dist 目录下有可执行文件,打开后若是没有报错,则说明打包成功。
大部分都是打包遇到的坑
Generated checksum for "electron-v6.0.2-darwin-x64.zip" did not match expected checksum。node 版本升级到 8.x 以上就好。
出现这种问题可能有如下几个缘由:
"build": {
...
+ "public/main.js"
...
}
复制代码
const remote = require('remote')
const app = remote.require('app')
console.log(app.getAppPath());
复制代码
在 electron 打包时,必定要分清哪些是生产环境依赖,哪些是开发环境依赖。避免出现此类错误:
cnpm 装的各类 node_modules,这种方式下全部的包都是扁平化的安装,一会儿 node_modules 展开就有很是多的文件,致使打包的过程很是慢。可是若是该用 npm 来安装 node_modules 的话,全部的包都是树状结构,层级变深。可是打包速度会快不少。具体见:electron打包过了2小时都没好?