python 打包桌面应用另类实现方法:基于 Python + Node.js + Vue.js 的桌面应用程序,使用 pywebview 提供原生桌面体验。
以本人项目举例:
### 智飞部桌面应用打包流程详解
智飞部桌面应用的打包流程设计旨在实现“一份代码,多环境分发”的目标,通过自动化的构建脚本将 Python 后端、Node.js 本地服务以及 Vue.js 前端资源整合为单个可执行文件。以下是基于项目架构的完整打包流程介绍。
#### 环境准备与依赖安装
在执行打包操作前,需确保开发环境已具备基础的运行依赖。首先,在 Python 环境中安装核心库,包括用于构建桌面窗口的 `pywebview`、处理系统互斥量的 `pywin32` 以及图像处理库 `Pillow`。其次,进入 `node_server` 目录,执行 `npm install` 以安装 Node.js 端所需的 Express 服务及更新模块依赖。这一步确保了本地服务能够正常启动并处理前端的代理请求。
#### 配置文件定制
项目采用 JSON 配置文件驱动应用行为,这是打包流程中实现多版本、多客户定制化的核心环节。开发者需根据目标环境(如测试环境、生产环境或特定客户定制版)准备相应的配置文件(如 `config.test.json`)。在配置文件中,需明确定义应用的基础信息(名称、版本号)、UI 表现(主题色、图标路径)、服务器地址(本地端口、远程更新地址、API 代理目标)以及窗口属性(宽高、调试模式)。通过修改这些字段,可以在不改动代码逻辑的情况下,生成不同品牌或连接不同后端服务的独立应用版本。
#### 执行自动化打包
项目推荐使用根目录下的 `build.py` 脚本进行自动化打包,该脚本封装了 PyInstaller 的复杂参数。
- **默认打包**:直接运行 `python build.py`,脚本将读取默认配置进行构建。
- **指定配置打包**:运行 `python build.py config.test.json` 或简写为 `python build.py test`,脚本会自动识别并加载对应的 JSON 配置文件。
脚本执行时,会自动调用 PyInstaller,通过 `--onefile` 参数将所有资源(包括 Node.js 运行时、`node_modules`、前端 `html` 目录、Python 模块及图标资源)打包进单个 exe 文件中。同时,脚本会处理 `--hidden-import` 参数,确保 `modules` 目录下的各个功能模块(如配置加载、单实例锁、窗口管理等)被正确包含。
#### 产物输出与验证
打包完成后,生成的可执行文件将输出至 `dist/` 目录,命名格式通常为“应用名称_版本号.exe”(例如 `智飞部_v1.0.0.exe`)。由于采用了单文件打包模式,该 exe 文件体积通常在 80-120 MB 之间(包含完整的 Node.js 环境)。开发者可直接运行该文件进行验证:应用启动时会初始化单实例互斥锁,自动拉起内置的 Node.js 本地服务,加载前端页面,并根据配置检查远端更新。
#### 远端更新资源准备
为了实现客户端的“热更新”功能,打包流程的最后一步涉及远端资源的部署。开发者需将前端构建产物(`html` 目录下的 `index.html`、`assets`、`version.json` 等)打包为 `dist.zip` 文件,并上传至配置文件 `server.remote_base_url` 指定的远程服务器根目录。当客户端启动时,Node.js 服务会自动对比本地与远端的 `version.json`,若有新版本则自动下载并解压该 ZIP 包,从而实现无需重新安装 exe 即可更新前端业务逻辑的能力。
# 智飞部桌面应用 ## 项目简介 基于 Python + Node.js + Vue.js 的桌面应用程序,使用 pywebview 提供原生桌面体验。 ### 核心特性 - 🚀 **单文件打包**:PyInstaller 打包为单个 exe,分发方便 - 🔄 **自动热更新**:启动时自动检测远端 `dist.zip`,解压即用,无需重装 - 🎨 **可配置化**:一份代码 + JSON 配置文件 = 多版本/多客户/多环境 - 🔒 **单实例运行**:互斥量 + 端口锁定,防重复启动 - 🧱 **模块化架构**:Python 端按功能拆分为 `modules/`,Node 端拆分为 `lib/` ## 技术栈 | 层 | 技术 | |---|---| | 前端 | Vue.js + Vite | | 本地服务 | Node.js + Express(API 代理 + 静态托管) | | 桌面框架 | Python + pywebview(Edge WebView2) | | 打包 | PyInstaller --onefile | ## 快速开始 ### 环境准备 ```bash # Python 依赖 pip install pywebview pywin32 Pillow # Node.js 依赖(进入 node_server 目录执行) cd node_server npm install ``` ### 开发运行 ```bash python main.py ``` > Node.js 服务器由 Python 自动启动,无需手动操作。 ### 打包 exe #### 方式一:自动化脚本(推荐) ```bash # 默认配置 python build.py # 指定配置 python build.py config.test.json # 简写(自动补全 config.xxx.json) python build.py test ``` 输出在 `dist/智飞部_v1.0.0.exe`。 #### 方式二:PyInstaller 命令行 ```bash pyinstaller --name 智飞部 --windowed --onefile ^ --icon app_icon.ico ^ --add-data "config.default.json;." ^ --add-data "node_server;node_server" ^ --add-data "html;html" ^ --add-data "modules;modules" ^ --add-data "logo.png;." ^ --hidden-import webview ^ --hidden-import modules ^ --hidden-import modules.config ^ --hidden-import modules.singleton ^ --hidden-import modules.resources ^ --hidden-import modules.server ^ --hidden-import modules.splash ^ --hidden-import modules.window ^ --hidden-import modules.app ^ main.py ``` --- ## 项目结构 ``` web-test/ ├── main.py # 入口(编排脚本,~107 行) ├── build.py # 自动化打包脚本 ├── generate_config.py # 交互式生成配置文件 │ ├── modules/ # Python 功能模块 │ ├── config.py # 配置加载 & 默认值 │ ├── singleton.py # 单实例互斥锁 │ ├── resources.py # 资源路径 & 用户数据目录 │ ├── server.py # Node.js 进程管理 & 更新监控 │ ├── splash.py # 启动界面(Tkinter) │ ├── window.py # 桌面窗口(pywebview) │ └── app.py # 应用生命周期(重启 / 启动流程) │ ├── node_server/ # Node.js 本地服务器 │ ├── server.js # Express 主入口 │ ├── lib/ │ │ ├── download.js # 下载 & ZIP 解压工具 │ │ └── updater.js # 版本检查 & 热更新逻辑 │ ├── node.exe # Node.js 运行时 │ ├── node_modules/ # npm 依赖 │ ├── package.json │ └── package-lock.json │ ├── html/ # 前端构建产物 │ ├── index.html │ ├── assets/ │ └── version.json │ ├── config.default.json # 默认配置 ├── config.test.json # 测试环境配置 ├── logo.png # 启动 Logo ├── app_icon.ico # 应用图标 │ └── dist/ # 打包输出 └── 智飞部_v1.0.0.exe ``` --- ## 配置系统 一份 JSON 文件驱动整个应用,支持多版本、多环境、多客户。 ```json { "app": { "name": "智飞部", "title": "智能业务管理平台", "window_title": "智飞部", "version": "1.0.0" }, "ui": { "logo": "logo.png", "icon": "app_icon.ico", "theme_color": "#1890ff", "background_color": "#f0f2f5" }, "server": { "port": 8080, "host": "127.0.0.1", "remote_base_url": "https://app.sys.zhifeibu.com", "api_target": "https://app.sys.zhifeibu.com", "api_prefix": "/adminapi/" }, "update": { "zip_filename": "dist.zip" }, "window": { "width": 1360, "height": 800, "min_width": 800, "min_height": 600, "debug": false } } ``` ### 配置项说明 | 字段 | 说明 | |---|---| | `app.name` | 应用名称(影响用户数据目录路径) | | `app.version` | 版本号(用于更新比较) | | `ui.theme_color` | 启动界面主题色 | | `server.port` | 本地服务端口 | | `server.remote_base_url` | 远端服务器根地址(版本检查 & 更新下载) | | `server.api_target` | API 代理目标地址 | | `update.zip_filename` | 远端 ZIP 包文件名(默认 `dist.zip`) | | `window.debug` | 是否开启 webview 调试工具 | ### 典型使用场景 | 场景 | 操作 | |---|---| | 开发环境 | `python main.py --config config.dev.json` | | 测试环境 | `python build.py config.test.json` | | 生产环境 | `python build.py config.prod.json` | | 客户定制 | 修改 `app.name` + `ui.theme_color` + `server.*` 后打包 | | 白标产品 | 替换 `logo.png` + `app_icon.ico`,调整配置即可 | --- ## 命令行参数 ```bash # 重置用户数据(清除缓存和已更新的资源) 智飞部.exe --reset # 指定配置文件 智飞部.exe --config config.test.json 智飞部.exe -c config.test.json ``` --- ## 自动更新机制 应用启动时 Node.js 服务器自动执行更新检查: 1. 读取本地 `html/version.json` 获取当前版本 2. 请求远端 `${remote_base_url}/version.json` 获取服务器版本 3. 版本号比较(语义化版本),有新版则继续 4. 下载 `dist.zip` 到临时目录 5. 清理旧 `html/` 目录,解压 `dist.zip` 覆盖 6. 前端页面自动刷新,应用新版本 > `dist.zip` 包含完整前端资源(`index.html`、`assets/`、`favicon.ico`、`version.json` 等),新增文件无需修改代码。 --- ## 常见问题 ### Q: 打包后 exe 文件很大? A: 正常。因为包含了完整的 Node.js 运行时和 node_modules。`--onefile` 模式下约 80-120 MB。 ### Q: 如何修改远端服务器地址? A: 修改配置文件中 `server.remote_base_url` 和 `server.api_target`,重新打包即可。 ### Q: 如何清除缓存? A: 运行 `智飞部.exe --reset`,或手动删除 `%LOCALAPPDATA%\智飞部\html` 目录。 ### Q: 能同时运行多个实例吗? A: 不能,有单实例保护。如需多版本并行,使用不同端口配置分别打包。 ### Q: 新增了 Python 模块怎么打包? A: 在 `build.py` 的 `--hidden-import` 列表中添加新模块名,在 `main.spec` 的 `hiddenimports` 列表中同步添加。 --- ## 许可证 本项目仅供学习和内部使用。