React Aria Components collections crash: host and text nodes ignore the portal container's ownerDocument

オープン
#163 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
49/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
react, typescript
領域
frontend

調査の方向性

Start with src/dom/reconcile.ts: inspect node creation around lines 599 and 1004, then child reordering around line 477. Reproduce with the Vite configuration and Tabs example from the issue, comparing behavior with and without the Redact plugin. Done means the collection mounts without either reported crash; the issue notes that the second crash is not confirmed in the minimal reproduction.

索引モデルが issue の本文から書いたものです。

説明

Versions

  • @tanstack/redact 0.3.1
  • react and react-dom 19.3.1
  • react-aria-components 1.22.1 (react-aria 3.53.1)
  • vite 8.3.5, production build, Chromium

What happens

Any React Aria Components collection (Tabs here) crashes on mount and leaves the root empty:

Uncaught TypeError: Cannot set property previousSibling of #<Node> which has only a getter
    at appendChild (react-aria collections Document)

The same app built without the redact() plugin renders both tabs with no console errors.

Reproduction

// vite.config.ts
import { redact } from "@tanstack/redact/vite"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"

export default defineConfig({ plugins: [react(), redact()] })
// src/main.tsx
import { createRoot } from "react-dom/client"
import { Tab, TabList, TabPanel, Tabs } from "react-aria-components"

createRoot(document.getElementById("root")!).render(
  <Tabs>
    <TabList aria-label="Example">
      <Tab id="a">A</Tab>
      <Tab id="b">B</Tab>
    </TabList>
    <TabPanel id="a">Panel A</TabPanel>
    <TabPanel id="b">Panel B</TabPanel>
  </Tabs>,
)

Run vite build && vite preview and open the page.

Cause

React Aria builds its collections by calling createPortal(children, doc), where doc is its own fake Document (react-aria/dist/private/collections/Document.mjs). Its nodes have their own appendChild, insertBefore and ownerDocument.

This relies on the renderer creating nodes through the portal container's ownerDocument, as I understand React DOM does. Redact uses the global document:

  • src/dom/reconcile.ts:1004: createHostNode(type, isSvg), whose owner parameter defaults to document
  • src/dom/reconcile.ts:599: document.createTextNode(text)

A real DOM node then reaches the fake appendChild, which assigns child.previousSibling and throws, because that property is a getter on a real Node.

Possible fix, partly tested

Using the parent's owner document got past this crash when applied to dist/dom/reconcile.js in a larger app, using a build-time transform:

fiber.n = createHostNode(type, isSvg, domParent.ownerDocument || document)
fiber.n = (domParent.ownerDocument || document).createTextNode(text)

I only tried this as an experiment in that app, not against Redact's test suite.

Second crash after that fix

With the fix applied, the larger app's page using Tabs then threw this:

TypeError: r.compareDocumentPosition is not a function

The likely source is src/dom/reconcile.ts:477, which calls d.compareDocumentPosition(targetNext) while reordering children. I found no such method in a search of React Aria's Document.mjs. I haven't confirmed the call site or reproduced this crash in the minimal app.

Impact

We evaluated Redact for a TanStack Start dashboard built on React Aria Components. With Redact enabled:

  • 318 of 1231 unit and story tests failed; all pass on React.
  • No E2E test passed, because the sign-in flow failed for every role.

Not all of those story failures are confirmed to be this bug. The most common error was Cannot read properties of undefined (reading 'toLowerCase') (116 occurrences), which I haven't diagnosed, so it may be a separate issue.

主要言語
TypeScript
スター
537
フォーク
22
平均マージ
10時間 27分
マージ済み PR(30日)
40

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

TanStack/redact のほかの issue

TanStack/redact の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。