Browser third-party libraries as build inputs
浏览器第三方库作为构建输入
Prebuilt browser plugins distribute their third-party implementations inside JavaScript, but production npm dependencies still make installers download those libraries separately and resolve their peers. When React is declared only for development, installers can select a different React version for those extra dependencies than the browser artifact uses. Both `[email protected]` and `@tanstack/react-virt
English
Problem
Prebuilt browser plugins distribute their third-party implementations inside JavaScript, but production npm dependencies still make installers download those libraries separately and resolve their peers. When React is declared only for development, installers can select a different React version for those extra dependencies than the browser artifact uses. Both [email protected] and @tanstack/[email protected] support the current React 18; this problem does not require a React upgrade.
Decision
Browser-only third-party dependencies belong in devDependencies, including implementations inlined into dynamic plugins, static browser-library inputs, and React shared by the Web shell. This partially supersedes the preservation of ordinary third-party declarations in published dependency faces; that note continues to govern package selection, Host value dependencies, and Cordis identity.
The dependency classifier collects build inputs from source imports and JSX. Third-party libraries reachable by the Host runtime take precedence as dependencies; additional Node build entries must also be checked. Type-only source references do not create Host runtime dependencies. Existing configuration-metadata and shared-Host-export classifications remain unchanged.
Npm sections do not select browser bundling behavior. Dynamic plugins inline private libraries and obtain React and other shared modules from the platform table; static browser libraries retain bare imports and styles for the final Vite build. Static packages are Web-shell build inputs, not independently installed libraries with every rebundling dependency provided. Source builds need development dependencies; installed published Web artifacts do not.
License classification follows distributed content. Dependency resolution through the real browser build configurations covers dynamic plugins and the Web shell; resolved third-party implementations remain runtime disclosures even when manifests declare them for development. Test tools, erased type imports, and build tools do not become distributed code merely by appearing in devDependencies.
Alternatives considered
Declare another production React or override peer resolution. This retains an extra installed graph that the browser does not use, without making that installed copy the browser's shared instance.
Inline every static-library dependency early. This changes Vite's third-party chunks, caching, and CSS handling; dependency classification does not require those build changes.
Move every third-party dependency of a Client-bearing package. Dual-face packages still load Host libraries, including fflate for ZIP output and zod for RPC validation; those installation relationships must remain.
Classify license disclosures directly by manifest section. Distributing browser code and having an installer download a same-named package are different facts; that distinction cannot remove license checks on distributed code.
Consequences
Production dependencies do not install third-party libraries a second time solely for browser implementations. React and React DOM retain one build version, and plugins consume the Web shell's shared instance. Classification tests constrain browser dev-only inputs, Host precedence, and idempotent repair; publication checks reject React installation leaks, while browser artifact verification independently covers module loading.
Classification remains source-based. License resolution likewise must not depend on existing lib/ files or write build outputs; its tests cover real resolution, type erasure, asset references, and missing dependencies. Developers independently consuming static packages or public types supply the corresponding build dependencies themselves; this decision adds no standalone browser-library support promise.
中文
问题
预构建浏览器插件的第三方实现已经随 JavaScript 分发,但生产 NPM 依赖仍让安装器另外下载这些库并解析其对等依赖(peer dependency)。React 只在构建期声明时,安装器可以为这些额外依赖选择与浏览器产物不同的 React 版本。[email protected] 与 @tanstack/[email protected] 都支持当前 React 18;问题不要求升级 React。
决策
浏览器专用第三方依赖属于 devDependencies,包括动态插件内联的实现、静态浏览器库的输入,以及由 Web 壳提供共享实例的 React。该规则部分取代已发布依赖分类对普通第三方声明的保留策略;该文档继续规定包的选择范围、Host 值依赖与 Cordis 实例身份。
依赖分类器从源码导入和 JSX 收集构建输入。Host 运行时可达的第三方库优先归入 dependencies;额外 Node 构建入口也必须纳入检查。源码中的纯类型引用不产生 Host 运行时依赖。配置元数据与共享 Host 导出的既有分类保持不变。
NPM 字段不决定浏览器打包方式。动态插件继续内联私有库,并从平台模块表读取 React 等共享模块;静态浏览器库继续保留裸导入及样式,由最终 Vite 构建处理。静态包是 Web 壳的构建输入,不承诺独立安装后具备二次打包所需的全部依赖。源码构建需要开发依赖;安装已发布的 Web 产物不需要它们。
许可证分类以交付内容为准。真实浏览器构建配置的依赖解析同时覆盖动态插件与 Web 壳;解析到的第三方实现仍计入运行时披露,即使清单将其列为开发依赖。测试工具、纯类型导入和构建工具不会仅因处于 devDependencies 而算作分发代码。
考虑过的替代方案
为生产安装额外声明 React,或强制覆盖对等依赖。 这保留了浏览器不使用的额外安装图,且并未使安装副本成为浏览器共享实例。
把静态库的所有依赖提前内联。 这会改变 Vite 对第三方分块、缓存和 CSS 的处理;依赖分类不需要改变这些构建行为。
把带 Client 的包的全部第三方依赖移走。 双面包仍可能在 Host 加载库,例如 ZIP 输出所用的 fflate 和 RPC 校验所用的 zod;这些安装关系必须保留。
按清单字段直接划分许可证披露。 浏览器代码的交付与安装器是否下载同名包不是同一事实,不能因此取消对分发代码的许可证检查。
结果
生产依赖不再为纯浏览器实现重复安装第三方库。React 与 React DOM 保持同一构建版本,插件继续消费 Web 壳的共享实例。分类测试同时约束浏览器 dev-only、Host 优先和修复幂等;发布检查拒绝 React 安装泄漏,浏览器产物验证独立覆盖实际模块加载。
分类检查保留源码执行方式。许可证解析也不能依赖已有 lib/ 或写入构建输出;其测试覆盖真实解析、纯类型擦除、资源引用与缺失依赖。独立消费静态包或公开类型的开发者需要自己提供相应构建依赖;本决策不增加独立浏览器库的支持承诺。