# -*- coding: utf-8 -*- """把生成物落到 webapp/,并打一份单文件分发版。 单文件时代这里做 8 路字符串替换再写 3 份 16MB 副本;现在前端本身就是 webapp/ 下的 文件,本脚本只剩两件事: write_data() 网格/工程图/行程/碰撞/螺钉 -> generated/00_data.js(普通脚本 const) build_single() 把 webapp/ 的 css/js 原样内联成 dist/机器人手臂3D查看器.html(分发用) S5 数据改 fetch() 后 write_data() 的 00_data.js 退役;S8 由 pack.py 的受限 ESM 内联器 接管 build_single()。 """ import io import json import os import re import sys import time try: sys.stdout.reconfigure(encoding="utf-8") except Exception: pass from arm.paths import DATA, DIST, DOCS, GEN, WEBAPP # 与 SHEET_METAS 的顺序一致;工程图读 draw_sheet 写出的真 SVG, # 不再维护第二份 sheets.jsdata(单文件时代的内联载体,内容与 SVG 完全重复)。 SHEET_ORDER = ["sheet_front", "sheet_joint", "sheet_exploded", "sheet_side"] def _read(path, dflt=None): if os.path.exists(path): return io.open(path, encoding="utf-8").read() if dflt is None: raise SystemExit("缺少查看器数据文件: %s(先跑 python -m arm.build_model)" % path) return dflt def write_data(): t0 = time.time() print("【数据】汇总查看器数据 -> webapp/generated/00_data.js", flush=True) os.makedirs(GEN, exist_ok=True) mesh = _read(DATA + "/mesh_arm.json") svgs = [_read(DOCS + "/%s.svg" % n) for n in SHEET_ORDER] trv = _read(DOCS + "/travel.json", "[]") col = _read(DOCS + "/collide.json", '{"caps":[],"parts":{}}') scr = _read(DOCS + "/screws.json", "[]") print(" - 网格 %d KB / 工程图 %d 张 / travel %d B / collide %d KB / screws %d B" % (len(mesh) // 1024, len(svgs), len(trv), len(col) // 1024, len(scr)), flush=True) out = ["/* 生成物,勿手改:由 python -m arm.viewer.build_viewer 写入。", " 普通脚本顶层 const —— 经典脚本共享全局词法作用域,后续脚本直接可见。 */"] for name, raw in (("DATA", mesh), ("TRAVEL", trv), ("COLLIDE", col), ("SCREWS", scr)): out.append("const %s = %s;" % (name, raw.strip())) out.append("const SHEETS = %s;" % json.dumps(svgs, ensure_ascii=False)) text = "\n".join(out) + "\n" tmp = GEN + "/00_data.js.tmp" io.open(tmp, "w", encoding="utf-8").write(text) os.replace(tmp, GEN + "/00_data.js") print(" 完成:%d KB, %.2fs ✓" % (len(text) // 1024, time.time() - t0), flush=True) def build_single(): """分发用单文件:仍是普通脚本,所以内联是平凡的(S5 变 ESM 后交给 pack.py)。""" t0 = time.time() os.makedirs(DIST, exist_ok=True) html = _read(WEBAPP + "/index.html") total = len(html) def sub(m, kind): nonlocal total body = _read(WEBAPP + "/" + m.group(1)) total += len(body) return ("") if kind == "css" \ else ("") out = re.sub(r'', lambda m: sub(m, "css"), html) out = re.sub(r'', lambda m: sub(m, "js"), out) left = re.findall(r'(?:src|href)="(?!data:)([^"]+)"', out) assert not left, "单文件里仍有外部引用: %s" % left[:5] assert len(out) >= total * 0.95, "内联后 %d 远小于各部之和 %d,疑似漏文件" % (len(out), total) dst = DIST + "/机器人手臂3D查看器.html" # Windows 上被浏览器打开的 html 是独占锁;写不进去就直接报,不要静默留旧版。 io.open(dst, "w", encoding="utf-8").write(out) print(" - 单文件分发版 %.2f MB, %.2fs ✓ %s" % (os.path.getsize(dst) / 1e6, time.time() - t0, dst), flush=True) def rebuild_viewer(): """build_model 流水线的最后一步(沿用旧函数名,调用点不改)。""" write_data() build_single() if __name__ == "__main__": rebuild_viewer()