T3 Code 非官方中文翻译不是官方产品,也不是 T3 Tools 官方文档。源提交 d2c25950b4d9英文原文GitHub 源文件
Skip to content

开源许可证声明 ​

许可证声明按交付它们的客户端(client)分别生成:

  • Web 构建会在 index.html 旁边产出 third-party-licenses.json。设置页加载这个静态文件,所以同一份产物在托管的 Web、和 npx t3 打在一起的客户端,以及桌面端都能用。
  • 移动端的 Metro 配置会在每一次开发、原生或空中更新(over-the-air)的 JavaScript 包之前,生成一个被忽略的虚拟模块。移动端只在许可证界面打开时才加载并解码这个模块,所以声明文本不会在平常启动应用时占用内存。它不需要发网络请求。

两条路径都不依赖已连接的环境(environment),也不依赖 RPC。

构建收集什么 ​

生成器会顺着已安装的生产依赖和可选依赖往下走,包括工作区包的依赖,并略过第一方的 @t3tools/* 包。Web 清单从 web、server 和 desktop 的包清单出发。移动端清单从移动端的包清单出发。Web 打包时,生成器还会核对已经输出的模块 id,抓住打进了包、却没有写在包清单里的 npm 导入。

移动端清单有意跟着 Expo 和 React Native 所声明的完整生产依赖闭包走。这样做偏保守,可能把最终 JavaScript 包里并不存在的构建工具也算进去,但能避免平台打包方式一变就漏掉一条声明。

收集到的包如果没有可分发的许可证标识,或者里面没有任何许可证或声明文本,构建就会失败。生成的声明使用已固定版本的 SPDX License List 中的许可证模板,这些模板提交在 third-party-licenses/spdx/ 下。构建从不会去下载它们,所以一次网络闪断不会让构建失败。配置里要的模板如果缺了,构建会失败;运行 vp run licenses:sync 把它下载下来,再提交这个新文件。

自定义声明和包覆盖 ​

仓库级的 third-party-licenses.config.json 为所有客户端(client)保存手工维护的例外。改编过的图标、字体、媒体、原生模块,或其他不是从 npm 包来的资源,往 customNotices 加一条:

json
{
  "name": "asset-name",
  "license": "CC-BY-4.0",
  "generatedNotices": [
    {
      "licenseId": "CC-BY-4.0",
      "preamble": ["Asset by Example Author. Changes: converted to MP3."]
    }
  ],
  "sourceUrl": "https://example.com/source",
  "bundles": ["assets", "web"]
}

每个 generatedNotices 项指定一份 SPDX 许可证模板,并可以为署名和出处加上 copyrights,或一段简短的 preamble。一份软件如果内嵌了分别授权的代码,多个项会合成一行。只有内嵌的源码树自己已经带有一份应当留在旁边的许可证文件时,才保留 noticeFile 或 noticeFiles。路径相对于配置文件。bundles 决定哪些生成的清单包含这条,并给出展示给用户的标签。当这两处需要分开时使用 includeInBundles,例如一个可选的服务器工具应当出现在两份客户端清单里,但并没有打包进任何一个客户端。

agent-device 和 expo-device-hub 的自定义声明,版本取自安装器锁定的版本。包名留在配置里;版本不用手工更新。

只有已安装的 npm 包归档漏了声明,或元数据不对时,才使用 packageOverrides:

json
{
  "name": "package-name",
  "version": "1.2.3",
  "generatedNotice": {
    "licenseId": "MIT",
    "copyrights": ["Copyright (c) 2026 Example Author"]
  },
  "license": "MIT",
  "sourceUrl": "https://example.com/package-name"
}

包里如果含有分别授权的代码,用带模板数组的 generatedNotices,不要用 generatedNotice。生成器会把每一份声明都放进这个包对应的那一行。

version、license 和 sourceUrl 是可选的。省掉 version,这条覆盖就会作用到该包每一个已安装的版本。同一个 monorepo 里的几个包共用同一份声明时,覆盖可以用 repositoryUrl 代替 name:

json
{
  "repositoryUrl": "https://github.com/example/project",
  "generatedNotice": {
    "licenseId": "Apache-2.0"
  }
}

两个包如果声明了相同的规范化仓库和许可证,生成器也会复用已安装的兄弟包的声明。写明了名称和版本的覆盖,始终优先于这些按仓库回退的结果。

@react-grab/cli 这条覆盖使用 React Grab 根仓库的 MIT 许可证,因为这个 CLI 的 npm 包归档既没有 license 字段,也没有许可证文件。在已发布的 CLI 包自己带上这份元数据之前,保留这条覆盖。

生成的移动端文件在 apps/mobile/.generated/ 下,并且被忽略。不要提交,也不要手改;更新依赖或配置,下一次构建就会刷新输出。

非官方译文 · 源提交 d2c25950b4d9 · 不代表 T3 Tools