mirror of
https://ghfast.top/https://github.com/aeroxw/easy_tdx_max.git
synced 2026-09-12 23:54:21 +08:00
fix(packaging): v1.19.2 修复干净 Windows 上 EXE 页面纯黑(MIME 类型)
根因:干净 Windows(无开发环境)注册表里没有 .js 的 Content Type 映射,
mimetypes.guess_type('.js') 返回 None,StaticFiles 回退到 text/plain。
浏览器 <script type="module"> 启用严格 MIME 检查,拒绝执行 text/plain
的 JS → Vue 不挂载 → 页面纯黑(/docs 不受影响因为它是 API 路由)。
修复:mount 前用 mimetypes.add_type 强制注册 .js/.mjs/.css/.svg 的正确
MIME,无论机器装没装开发工具都生效。
同时改 easy_tdx.spec:datas 用 pathlib.rglob 逐文件展开,更可靠。
This commit is contained in:
@@ -2,6 +2,15 @@
|
||||
|
||||
本文件记录 easy-tdx 的版本变更。格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/)。
|
||||
|
||||
## [1.19.2] — 2026-07-07
|
||||
|
||||
**修复干净 Windows 上 EXE 双击后页面纯黑** —— v1.19.1 在没装开发工具的 Windows(如老人电脑)上双击 EXE,浏览器打开 `localhost:8000` 后页面纯黑、`/docs` 却能正常打开。根因:干净 Windows 的注册表里没有 `.js` 文件的 `Content Type` 映射,Python 的 `mimetypes.guess_type('.js')` 返回 `None`,FastAPI/Starlette 的 `StaticFiles` 回退到 `text/plain`。但 `index.html` 里的 `<script type="module">` 启用严格 MIME 检查,浏览器拒绝执行 `text/plain` 的 JS(报错 `Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of "text/plain"`),Vue 根本不挂载 → 纯黑。修复:在 mount 前用 `mimetypes.add_type` 强制注册 `.js/.mjs/.css/.svg` 的正确 MIME,无论机器装没装开发工具都生效。
|
||||
|
||||
### 修复
|
||||
|
||||
- **EXE 页面纯黑(MIME 类型)**(`src/easy_tdx/web/app.py`)—— mount StaticFiles 前强制 `mimetypes.add_type("application/javascript", ".js")` 等 4 项。在干净 Windows(用户名 INTEL、无开发环境)实测复现并修复:JS/CSS 现在返回正确的 `Content-Type`,浏览器不再拒绝执行 module script。
|
||||
- **spec 前端文件打包**(`easy_tdx.spec`)—— v1.19.1 的 `datas += [("web-ui/dist", "web_dist")]` 实际能工作(PyInstaller 把目录路径当 glob 处理),但为可靠性改为用 `pathlib.rglob` 逐文件展开成 `(src_file, dest_dir)` 元组列表,并加 dist 不存在时的 WARNING 提示。
|
||||
|
||||
## [1.19.1] — 2026-07-07
|
||||
|
||||
**支持打包成单一 Windows EXE + GitHub Actions 自动发版** —— 面向"一点都不懂的老年"用户群,让 easy-tdx 能从"开发者双进程"形态变成"双击 EXE → 浏览器自动打开 → 看到回测界面"的零门槛形态。本版为 Phase 1(未签名自测版);Phase 2 引入代码签名消除 SmartScreen 提示,Phase 3 加 macOS。
|
||||
|
||||
+21
-2
@@ -36,8 +36,27 @@ datas: list[tuple[str, str]] = []
|
||||
datas += collect_data_files("tzdata")
|
||||
# Pillow 的图像格式插件(PngImagePlugin 等)随数据文件一起收集
|
||||
datas += collect_data_files("PIL")
|
||||
# 前端 dist 打包到运行时 sys._MEIPASS/web_dist
|
||||
datas += [("web-ui/dist", "web_dist")]
|
||||
|
||||
# 前端 dist 整目录收集到运行时 sys._MEIPASS/web_dist。
|
||||
# 关键坑(v1.19.1 的 bug):PyInstaller 的 datas=[(src, dst)] 里 src 必须是
|
||||
# **文件路径**而非目录——写成 ('web-ui/dist', 'web_dist') 会被当成不存在的
|
||||
# 文件静默跳过(EXE 内 0 个前端文件 → 页面纯黑)。正确做法是用 glob 展开
|
||||
# dist 下每个文件为独立的 (src_file, dest_dir) tuple。spec 在仓库根执行,
|
||||
# 所以相对路径基于仓库根。
|
||||
from pathlib import Path
|
||||
|
||||
_dist_root = Path("web-ui/dist")
|
||||
if _dist_root.is_dir():
|
||||
for f in _dist_root.rglob("*"):
|
||||
if f.is_file():
|
||||
# 目标目录:保留 dist 内的相对结构(如 assets/),
|
||||
# 整体放到 web_dist/ 下。例如 web-ui/dist/assets/x.js
|
||||
# → web_dist/assets/,文件名 x.js 由 PyInstaller 自动拼。
|
||||
rel_parent = f.parent.relative_to(_dist_root)
|
||||
dest_dir = f"web_dist/{rel_parent.as_posix()}" if str(rel_parent) != "." else "web_dist"
|
||||
datas.append((str(f), dest_dir))
|
||||
else:
|
||||
print("WARNING: web-ui/dist 不存在,EXE 将无前端界面!请先 npm run build")
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "easy-tdx"
|
||||
version = "1.19.1"
|
||||
version = "1.19.2"
|
||||
description = "通达信 TCP 协议行情数据客户端,支持在线行情、离线数据读取与写入同步"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@@ -232,6 +232,18 @@ def _create_app(
|
||||
# --- 前端 dist 托管(生产/打包态同源服务,开发态可缺省) ---
|
||||
# 必须在所有 API 路由注册之后:StaticFiles(html=True) 挂在 "/" 会吞掉
|
||||
# 未匹配路径,放最后保证 /api/v1/* 优先命中路由表。
|
||||
# 强制注册 MIME 类型:干净 Windows(无开发环境)的注册表里可能没有
|
||||
# .js/.mjs/.css 的 Content Type,导致 mimetypes.guess_type 返回 None,
|
||||
# StaticFiles 回退到 text/plain。浏览器的 <script type="module"> 启用
|
||||
# 严格 MIME 检查,拒绝执行 text/plain 的 JS → 页面纯黑(v1.19.1 bug)。
|
||||
# add_type 会覆盖/补充注册表缺失的映射,无论机器装没装开发工具都生效。
|
||||
import mimetypes
|
||||
|
||||
mimetypes.add_type("application/javascript", ".js")
|
||||
mimetypes.add_type("application/javascript", ".mjs")
|
||||
mimetypes.add_type("text/css", ".css")
|
||||
mimetypes.add_type("image/svg+xml", ".svg")
|
||||
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
dist_dir = _resolve_web_dist_dir()
|
||||
|
||||
Reference in New Issue
Block a user