# 2026-06-04 — Monaco 与静态 JS 全部自托管

## 摘要

- `web/app/api.js` 预加载 Monaco 由 jsDelivr 改为 `/app/vendor/monaco/vs`（monaco-editor@0.45.0）。
- `scripts/sync_frontend_vendor.py` 增加从 npm  tarball 解压 `min/vs/`，并支持批量 patch 根目录 `*.js`。
- 安全单测扩展：除 `*.html` 外检查 `web/app/*.js`，并断言 `vendor/monaco/vs/loader.js` 存在。

## 动机

- 预览页已去 CDN；业务页 `api.js` 仍在运行时请求 `cdn.jsdelivr.net`（Monaco ~数 MB），内网/离线不可用。
- 与 `docs/changelog/2026-05-22-frontend-vendor-selfhost.md`（F2e-06）策略一致。

## 涉及文件

| 文件 | 变更 |
|------|------|
| `web/app/api.js` | Monaco `paths.vs` → 本地 |
| `web/app/vendor/monaco/vs/**` | 新增（npm 包解压） |
| `web/app/vendor/manifest.json` | 增加 `monaco` 元数据 |
| `scripts/sync_frontend_vendor.py` | `download_monaco` + `patch_app_js_files` |
| `tests/test_security_unit.py` | `test_app_root_js_*` + `test_monaco_vendor_*` |
| `docs/template.html` | 文档示例改为 vendor 路径 |

## 升级 Monaco

```bash
# 1. 修改 scripts/sync_frontend_vendor.py 中 MONACO_VERSION
# 2. 执行（需外网或代理）
python scripts/sync_frontend_vendor.py
# 3. 提交 vendor/monaco/ + manifest.json + api.js
```

## 验证

```bash
pytest tests/test_security_unit.py -k cdn -q
rg 'cdn.jsdelivr|unpkg.com' web/app --glob '!vendor/**'
# 浏览器打开含 api.js 的页面，Network 无 cdn.jsdelivr.net
```

## 迁移 / 重启

- 仅静态资源；`git pull` 或 tar 部署 `web/app/vendor/monaco/` 后无需 DB 迁移，重启 uvicorn 可选。
