# 从零搭建Electron应用 的一系列简单的 Demo

标签: electron 应用 系列 | 发表时间:2020-04-03 16:11 | 作者:王玉略
出处:https://juejin.im/welcome/frontend

Electron 是一个优秀的跨平台桌面应用程序开源库,目前接触 Electron 的开发者也越来越多。但是笔者发现,目前社区里缺少对初学者足够友好的入门教程来帮助初学者用 Electron 搭建一个完整的开发框架。

为了解决这个问题,笔者将结合平时的一些 Electron 开发经验,渐近式的带领读者从零开始搭建一个完整的 Electron 应用。在这个教程中,笔者将使用 React 构建渲染进程。当然,读者也可以用其他框架来构建渲染进程,各种前端框架脚手架已经足够友好,所以这一点不用担心。

阅读完这篇教程,读者将会了解到:

  • Electron的核心知识点
  • 如何搭建一个最简单的 Electron
  • 如何将 Electron 和前端应用相结合
  • 如何配置 TypeScript 以保证代码质量
  • 如何跨平台打包 Electron 应用
  • 如何调试 Electron

笔者将通过以下 8 个小 Demo 来介绍上面的知识点,为了保证学习质量,建议读者手把手跟着练习这些 Demo,读者可以 点击这里来下载项目代码。

  • 搭建一个最简单的Electron
  • 从零搭建一个React应用(TypeScript,Scss,热更新)
  • 将 Electron 与 React 结合
  • 打包 Electron 应用
  • 实际开发一个小 Demo
  • 主进程使用 TypeScript 构建
  • 主进程监听文件变化并重启
  • 在 vscode 中调试主进程和渲染进程

在开始之前,我们先聊一聊 Electron 的基础概念

Electron 基础概念

Electron 是什么?

Electron 是一个可以用 JavaScript、HTML 和 CSS 构建桌面应用程序的库。这些应用程序能打包到 Mac、Windows 和 Linux 系统上运行,也能上架到 Mac 和 Windows 的 App Store。

Electron 由什么组成?

Electron 结合了 Chromium、Node.js 以及 操作系统本地的 API(如打开文件窗口、通知、图标等)。

一些历史

  • 2013年4月Atom Shell 项目启动 。

  • 2014年5月Atom Shell 被开源 。

  • 2015年4月Atom Shell 被重命名为 Electron 。

  • 2016年5月Electron 发布了 v1.0.0 版本 。

  • 2016年5月Electron 构建的应用程序可上架 Mac App Store 。

  • 2016年8月Windows Store 支持 Electron 构建的应用程序 。

Electron 基础架构

Electron 与 Chromium 在架构上很相似

Chromium运行时有一个 Browser Process,以及一个或者多个 Renderer Process

Renderer Process 顾名思义负责渲染Web页面。 Browser Process 则负责管理各个 Renderer Process 以及其他部分(比如菜单栏,收藏夹等等),如下图:

在 Electron中,结构仍然类似,不过这里是一个 Main Process 管理多个 Renderer Process

而且在 Renderer Process 可以使用 Node.js 的 API,这就赋予来 Electron 极大的能力,以下是主进程以及渲染进程可以访问到的API:

如何将 Chromium 与 Node 整合

Electron 最让人兴奋的地方在于 Chromium 与 Node 的整合。通俗的讲,我们可以在 Chromium 的控制台上做任何 Node 可以做的事。

能够做这个整合,首先得益于 Chromium 和 Node.js 都是基于 v8 引擎来执行 js 的,所以给了一种可能,他们是可以一起工作的。

但是有一个问题,Chromium 和 Node.js 的事件循环机制不同。我们知道,Node.js 是基于 libuv 的,Chromium 也有一套自己的事件循环方式,要让他们一起工作,就必须整合这两个事件循环机制。

如上图所示,Electron 采用了这样一种方式,它起了一个新的线程轮询 libuv 中的 backend fd,从而监听 Node.js 中的事件,一旦发现有新的事件发生,就会立即把它 post 到 Chromium 的事件循环中,唤醒主线程处理这个事件。

Electron 与 NW.js 的对比以及区别

和 Electron 同样出名的跨平台桌面应用开源库还有 NW.js。他们都有非常出名的应用,例如用Electron开发的有 vscode,用 NW.js 开发的有钉钉。

Electron 的原名叫 Atom ShellNW.js 的原名叫 node-webkit;他们起初是同一个作者开发,而且这个这个作者是国人,先向 大佬致敬,为我们开源这么优秀的开源工具。后来种种原因分为两个产品,一个命名为 NW.js(英特尔公司提供技术支持)、 另一命名为 Electron(Github 公司提供技术支持)。

两者在GitHub上的数据对比

  nw.js    (36.7k star,  4051 commits, 256 releases,  748 open issues,  5862 closed)
electron (81.7k star, 23364 commits, 849 releases, 1047 open issues, 11612 closed)
复制代码

可以看出 Electron 更加活跃。

两者程序的入口不同

NW.js 中,应用的主入口是网页或者JS脚本。 你需要在 package.json 中指定一个html或者js文件,一旦应用的主窗口(在html作为主入口点的情况下)或脚本被执行,应用就会在浏览器窗口打开。

Electron 中,入口是一个 JavaScript 脚本。 不同于直接提供一个URL, 你需要手动创建一个浏览器窗口,然后通过 API 加载 HTML 文件。 你还可以监听窗口事件,决定何时让应用退出。

Electron 的工作方式更像 Node.js 运行时 ,Electron 的 APIs 更加底层。

Node 集成

NW.js,网页中的 Node 集成需要通过给 Chromium 打补丁来实现。但在 Electron 中,我们选择了另一种方式:通过各个平台的消息循环与 libuv 的循环集成,避免了直接在 Chromium 上做改动。这就意味着 Electron 迭代的成本更低。

准备工作

有了上面这些基础概念,接下来开始将下面 8 个 Demo 的学习。

在开始之前,我们先做一些基础的准备,

安装依赖:

  yarn

# or

npm install
复制代码

为了防止意外报错,我们约定 cd 到每个 demo 里来运行相应 package.json 中的脚本。

以下的 demo 都将基于 Electron 8.0.0 版本讲解。

Demo01: 搭建一个最简单的 Electron

首先,我们会搭建一个最简单的 Electron 应用,它只有 3 个文件, 点这里查看Demo01代码

创建 demo01 目录:

1、新建 package.json 文件

  {
  "name": "demo01",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "../node_modules/.bin/electron ."
  }
}
复制代码

2、新建 index.html 文件

  
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!title>
  head>
  <body>
    <h1>Hello World!h1>
    We are using node <script>document.write(process.versions.node)script>,
    Chrome <script>document.write(process.versions.chrome)script>,
    and Electron <script>document.write(process.versions.electron)script>.
  body>
html>
复制代码

3、新建 main.js 文件

  const { app, BrowserWindow } = require('electron')

function createWindow () {   
  // 创建浏览器窗口
  let win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })

  // 加载index.html文件
  win.loadFile('index.html')
}

app.whenReady().then(createWindow)
复制代码

运行 yarn start,第一个 electron 项目就轻松启动起来了。

注意 package.json 中的 main 字段,它指定了 electron 的入口文件。

main.js 中,我们注意到, electron 模块所提供的功能都是通过命名空间暴露出来的。 比如说: electron.app 负责管理 Electron 应用程序的生命周期, electron.BrowserWindow 类负责创建窗口。

细心的同学注意到,Demo01 其实是 Electorn 官方文档中的 范例;是的,官方的范例写的非常简单友好,所以用它来作为我们一系列 Demo 的开始是非常好的选择。

Demo02: 从零搭建一个React应用

在 Demo02 中,我们会做一件与 Electron 无关事情 —— 从零搭建一个 React 应用。

在这个 React 应用中,我们将支持 TypeScript、Scss、热更新。

虽然说有 create-react-app 这样的的官方脚手架可以快速搭建项目,但是从零搭建可以将项目尽可能的在自己的掌控范围之内。

由于这个 Demo 与 本教程的主题无关,所以这边就不展开讲了,只展现一下 Demo 的目录结构:

  demo
└─src
  ├─index.tsx
  └─container
    └─App
      ├─index.tsx
      └─index.scss
├─index.html
├─package.json
├─tsconfig.json
└─webpack.config.js
复制代码

对这个 Demo 感兴趣的同学可以查看 Demo02代码

以下是这个 Demo 必要的相关依赖安装:

  # 安装 webpack 相关依赖
yarn add webpack webpack-cli webpack-dev-server -D
yarn add html-webpack-plugin -D 
# 安装 typescript 相关依赖
yarn add typescript ts-loader -D
# 安装 react 相关依赖
yarn add react react-dom
yarn add @types/react @types/react-dom -D
# 安装 scss 相关依赖
yarn add sass-loader node-sass -D
yarn add style-loader css-loader -D
复制代码

Demo03: 将 Electron 与 React 结合

众所周知,前端项目在浏览器运行,而 Electron 是在桌面环境中运行。

在 Demo03 中,我们将尝试在 Electron 运行 React 项目。在开发环境中,Electron 将引用 React 开发环境下的 URL,以保证获得 React 热更新的能力,这也是我们在这个 Demo 中要做的事情。

在下一个 Demo 中,我们还会讲到在 Electron 打包后,Electron 将引用 React 打包后的文件,以获得更好的性能。我们先来看这个 Demo。

首先,拷贝 Demo02 文件夹,将其改名为 Demo03,并进入 Demo03:

1、将 Demo01 中的 main.js 也拷贝过来,将 main.js 中的 createWindow 修改如下:

      function createWindow() {
      // 创建浏览器窗口
      let win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          nodeIntegration: true
        }
      })

+    win.loadURL('http://localhost:3000')
-    win.loadFile('index.html')
   }
复制代码

这样 Electron 就可以加载 React 开发环境项目了。

2、在 package.json 中将 script改成:

  {
  "start-electron": "../node_modules/.bin/electron .",
  "start": "../node_modules/.bin/webpack-dev-server --config webpack.config.js"
}
复制代码

其中 start 启动 React 项目, start-electron 启动 Electron 项目。

3、在 webpack.config.js 中的 devServer 里添加 after 钩子函数,以便在运行 react 项目后拉起 electron 项目:

  {
  after() {
    spawn('npm', ['run', 'start-electron'], {
      shell: true,
      env: process.env,
      stdio: 'inherit'
    })
      .on('close', code => process.exit(code))
      .on('error', spawnError => console.error(spawnError));
  }
}
复制代码

经过以上配置后,运行 yarn start 就可以同时把 React 项目 和 Electron 都启动起来了。

Demo03 详细的代码可以 戳这里查看。

Demo04: 打包 Electron 应用

在上面的Demo中,我们简单搭建了开发环境的项目配置,但是读者的心里可能还没底,它在打包后还能正常运行吗?

有过前端开发经验的同学就会知道,很多时候,明明开发环境项目运行的很好,但是一打包之后就出问题了。不是路径引用错误就是 找不到 icon。所以,为了打消同学们的顾虑,我们将在 Demo04 中实践如何打包 Demo03 中的项目。

首先,拷贝 Demo03 文件夹,将其改名为 Demo04,并进入 Demo04:

在开始之前,笔者先简单介绍一下 Electron 主流的两款打包工具 electron-packagerelectron-builder

electron-builder 在社区相对更加活跃,而且笔者项目实际开发中用的也是 electron-builder ,于是我们在这个demo中也用 electron-builder 来打包 Electron。

1、由于打包需要当前目录有 Electron 可执行文件,所以所以首先安装 Electron

  yarn add [email protected] -D
复制代码

2、在 package.json 中加入 build 字段,这个字段会告诉 electron-builder 如何来打包应用。

  "build": {
  "productName": "electron-demos",
  "files": [
    "dist/",
    "main.js"
  ],
  "dmg": {
    "contents": [
      {
        "x": 110,
        "y": 150
      },
      {
        "x": 240,
        "y": 150,
        "type": "link",
        "path": "/Applications"
      }
    ]
  },
  "win": {
    "target": [
      {
        "target": "nsis",
        "arch": [
          "x64"
        ]
      }
    ]
  },
  "directories": {
    "output": "release"
  }
}
复制代码

其中,要重点关注 files 字段,它指定了打包时要包括的文件。在这个 demo 中,我们需要包括主进程的 main.js 和渲染进程需要的React项目打包后的 dist 文件夹。

此外,再关注一下 directories.output 字段,它表示 Eletron 打包后的输出目录,如果不配置,默认为 dist,但是这和我们 React 项目的输出目录冲突,所以在这里我们改为 release

关于 electron-builder 的详细配置,干兴趣的同学可以查看 文档

3、修改 package.json 中的 scripts 字段。

3.1、修改 start-electron 命令,通过 corss-env 为其添加 ENV 环境变量:

  "start-electron": "../node_modules/.bin/cross-env ENV=development ../node_modules/.bin/electron .",
复制代码

这么做是因为 Electron 接下来要通过这个环境变量来判断此时是开发环境还是生产环境,从而做出不同的行为。

3.2、添加 build-render 命令:

  "build-render": "../node_modules/.bin/webpack --config webpack.config.js"
复制代码

它会打包 React 项目,并且在当前目录下生成 dist 输出文件。

3.3、添加 build-electron 命令:

  "build-electron": "../node_modules/.bin/electron-builder build -mwl",
复制代码

它会读取 package.jsonbuild 字段中的配置,并打包 Electron 项目,然后在当前目录下生成 release 输出文件。

命令中的 -mwl 表示打包 macwindowslinux 三平台。如果读者只想打包一个平台的包,比如 Mac 版的,可以改成 -m

3.4、添加 build 命令:

  "build": "npm install && npm run build-render && npm run build-electron"
复制代码

build 命令很简单,它将安装依赖、打包 React 项目、打包 Electron 项目结合在以前,这样的话,我们只要运行 yarn build 就能成功打包 Electron 了。

4、上面提到,由于此时demo要兼顾开发环境和生产环境,在开发环境中,Electron 要引用 React 开发环境下的 URL,以获得 React 热更新的能力。在生产环境中,Electron 要引用 React 打包后的文件。所以,我们要对 mian.js 做一些微小的改造。

      const { app, BrowserWindow } = require('electron')
+   const path = require('path');

+   const isDev = process.env.ENV === 'development';

    function createWindow() {
      // 创建浏览器窗口
      let win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          nodeIntegration: true
        }
      })

-     win.loadURL('http://localhost:3000')

+     if (isDev) {
+       win.loadURL(`http://localhost:3000`);
+     } else {
+       win.loadFile(path.resolve(__dirname, './dist/index.html'));
+     }
    }

    app.whenReady().then(createWindow)
复制代码

我们可以看到,此时我们根据此时的环境来加载不同的资源,开发环境加载 http://localhost:3000,生产环境加载打包后的文件。

经过以上配置后,运行 yarn build 我们就可以打包 Electron 项目了。

Demo04 详细的代码可以 戳这里查看。

Demo05: 实际开发一个小 Demo

上面的四个 Demo 中,我已经体验了从零开始Electron项目到成功打包一个Electron的完整过程。

但是我们上面做的无非是在Eletron中套一个可以在浏览器中跑的项目,到目前为止,我们还没有体验到 Electron 其他能力,例如:

  • 调用 Node.js 的 API(如文件读写)
  • 调用操作系统本地功能的 API(如打开文件窗口、通知)

在 Demo05 中,笔者将带领读者完成一个非常简单的文件读写应用,它将支持以下功能:

  • 列出指定目录下的文件列表
  • 支持在指定目录中添加文件
  • 文件添加成功后调用系统的通知功能

此外,在这个 Demo 中,我们还会测试主进程与渲染进程之间的通信功能。

需要注意的是,Demo05的 React 项目将无法在浏览器上运行,因为此时 React 会有很多 node 代码,而浏览器中并没有对应的 API。

首先,拷贝 Demo04 文件夹,将其改名为 Demo05,并进入 Demo05:

1、由于接下来会在我们的 React 项目中加入大量的 node 代码,比如 require('fs'),这样的话原来 React 的 webpack 配置运行后肯定会报错,幸运的是,webpack 贴心的为我们准备了 Electron 的相关配置项。

我们可以在 webpack.config.js 中的里添加 target 字段,以表示接下来 React 的运行环境将在 Electron 的 render 进程中:

  {
  target: 'electron-renderer'
}
复制代码

关于 webpacktarget 字段的配置,感兴趣的同学可以阅读 官方文档

2、接下来我们将在 React 项目中添加一个组件,用它来查看文件列表并添加新的文件:

在 Demo05 中新建 src/container/file-list 目录,并添加 index.tsx 文件:

  import React, { Component } from 'react';
import { remote, OpenDialogReturnValue } from 'electron';
import './index.scss';

const path = require("path");
const fs = require('fs');
const { dialog, Notification } = remote;

const readDistFiles = (path: string, callBack: (data: string[]) => void) => {
  fs.readdir(path, (err: any, files: any) => {
    const data: string[] = [];
    files.forEach((file: any) => {
      console.log(file);
      data.push(file);
    });
    if (callBack) {
      callBack(data);
    }
  })
}

interface IState {
  path: string;
  data: string[];
  addFileName: string;
  addFileContent: string;
}

class FileList extends Component {
  constructor(props: any) {
    super(props);
    this.state = {
      path: '',
      data: [],
      addFileName: '',
      addFileContent: '',
    }
  }

  onChooseFile = () => {
    dialog.showOpenDialog({
      properties: ['openDirectory']
    }).then((res: OpenDialogReturnValue) => {
      const filenames = res.filePaths;
      if (filenames && filenames.length > 0) {
        this.setState({ path: filenames[0] })
        readDistFiles(filenames[0], (data: string[]) => {
          console.log('data', data);
          this.setState({ data })
        })
      }
    });
  }

  onAppendFile = (name: string, content: string) => {
    fs.appendFile(path.resolve(this.state.path, name), content, (err: any) => {
      if (err) throw err;
      console.log('Saved!');
      let myNotification = new Notification({ title: '渲染进程通知', body: '新文件添加成功' });
      myNotification.show();
      readDistFiles(this.state.path, (data: string[]) => {
        this.setState({ data })
      })
    });
  }

  render() {
    return (
      
        选择要展示的文件夹
           
当前文件夹路径:{this.state.path}
文件夹下文件列表:
{ this.state.data.map(file => { return (
{file}
) }) }
文件名称: this.setState({ addFileName: e.target.value })} />
文件内容: this.setState({ addFileContent: e.target.value })} />
this.onAppendFile(this.state.addFileName, this.state.addFileContent)} style={{ 'marginLeft': '10px' }}> 添加文件
) } } export default FileList; 复制代码

上面的组件比较简单,我们可以看到,在选择文件夹时,会调用 remote.dialog.showOpenDialog, 它会打开系统的文件窗口。然后,我们可以用 node 的 fs 模块来写入或者读取文件。在读取成功后,我们还可以通过 remoteNotification 来调用系统的通知功能。

总的来说,在前端项目中调用 node 相关的模块,体验很奇妙。

3、通过 ipcMainipcRenderer 我们可以实现渲染进程与主进程之间的通信。

ipcMain 在主进程中使用,用来处理渲染进程(网页)发送的同步和异步的信息:

  const {ipcMain} = require('electron')

// 监听渲染程序发来的事件
ipcMain.on('something', (event, data) => {
  event.sender.send('something1', '我是主进程返回的值')
})
复制代码

ipcRenderer 在渲染进程中使用,用来发送同步或异步的信息给主进程,也可以用来接收主进程的回复信息。

  const { ipcRenderer} = require('electron') 

// 发送事件给主进程
ipcRenderer.send('something', '传输给主进程的值')  

// 监听主进程发来的事件
ipcRenderer.on('something1', (event, data) => {
  console.log(data) // 我是主进程返回的值
})
复制代码

当然,我们还可以在 Render 进程中直接使用 remote 模块, 这样的话就可以直接调用 main 进程对象的方法, 而不必显式发送进程间消息。

  const { dialog } = require('electron').remote
dialog.showMessageBox({type: 'info', message: '在渲染进程中直接使用主进程的模块'})
复制代码

经过以上改造,运行 yarn start 我们就可以体验真正意义上的桌面应用了。

Demo05 详细的代码可以 戳这里查看。

Demo06: 在主进程中使用 Typescript

在之前的 Demo 中,我们会发现,在渲染进程中,我们已经用上来 TypeSctipt。但是在主进程中,用的依旧是 javascript。考虑将来项目会越来越大,为了保证项目的可靠性,在这个 demo 中,我们会将主进程也改造成 Typescipt。

首先,拷贝 Demo05 文件夹,将其改名为 Demo06,并进入 Demo06:

1、新建 webpack.main.config.js 文件,之后我们会用这个文件的 wabpack 配置来打包主进程的代码,配置如下:

  const path = require('path');

module.exports = {
  target: 'electron-main',
  mode: 'development',
  entry: './main.ts',
  output: {
    filename: './main.js',
    path: path.resolve(__dirname, '')
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  node: {
    __dirname: false,
    __filename: false
  },
}
复制代码

这是一段很简单的 webpack 配置,其中主要注意两点:

1.1、需要将 target 配置为 electron-main 表示以接下来 打包的代码将在 Electron 的 mian 进程中执行

1.2、由于 webpack 会对 __dirname__filename 做其他额外的处理,为了保证 __dirname__filename 的行为和在 node 中保持一致,添加如下配置:

  node: {
  __dirname: false,
  __filename: false
}
复制代码

如果不这样配置,打包后 __dirname__filename 将都是 /;

2、将 webpack.config.js 改名为 webpack.renderer.config.js,用来和 webpack.main.config.js 保持对应。

3、修改 package.json 中的 script 字段:

      {
-     "start-electron": "../node_modules/.bin/cross-env NODE_ENV=development ../node_modules/.bin/electron .",
+     "start-electron": "npm run build-main && ../node_modules/.bin/cross-env ENV=development ../node_modules/.bin/electron .",
-     "start": "../node_modules/.bin/webpack-dev-server --config webpack.config.js",
+     "start": "../node_modules/.bin/webpack-dev-server --config webpack.renderer.config.js",
-     "build-render": "../node_modules/.bin/webpack --config webpack.config.js",
+     "build-render": "../node_modules/.bin/webpack --config webpack.renderer.config.js",
+     "build-main": "../node_modules/.bin/webpack --config webpack.main.config.js",
      "build-electron": "../node_modules/.bin/electron-builder build -mwl",
-     "build": "npm install && npm run build-render && npm run build-electron"
+     "build": "npm install && npm run build-render && npm run build-main && npm run build-electron"
    }
复制代码

其中注意两点:

3.1、 start-electron 将在运行 electron . 先打包主进程的 typescrip 代码。

3.2、 build 执行后将先打包渲染进程,再打包主进程,最后再打包整个 Electron 应用。

经过以上改造,主进程也改造成 typescript 了,项目的可靠性大大增强。

Demo06 详细的代码可以 戳这里查看。

经过以上 6 个 demo 的学习,同学们已经有能力搭建一个完整的 Electron 应用。但是我们还有一些进阶的用法,感兴趣的同学可以继续往下阅读。

Demo07: 主进程监听文件变化并重启

前面的开发中我们发现,渲染进程修改后可以自动刷新,而主进程却不行,这可能会影响到我们的开发效率。

所以,在 Demo07 中,通过 nodemon,我们将主进程也改造成修改后可以自动刷新。

首先,拷贝 Demo06 文件夹,将其改名为 Demo07,并进入 Demo07:

1、安装 nodemon

  yarn add nodemon -D
复制代码

2、在 package.json 添加一行脚本:

  {
  "start-electron-with-nodemon": "nodemon --watch main.ts --exec 'npm run start-electron'",
}
复制代码

我们之后会通过 nodemon 来启动 Electron,它将监听 main.ts 的文件变化。如果发生变化,则会从新运行 start-electron 命令。

3、将 webpack.renderer.config.jsdevServer 的 after 钩子中的 start-electron 改为 start-electron-with-nodemon

      devServer: {
      port: 3000,
      after() {
+       spawn('npm', ['run', 'start-electron-with-nodemon'], {
-       spawn('npm', ['run', 'start-electron'], {
          shell: true,
          env: process.env,
          stdio: 'inherit'
        })
          .on('close', code => process.exit(code))
          .on('error', spawnError => console.error(spawnError));
      }
    }
复制代码

经过以上的简单配置,我们的主进程也能修改文件后自动刷新了。

Demo07 详细的代码可以 戳这里查看。

Demo08: 在 vscode 中调试主进程和渲染进程

任何时候,如果代码出了 bug,我们的第一反应是打印 log 看一下出了什么问题。但是这样的调试方式相对低效,有些时候,我们需要借用编辑器的调试功能来帮助我们调试代码。

在这个 Demo 中,笔者将尝试用 vscode 自带的调试工具来调试 electron 的主进程和渲染进程;

由于 vscode 中的调试配置项相对较多,所以强烈建议大家先看一遍 vscode 调试的 官方文档,或者看一下 github 上 Electron调试实际案例

本文的配置与上面提到的 实际案例有一些差异,因为我们 demo 开发环境的 render 进程是用一个 web server 启动的。

首先,拷贝 Demo07 文件夹,将其改名为 Demo08,并进入 Demo08:

1、在 webpack.main.config.jswebpack.render.config.js 中添加 devtool: 'source-map'。因为主进程和渲染进程都是用 typescript 写的,需要在打包时生成 source maps 以形成映射,才能在 typescript 文件中正确的调试代码。详情可以查看 官方文档

2、改造 webpack.renderer.config.js,将 devServer 的 after 钩子函数。

      devServer: {
      port: 3000,
      after() {
-       spawn('npm', ['run', 'start-electron-with-nodemon'], {
+       spawn('npm', ['run', 'build-main'], {
          shell: true,
          env: process.env,
          stdio: 'inherit'
        })
-         .on('close', code => process.exit(code))
          .on('error', spawnError => console.error(spawnError));
      }
    }
复制代码

这也就意味着运行渲染进程后,只会将主进程的代码打包一下,而不再将主进程启动起来。因为在稍后的调试中我们会在 vscode 的 launch.json 中启动主进程。

3、运行 yarn start,启动渲染进程,并且给主进程打包。

4、在当前项目目录下创建一个 .vscode 目录,并且在该目录下创建一个 launch.json 文件,在该文件里添加如下配置:

  {
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Electron: Main",
      "protocol": "inspector",
      "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
      "runtimeArgs": [
        "--remote-debugging-port=9233",
        "./demo08/main.js"
      ]
    },
    {
      "type": "chrome",
      "request": "attach",
      "name": "Electron: Renderer",
      "port": 9233,
      "url": "http://localhost:3000",
      "webRoot": "${workspaceFolder}/demo08",
    },
  ],
  "compounds": [
    {
      "name": "Electron: All",
      "configurations": [
        "Electron: Main",
        "Electron: Renderer"
      ]
    }
  ]
}
复制代码

我们可以看到,在 configurations 中有两个对象:

其中 "Electron: Main" 表示的是对主进程的调试,它的 requestlaunch,表示在调试的时候启动主进程。我们还可以通过 env 来传入环境变量。它还会暴露一个 --remote-debugging-port 的远程调试端口,这个端口很重要,因为在接下来调试渲染进程时会用到它。

"Electron: Renderer" 表示的是对渲染进程的调试,它的 requestattach,表示只是连接到正在调试的进程。而它的 port 刚好是 --remote-debugging-port 暴露出来的端口, url 则是本地渲染进程的地址。

接着,我们会看到 compounds,它的作用很简单,就是把主进程调试和渲染进程调试结合起来。当调试时选择 Electron: All 时,就可以把 "Electron: Main" 和 "Electron: Renderer" 都拉起来。

这一块的配置比较多,其中每个配置的作用可以参考 vscode 的 官方文档

5、点击 vscode 自带的调试按钮,选择 Electron: All,就可以将 electron 启动起来了,这时候在主进程的 .ts 文件和渲染进程的 .ts 文件中打断点就可以发现都能起作用了。

注意,实际测试发现,主进程的调试需要在打包后的 main.js 中打一次断点,然后在通过 source map 和 js 文件生成的只读的 typescipt 文件中打断点才能顺利调试。

经过以上的配置,我们可以顺利的在主进程和渲染进程中调试代码了。

Demo08 详细的代码可以 戳这里查看。

总结

通过以上的一系列 Demo,我们重零搭建一个完整的 Electron 应用。

我们了解了 Electron的核心知识点、搭建一个最简单的 Electron,将 Electron 和前端应用相结合,配置 TypeScript 以保证代码质量,跨平台打包 Electron 应用以及 如何调试 Electron。

这些 demo 的完整代码可以 点这里查看,如果感觉这些 demo 写的不错,可以给笔者一个 star,谢谢大家阅读。

原文链接

从零搭建 Electron 应用

相关 [electron 应用 系列] 推荐:

# 从零搭建Electron应用 的一系列简单的 Demo

- - 掘金前端
Electron 是一个优秀的跨平台桌面应用程序开源库,目前接触 Electron 的开发者也越来越多. 但是笔者发现,目前社区里缺少对初学者足够友好的入门教程来帮助初学者用 Electron 搭建一个完整的开发框架. 为了解决这个问题,笔者将结合平时的一些 Electron 开发经验,渐近式的带领读者从零开始搭建一个完整的 Electron 应用.

【译】使用 AngularJS 和 Electron 构建桌面应用

- - SegmentFault 最新的文章
原文: Creating Desktop Applications With AngularJS and GitHub Electron. GitHub 的 Electron 框架(以前叫做 Atom Shell)允许你使用 HTML, CSS 和 JavaScript 编写跨平台的桌面应用.

Electron+Vue开发跨平台桌面应用

- - SegmentFault 最新的文章
虽然B/S是目前开发的主流,但是C/S仍然有很大的市场需求. 受限于浏览器的沙盒限制,网页应用无法满足某些场景下的使用需求,而桌面应用可以读写本地文件、调用更多系统资源,再加上Web开发的低成本、高效率的优势,这种跨平台方式越来越受到开发者的喜爱. Electron是一个基于Chromium和 Node.js,使用 HTML、CSS和JavaScript来构建跨平台应用的跨平台开发框架,兼容 Mac、Windows 和 Linux.

Electron架构揭秘

- - 掘金前端
本文已收录在前端食堂同名仓库Github. github.com/Geekhyt,欢迎光临食堂,如果觉得酒菜还算可口,赏个 Star 对食堂老板来说是莫大的鼓励. 昨晚搬砖回家看到 Peter 发了条朋友圈,腾讯云游戏平台 START 公测发布,他在用 MAC 打 LOL. 我紧随其后体验了一波,毕竟 LOL 是我们这代人的青春,工作后很少有时间玩,用上 MAC 后,之前的游戏本也放在箱底很久了.

初探Electron,从入门到实践 - 葡萄城技术团队博客 - OSCHINA

- -
在开始之前,我想您一定会有这样的困惑:标题里的Electron 是什么. 许多伟大的公司使用Electron框架的原因又是什么. 带着这些问题和疑惑,通过本文的介绍,可助您全面地认识Electron这门新兴的技术,迅速找到其入门途径,并理解Electron为何被称为当下开发桌面App的最佳选择. (为何称之为“跨平台桌面浏览器”).

[iPad]限时免费 CheerZ Kids系列幼儿教育应用

- - 178苹果专区 apple.178.COM
CheerZ Kids是一个面向儿童的高品质产品系列,由华东师范大学学前教育专家项目组牵头推出,培养孩子的观察、注意、记忆、思维、想象力以及自理自律能力等等,让孩子在努力尝试和不断探索中获得心智的发展. 注意力训练:花儿朵朵开 http://itunes.apple.com/cn/app//id489157352?mt=8.

【监控应用服务器】系列博文目录

- - CSDN博客架构设计推荐文章
前言:做了一个监控应用服务器(Tocmat、WebSphere、WebLogic)的项目,为了留下点印记,给后来人留下点经验之谈,助之少走弯路,特意把这些经验整理出来,与大家分享. 如有疑问,可以Q我:562116039. 监控Tomcat解决方案(监控应用服务器系列文章一). 讲解两种监控Tomcat的解决方案:一是通过Tomcat提供的manager应用,二是通过JMX的方式.

Android学习系列(35)--App应用之启动界面SplashActivity

- - 博客园_首页
当前比较成熟一点的应用基本上都会在进入应用之显示一个启动界面. 这个启动界面或简单,或复杂,或简陋,或华丽,用意不同,风格也不同. 下面来观摩几个流行的应用的启动界面.. 以腾讯qq,新浪weibo,UC浏览器,游戏神庙逃亡等7个应用为例,比比看:. (我认为最精美的界面应该是qq2012,虽然只有一张图,基本的应用名称,版本,图标这些信息都有,但是看着舒服,觉得美.).

Windows 8实例教程系列 - 理解应用框架

- - 博客园_首页
Windows 操作系统之所以风靡世界,是因为其“易学易用”,从用户的角度出发,让数以万计的非IT人员使用计算机实现娱乐,工作等目的. Windows 8继承Windows桌面的优点,同时提供一种新的用户体验模式 - Windows store风格. 换句话说,Windows 8操作系统存在两种不同风格的应用.

34个漂亮的应用程序后台管理界面(系列一)

- 飞虫 - 博客园-首页原创精华区
  今天这篇文章收集了34个漂亮的应用程序后台管理界面分享给大家. 这些界面都是来自themeforest网站,如果要下载的话是要付费的,不过设计师可以根据预览图自己设计,希望这些后台管理界面主题能帮助到你. 非常有用的免费UI设计工具和资源. 分享35套精美的 PSD 图标素材. 分享20个很不错的UI图标集资源.