# 构建生产版本

选择工具链构建或原生构建，配置 PWA 与预算并验证产物。

需要 WU CLI `1.2.0`，应用 API 需要 WU Framework `4.0.0`。请检查 `wu --version` 和项目依赖。

<span id="dos-caminos-de-construcción"></span>

<span class="section-anchor" id="section-1"></span>

## 两种构建路径

```sh
wu build
wu build --native
wu serve 4100
```

`wu build` 保留工具链流程：通过各自命令构建宿主和应用，汇总到 `dist/`，写入清单并生成 HTTP 策略。`wu build --native` 在生产模式启动 WU 服务器，遍历模块图并将响应保存为静态文件。每次构建选择一种路径，并在浏览器验证结果。

| 选项 | 作用 |
| --- | --- |
| `--native` | 根据 WU 服务器响应构建。 |
| `--no-pwa` | 禁用本次原生构建的 PWA。 |
| `--budget-warn` | 将超出预算改为警告。 |
| `--jobs <n>`, `-j <n>` | 1 至 64 个并行构建；默认为 `min(CPU, 4)`。 |
| `--no-cache` | 不复用 `.wu-cache/builds/` 中的输出。 |
| `--sign <key.pem>` | 使用 ECDSA P-256 签署 `dist/wu-integrity.json`。 |

没有 `--watch`、`--app`、`--out-dir` 或 `--minify` 参数。编译失败、应用无输出、文件无法写入或超出预算均返回 `1`。构建在 `dist.tmp-<id>/` 中进行，仅成功后替换 `dist/`；失败时保留旧构建，并将证据留在 `dist.failed/`。`.wu-cache/build.lock` 会拒绝第二个并发构建。

<span id="caché-de-compilación-y-builds-anteriores"></span>

<span class="section-anchor" id="section-2"></span>

## 构建缓存与历史构建

未更改的应用从 `.wu-cache/builds/` 恢复输出。缓存键包含本地源码、`.env*`、根清单、锁文件、覆盖映射、命令、框架、共享模块和 CLI 版本。应用目录外的导入源码及 `node_modules` 中的编辑不会被检测，应使用 `--no-cache`。Windows 上也不纳入进程环境变量；更改后应避免复用缓存。

`build.keepPreviousBuilds` 默认保留前两次构建的哈希文件；`0` 仅保留当前构建。私有记录 `dist/.wu-builds.json` 让旧标签页继续加载其 chunk。干净的 CI 环境需在构建间保留 `dist/`，或使用能保留这些文件的托管服务。HTML、清单和 service worker 仅属于当前构建。

```json
{ "build": { "keepPreviousBuilds": 2 } }
```

<span id="un-runtime-compartido"></span>

<span class="section-anchor" id="section-3"></span>

## 一个共享运行时

CLI 检测 `wu-framework` 及浏览器子路径导入，共享核心并为常规构建创建 import map。要将这些导入外置，`build_cmd` 必须直接调用 `vite build`。`npm run build` 等不透明命令可能使 WU 无法注入 externals 和 aliases；请检查警告和模块请求。

`wu create` 为生成的框架配置 `shared`，`wu add` 会扩展它。共享 React 或 Preact 时也会包含编译器生成的 JSX runtime。请显式导入宿主使用的[可选子系统](/zh-cn/docs/framework/runtime-composition/)。缺少本地工具链时运行 `wu install`，不要假设 CLI 会改用根目录版本。

导入映射会在每个 HTML 页面 `<head>` 之后插入或合并；片段及超过 8 MiB 的文件会跳过。共享 Qwik 或 Svelte 适配器时也会共享其运行时。WU 生成的入口为脚本和 modulepreload 添加 SRI，并在导入映射中加入 `integrity`。生成的辅助脚本为外部文件。

<span id="qué-publica-el-build-nativo"></span>

<span class="section-anchor" id="section-4"></span>

## 原生构建发布的内容

原生构建遍历所有 shell 页面和应用入口。模块、CSS 和资源使用由 SHA-256 派生的文件名发布，替代旧的 `?v=<build>`。内容未变时保留 URL 和模块身份。编译错误会停止构建，而不会发布错误覆盖层模块。

通过字面量导入遍历无法发现 URL 动态计算的导入。`.module.css` 仍保留开发服务器的样式注入。选择原生构建前应验证这些场景；应用需要不同处理方式时，继续使用工具链构建。

<span id="pwa-caché-y-actualizaciones"></span>

<span class="section-anchor" id="section-5"></span>

## PWA、缓存与更新

启用 PWA 时，原生构建生成 `wu-sw.js`、`wu-sw-register.js`、`manifest.webmanifest` 和图标，并预缓存已发现文件。导航及清单请求优先访问网络，离线时回退到缓存。外部 API 数据和未发现的文件不会自动预缓存。

`wu.config.json` 根级的 `pwa: false` 或 `--no-pwa` 可禁用生成。已有宿主 manifest 会保留。worker 从 `wu-apps` 缓存提供 `/@wuapp/` 下的已安装应用，并在构建更新时保留该缓存。宿主需要展示更新状态时可监听 `wu:update-available` 和 `wu:sw`。

其他窗口仍打开时，新 worker 会等待。`wu:update-available` 事件提供 `event.detail.activate()`，由 shell 决定何时激活替换。离线导航恢复各自页面；同源 API 不会自动进入站点缓存。

<span id="presupuestos-por-app"></span>

<span class="section-anchor" id="section-6"></span>

## 应用预算

```json
{ "budget": "150kb", "apps": [
  { "name": "cart", "dir": "mf-cart", "framework": "react", "port": 5001, "budget": "80kb" }
] }
```

应用预算优先于根预算。可使用字节数或 `80kb`、`1.5mb` 等以 1024 为基数的单位。统计未压缩的 `.js`、`.mjs` 和 `.css`，不含图片与字体。超出预算返回 `1` 并保留原 `dist/`。`--budget-warn` 保留警告但不使构建失败。这是项目限制，不是与其他框架的性能比较。

<span id="revisar-el-resultado"></span>

<span class="section-anchor" id="section-7"></span>

## 验证输出

检查 `dist/wu-manifest.json`、应用入口、`_headers`、`vercel.json` 和 `wu-security.conf`。提供 `dist/`，刷新深层路由，挂载每个应用并检查 CSS、通信和控制台。使用 PWA 时还应测试离线刷新。要分发单个应用，请继续阅读 [wu pack](/zh-cn/docs/cli/pack/)。

<span id="publicar-y-verificar-un-build-firmado"></span>

<span class="section-anchor" id="section-8"></span>

## 发布并验证签名构建

```sh
wu pack --keygen keys/deploy.pem
wu build --sign keys/deploy.pem
wu doctor --url https://example.com --integrity --pubkey keys/deploy.pub.json --json
```

将 `--keygen` 输出的公有 JWK 保存到 `keys/deploy.pub.json`。发布整个 `dist/`（包括 `wu-integrity.json`）以及同一构建的策略文件。签名清单记录哈希、类型、导入映射和逐页 CSP。`doctor --integrity` 验证签名和响应；不带 `--pubkey` 时仅检查清单自身携带的密钥，不验证可信身份。

CDN 必须保留字节、MIME、CSP 和导入映射：签名后的自动转换会使验证失败。仅对带哈希的文件使用不可变缓存，对 HTML、清单和 worker 重新验证。保留期内不要删除旧 chunk。WU 为 `_headers`、`vercel.json` 和 `wu-security.conf` 生成逐页策略，保留 shell 的 `_headers`，并提示 Cloudflare 的规则数和行长度限制。

<span id="referencia-de-implementación"></span>

<span class="section-anchor" id="section-9"></span>

## 实现参考

- `wu-cli/src/commands/build.zig`
- `wu-cli/src/commands/build-native.cjs`
- `wu-cli/src/commands/deploy.zig`
- `wu-cli/src/commands/build_cache.zig`
- `wu-cli/tests/build-deploy.test.cjs`
- `wu-cli/tests/build-native-pages.test.cjs`
- `wu-cli/tests/build-failures.test.cjs`
- `wu-cli/tests/build-shares-adapter-runtime.test.cjs`