# 同一 React/Vite 代码库，不同宿主边界

> WorldScript Studio 在 PWA 与 Tauri 间共享 React/Vite 产品语义，同时让存储、网络、缓存和安全策略服从各自宿主。

WorldScript Studio 用同一套 React/Vite 代码运行 Web、已安装 PWA、边缘托管环境 和 Tauri 桌面应用 版本。作者在 2026 年 9 月 27 日发布的案例分析中介绍了做法：领域概念共用，存储、网络、安全策略和缓存行为则按明确的平台边界选择实现。共享代码库后，这些宿主仍不能互换
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

<span id="项目共享什么"></span>

## 共用的产品语义

WorldScript Studio 把自己描述为 local-first 创作工作区。仓库说明，它不要求 WorldScript 账号，
也没有中心化稿件数据库；项目状态保存在 browser/PWA 存储或 desktop app 的本地数据目录。仓库还
表示，PWA shell 缓存后，核心写作与规划在离线时仍可使用，而明确需要网络的功能仍然需要连接
（[WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)）。

案例把产品模型视为共享层。项目的定义、权威状态、导出语义，以及可选 provider 不可用时的行为，
不应仅因 renderer 宿主不同而改变；这些语义之下的实现机制可以不同。作者给出的规则是共享领域语义
和互操作协议，同时通过显式 adapter 暴露各宿主能力
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

React 与 Vite 属于仓库的公共 Web 技术层。README 把 React 列为主 UI，把 Vite 列为 Web/PWA
构建系统，而 Tauri 提供 desktop shell。Tauri 的 Vite 指南直接记录了这种集成：Tauri 可以启动
Vite 开发服务器、执行 Vite build 命令，并通过 `tauri.conf.json` 设置加载生成的 dist 目录
（[Tauri Vite 指南](https://tauri.app/start/frontend/vite/)）。

这种集成共享 frontend asset，却没有抹去宿主。Tauri 指南配置不同的开发与生产位置，固定开发
端口，把 Tauri 环境值暴露给 Vite，并为指南列出的 WebView 平台设置构建 target。这些是在同一
frontend 工具链周围作出的宿主感知选择，不能证明 browser tab 与 desktop WebView 拥有相同 API
或相同权限（[Tauri Vite 指南](https://tauri.app/start/frontend/vite/)）。

## 存储仍由宿主决定

仓库的存储表把 browser/PWA 与 Tauri 列赋予不同职责。browser 的项目状态、snapshot 与 asset
使用 IndexedDB，desktop 则使用 app data 下的 local filesystem store。API key 在两边都留在
独立的 IndexedDB 加密 secret store，包括 desktop WebView。表格还表示，受保护的 IndexedDB
项目数据可选择加密，但 filesystem-backed desktop 项目存储没有应用层静态加密
（[WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)）。

案例从差异中得出一条产品文案要求：两个控件外观相近，也可能保护不同的持久化路径。真实的
browser 或 filesystem backend 决定数据位置、生命周期和某条加密路径是否适用。共享界面因而需要
标识激活的 backend，不能只凭共同标签承诺相同保护
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

浏览器存储 还受 origin 限制。README 表示，GitHub Pages、Vercel、localhost 与 custom
domain 部署不会自动共享 IndexedDB 或 model cache。desktop filesystem store 遵循另一套位置与
访问模型。即使用户看到相同 React 界面，产品也不能推断某个 Web origin 保存的数据会出现在另一
部署或 native store 中（[WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)）。

## 网络和策略随宿主改变

报道区分 browser fetch 与 Tauri native HTTP 路径。WorldScript 的 adapter 在 Tauri runtime
选择 native plugin，在其他环境使用 browser `fetch`。作者用这一差异让 desktop 访问获准的本地
与 cloud endpoint，同时让 browser 请求继续受 origin 规则与 server configuration 约束
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

Tauri 把 command scope 记录为细粒度 allow 或 deny 规则。其指南用 filesystem plugin 说明目录
限制，用 HTTP plugin 说明 URL 过滤；还表示 deny scope 优先于 allow scope，并提醒 command
作者审计实现以防绕过。这支持收窄的 capability boundary，但不表示 native request 无需正确配置
与实现就自然安全（[Tauri command scope](https://tauri.app/security/scope/)）。

host 也影响 response policy。WorldScript README 表示，GitHub Pages 部署不能注入 HTTP security
header，因此在那里依赖 meta CSP；Vercel 部署则可提供 response security header 与 same-origin
relay。案例用这个对照说明，相同静态界面也可能运行于不同交付与 server function 保证之下
（[WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)）。

这些事实要求 capability check 点名宿主路径。browser 部署可以提供 浏览器存储 与 browser
network behavior；边缘托管环境 可以增加 server function 与 response header；Tauri 可以暴露获准的
native command。某个组件出现在 source tree 中，不能单独证明相关能力存在，adapter 与部署配置
共同决定可用路径
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

## Service Worker 在 desktop 边界停止

Web surface 使用 Service Worker 提供 cached shell 与 offline fallback。案例表示，Tauri 分支执行
相反动作：取得已有 Service Worker registration 并逐个 unregister，然后枚举 Cache Storage，
删除 WorldScript 自己的 cache name。报道把它解释为避免 stale browser cache 把 offline fallback
覆盖到真实 bundled desktop application 之上
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

注销 Service Worker 是这个项目为了区分 缓存中的 Web 应用外壳 和 原生应用包 所作的决定，不能套用到所有 Tauri 应用。你需要确定每个宿主由谁负责离线交付：Web 端如果靠 Service Worker，desktop 端靠 打包后的桌面应用，代码就要明确切换这项职责
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

<span id="这对-pwa-开发者为什么重要"></span>

## 宿主差异对存储和发布测试的影响

这个案例提供了一条位于「万能实现」与「完全不同产品」之间的具体路径。产品实体与文件格式可以
共享；存储、网络传输、离线交付、安全策略与操作系统集成可以置于收窄的宿主 adapter 后面。这样
能让平台差异在影响用户数据与能力的位置保持可见
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

对于已安装 PWA，安装不会把 origin-scoped browser data 变成 native filesystem store。
WorldScript 自身的 matrix 仍把 PWA 路径写为 浏览器存储，把 Tauri 路径写为 filesystem
persistence。这项区别影响 migration、backup、recovery、加密承诺，以及 UI 对项目保存位置的表述
（[WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)）。

同一原则也适用于依赖网络的功能。cached PWA shell 可以加载，但可选 remote provider、协作服务、
model 首次下载或其他网络集成仍可能不可用。WorldScript README 明确区分 offline-capable 核心写作
与需要连接的功能。产品状态应分别描述这些能力，不能把 shell 可用当成每项集成都已就绪的证据
（[WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)）。

测试可以沿用同一张边界图。共享 domain test 可以建立不变的项目语义；adapter test 可以确认选择
了哪种持久化与 transport；宿主 integration test 再分别覆盖 browser origin、Service Worker
lifecycle、Tauri scope 和 filesystem behavior。来源没有提供普遍适用的 test suite，但其架构让
这些职责可以分别观察
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

文档也必须保持同样精确。仓库警告，不应把某一部署行里的保证泛化到另一行。功能说明需要点名哪个
host 提供 storage、header、server function、native transport 或 offline behavior。这样才能防止
一个关于单一 build target 的真实陈述，变成错误的全产品承诺
（[WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)）。

发布资格同样不能只看共享的 Web pipeline。README 明确表示，普通 Web PR pipeline 并不是完整的
native release qualification surface；涉及 native 或 Tauri 的修改需要专用 desktop build
workflow 及其平台证据。仓库还区分 updater artifact 使用的完整性签名与操作系统 code signing，
并分别点名 Windows Authenticode 和 macOS Developer ID signing/notarization。共用前端构建
通过后，桌面应用发布仍有独立的宿主级验证责任，两类签名路径不能互相替代
（[WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)）。

WorldScript Studio 采用「共享契约、选择实现、说明边界」的做法。存储表、部署说明、fetch adapter、Tauri scope 和 Service Worker teardown 都明确列出了共同 React/Vite 界面下的差异。共享界面并不能做到「构建一次，到处行为相同」
（[跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)）。

## 站内相关条目

- [Capabilities](/zh/reference/capabilities/)：Web 应用能力目录。
- [Performance](/zh/reference/performance/)：性能参考。
- [Storage](/zh/reference/storage/)：浏览器存储 API 与持久化。

## 待核实

- WorldScript Studio 是否会在参考 revision 后改变任何 adapter、backend 或部署边界，尚未确认。
- 另一个 React/Vite 与 Tauri 产品是否应采用相同存储分工，尚未确认。
- 该项目 browser store 与 desktop filesystem store 之间的 migration 路径，尚未确认。
- 每个可选 provider 在各种 offline transition 下的行为，尚未确认。
- 项目 native release workflow 在各平台上的结果，尚未确认。
- 项目未来 desktop roadmap 是否保留相同 Tauri 边界，尚未确认。

## 参考来源

- [跨 PWA 与 Tauri 的 React/Vite 产品](https://dev.to/qnbs/one-reactvite-product-across-pwa-and-tauri-without-pretending-they-are-identical-17ld)（dev.to）
- [WorldScript Studio README](https://github.com/qnbs/WorldScript-Studio/blob/main/README.md)（github.com）
- [Tauri 与 Vite](https://tauri.app/start/frontend/vite/)（tauri.app）
- [Tauri command scope](https://tauri.app/security/scope/)（tauri.app）