☰
react-intersection-observer 贡献指南:从本地开发到 CI 发布的全流程
2026/10/12 1:25:11 网站建设 项目流程
  • 前端
  • UI组件

【免费下载链接】react-intersection-observer

React implementation of the Intersection Observer API to tell you when an element enters or leaves the viewport.

项目地址:https://gitcode.com/gh_mirrors/re/react-intersection-observer
点击查看免费下载

react-intersection-observer是一个基于 TypeScript、采用 PNPM workspaces 管理的 React 开源仓库,其核心交付物是通过 Intersection Observer API 为骨架,结合仓库内真实的配置文件、源码与测试用例,完整梳理一条贡献者路径:从搭建本地开发环境、编写与测试代码、遵循提交规范,到最终由 CI 自动发布到 npm 的全过程。读完本文,你将掌握该仓库的开发命令、测试架构、代码规范与发布机制,能够直接上手提交高质量的 PR。

仓库概览:三个 workspace 应用的分工

整个仓库是一个 PNPM monorepo,由根目录 pnpm-workspace.yaml 声明apps/*与packages/*两个包分组:

packages: - apps/* - packages/*

CONTRIBUTING.md 明确划分了三个工作区:

  • packages/react-intersection-observer:对外发布的正式包,包含useInViewHook 和InView组件。从源码 packages/react-intersection-observer/src/index.tsx 可以看到它实际导出四样东西:InView(渲染属性组件)、useInView(状态型 Hook)、useOnInView(副作用回调型 Hook)以及底层observe工具函数。
  • apps/storybook:用于开发与测试的 Storybook 项目,端口固定为 9000,其dev脚本为storybook dev -p 9000(见 apps/storybook/package.json),存放于 apps/storybook/stories 的 stories 覆盖了InView、useInView、useOnInView三种用法。
  • apps/docs:基于 Blume 构建的文档站点,开发命令为blume dev(见 apps/docs/package.json),其内容目录在 apps/docs/docs。

根目录 package.json 中的脚本把这三个工作区串成统一的开发入口,同时 turbo.json 为build、test、lint、typecheck、dev等任务定义了缓存与依赖关系(例如test依赖^build,dev关闭缓存并标记为persistent)。

本地开发环境搭建

1. 克隆与安装依赖

贡献的第一步是 fork 仓库、克隆到本地,然后用PNPM安装依赖:

pnpm install

仓库根目录 package.json 通过packageManager字段锁定了pnpm@10.5.2,并在pnpm-workspace.yaml中声明了onlyBuiltDependencies(@biomejs/biome、esbuild、msw、simple-git-hooks),确保安装阶段需要执行构建脚本的依赖被正确允许。

2. 启动开发服务器

CONTRIBUTING.md 推荐直接启动全部应用:

pnpm dev

该命令实际展开为(见根目录 package.json):

"dev": "pnpm --parallel --filter react-intersection-observer --filter storybook --filter docs dev"

即并行启动包源码、Storybook 与文档站点三个dev任务。如果只想启动其中一个,可以分开执行:

pnpm dev:storybook pnpm dev:docs

pnpm dev:storybook对应pnpm --filter storybook dev,pnpm dev:docs对应pnpm --filter docs dev。包自身的 watch 构建则通过pnpm --filter react-intersection-observer dev:package(内部为tsup src/index.tsx --watch)完成。

语义化版本管理

CONTRIBUTING.md 声明项目遵循Semantic Versioning 2.0,版本号格式为<major>.<minor>.<patch>:

  • major:破坏性变更(Breaking changes)或新功能;
  • minor:向后兼容的功能增强;
  • patch:Bug 修复与文档变更。

这一约定在仓库中有两处直接体现。一是 packages/react-intersection-observer/package.json 中当前版本为11.0.0;二是发布工作流 .github/workflows/release.yml 用pnpm exec bumpp ${{ inputs.version }} --yes执行版本号提升——version输入的可选项正是patch、minor、major以及prepatch、preminor、premajor、prerelease等预发布变体,与 SemVer 规范一一对应。

Pull Request 流程与提交规范

CONTRIBUTING.md 要求在每个 fork 分支上完成改动后,按以下清单提交 PR:

  1. 为改动添加测试;
  2. 确保全部测试通过;
  3. 若改动影响文档,同步更新README.md;
  4. 遵循下述提交信息约定。

Commit message 约定:Conventional Commits

提交信息遵循 Conventional Commits 规范,格式为:

<type>: <subject>
  • <type>表示变更类型:feat用于新功能,fix用于 Bug 修复,docs用于文档,chore用于不触碰代码本身的改动(如依赖更新);
  • <subject>是对变更的简短描述。

这种格式化的提交信息让 CI 生成的发布说明(release notes)保持可读。仓库根目录还通过simple-git-hooks与lint-staged配置了 pre-commit 钩子:对*.{js,json,css,md,ts,tsx}文件自动执行biome check --fix(见根目录 package.json),从源头保证提交进度的代码已经过格式化。

代码风格与静态检查:Biome

CONTRIBUTING.md 指定项目使用Biome做格式化与 lint,打开 PR 前必须用 Biome 格式化改动。仓库的 biome.json 给出了实际配置:

  • 启用 formatter,indentStyle: space(空格缩进);
  • 启用 linter,采用recommended规则集,并针对该库做了少量豁免,例如关闭noForEach、将noUnusedVariables降级为 warn、关闭noSvgWithoutTitle等。

对应的检查命令在包内为biome check .(见 packages/react-intersection-observer/package.json),仓库根目录提供聚合的pnpm lint。

测试:Vitest + Playwright Browser Mode + Node SSR 双项目

CONTRIBUTING.md 说明测试框架是Vitest,并强调了两点关键事实:组件测试运行在 Vitest Browser Mode(基于 Playwright),SSR 测试则运行在独立的 Node 项目中。执行:

pnpm test

其背后是 packages/react-intersection-observer/vitest.config.ts 中定义的两个测试项目:

projects: [ { test: { name: "node", environment: "node", include: ["src/**/*.ssr.test.ts"], }, }, { test: { name: "browser", include: ["src/**/*.test.{ts,tsx}"], exclude: ["src/**/*.ssr.test.ts"], browser: { enabled: true, provider: playwright(), headless: true, instances: [{ browser: "chromium" }], }, }, }, ],

也就是说:

  • 文件名以.ssr.test.ts结尾的测试(如 src/tests/useInView.ssr.test.ts,验证useInView在renderToString下无警告地渲染出false)走 Node 环境;
  • 其余.test.{ts,tsx}文件(如 src/tests/useOnInView.test.tsx、src/tests/observe.test.ts)走 Chromium 浏览器的 Browser Mode,由 Playwright 驱动。
内置的 IntersectionObserver 测试工具

该仓库为测试做了专门的工程化铺垫:包额外导出一个react-intersection-observer/test-utils入口(见 packages/react-intersection-observer/package.json 的exports字段,源码位于 packages/react-intersection-observer/src/test-utils.ts)。它提供:

  • setupIntersectionMocking(mockFn):把window.IntersectionObserver替换为可记录的 mock,并跟踪被观察的元素集合;
  • resetIntersectionMocking():重置 mock 与观察状态;
  • mockAllIsIntersecting(value)/mockIsIntersecting(element, value):模拟所有(或指定)元素进入/离开视口,value既可以是布尔值,也可以是表示intersectionRatio的数字;
  • intersectionMockInstance(element):拿到某个元素对应的(mock)Observer 实例,用于断言observe/unobserve调用。

测试环境(Jest 或 Vitest)下该工具会在beforeEach中自动启用 mock、在afterEach中自动重置;非测试环境调用时会输出一段提示,指导在测试 setup 文件中手动配置。这让「先写测试再提交」在仓库里有了现成的脚手架支撑。

底层实现与测试的呼应

observe.test.ts印证了 packages/react-intersection-observer/src/observe.ts 的核心设计——相同选项的 Observer 会被复用:

  • optionsToId(options)把root、rootMargin、threshold、scrollMargin、trackVisibility、delay等选项排序后拼成唯一字符串 ID,测试断言如optionsToId({ rootMargin: "10px 10px", threshold: [0, 1] })得到"root_0,rootMargin_10px 10px,threshold_0,1";
  • 同一 ID 对应的IntersectionObserver实例存放在全局observerMap中复用,每个元素维护自己的回调数组;
  • observe()返回的清理函数具备幂等性:重复调用只清理一次,只有当元素的回调全部移除后才unobserve,只有当实例没有任何元素时才disconnect并从observerMap删除。测试"should only clean up each observer callback once"正是对这一行为的验证。

此外,由于useOnInView(见 packages/react-intersection-observer/src/useOnInView.tsx)与useInView(见 packages/react-intersection-observer/src/useInView.tsx)都经由useIntersectionObserverRef(见 packages/react-intersection-observer/src/useIntersectionObserverRef.ts)调用底层observe,测试文件里还覆盖了 ref 生命周期、Strict Mode 下的重复挂载清理、ref 合并、同一元素多回调等边界场景,这些都可以作为新增测试的参考范式。

构建产物验证

CONTRIBUTING.md 建议在提交前构建包与两个应用:

pnpm build:all

该命令的完整展开为(根目录 package.json):

"build:all": "pnpm build && pnpm --filter storybook build && pnpm --filter docs build"

其中pnpm build指pnpm --filter react-intersection-observer build。包的构建由 packages/react-intersection-observer/tsup.config.ts 驱动:基于 tsup 同时产出esm/cjs双格式与类型声明(dts: true),主入口src/index.tsx输出到dist,测试工具入口src/test-utils.ts输出到test-utils。构建后还会执行attw --pack、publint与 size-limit 校验——packages/react-intersection-observer/package.json 中为InView、useInView、useOnInView、observe分别设置了1.5 kB、1.36 kB、1.12 kB、0.9 kB的体积预算,防止贡献导致包体膨胀。

发布流程:CI 上的 npm Trusted Publishing

CONTRIBUTING.md 特别强调:发布只发生在 CI,本地没有发布步骤。原因是仓库采用 npm 的 trusted publishing(信任发布者)机制,仓库内不存在任何 npm token,发布时自动附加 provenance(来源证明);从本地执行npm publish会被拒绝。

手动触发 Release 工作流

要发布一个版本,维护者在仓库的Actions选项卡中选择Release工作流,并从要发布的分支运行它。工作流有两个输入参数(见 .github/workflows/release.yml):

  • version:选择版本增量,可选patch、minor、major,以及prepatch、preminor、premajor、prerelease,默认patch;
  • tag:指定 npm dist-tag,默认latest,预发布版本使用beta。

工作流的完整执行链条

release.yml中的 job 完整呈现了 CONTRIBUTING.md 描述的流程:

  1. 铸造 GitHub App token:因为main分支受保护,而 GitHub Actions 应用不能作为用户仓库 ruleset 的 bypass actor,工作流通过actions/create-github-app-token@v2使用vars.RELEASE_APP_ID与secrets.RELEASE_APP_KEY铸造一个短期 token,用于推送版本提交;该 token 在 job 结束时自动失效。
  2. 检出代码:以fetch-depth: 0全量检出,方便生成版本与发布说明。
  3. 环境准备:启用 corepack、安装 Node.js 24、更新 npm(trusted publishing 要求 npm 11.5.1+)、pnpm install --frozen-lockfile锁定依赖。
  4. 提升版本并提交:执行pnpm exec bumpp ${{ inputs.version }} --yes,在 bump 版本号的同时完成 commit 与 tag。
  5. 构建:在packages/react-intersection-observer目录执行pnpm build。
  6. 发布到 npm:npm publish --tag ${{ inputs.tag }}。注释明确写到 "No NODE_AUTH_TOKEN: npm authenticates through the OIDC token",即通过 job 的id-token: write权限完成 OIDC 认证,provenance 由 trusted publishing 自动证明。
  7. 创建 GitHub Release:gh release create "v${{ steps.version.outputs.version }}" --generate-notes,基于 Conventional Commits 自动生成发布说明;pre*版本还会追加--prerelease标记。

这解释了 CONTRIBUTING.md 中「版本提交由 GitHub App 铸造的短期 token 推送,App ID 存放于RELEASE_APP_ID变量、私钥存放于RELEASE_APP_KEYsecret」的完整工程背景。

小结

对react-intersection-observer的贡献者而言,完整的工作流可以浓缩为四条主线:

  • 开发:pnpm install后用pnpm dev(或pnpm dev:storybook/pnpm dev:docs)并行启动包、Storybook 与文档站点;
  • 提交:遵循<type>: <subject>的 Conventional Commits 规范,交给 pre-commit 钩子与 Biome 统一格式;
  • 测试:pnpm test同时运行 Browser Mode(Playwright + Chromium)与 Node SSR 两套 Vitest 项目,借助react-intersection-observer/test-utils内置的 IntersectionObserver mock 编写确定性测试;提交前用pnpm build:all验证构建与体积预算;
  • 发布:无需本地 npm token,在 Actions 中运行 Release 工作流,选择version与tag后,CI 完成 bump、构建、trusted publishing 与 GitHub Release 生成。

对源码级细节感兴趣的读者,可以继续深入 packages/react-intersection-observer/src/observe.ts 理解共享 Observer 机制,翻阅 packages/react-intersection-observer/src/tests学习测试范式,或对照 .github/workflows/release.yml 复现完整的发布流水线。

  • 前端
  • UI组件

【免费下载链接】react-intersection-observer

React implementation of the Intersection Observer API to tell you when an element enters or leaves the viewport.

项目地址:https://gitcode.com/gh_mirrors/re/react-intersection-observer
点击查看免费下载
上一篇:markitdown:5 分钟把办公文档变成可检索文本
下一篇:MTEB项目中的可复现工作流详解

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询