• electron + flask server 开发/打包项目示例


    electron + flask server 开发/打包项目示例

    开发环境

    python3.6.8

    node v12.22.5

    win7

    初始化项目

    mkdir python-electron-app
    cd python-electron-app
    npm init -y
    

    初始化后,在项目python-electron-app中,生成的pacakge.json大致如下

    {
      "name": "python-electron-app",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo "Error: no test specified" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    

    开发 flask server

    • (建议) 创建python虚拟环境进行管理
      python -m venv venv
    
      venvScriptsactivate.bat
    
    • 安装本相关python模块
      pip install flask==2.0.1
      pip install flask-cors==3.0.10
      pip install simplecalculator==0.0.4
      pip install dataclasses==0.6
      pip install pyinstaller==4.5.1
    
    • 在项目根目录下,创建py文件夹,后续在py文件夹下进行python代码开发

    • 创建flask app.py 内容如下:

    from calculator.simple import SimpleCalculator
    from flask import Flask, render_template
    from flask_cors import cross_origin
    
    app = Flask(__name__)
    
    
    def calcOp(text):
        """based on the input text, return the operation result"""
        try:
            c = SimpleCalculator()
            c.run(text)
            return c.log[-1]
        except Exception as e:
            print(e)
            return 0.0
    
    
    @app.route('/')
    def homepage():
        home = 'flask_welcome.html'
        return render_template(home)
    
    
    @app.route("/<input>")
    @cross_origin()
    def calc(input):
        return calcOp(input)
    
    
    if __name__ == "__main__":
        app.run(host='127.0.0.1', port=5001, use_reloader=False)
        # 注意,如果没有指定use_reloader=False,后续将其打包成exe后,运行exe会产生两个进程,在electron窗口关闭时kill掉进程时,会有一个守护进程无法kill掉
    
    
    
    • 创建flask template 如下:
      templates/flask_welcome.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>Welcome to Flask</h1>
        <h3>This is a homepage rendered by flask.</h3>
    </body>
    </html>
    
    • 测试 flask server 运行情况
    python py/app.py
    

    访问 127.0.0.1:5001 后,正常情况会返回flask_welcome.html中的内容;

    访问 127.0.0.1:5001/1 + 1 ,正常情况会返回calc视图的响应内容:result:2.0

    安装局部electron

    cnpm install --save-dev electron@14.0.1 -S

    本版本安装的electron版本为“14.0.1”

    创建electron主入口

    主入口由package.json 中的main指定,如本项目,主入口为index.js

    • 在项目根目录下创建index.js 如下
    // 引入nodejs模块
    const {app, BrowserWindow} = require('electron');
    const path = require('path');
    
    // 创建窗口函数
    function createWindow() {
        win = new BrowserWindow({ // 设置窗口option
             800,
            height: 600,
            webPreferences: {
                nodeIntegration: true,
                contextIsolation: false, // 注意如果没有该选项,在renderer.js 中 require is not defined
                enableRemoteModule: true
            }
        });
        win.loadFile('index.html');// 窗口加载本地html
        win.webContents.openDevTools();   // 打开开发者工具调试选项
    }
    
    // 启动flask server,通过python-shell 调用python脚本(开发调试阶段)
    function startServer_PY() {
        var {PythonShell} = require('python-shell');
    
        let options = {
            mode: 'text',
            pythonPath: 'venv/Scripts/python'
        };
    
        PythonShell.run('./py/app.py', options, function (err, results) {
            if (err) throw err;
            // results is an array consisting of messages collected during execution
            console.log('response: ', results);
        });
    }
    
    
    
    // 初始化函数
    function initApp() {
        startServer_PY();
        createWindow();
    }
    
    
    // electron ready 事件触发
    app.on('ready', initApp);
    
    // electron 窗口关闭事件触发
    app.on('window-all-closed', () => {
        if (process.platform !== 'darwin') {
            app.quit()
        }
    });
    
    
    
    • 安装python-shell 模块

    cnpm install python-shell -S

    • 在项目根目录下创建index.html 如下
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Calling Python from Electron!</title>
        <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';connect-src *">
    </head>
    
    <body>
    <h1>Simple Python Calculator!</h1>
    <p>Input something like <code>1 + 1</code>.</p>
    <input id="input" value="1 + 1"></input>
    <input id="btn" type="button" value="Send to Python!"></input>
    </br>
    Got <span id="result"></span>
    <a href="http://127.0.0.1:5001/">go flask template</a>
    
    <script src="./renderer.js"></script>
    
    </body>
    </html>
    
    
    • 创建渲染进程renderer.js 如下
    let input = document.querySelector('#input');
    let result = document.querySelector('#result');
    let btn = document.querySelector('#btn');
    
    function onclick() {
        // 发送http请求
        fetch(`http://127.0.0.1:5001/${input.value}`).then((data) => {
            return data.text();
    
        }).then((text) => {
            console.log("data: ", text);
            result.textContent = text;
        }).catch(e => {
            console.log(e);
        })
    }
    
    // 添加按钮点击事件
    btn.addEventListener('click', () => {
        onclick();
    });
    

    运行electron

    在package.json 的scripts中添加运行命令如下
    "start": "electron ."

    在项目根目录下,执行命令运行
    npm run start

    运行后,正确情况是打开electron窗口:

    点击按钮"Send to Python"后,会正确发送请求到flask中并获得响应;

    点击链接“go flask template” 则会跳转到flask_welcome.html中。

    flask 打包成exe

    • 在package.json 中的scripts 里面添加python打包脚本

    "build-python": "pyinstaller -D -p ./venv/Lib/site-packages py/app.py --add-data=py/templates;templates --distpath ./pydist",

    -p 指定依赖包位置,如果没有指定,打包后会缺少响应的依赖模块

    --add-data 指定外部资源位置,如果没有指定,运行后会找不到flask template 资源

    • 运行打包脚本
      npm run build-python

    打包完成后,会生成可执行文件 pydist/app/app.exe,可运行该exe检查flask是否正确运行

    调整electron index.js

    调整前,是使用python-shell调用app.py 脚本来启动flask。当flask打包成exe后,需调整启动flask位置的命令
    调整后如下

    // 引入nodejs模块
    const {app, BrowserWindow} = require('electron');
    const path = require('path');
    
    // 创建窗口函数
    function createWindow() {
        win = new BrowserWindow({ // 设置窗口option
             800,
            height: 600,
            webPreferences: {
                nodeIntegration: true,
                contextIsolation: false, // 注意如果没有该选项,在renderer.js 中 require is not defined
                enableRemoteModule: true
            }
        });
        win.loadFile('index.html');// 窗口加载本地html
        win.webContents.openDevTools();   // 打开开发者工具调试选项
    }
    
    // 启动flask server,通过python-shell 调用python脚本(开发调试阶段)
    function startServer_PY() {
        var {PythonShell} = require('python-shell');
    
        let options = {
            mode: 'text',
            pythonPath: 'venv/Scripts/python'
        };
    
        PythonShell.run('./py/app.py', options, function (err, results) {
            if (err) throw err;
            // results is an array consisting of messages collected during execution
            console.log('response: ', results);
        });
    }
    
    // 启动flask server,通过子进程执行已经将python项目打包好的exe文件(打包阶段)
    function startServer_EXE() {
        let script = path.join(__dirname, 'pydist', 'app', 'app.exe')
        pyProc = require('child_process').execFile(script)
        if (pyProc != null) {
            console.log('flask server start success')
        }
    }
    
    // 停止flask server 函数
    function stopServer() {
        pyProc.kill()
        console.log('kill flask server  success')
        pyProc = null
    }
    
    // 初始化函数
    function initApp() {
        startServer_EXE();
        createWindow();
    }
    
    
    // electron ready 事件触发
    app.on('ready', initApp);
    
    // electron 窗口关闭事件触发
    app.on('window-all-closed', () => {
        if (process.platform !== 'darwin') {
            app.quit()
        }
        stopServer()
    });
    
    
    • 重新运行electron进行调试
      npm run start

    electron 打包

    • 安装electron打包模块

    cnpm install --save-dev electron-packager@15.4.0 -S

    • 在package.json 的scripts中添加打包命令

    "pack-app": "electron-packager . --overwrite --ignore=py$ --arch=x64 --download.mirrorOptions.mirror=https://npm.taobao.org/mirrors/electron/"

    注意,如果没有指定--download.mirrorOptions.mirror,下载对应系统的electron-xxx.zip 包会耗时非常长!!!

    • 运行electron 打包命令

    npm run pack-app

  • 相关阅读:
    linux常用命令
    Python 父类调用子类方法
    import win32api 安装pip install pypiwin32
    Python 封装DTU-215码流卡 第一天
    git apply -v 提示 Skipped patch 打不上patch的解决办法
    2019/10/29
    12/9/2019
    11/9/2019
    9/7/2019
    人生若有命中注定
  • 原文地址:https://www.cnblogs.com/guanfuchang/p/15322947.html
Copyright © 2020-2023  润新知