使用create-react-app创建Electron应用

参考文章:⚡️ From React to an Electron app ready for production,原文较为久远了,所以本文对部分代码进行了修改

使用React构建Electron应用时,官网推荐使用electron-react-boilerplate 。但是这个项目有些重,于是想使用比较熟悉的create-react-app进行构建,记录一下踩坑过程。

初始化create-react-app项目

个人比较喜欢TypeScript,所以使用create-react-app的TypeScript模板进行构建

npx create-react-app electron-cra --template typescript

不过后面都跟TypeScript无关了,所以习惯js的可以省略--template typescript
然后安装一些依赖

yarn add electron electron-builder cross-env wait-on concurrently --dev
yarn add electron-is-dev

这时运行yarn start可以启动网页。很常规的CRA流程。
接下来将项目改造成为Electron应用。

Electron改造

按照Electron官网的教程,向根目录下添加main.js

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

function createWindow() {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true
        }
    })
    // 这里对官网代码进行了修改,因为cra是启动了web服务而非静态文件
    // win.loadFile('index.html');
    win.loadURL('http://localhost:3000/');
    win.webContents.openDevTools();
}

app.whenReady().then(createWindow)

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

app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
        createWindow()
    }
})

然后在package.json中添加"main": "main.js"
这时候启动两个终端,一个运行yarn start,一个运行yarn electron ./,就能看到Electron运行起来了
在这里插入图片描述
但这只是开发环境,部署使用electron-builder显然不能使用这种方式,因此要使用create-react-app 构建后的结果。
运行yarn build,生成build目录,里面就是create-react-app编译之后的文件。
打开build目录下的index.html文件,发现是一片空白😱,F12一下,发现是资源路径不对。解决方案是在package.json中添加"homepage": "./"。添加之后再进行build,打开index.html,就能看到正常页面了。
直接运行yarn electron-builder进行打包,报错

Application entry file "build\electron.js" in the "......\electron-cra\dist\win-unpacked\resources\app.asar" does not exist. 
Seems like a wrong configuration.

原来在打包时需要build\electron.js文件,这个文件的作用和main.js是一样的。在build目录下直接建一个electron.js显然不太合理,那怎么办呢?
解决方法是将electron.js放在public目录里,因为编译时public目录内的内容是会被复制到build目录下的;然后将public/electron.js指定为Electron的入口。
public目录下新建electron.js,内容和main.js基本一致,除了将

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

修改为

win.loadURL(`file://${__dirname}/index.html`);

然后将package.json中的"main"项修改为"public/electron.js",并增加"build"项:

"build": {
  "appId": "com.example.electron-cra",
  "files": [
    "build/**/*",
    "node_modules/**/*"
  ],
  "directories":{
    "buildResources": "assets"
  },
  "extraMetadata":{
      "main":"build/electron.js"
    }
}

(根据原文的说法,filesdirectories项是为了避免electron-builder和CRA的冲突,但是我没看懂……总之就先留着吧。extraMetadata项是从原文中一个错误命令build --em.main=build/electron.js修改来的)
现在,执行

yarn build
yarn electron-builder

就能在dist目录下看到打包好的程序了。为了将两个步骤结合起来,可以在package.jsonscript节中增加命令:

"electron-pack": "electron-builder",
"preelectron-pack": "yarn build"

这样,执行electron-pack,就能同时执行编译和打包。

自动识别开发环境

经过以上改造,打包程序的工作完成了,但又有了新问题:publlic/electron.js中指定了

win.loadURL(`file://${__dirname}/index.html`);

这样我们就不能在开发环境执行Electron,也不能使用CRA的动态加载修改功能了。解决方法就是在publlic/electron.js中增加开发环境的判断,在开头增加引用

const isDev = require('electron-is-dev');

然后修改前面的那行代码为

win.loadURL(isDev ? 'http://localhost:3000' : `file://${__dirname}/index.html`);

这样Electron就能识别当前环境,选择合适的渲染来源了。

合并启动命令

最后一个问题,现在要在开发环境下运行,还是需要启动两个终端,分别运行Web服务器和Electron。可以使用concurrently将两个命令集成为一个。
package.jsonscript节中增加命令:

"electron-dev": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electron .\""

就可以通过执行yarn electron-dev,同时开启web服务和Electron了。

最后放上最终版的publlic/electron.jspackage.json

//publlic/electron.js
const { app, BrowserWindow } = require('electron')
const isDev = require('electron-is-dev');

function createWindow() {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true
        }
    })
    win.webContents.openDevTools();
    win.loadURL(isDev ? 'http://localhost:3000' : `file://${__dirname}/index.html`);
}

app.whenReady().then(createWindow)

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

app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
        createWindow()
    }
})

//package.json
{
  "name": "electron-cra",
  "version": "0.1.0",
  "private": true,
  "homepage": "./",
  "main": "public/electron.js",
  "build": {
    "appId": "electron.antd",
    "files": [
      "build/**/*",
      "node_modules/**/*"
    ],
    "directories": {
      "buildResources": "assets"
    },
    "extraMetadata": {
      "main": "build/electron.js"
    }
  },
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "@types/jest": "^26.0.15",
    "@types/node": "^12.0.0",
    "@types/react": "^16.9.53",
    "@types/react-dom": "^16.9.8",
    "electron-is-dev": "^1.2.0",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.1",
    "typescript": "^4.0.3",
    "web-vitals": "^0.2.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "electron-dev": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electron .\"",
    "electron-pack": "electron-builder",
    "preelectron-pack": "yarn build"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "concurrently": "^5.3.0",
    "cross-env": "^7.0.3",
    "electron": "^11.1.1",
    "electron-builder": "^22.9.1",
    "wait-on": "^5.2.0"
  }
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值