使用create-react-app编写Electron app

目录

  • Electron简介

    • 打造你第一个 Electron 应用
    • 下一步
  • 整合

    • create-react-app创建工程
    • 整合antd
      • 修改package.json
      • config-overrides.js
      • src/App.js
      • 运行
    • 整合Electron
      • 安装Electron库
      • 添加Electron启动文件
      • 配置Electron入口
      • 修改界面
      • 调试运行
      • 生产环境运行
  • 分发应用

    • 简介
    • electron-builder 生成安装包
      • 安装electron-builder
      • 配置icon
      • 配置package.json
      • 生成安装包
  • 参考文档

Electron简介

Electron是一个利用javascript/css/html来开发跨平台(Mac/Windows/Linux)桌面应用的框架。
VS Code/Atom/GitHub Desktop等软件是基于Electron编写的。

# 可以简单这样理解
Electron = nodejs + chrome内核
  • 因为内置一个chrome内核,所以开发者可以使用javascript/html/css来构建界面;这一部分运行在渲染进程中。
  • 因为内置nodejs环境,所以可以访问计算机本地的资源:读写磁盘文件、创建进程、本地通知、、、;这一部分运行在主进程中。

打造你第一个 Electron 应用

下一步

Electron并没有限制我们使用什么技术/框架来渲染UI,我们希望结合Electron+create-react-app+redux+react router+antd共同打造一个高效、快速的、工程化的开发体验。

整合

完整的示例可从这里下载

create-react-app创建工程

# 使用create-react-app创建工程
$ create-react-app demo-app

整合antd

# 添加antd库
$ yarn add and

# 这个库可以让我们不必运行CRA的eject
$ yarn add react-app-rewired --dev

# 按需加载
$ yarn add babel-plugin-import --dev
修改package.json
# 修改 start/build/test 脚本
...
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom",
}
...
config-overrides.js

在项目的根目录下增加一个config-overrides.js文件

const { injectBabelPlugin } = require('react-app-rewired');
module.exports = function override(config, env) {
    config = injectBabelPlugin(['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }], config);
    return config;
};
src/App.js
import React, { Component } from 'react';
import { Button } from 'antd';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Button type="primary">Button</Button>
      </div>
    );
  }
}
export default App;
运行
# 调试运行,访问:http://localhost:3000/
$ npm start

# 生成release包
$ npm build

整合Electron

安装Electron库
# 安装electron
$ yarn add electron --dev
添加Electron启动文件

添加public/electron.js

// `主进程`入口
const electron = require('electron');
const platform = require('os').platform();  // 获取平台:https://nodejs.org/api/os.html#os_os_platform
// 控制app生命周期.
const app = electron.app;
// 浏览器窗口.
const BrowserWindow = electron.BrowserWindow;

const path = require('path');
const url = require('url');

console.log(platform);

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow()
{
    // 创建一个浏览器窗口.
    mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: {
        webSecurity: false, // 这样可以在 webview 中加载/显示本地计算机的图片。
    } });

    // 这里要注意一下,这里是让浏览器窗口加载网页。
    // 如果是开发环境,则url为http://localhost:3000(package.json中配置)
    // 如果是生产环境,则url为build/index.html
    const startUrl = process.env.ELECTRON_START_URL || url.format({
        pathname: path.join(__dirname, '/../build/index.html'),
        protocol: 'file:',
        slashes: true
    });
    // 加载网页之后,会创建`渲染进程`
    mainWindow.loadURL(startUrl);

    // 打开chrome浏览器开发者工具.
    if(startUrl.startsWith('http'))
    {
        mainWindow.webContents.openDevTools();

        // 加载 react/redux 调试工具(如果有需要的话)
        if('darwin' === platform)
        {
            BrowserWindow.addDevToolsExtension('/Users/issuser/Library/Application\ Support/Google/Chrome/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/3.1.0_0');
            BrowserWindow.addDevToolsExtension('/Users/issuser/Library/Application\ Support/Google/Chrome/Default/Extensions/lmhkpmbekcpmknklioeibfkpmmfibljd/2.15.2_0');
        }
    }

    // Emitted when the window is closed.
    mainWindow.on('closed', function () {
        mainWindow = null
    });
}

app.on('ready', createWindow);

app.on('window-all-closed', function () {
    if (process.platform !== 'darwin')
    {
        app.quit();
    }
});

app.on('activate', function ()
{
    if (mainWindow === null)
    {
        createWindow();
    }
});

// 这是一个示例,展示了`渲染进程`发送了`chooseFolder `事件后,`主进程`打开选择目录的对话框。
electron.ipcMain.on('chooseFolder', function(){
    const dialog = electron.dialog;
    dialog.showOpenDialog(mainWindow, {
        properties: ['openDirectory']
    });
});
配置Electron入口

package.json文件

{
  ...
  "main": "public/electron.js",
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "electron": "electron .",
    "electron-dev": "ELECTRON_START_URL=http://localhost:3000 electron ."
  },
  ...
}
修改界面
// src/App.js
// UI界面运行在`渲染进程`
import React, { Component } from 'react';
import { Button } from 'antd';
import './App.css';

// 渲染进程可以通过`ipcRenderer`向主进程发送消息。
const electron = window.require('electron');
const fs = electron.remote.require('fs');
const ipcRenderer  = electron.ipcRenderer;

class App extends Component {
    render() {
        return (
            <div className="App">
                <Button type="primary" onClick={this.showNativeDialog}>Button</Button>
            </div>
        );
    }
    showNativeDialog() {
        // 选择文件示例
        // const dialog = electron.remote.dialog;
        // dialog.showOpenDialog({
        //     properties: ['openDirectory']
        // }, (filePaths)=>{
        //     console.log(filePaths);
        // });

        ipcRenderer.send('chooseFolder');
    }
}

export default App;
调试运行
# 调试运行web程序
$ npm start

# 调试运行electron,并用浏览器窗口(BrowserWindow)加载上面的web程序
$ npm run electron-dev
生产环境运行
# 编译生成web页面的release包,结果保存在build目录
$ npm run build

# 运行electron,并用浏览器窗口(BrowserWindow)加载build/index.html文件
$ npm run electron
效果图

分发应用

简介

我们希望将Electron的app打包成.app/.exe发布给其他人下载安装。
分发的方式有好几种:

  • 可以通过第三方
  • 也可以下载Electron官方提供的壳子app,然后把package.json/build目录/public目录放到壳子对应的目录下即可

详情见官网指南分发应用

electron-builder生成安装包

安装electron-builder
$ npm install electron-builder --save-dev
配置icon

放在public/icon.png,尺寸:512x512

配置package.json
{
  "name": "demo-app",
  // 配置app的名称
  "productName": "示例",
  "description": "描述信息",
  "author": "作者",
  "version": "0.1.0",
  "private": true,
  // 入口
  "main": "./public/electron.js",
  "homepage": "./",
  // 把dependencies里面的内容都放到devDependencies里面去
  "dependencies": {},
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom",
    "eject": "react-scripts eject",
    "electron": "electron .",
    "electron-dev": "ELECTRON_START_URL=http://localhost:3000 electron .",
    "packager": "npm run build && rm -rf dist && electron-builder"
  },
  "build": {
    "appId": "com.isoftstone.apptools",
    "mac": {
      "category": "public.app-category.developer-tools"
    },
    "files": [
      {
        "from": "./",
        "to": "./",
        "filter": [
          "**/*",
          "!node_modules"
        ]
      },
      {
        "from": "./node_modules/image-size",
        "to": "./node_modules/image-size"
      }
    ],
    "directories": {
      "buildResources": "public"
    }
  },
  "devDependencies": {
    "antd": "^3.3.0",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-scripts": "1.1.1",
    "babel-plugin-import": "^1.6.6",
    "electron": "^1.8.3",
    "electron-builder": "^20.8.1",
    "electron-load-devtool": "^1.0.0",
    "image-size": "^0.6.2", // 这是一个第三方node模块
    "react-app-rewired": "^1.5.0"
  }
}

生成安装包
$ npm run packager
生成的安装包

参考文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容