# 小工具 ZIP 静态包构建规范 > 小工具是基于离线 H5 的 app 形式,**纯本地、不联网**,所有资源须打包在 zip 内。窗口样式、导航栏、下拉刷新等外壳行为由**容器**统一控制,无需在包内声明。 ## 目录 - §1 目录结构与打包 - §2 支持的文件类型 - §3 资源加载规则(容器 CSP) - §4 路径与引用规则 - §5 index.html 模板 - §6 打包前自检 --- ## 1. 目录结构与打包 **唯一硬性要求:`index.html` 位于 zip 根目录作为入口。** 其余文件 / 文件夹随你组织 —— 可平铺,也可按需分目录(`assets/`、`images/`、`audios/` 等),用相对路径引用即可。 平铺示例: ``` tool.zip ├── index.html # 必需 — 入口,必须在根目录 ├── main.js ├── style.css └── logo.png ``` 分目录示例: ``` tool.zip ├── index.html # 必需 — 入口,必须在根目录 └── assets/ ├── style.css ├── main.js └── images/ └── ... ``` | 路径 | 要求 | 说明 | | --- | --- | --- | | `index.html` | **必须在 zip 根目录** | 唯一入口;不可改名、不可放进子目录 | | 其余文件 / 文件夹 | 自由 | JS / CSS / 图片 / 音频等,平铺或分目录皆可,相对路径引用 | ### 禁止出现在 zip 内 - `node_modules`、`.git`、`.DS_Store` - `*.map`、构建配置文件(`vite.config.*`、`webpack.config.*` 等) - 把整个项目多包一层目录,导致 `index.html` 不在根(错误:`app/index.html`;正确:根目录就有 `index.html`) ### 打包方式(关键) **压缩的是「与 `index.html` 同级的那批文件」本身,不是它们所在的文件夹。** 必须先进入该目录再压缩当前目录内容,否则解压后会多套一层目录、`index.html` 不在根,容器无法加载。 ```bash # ✅ 正确:进入目录,压缩目录“内容”(index.html 直接在 zip 根) cd dist && zip -r ../tool.zip . -x '*.DS_Store' # ❌ 错误:压缩目录“本身”,解压后多一层 dist/,index.html 变成 dist/index.html zip -r tool.zip dist ``` 解压后顶层应直接看到 `index.html`,而不是先看到一个文件夹再点进去。 --- ## 2. 支持的文件类型 zip 内仅允许以下类型: | 类型 | 用途 | | --- | --- | | `.html` | 入口,有且只有一个 `index.html` | | `.css` | 样式文件 | | `.js` | 脚本文件 | | `.png` / `.jpg` / `.jpeg` / `.gif` / `.webp` / `.svg` | 图片资源 | | `.woff` / `.woff2` | 字体文件 | | `.json` | 小型静态数据 / 配置;不得作为大型内置数据库,体积门禁见 [performance-budget.md](./performance-budget.md) | --- ## 3. 资源加载规则(容器 CSP) 容器对页面**如何加载各类资源**有强制约束。除包内文件外,按类型另允许 `data:` / `blob:` 等内存来源。 | 资源类型 | 允许 | 禁止 | | --- | --- | --- | | 脚本 ``;行内事件 `onclick="..."`;`javascript:` URI;`eval()` / `new Function()`;WebAssembly;外部域名 / `data:` / `blob:` 脚本 | | 样式 ` ``` | 规则 | 原因 | | --- | --- | | viewport 含 `width=device-width, initial-scale=1.0, viewport-fit=cover` | 真机 + 模拟器布局与安全区 | | 资源全为相对路径 `./assets/...` | 离线 zip 根为 `/` | | 脚本外置 `