Electron+React学习笔记-环境准备

1,709 阅读4分钟

写的跟憨逼一样的文档是阻碍恐怖直立猿在开发中不可逾越的障碍

配置环境

网不好安装electron很难,用cnpm也可以,但是cnpm安装的包在打包的时候会很慢

第一次知道原来命令行默认是不走玄学的,这个1080,是玄学上网的端口
yarn config set proxy http://127.0.0.1:1080
// 记得删除 
yarn config delete proxy

如果不行的话,cnpm硬怼吧

准备工作

公司的技术栈是react,如果是vue的话,会简单很多,建议各位了解下vue-electron,这个react好像没有,多说无益,vue牛逼,另外github的star早已反超react,没错我很喜欢vue

入口文件

electron启动是根据package.json中的main字段来决定的,也是electron中的主线程 比如

// package.json
{
    "main": "electron/main.js",
    "scripts": {
        "start:elec": "electron electron/main.js"
    }
}

另外给一份main.js配置,记得安装包,主要参考electron-quick-start

// electron.app管理整个应用程序生命周期,比如启动销毁等
// electron.BrowserWindow负责创建窗口
const { app, BrowserWindow } = require('electron')
const isDev = require('electron-is-dev');

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })

  mainWindow.loadFile('index.html')

  isDev && mainWindow.webContents.openDevTools()
}

function createDevTools() {
  //BrowserWindow.addDevToolsExtension(path.join(__dirname, 'chrome-extensions', 'react-dev-tools'));
}

// 等待electron初始化完成,有两种方法,
// 适合主流
app.on('ready', function () {
  createWindow()
  isDev && createDevTools()
})

// whenReady应该是新方法,但可能会有问题, 等过个一年半载可以用这个,返回一个Promise
// [参考](https://github.com/electron/fiddle/pull/362)
// app.whenReady().then(() => {
//   createWindow()

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

app.on('window-all-closed', function () {

  if (process.platform !== 'darwin') app.quit()
})

react-app-rewired

使用create-react-app创建工程如果水平高的话,可以自己手动改webpack,或者用react-app-rewired,配置起来会简单很多,scripts中的字段改成react-app-rewired开头,具体可以查查

"scripts": {
   "start": "react-app-rewired start",
   "build": "react-app-rewired build",
}
// 根目录config-verrides.js
module.exports = function override(config, env) {
  //do stuff with the webpack config...
  return config;
};

electron-is-dev

区分开发环境还是生产环境,开发和生成用的配置肯定会有点区别,用法很简答

const isDev = require('electron-is-dev');
// 返回的是一个布尔值,开发环境true,可以在控制台打印输出下

concurrently,wait-on,cross-env

打开多个命令行的,electron结合react的思路相当于是一个命令行运行react,另一个命令行运行electron,加载win.loadURL('http://localhost:3000'),concurrently可以用一个命令启动两个命令行

wait-on就是等待http://localhost:3000启动成功后再运行

使用cross-env,在调试electron的时候其实不需要启动浏览器,所以"start:elec": "cross-env BROWSER=none xxxx

// 不要照抄,根据自己实际情况来
  "scripts": {
    "start": "react-app-rewired start",
    "start:elec": "concurrently \"npm run start:react\" \"npm run start:electron\"",
    "start:react": "cross-env BROWSER=none react-app-rewired start",
    "start:electron": "wait-on http://localhost:3000 && electron app"
  },

Electron 使用whenReady会有很多问题,慎用,目前版本建议用on('ready')

如何和react相结合

React和electron相结合会报些奇怪的错误,毕竟是两种不同的框架,electron也不是专门给react做的,常见的错误 fs.existsSync is not a function

简单的说,用create-react-app创建项目添加electron时,默认webpack输出的是web环境,react和vue开发的时候就是这个,但是在解析electron行不通,导致模块报错,可以看这里,target有electron-main的选项

在这里先列出一种方法 把electron挂在到electron的window

主线程的引入方式不变

const { app, BrowserWindow } = require("electron");

渲染线程

// test.js
import React from "react";
const remote = window.require("electron").remote

const BrowserWindow = remote.BrowserWindow;
export const Index = () => {
  const btn = () => {
    const newWin = new BrowserWindow({
      width: 500,
      height: 500,
      webPreferences: {
        nodeIntegration: true,
      },
    });
    newWin.loadURL("https://www.baidu.com/");
  };

  return (
    <div>
      <button onClick={btn}>弹窗测试</button>
    </div>
  );
};

当然,最好修改webpack的target方式,但在某些场景可能会有问题,灵活选择

electron在react中打开子窗口该怎么办

electron打开窗口有两种方式

  1. win.loadURL()
  2. win.loadFile()

loadFile一般是打开静态页面的时候,比如react打包好生成静态文件后用loadFile加载,但是,有点问题,首页可以,子窗口呢?我想把子窗口用react组件的方式编写,但是electron不认js文件,也不可能专门给子页面打包成一个静态的,那这样也low的可以, 唯一的选择就是用loadURL的方式,那具体怎么做,简单,用路由

  1. 注册路由,只注册就行,什么<Link to="/test/">跳转</Link>,这个东西不用管,注册到哪里,看需求了,举个栗子
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";

import { Index } from "./components/Index";
import {Camera} from './components/Camera'
function App() {
  return (
    <div className="App">
      <Router>
        <Route path="/" exact
          component={Index}></Route>
          // Camera是我要打开的子弹窗
        <Route path="/camera/" component={Camera}></Route>
      </Router>
    </div>
  );
}

export default App;
  1. 跳转路由
export const Index = () => {
  const btn = () => {
    const newWin = new BrowserWindow({
      width: 500,
      height: 500,
      webPreferences: {
        nodeIntegration: true,
      },
    });
    // 由这里跳转
    newWin.loadURL("http://localhost:3000/camera/");
  };

  return (
    <div>
      <button onClick={btn}>弹窗测试</button>
    </div>
  );
};

当然我这种思路也有局限,还是要依赖服务器,服务器挂了,electron就挂了,不是纯静态exe,暂时还没想到怎么脱离web做成纯桌面程序,有思路的老哥麻烦指点下