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
  venv\Scripts\activate.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
        width: 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
        width: 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM