Electron 入门 01 | 安装和运行 Hello World

360 阅读10分钟

 hello,今天要和大家分享的是一个可以扩展自身在前端的应用实践领域和增加求职面试加分项的前端框架 Electron。

 大家熟悉的 Web 端、手机 App、h5 和小程序等都有对应的前端解决方案,也涌现出很多兼容性较好的框架。前端技术栈几乎在所有不同的端中都有比较成熟的应用。相对于手机 App 和小程序如火如荼的发展,前端技术栈基于桌面系统的应用软件开发正在悄然升温,其中最成熟的前端框架就是 Electron。学习它,不仅能扩展我们前端开发者的应用场景,提升自己的技术竞争力,也能在面值求职中体现出技术深度获得加分。

 本讲我们将用最简洁的方式来展示出 Electron 启动。你会发现在学习过程中没有任何阻碍。因为全是大家熟悉的前端语言。

Electron 框架简介

Electron 是一个用前端技术 HTML、JS 和 CSS 来构建跨平台(Windows,Linux,Mac)的桌面应用程序的框架。它的最终产出是基于操作系统的安装包,如 exe、dmg 等。开发技术则是前端技术栈。我们可以像开发前端 Web 应用一样来开发一个桌面应用软件,最后构建打包即可。

Electron 内嵌了 Chrome 内核用于运行 JavaScript,可以方便的使用 ES6 或者 Node.js 的 API,所以不用关心浏览器兼容问题。除了能够使用第三方 NPM 包以外,Electron 本身还提供了丰富的 API 来帮助实现常用的基于操作系统的本地功能,比如打开一个原生对话框或原生窗口。

Electron 是开源的,由 GitHub 维护,社区非常活跃,文档资料齐全。包括 Visual Studio Code、Atom 以及 钉钉、飞书等后起之秀,多款常用软件都是基于其开发的,因此 Electron 未来的发展和稳定性定是经得住考验的。 怎么样? 是不是发现前端的能力居然这么强大。我们现在已经对 Electron 有一个初步认识了,也知道它具体是做什么的。下面,我们先从安装 Electron 的 npm 包开始,了解 Electron 的使用方式。

安装和运行

请确保已经安装好 Node.js,这里不再介绍 Node.js 的安装。首先我们初始化一个新项目,然后安装 Electron 的 NPM 包:

npm init
npm install electron

这时框架已经准备好了,这里需要介绍下 Electron 的整体结构,Electron 的运行是由主进程渲染进程组成的。

主进程可以简单理解为整个应用的控制台,应用的启动、生命周期和一些与操作系统的交互都在主进程里面。它其实就是一个 js 文件。当我们的应用启动时,其实执行的就是这个文件。在这个文件里面我们可以调用 API 来打开多个窗口,并且告诉这些窗口加载哪个 html 文件。

渲染进程可以先简单理解为就是由主进程打开的这些窗口。这些窗口展示的内容就是由我们的 HTML 生成的内容,这些窗口就像浏览器一样将 HTML 渲染出来,每一个窗口都是一个独立的渲染进程。我们的大部分业务逻辑都是在渲染进程中完成的。   接下来,我们为 Electron 创建主进程文件 main.js,并且书写代码让其在运行时打开一个窗口,如下所示:

// main.js
const { app, BrowserWindow } = require('electron')
// 定义一个方法用于创建窗口
function createWindow () {
  // new 一个窗口实例
  const win = new BrowserWindow({
    width: 800,
    height: 600
  })
  win.loadFile('index.html')
}
// 应用准备好后调用打开窗口的方法 
app.whenReady().then(createWindow)

上面代码我们从 Electron 中引入了两个对象 App 和 BrowserWindow。App 是管理整个应用的生命周期的,而 BrowserWindow 则是 Electron 提供给我们用于窗口管理的。一个 BrowserWindow 实例则是一个新的窗口,它提供了窗口相关的所有操作。它们的所有 API 在官网都有罗列。

上面 main.js 中的代码含义就是在 Electron 初始化完成后,新开一个宽 800,高 600 的窗口。窗口的内容则是 index.html。

主进程创建完成了,接下来我们添加渲染进程的 index.html,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>Hello World!</div>
</body>
</html>

然后我们就可以来运行这个应用了,Electron 的运行指令是 electron ., 我们将其添加到 package.json 中即可。上面讲了 main.js 是我们的应用入口,所以需要修正一下 package.json 中的默认入口(注意:package.json 中不能有注释)。其中 name 属性表示应用的名称,main 属性表示应用启动入口,即 main.js,version 表示当前软件的版本号,自动升级也会用到。这些都是可以自己定义和修改的。

{
    "name": "electron-app",
    "version": "0.1.0",
    "author": "your name",
    "description": "My Electron app",
    "main": "main.js",
    "scripts": {
        "start": "electron ."
    }
}

最后在命令行执行 npm start,至此我们的 demo 程序就运行起来了,效果如下:

image.png

入门进阶

上面我们已经完成了最简单的 hello world 运行。也了解到 Electron 中主进程是一个用来启软件的 js 入口文件,渲染进程是一个主进程用来启动一个窗口的 html 入口文件。那么下面我们在此基础上稍微补充一些经验之谈。

目录调整

上面的例子中所有文件都是在同一层目录的。接下来,我们结合实际经验,对它们的目录进行一下简单调整。

实际项目中渲染进程会承担大部分业务逻辑(即用户能看到、能操作的内容),也可能用到前端框架来开发,而主进程除了控制应用的基本生命周期外,还可能承担一些其他逻辑,诸如通信等。所以我们一般会将主进程(main.js)和渲染进程独立成两个不同的目录来管理,如下图,因此我们可以在 Render 目录中基于 Vue 或 React 来构建单页应用。这样就能方便地开发各个模块功能。

image.png

主进程补充

至此,你已经了解最简单的主进程代码已经足以运行起整个应用了。不过实际项目中,有很多特别有用的配置支持我们设置,比如我们打开一个窗口时除了 loadFile() 本地的 HTML,也可以通过 locaURL() 加载远程的 http 路径,还有窗口的工具栏也可以自定义配置。下面稍微完善一下主进程的代码,请参考里面的注释,更详细的参数可查看 Electron 官网

// main.js
const { app, BrowserWindow } = require('electron')
function createWindow () {
  const win = new BrowserWindow({
    show: false, // 窗口最开始隐藏
    backgroundColor: '#ffffff', // 设置窗口默认背景是白色
    width: 800,
    height: 600,
    resizable: true, // 窗口是否允许调整尺寸
    movable: true, // 窗口是否可拖动
    minimizable: true, // 是否可以最小化
    maximizable: true, // 是否可以最大化
    webPreferences: {
      nodeIntegration: true // 允许渲染进程访问 nodejs api
    }
  })
  // 等到窗口内容准备好了再显示出来,避免白屏
  win.once('ready-to-show', () => {
    win.show()
  })
  win.loadFile('dist/index.html')
  // 打开窗口的调试面板,就像浏览器控制台一样
  win.webContents.openDevTools();
}
app.whenReady().then(createWindow)

编译构建

前面的 Hello world 示例是最原始的页面。如果我们的 JS 需要编译,比如用到 Vue、React 或最新的 ES6 语法后,那只需要通过 Webpack 分别编译出 Main 和 Render 两个目录下的入口文件即可。然后修改 package.json 中的入口字段为编译后的路径。所以我们需要创建两个 Webpack 的配置文件,分别编译主进程和渲染进程的源代码(因为主进程和渲染进程是两个进程的独立入口),如下所示:

// 渲染进程 webpack 配置 render.webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');


module.exports = {
  entry: './src/render/index.js',
  target: 'electron-renderer', // 渲染进程
  output: {
    filename: 'index.js',
    path: path.resolve(__dirname, '../dist'),
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/render/index.html',
    })
  ]
};
// 主进程 webpack 配置 main.webpack.config.js
const path = require('path');


module.exports = {
  entry: './src/main/main.js',
  target: 'electron-main',// 主进程
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, '../dist'),
  }
};

注意上面配置中 target 字段的区别,主进程中我们一般配置为“electron-main”, 因为主进程实际运行时的环境是 Electron 为其提供的 Node.js 的环境;而渲染进程我们前面说了其实就是一个 Chrome 浏览器的环境,所以配置成“electron-renderer”。举个例子:require 语法,我们可以在 Node.js 中直接使用,但是在浏览器环境就需要 Webpack 帮我们转换一下。所以 Webpack 会根据不同配置为我们生成不同的构建产物。

然后我们再调整一下 main.js 打开窗口的路径以及 package.json 中的字段。

// main.js
win.loadFile('dist/index.html')
// package.json
"main": "dist/main.js"

最后执行编译和运行。这样一个项目的工程雏形就差不多了。补充:其实上面的 Webpack 配置最终可以通过一个 js 文件合并起来,通过 JS 来调用 Webpack,而不是通过 Script 指令,这个不再详细讲解。

引入 Vue 或 React 框架

通过上面的学习,我们知道其实这和普通 Web 项目非常类似,既然可以尽情安装 npm 包,那么我们当然可以通过 Install Vue, 然后在 Render 目录构建一个 Vue 程序来应用 Vue 框架,React 同理。还可以通过 Vue 脚手架的 Electron-Vue 模板快速构建出 Electron+Vue 的应用,不过对于初学者前期不建议直接使用 Electron-Vue 这种高度集成的脚手架,因为这样会让我们前期就依赖框架而忽略它的内部过程,削弱我们后期排查问题的能力。实际上我们前期不依赖这种脚手架,也并不会复杂多少,因为上面的 demo 就已经完成一大部分了。

总结

本讲简单介绍了 Electron 的技术栈以及第一个 Demo 的安装运行方法,初步解释了主进程和渲染进程的结构和作用,主进程是用来启动软件运行和控制软件生命周期的进程,形式是一个 js 入口文件。渲染进程是一些以 html 页面为主的窗口。同时结合实际项目经验,初步划分了项目目录以及 Webpack 在 Electron 上的配置。最后了解了如何基于 Vue 或 React 框架构建 Electron 应用。

学完本讲,应该能徒手搭建起一个 Electron 初级应用。并且尝试书写一些带交互的功能。同时建议你可以去了解更多关于 BrowserWindow 的配置项。

本讲中体现出了 Electron 的入门运行时及其简单的一个过程,其实就是一个 npm 包的安装和调用过程。至于其强大的应用开发能力主要都集中在两个进程的编码运用中了。这里我们知道了主进程和渲染进程的大致配合方式。下一讲将更具体的介绍这两个进程的相关模块和能做的事情。

思考

我们知道了 Electron 软件的生命周期主要可以在主进程中控制,那么想一下,一个完整的桌面软件理应具备哪些生命周期呢?我们在开发过程中,在不同的生命周期一般有哪些必要的应用场景呢?