使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能

我正在参与CSDN《新程序员》有奖征文,活动链接:https://marketing.csdn.net/p/52c37904f6e1b69dc392234fff425442

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第1张图片

上一节 使用Electron构建跨平台的桌面应用程序(一)快速入门 简单的熟悉了一下Electron,这一节,主要是如何构建一个桌面应用,鉴于只使用 Electron 来构架工具开发效率较慢的原因,所以本文使用React【Umijs框架】 + Electron + Antd 来实现一个简单的计算器功能。

使用React【Umijs框架】 + Electron+ Antd 来实现一个简单的计算器功能

      • 一、环境搭建
        • 1、创建react项目
          • (1)、使用umijs脚手架
          • (2)、安装依赖
          • (3)、启动项目
          • (4)、修改配置
        • 2、引入electron
        • 3、引入antd
      • 二、项目文件部署
        • 1、simple-calculator 目录文件
          • (1)、input-button.tsx文件
          • (2)、 input-text.js文件
          • (3)、入口文件 index.tsx
          • (4)、样式文件simple-calculator.less
        • 2、编写Electron主进程文件
          • (1)、main.js文件
          • (2)、preload.js
          • (3)、修改package.json
          • (4)、代码执行
      • 三、Electron App打包
        • 1、安装和配置electron-builder
        • 2、webpack打包时修改配置
        • 3、 脚本命令配置


一、环境搭建

需要创建 Reat 环境,如果已有环境可忽略。

1、创建react项目

(1)、使用umijs脚手架
mkdir my-first-tool-app && cd my-first-tool-app
yarn create @umijs/umi-app

执行结果如图所示:

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第2张图片

(2)、安装依赖
yarn

如图所示:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第3张图片

(3)、启动项目
yarn start

如图所示,访问 http://localhost:8000 :
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第4张图片
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第5张图片

(4)、修改配置

默认的脚手架内置了 @umijs/preset-react,包含布局、权限、国际化、dva、简易数据流等常用功能。比如想要 ant-design-pro 的布局,编辑 .umirc.ts 配置 layout: {},并且需要安装 @ant-design/pro-layout

先安装 @ant-design/pro-layout

yarn add @ant-design/pro-layout

再修改文件:

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  layout: {},
  routes: [
    { path: '/', component: '@/pages/index' },
  ],
  fastRefresh: {},
});

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第6张图片
直接访问 http://localhost:8000 即刻看到效果,效果如图所示:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第7张图片
更详细的使用说明 可以去看 Umijs文档。

2、引入electron

先进入项目根目录,如果已在根目录则忽略:

cd my-tool-app/

引入electron使用命令:

yarn add electron --dev

3、引入antd

使用命令:

yarn add antd

二、项目文件部署

此时项目目录文件如下:

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第8张图片

为了便于项目文件管理,在pages目录下新建 simple-calculator目录。

此时,我们如果想通过入口的按钮入口使用计算器,那就需要路由进行管理。

路由支持:
.umirc.ts 文件中加入路由,文件内容为:

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  layout: {},
  routes: [
    { path: '/', component: '@/pages/index',name:'首页' },
    { path: '/simple-calculator', component: '@/pages/simple-calculator/',name:'计算器' },
  ],
  fastRefresh: {},
});

截图如下:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第9张图片

1、simple-calculator 目录文件

计算器展示区可分为两块,一块显示计算结果区,一块为按钮操作区,现在新建两个组件 input-button.tsx, input-text.tsx,入口文件 index.tsx 以及 样式文件simple-calculator.less

代码参考地址:https://www.jianshu.com/p/ab31487779c9

(1)、input-button.tsx文件
/*
 * @Author: your name
 * @Date: 2021-06-26 15:41:34
 * @LastEditTime: 2021-06-29 17:35:20
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /my-tool-app/src/pages/input-button.js
 */
// # input-button.js
import React, { Component,MouseEvent } from "react";
import { Button } from "antd";
import PropTypes from "prop-types";

interface IProps {
  onClick (event: MouseEvent<HTMLDivElement>): void,
}
class inButton extends Component <any,any> {
  static propTypes = {
    className: PropTypes.string,
  };
  static defaultProps = {
    className: "same_size",
  };
  render() {
    return (
      <Button
        className={this.props.className}
        value={this.props.value}
      >
        {this.props.value}
      </Button>
    );
  }
}
export default inButton;
(2)、 input-text.js文件
/*
 * @Author: your name
 * @Date: 2021-06-26 15:39:21
 * @LastEditTime: 2021-06-29 16:15:01
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /my-tool-app/src/pages/simple-calculator/input-text.js
 */
import React, { Component } from "react";
import { Input } from "antd";

const { TextArea } = Input;

class inText extends Component <any,any> {
  render() {
    return (
      <TextArea
        id="content"
        autoSize={false}
        value={this.props.value}
        readOnly={true}
      />
    );
  }
}
export default inText;
(3)、入口文件 index.tsx

代码如下:

/*
 * @Author: your name
 * @Date: 2021-06-29 13:57:46
 * @LastEditTime: 2021-06-29 17:42:55
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /my-first-tool-app/src/pages/simple-calculator/index.tsx
 */
import  './simple-calculator.less';
import React, { Component } from 'react';
import Button from './input-button'
import Text from './input-text'
type onClick = (value: string ) => (e: React.MouseEvent) => void;

class SimpleCalculator extends Component<any, any>  {
  
  constructor(props : any) {
   super(props);
   this.state = {
     string: "",
   };
   //const handleButton = (text: any) => this.handleButton.bind(this);
   this.handleButton = this.handleButton.bind(this);
  // const onClick =  (text: any)=> this.handleButton.bind(this);
  

 }


 public  handleButton(e: any | { target: { value: string }} ) {
   if (e.target.value !== undefined) {
     let instring = e.target.value;
     let prvcontent = this.state.string;
     let content = "";
     if (
       instring === "+" ||
       instring === "-" ||
       instring === "*" ||
       instring === "/"
     ) {
       content = prvcontent + " " + instring + " ";
     } else if (instring === "附加") {
       content = "";
     } else if (instring === "C") {
       content = "";
     } else if (instring === "Back") {
       if (prvcontent) {
         let newcontent = String(prvcontent);
         if (
           newcontent[newcontent.length - 1] === " " &&
           newcontent[newcontent.length - 3] === " "
         ) {
           prvcontent = newcontent.slice(0, newcontent.length - 3);
         } else {
           prvcontent = newcontent.slice(0, newcontent.length - 1);
         }
       }
       content = prvcontent;
     } else if (instring === "=") {
       if (prvcontent) {
         if (prvcontent.indexOf(" ") !== -1) {
           let arr = prvcontent.split(" ");
           let ans: string[] | number[] = [];
           let i = 0;
           while (i < arr.length) {
             if (arr[i] === "") {
               i++;
             } else if (arr[i] === "+") {
               ans.push(arr[i + 1] as never);
               i += 2;
             } else if (arr[i] === "-") {
               ans.push(-arr[i + 1] as never);
               i += 2;
             } else if (arr[i] === "*") {
               let a;
               let b = ans.pop();
               if (arr[i + 1] === "-") {
                 a = -arr[i + 2];
                 i += 3;
               } else {
                 a = arr[i + 1];
                 i += 2;
               }
              if(b!==undefined){
                b=parseFloat(b.toString());
               ans.push( b * a as never);
              }
             } else if (arr[i] === "/") {
               let a;
               let b = ans.pop();
               if (arr[i + 1] === "0") {
                 content = "ERROR!";
                 return;
               } else if (arr[i + 1] === "-") {
                 a = -arr[i + 2];
                 i += 3;
               } else {
                 a = arr[i + 1];
                 i += 2;
               }
               if(b!==undefined){
                b=parseFloat(b.toString());
                ans.push( (b / a) as never);
               }
             } else {
               ans.push(arr[i] as never);
               i++;
             }
           }
           let fin_ans = parseFloat(ans[0].toString());
           for (i = 1; i < ans.length; i++) {
             fin_ans += parseFloat(ans[i].toString());
           }
           content = fin_ans.toString();
         } else {
           content = prvcontent;
         }
       } else {
         content = "";
       }
     } else {
       if (prvcontent && parseInt(prvcontent) !== 0) {
         content = prvcontent + instring;
       } else {
         content = instring;
       }
     }
     this.setState({
       string: content,
     });
   }
 }

render() {
   return (

     <div id="main">
       <div id="input_text">
         <Text value={this.state.string} />
       </div>
       <div id="input_button" onClick={this.handleButton}>
         <Button value={1} />
         <Button value={2} />
         <Button value={3} />
         <Button value={"Back"} />
         <Button value={"C"} />
         <Button value={4} />
         <Button value={5} />
         <Button value={6} />
         <Button value={"+"} />
         <Button value={"-"} />
         <Button value={7} />
         <Button value={8} />
         <Button value={9} />
         <Button value={"*"} />
         <Button value={"/"} />
         <Button value={"附加"} />
         <Button value={0} />
         <Button value={"."} />
         <Button value={"="} className={"equal_size"} />
       </div>
     </div>

   );
 }
}





export default SimpleCalculator;
(4)、样式文件simple-calculator.less

代码如下:

@import '~antd/dist/antd.less';
*{
    margin: 0px;
    padding: 0px;
    }
.content{
    width: 170px;
    margin:100px 0 0 100px;
}
#main{
    margin: 0 auto;
    width: 50%;
    height: 90vh;
  }
  
  #input_text{
    padding: 3%;
    height: 25%;
    display: flex;
  }
  #input_button{
    /*border: 1px solid black;*/
    margin: 0 2%;
    width: 96%;
    height: 70%;
    display: flex;
    flex-wrap: wrap;
  }
  
  #input_text #content{
    flex: auto;
    resize: none;
    margin: 0;
    width: 100%;
    padding: 10px;
    font-size: 2vw;
    border: 1px solid #d9d9d9;
  }
  #input_button .same_size{
    flex: auto;
    margin: 1%;
    width: 18%;
    height: 20%;
    font-size: 2vw;
  }
  #input_button .equal_size{
    flex: auto;
    margin: 1%;
    width: 38%;
    height: 20%;
    font-size: 1.5vw;
  }
  #components-layout-demo-top-side .logo {
    float: left;
    width: 120px;
    height: 31px;
    margin: 16px 24px 16px 0;
    background: rgba(255, 255, 255, 0.3);
  }
  
  .ant-row-rtl #components-layout-demo-top-side .logo {
    float: right;
    margin: 16px 0 16px 24px;
  }
  
  .site-layout-background {
    background: #fff;
  }
  .site-layout-content {
    min-height: 280px;
    padding: 24px;
    background: #fff;
  }
  #components-layout-demo-top .logo {
    float: left;
    width: 120px;
    height: 31px;
    margin: 16px 24px 16px 0;
    background: rgba(255, 255, 255, 0.3);
  }
  .ant-row-rtl #components-layout-demo-top .logo {
    float: right;
    margin: 16px 0 16px 24px;
  }

结果如下:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第10张图片

2、编写Electron主进程文件

根据上一节:使用Electron构建跨平台的桌面应用程序(一)快速入门。先在根目录创建main.jspreload.js 文件

(1)、main.js文件

注意,地址端口和 上一节 内容不同,需新增部分:

  mainWindow.loadURL("http://localhost:8000");
  mainWindow.openDevTools();

文件整体内容如下:

/*
 * @Author: your name
 * @Date: 2021-06-26 13:52:47
 * @LastEditTime: 2021-06-30 11:36:49
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /my-tool-app/public/electron.js
 */
// electron.js
// Modules to control application life and create native browser window
// 导入作为公共JS模块:
const { app, BrowserWindow } = require('electron')
const path = require('path')

let mainWindow;

function createWindow () {
  // Create the browser window.
   mainWindow = new BrowserWindow({
    width: 1000,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  // and load the index.html of the app.
  mainWindow.loadFile('index.html')

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()

  mainWindow.loadURL("http://localhost:8000");
  mainWindow.openDevTools();
  

  mainWindow.on("closed", function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
  createWindow()

  app.on('activate', function () {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})

// In this file you can include the rest of your app's specific main process
// code. 也可以拆分成几个文件,然后用 require 导入。
(2)、preload.js

该文件内容不变,用上一节的即可。

/*
 * @Author: your name
 * @Date: 2021-06-26 14:08:33
 * @LastEditTime: 2021-06-26 14:08:34
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /my-tool-app/public/preload.js
 */
// preload.js

// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener('DOMContentLoaded', () => {
    const replaceText = (selector, text) => {
      const element = document.getElementById(selector)
      if (element) element.innerText = text
    }
  
    for (const dependency of ['chrome', 'node', 'electron']) {
      replaceText(`${dependency}-version`, process.versions[dependency])
    }
  })
  
(3)、修改package.json

在package.json中配置程序主入口main.js,并且添加运行Electron的脚本命令,如图:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第11张图片
文件整体代码如下:

{
  "name": "my-first-tool-app",
  "version": "0.1.0",
  "main": "main.js",
  "description": "my-first-tool-app",
  "author": "sunct",
  "private": true,
  "scripts": {
    "start": "umi dev",
    "build": "umi build",
    "postinstall": "umi generate tmp",
    "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
    "test": "umi-test",
    "test:coverage": "umi-test --coverage",
    "electron": "electron ."
  },
  "gitHooks": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "*.{js,jsx,less,md,json}": [
      "prettier --write"
    ],
    "*.ts?(x)": [
      "prettier --parser=typescript --write"
    ]
  },
  "dependencies": {
    "@ant-design/icons": "^4.6.2",
    "@ant-design/pro-layout": "^6.20.0",
    "@umijs/preset-react": "1.x",
    "antd": "^4.16.6",
    "umi": "^3.4.25"
  },
  "devDependencies": {
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "@umijs/test": "^3.4.25",
    "electron": "^13.1.4",
    "lint-staged": "^10.0.7",
    "prettier": "^2.2.0",
    "react": "17.x",
    "react-dom": "17.x",
    "typescript": "^4.1.2",
    "yorkie": "^2.0.0"
  }
}

(4)、代码执行

依次执行:

npm start 
npm run electron

执行后会弹出一个程序窗口,结果如图:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第12张图片
为了简化执行,可以使concurrently库同步运行多命令,同时运行electron和react。使用wait-on库等待8000端口启动完成之后运行electron。具体的脚本命令如下:

yarn add concurrently wait-on --dev

修改 package.json 文件:

    "electron": "concurrently \"umi dev start\" \"wait-on http://localhost:8000 && electron .\""

然后先关掉前面执行的npm startnpm run electron命令,再次重新执行:

npm run electron

运行结果如下:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第13张图片
接下来就是打包程序。


三、Electron App打包

这是完成程序包前的最后一步,既是最重要的一步,也是相对麻烦的一步。

基于Umi搭建Electron App,其实可以理解为通过Electron将使用Umi搭建的Web应用包装成桌面应用。这就需要对Web应用和Elecrton分别打包。

①、 web应用打包:使用webpack打包
② 、桌面应用程序打包:使用electron-builder打包
③ 、将Web应用打包后的文件(build文件夹中的所有文件)复制到桌面应用程序中(通过electron-builder中的files配置。

1、安装和配置electron-builder

Electron App的打包方式 上一节 使用的是electron-forge,那这次来使用electron-builder

参考electron-builder官网 或 代码仓库,执行以下命令安装electron-builder作为开发依赖。

  • 安装electron-builder

命令如下:

yarn add electron-builder --dev
  • 配置electron-builder

在package.json文件后面加入以下配置:

 "build": {
    "appId": "my-first-tool-app",
    "files":[
      "build/**/*"
    ],
    "productName":"my-first-tool-app",
    "directories":{
      "output":"dist"
    },
    "mac": {
      "category": "your.app.category.type",
      "icon": "icon.icns"
    }
  }

其他配置项请参考 electron-builder官方配置文档。

2、webpack打包时修改配置

  • .umirc.ts中修改或增加配置:
 publicPath: './',
  outputPath:'build',
  hash: true,
  history: {
    type: 'hash',
  },

如图所示:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第14张图片

  • Electron主进程文件main.js 修改:

① 代码修改

const isPro = process.env.NODE_ENV !="development";

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第15张图片

  if (isPro) {
    mainWindow.loadFile("./build/index.html");
  } else {
    mainWindow.loadURL("http://localhost:8000");
    mainWindow.openDevTools();
  }

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第16张图片

在生产环境和开发环境下加载渲染进程的方式不同,所以需要判断当前的环境然后进行分别处理。
环境变量的配置可以看一下 cross-env 这个库,在使用Umi创建工程时,cross-env是默认安装的。

如果没有则可以手动安装,命令: npm install --save-dev cross-envyarn add cross-env --save-dev

② 位置变动

之前在编写Electron主进程文件的时候,暂时将·main.js·放在了根目录,由于main.js与其他模块之间没有任何引用关系,所以webpcak打包时无法把main.js打进去。生产环境下main.js中加载index.html就找不到这个文件,执行打包文件会出现白屏的情况。

解决办法:
把main.js放到public文件夹下,因为webpack打包时public文件夹下的文件都会原封不动地复制到build文件夹中(如果有自己写的依赖,也顺便移到public目录下。
package.json中配置项"main"的值由"main.js“改为”build/main.js"。

  "main": "build/main.js",

图标部分也改成:

  "build": {
  ... 
	 "mac": {
	      "category": "your.app.category.type",
	      "icon": "build/icon.icns"
	    }
}

如果没有public 目录,则手动创建一个,其中包含文件如下:

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第17张图片

3、 脚本命令配置

  • 生产环境和开发环境下electron启动命令

通过在package.json中配置脚本命令的方式来设置当前的环境,如下:


  "electron-start":"yarn build && cross-env NODE_ENV=production electron build/main.js",
  "electron-dev":"concurrently \"cross-env BROWSER=none yarn start \" \"wait-on http://localhost:8000 && cross-env NODE_ENV=development electron public/main.js\" "
  

在这里插入图片描述
图中第16行是生产环境下electron启动命令,通过cross-env NODE_ENV=production来设置环境变量为“production”表明是生产环境,生产环境下electron主进程是直接执行的打包生成的build文件夹下的main.js文件。

图中第17行是开发环境下electron启动命令,设置环境变量的方式与生产环境类似,但是开发环境下electron主进程是执行的public文件下的main.js

  • 针对不同平台的electron打包命令:

package.json里我只配置了windows和mac两种平台的打包命令(它们的共同点是都要先执行yarn build对react进行打包),因为我的电脑是mac,我只尝试了mac下的打包。

配置如下:


    "dis-mac":"yarn build && electron-builder --mac",
    "dis-win32":"yarn build && electron-builder --win --ia32",
    "dis-win64":"yarn build && electron-builder --win --x64"
    

在这里插入图片描述
打包如下:

npm run dis-mac

执行结果如下:

$ npm run dis-mac
Debugger attached.

> [email protected] dis-mac
> yarn build && electron-builder --mac

Debugger attached.
yarn run v1.15.2
$ umi build
Debugger attached.

✔ Webpack
  Compiled successfully in 30.69s

Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db

Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
Debugger attached.
Debugger attached.
Debugger attached.
Waiting for the debugger to disconnect...
Waiting for the debugger to disconnect...
Waiting for the debugger to disconnect...
 DONE  Compiled successfully in 30689ms                                                                                        下午3:00:28

 File                        Size                   Gzipped

 build/umi.d1347c73.js       933.1 KB               298.8 KB
 build/main.js               624.0 B                395.0 B
 build/preload.js            204.0 B                180.0 B
 build/umi.53ebdfcc.css      514.8 KB               65.3 KB

  Images and other types of assets omitted.

Waiting for the debugger to disconnect...
✨  Done in 33.60s.
Waiting for the debugger to disconnect...
Debugger attached.
  • electron-builder  version=22.11.7 os=20.3.0
  • loaded configuration  file=package.json ("build" field)
  • writing effective config  file=dist/builder-effective-config.yaml
  • rebuilding native dependencies  dependencies=[email protected] platform=darwin arch=x64
  • packaging       platform=darwin arch=x64 electron=13.1.4 appOutDir=dist/mac
  • skipped macOS application code signing  reason=cannot find valid "Developer ID Application" identity or custom non-Apple code signing certificate, see https://electron.build/code-signing allIdentities=     0 identities found
                                                Valid identities only
     0 valid identities found
  • building        target=macOS zip arch=x64 file=dist/my-first-tool-app-0.1.0-mac.zip
  • building        target=DMG arch=x64 file=dist/my-first-tool-app-0.1.0.dmg
  • building block map  blockMapFile=dist/my-first-tool-app-0.1.0.dmg.blockmap

目录如下:

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第18张图片
找到 dmg 包并安装即可,安装结果:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第19张图片
打开软件并使用:
使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第20张图片



END

如有问题请在下方留言。

或关注我的公众号“孙三苗”,输入“联系方式”。获得进一步帮助。

使用Electron构建跨平台的桌面应用程序(二)使用React【Umijs框架】+ Electron+ Antd 来实现一个简单的计算器功能_第21张图片

你可能感兴趣的:(Electron,Electron,node.js,Umijs,Reat,Antd)