React+Electron build desktop application methods and steps

React+Electron build desktop application methods and steps

step:

[1: Build and configure the entrance]

  1. Create a react project application
  2. Install Electron dependencies
  3. Modify the package.json file
  4. New main thread file main.js main thread file
  5. run project

[Two: Transform configuration, environment domain name]

  1. Not required: add the merge start execution command , (there is a configuration environment, do not use)
  2. Not required: install the cross-env environment variable , (request different domain names and content according to the environment)

Specific steps are as follows:

[1: Build and configure the entrance]

[1.1] Create a react project application

Create a react app:

// 安装react脚手架
npm install -g create-react-app

// 创建项目(projectname替换自己的项目名,不能有横杠大写,可以用下划线)
create-react-app projectname

// 打开目录
cd projectname

//启动测试是否正常
npm start

See my other blog for details:
react+js or react+ts(tsx) build steps using creat-react-app and yarn

[1.2] Install Electron dependencies in the react project

// 优先使用这个
npm i --save-dev electron

// 或者(node版本过低的不能用):
npm install electron

[1.3] Modify the package.json file

  • Add to define the execution command , see [1.5] for details
  • Actually need to remove all comments inside package.json . The last element of the object array cannot have a comma at the end
{
    
    
  "name": "my-electron",
  "version": "0.1.0",
  "private": true,
  "main": "main.js", // 配置启动文件 -- 需新建
  "homepage": ".", // 设置应用打包的根路径
  "dependencies": {
    
    
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "react": "^17.0.1",
    "react-dom": "^18.0.0",
    "react-scripts": "4.0.1",
    "web-vitals": "^0.2.4"
  },
  "scripts": {
    
    
    "start": "react-scripts start", // 【原始】react 启动命令,需要额外执行 electron。同时启动这两个
    "electron": "electron .", // 【添加】electron 启动命令,需要额外执行 start。同时启动这两个
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "dev": "react-scripts start | electron . --debug", // 【2.1介绍】合并命令,若有环境变量配置,不能使用
    "dev:debug": "react-scripts start | electron . --debug", // 【2.1介绍】合并命令,debug 模式。若有环境变量配置,不能使用
    "start:dev": "cross-env MODE_ENV=development react-scripts start", // 【2.2介绍】配置环境变量
    "electron:dev": "cross-env MODE_ENV=development electron ." // 【2.2介绍】配置环境变量
  },
  "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": {
    
    
    "electron": "^18.1.0"
  }
}

[1.4] Create a new main.js main thread file

Path: same level as package.json

// 导入app、BrowserWindow模块
// app 控制应用程序的事件生命周期。事件调用app.on('eventName', callback),方法调用app.functionName(arg)
// BrowserWindow 创建和控制浏览器窗口。new BrowserWindow([options]) 事件和方法调用同app
// Electron参考文档 https://www.electronjs.org/docs

const {
    
     app, BrowserWindow, nativeImage } = require('electron');
// const url = require('url');
// const path = require('path');

function createWindow () {
    
    
  let mainWindow = new BrowserWindow({
    
    
    width: 1000, // 窗口宽度
    height: 800, // 窗口高度
    title: "Electron", // 窗口标题,如果由loadURL()加载的HTML文件中含有标签<title>,该属性可忽略
    icon: nativeImage.createFromPath('src/public/favicon.ico'), // "string" || nativeImage.createFromPath('src/image/icons/256x256.ico')从位于 path 的文件创建新的 NativeImage 实例
    webPreferences: {
    
     // 网页功能设置
      nodeIntegration: true, // 是否启用node集成 渲染进程的内容有访问node的能力
      webviewTag: true, // 是否使用<webview>标签 在一个独立的 frame 和进程里显示外部 web 内容
      webSecurity: false, // 禁用同源策略
      nodeIntegrationInSubFrames: true // 是否允许在子页面(iframe)或子窗口(child window)中集成Node.js
    }
  });

// --------------------------------------------------------------------------------------------

  // 【二选一:打包时候使用】__dirname为当前文件路径
  // mainWindow.loadURL(url.format({
    
    
  //   pathname: path.join(__dirname, './build/index.html'),
  //   protocol: 'file:',
  //   slashes: true
  // }));

  // 【二选一:开发时候使用】
  //需要和本地项目启动会端口号一致,一般不需要改。多项目启动会有端口被占用而 改变情况
  mainWindow.loadURL('http://localhost:3000/'); 

// --------------------------------------------------------------------------------------------

  // 解决应用启动白屏问题
  mainWindow.on('ready-to-show', () => {
    
    
    mainWindow.show();
    mainWindow.focus();
  });

  // 当窗口关闭时发出。在你收到这个事件后,你应该删除对窗口的引用,并避免再使用它。
  mainWindow.on('closed', () => {
    
    
    mainWindow = null;
  });
}

app.whenReady().then(createWindow);

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

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

[1.5] Run the project

[Before transformation] In the development stage, two terminals (react + electron) had to be started and run at the same time

// 第一个
npm run start

// 第二个
npm run electron

.

[Two: Transform configuration, environment domain name]

[2.1] Not required: Add merge start execution command
If you configure the environment variable [2.2], this step is ignored

Location: package.json/scripts. For details, see: [1.3]

"dev": "react-scripts start | electron .", // 【2.1介绍】合并命令,若有环境变量配置,不能使用
"dev:debug": "react-scripts start | electron . --debug" // 【2.1介绍】合并命令,debug 模式。若有环境变量配置,不能使用

Excuting an order

npm run dev
// 或:
npm run dev:debug

If the blank page is refreshed, react's local service is not started and the client is opened

[2.2] Not required: Configure environment variables , distinguish between development and packaging modes, and use different environment interface addresses

  • If you don't mind the trouble, you can manually switch the annotations yourself

For details, see: My other blog: React custom node, cross-env, webpack and other ways to organize different environment configuration commands https://blog.csdn.net/weixin_44461275/article/details/122988359

  • Install: cross-env
npm方式:
	npm install --save cross-env

cnpm方式:
	cnpm install --save cross-env

yarn方式:
	yarn add cross-env
  • Configuration execution command: see [1.3] package.json file for details
"start:dev": "cross-env MODE_ENV=development react-scripts start",
"electron:dev": "cross-env MODE_ENV=development electron .",
  • Modify main.js
// 导入app、BrowserWindow模块
// app 控制应用程序的事件生命周期。事件调用app.on('eventName', callback),方法调用app.functionName(arg)
// BrowserWindow 创建和控制浏览器窗口。new BrowserWindow([options]) 事件和方法调用同app
// Electron参考文档 https://www.electronjs.org/docs

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

function createWindow () {
    
    
  let mainWindow = new BrowserWindow({
    
    
    width: 1000, // 窗口宽度
    height: 800, // 窗口高度
    title: "Electron", // 窗口标题,如果由loadURL()加载的HTML文件中含有标签<title>,该属性可忽略
    icon: nativeImage.createFromPath('src/public/favicon.ico'), // "string" || nativeImage.createFromPath('src/image/icons/256x256.ico')从位于 path 的文件创建新的 NativeImage 实例
    webPreferences: {
    
     // 网页功能设置
      nodeIntegration: true, // 是否启用node集成 渲染进程的内容有访问node的能力
      webviewTag: true, // 是否使用<webview>标签 在一个独立的 frame 和进程里显示外部 web 内容
      webSecurity: false, // 禁用同源策略
      nodeIntegrationInSubFrames: true // 是否允许在子页面(iframe)或子窗口(child window)中集成Node.js
    }
  });

  // -----------------------------------------------------------------------------

  console.log('process.env.MODE_ENV--------------');
  console.log(process.env.MODE_ENV);

  if (process.env.MODE_ENV === 'development') {
    
    
    // 【开发时候使用】
    //需要和本地项目启动会端口号一致,一般不需要改。多项目启动会有端口被占用而 改变情况
    mainWindow.loadURL('http://localhost:3000/'); 
  } else {
    
    
    // 【打包时候使用】__dirname为当前文件路径
    mainWindow.loadURL(url.format({
    
    
      pathname: path.join(__dirname, './build/index.html'),
      protocol: 'file:',
      slashes: true
    }));
  }

  // -----------------------------------------------------------------------------

  // 解决应用启动白屏问题
  mainWindow.on('ready-to-show', () => {
    
    
    mainWindow.show();
    mainWindow.focus();
  });

  // 当窗口关闭时发出。在你收到这个事件后,你应该删除对窗口的引用,并避免再使用它。
  mainWindow.on('closed', () => {
    
    
    mainWindow = null;
  });
}

app.whenReady().then(createWindow);

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

app.on('activate', () => {
    
    
  if (BrowserWindow.getAllWindows().length === 0) {
    
    
    createWindow()
  }
});
  • Run: (all executed)
npm run start:dev
// +
npm run electron:dev

.

【3】Package items

[3.1] Check the configuration information in package.json: homepage: "." , if not, add it, see [1.3] for details

  • After the react project is packaged, all resource file paths are /static, and the entry point called by Electron is the file: protocol, and /static
    will be located in the root directory, so no static files can be found.
  • After the homepage field in the package.json file is set to ".", the path of the static file becomes a relative path.

[3.2] Modify the main.js packaging item

  • If the [2.2] environment variable is configured, this step is omitted . Already configured in a better way, no need to manually comment and unpack the code before executing
  • For details, see: [1.4]
  // 【二选一:打包时候使用】__dirname为当前文件路径
   mainWindow.loadURL(url.format({
    
    
     pathname: path.join(__dirname, './build/index.html'),
     protocol: 'file:',
     slashes: true
   }));

  // 【二选一:开发时候使用】
  //需要和本地项目启动会端口号一致,一般不需要改。多项目启动会有端口被占用而 改变情况
  // mainWindow.loadURL('http://localhost:3000/'); 

[3.3] Install electron-packager packaging dependencies

npm install electron-packager --save-dev
或:
npm install electron-packager -g

[3.4] Install electron-packager packaging dependencies

Not finished yet, to be finished

Guess you like

Origin blog.csdn.net/weixin_44461275/article/details/124411281