プログラミング
レンダリングされたことのないReactコンポーネントの編集
Editing React components that never rendered (blog.crossui.com)
要約
開発ツールがコードベースを理解する方法には、実行時のイントロスペクションと静的なAST解析の2つがあります。CrossUI Studioが採用する静的なAST解析は、アプリがクラッシュした場合でもコード構造を分析できるため、レンダリングに失敗したコードのデバッグや編集に優れています。このアプローチにより、実行時の状態に依存せず、コードの構造(AST)を基盤としてコンポーネントを孤立して編集できます。
全文翻訳
ツールがReactコードの形状を把握するには、2つの方法しかありません。どちらを選ぶかによって、ツールの最も重要な点が決まります。それは、最も必要とされている瞬間に利用可能かどうかです。
コードベースを知る2つの方法
実行時のイントロスペクションは、実行中のアプリを監視します。React DevTools、プロファイラー、エラーオーバーレイなどは、アプリのマウント後にライブのファイバーツリーを読み取ります。これはより豊かな情報を提供します。実際のプロップ値、実際の状態、実際にレンダリングされたものを知ることができます。しかし、それらすべては1つの条件に依存します。アプリが最初に正常に実行されなければなりません。レンダリングが失敗した瞬間、それらは機能しなくなります。何もマウントされていないので、検査するものがありません。そして、初期化に失敗したモジュールは、定義上、それらには見えません。
静的なAST解析はソースコードを読み取ります。各ファイルを抽象構文木(AST)に解析し、コードを実行せずに、すべてのJSXノード、すべてのインポート、すべてのプロップの構造を直接読み取ります。これはある意味では貧弱です。何も実行されていないため、午後2時4分に変数が何を持っていたかを知ることはできません。しかし、それは実行時のツールには真似できない特性を持っています。それは、一度も正常にレンダリングされたことのないコードでも機能することです。
ほとんどの開発者ツールは、最初のモデルに基づいて構築されています。私たちは、React用のビジュアルエディタであるCrossUI Studioを、意図的に2番目のモデルに基づいて構築しました。この記事では、その制約がなぜ全体的なポイントになったのかについて説明します。
ツールがあなたを見捨てるとき
決定を形作ったシナリオを次に示します。あるコンポーネントが空白をレンダリングします。スタックトレースはそのコンポーネントを指していますが、本当の失敗は5つのインポート先です。動的なインポートが解決されなかった、ピア依存関係が更新された、最初のアクセス時に未定義の循環参照がある、などです。コンポーネントは無実です。それが間接的に引き込んでいるものが原因です。このまさに、コードの構造を理解する必要があるときです。どのファイルが何をインポートしているか、どこが壊れているか、周囲のコードがどのようになっているかです。そして、まさにその時、すべての実行時ツールが機能しなくなります。アプリがレンダリングされなかったからです。DevToolsは何も表示しません。プロファイラーはプロファイルするレンダリングがありません。エラーオーバーレイは行番号を提供しますが、その周囲のコードの形状は提供しません。それらはすべてアプリが最初に実行されることを必要としますが、問題全体はそれが実行されないことです。コードの構造を見るのに最も必要な瞬間は、実行時ツールがそれを提供することを拒否する瞬間です。静的なASTツールにはそのような依存関係はありません。ファイルを開いたときにファイルを解析しました。それは完全なインポートグラフを描画し、壊れたモジュールを指し示し、アプリが完全にクラッシュしていても、その周囲のコードを表示できます。
壊れたページは行き止まりではありません。それは入り口です。
実行できないものを編集する
同じ特性が、より奇妙なことを可能にします。レンダリングされていないコンポーネントを、開いたことのないファイルで編集することです。通常のビジュアルエディタが、.map()の中に存在する<Card>をレンダリングするために何が必要かを考えてみてください。そのCardをキャンバスに配置するには、それがどのアイテムであるかを知る必要があります。そして、アイテムは実行時にループの中で、実際のデータが流れるときにのみ存在します。実行時ベースのエディタは、そのCardを孤立してレンダリングできません。それを供給するためのライブなアイテムが存在しないからです。そのため、ほとんどのビジュアルエディタは、.map()の中には入らないように静かに拒否します。
ASTから作業すると、問題が再定義されます。実行中のループは必要ありません。ノードが必要です。ファイルを解析し、マップコールバックの中のJSXを見つけ、そのサブツリーを孤立してレンダリングします。欠けている唯一のものはアイテムの値です。そのため、アプリにそれを生成させるのではなく、それを要求します(パネル内の小さなモック)。Cardは、実際のテーマ設定で、ライブでレンダリングされ、単独で機能します。そして、理解の単位がマウントされたコンポーネントではなくASTノードであるため、ドリルダウンはファイル境界で停止しません。別のファイルからインポートされた子コンポーネントは、グラフの別のエッジにすぎません。インポートをたどり、そのファイルを解析し、そのノードをレンダリングします。あなたは、どこにも開いたことのない場所で定義されたコンポーネントを編集しています。全体として一度もレンダリングされなかったかもしれないアプリでさえです。
制約のコスト
これらはすべて無料ではありません。そうでないと偽るのは不誠実でしょう。静的解析は、実行時知識を放棄することで、無条件の可用性を購入します。動的に計算されたパスを持つimport('./pages/' + name)のような完全に動的なインポートは、静的に解決できません。私たちはエッジを推測するのではなくマークします。私たちは構造を見ますが、値は見ません。ASTはAIPanelがTreeSitterに到達することを示しますが、特定のレンダリングでパーサーが何を返したかを知ることはできません。モックデータは実際のデータの代わりになります。それはそれを再生しません。エキゾチックな解決には設定が必要です。非標準のバンドラーエイリアスやモノレポのパスマジックは、tsconfig/jsconfigを読み取れる場合に最もよく解決されます。それがない場合、一部のエッジは生の指定子にフォールバックします。
これらは現実の境界です。しかし、それらのどれもコアの約束に触れていないことに注意してください。ツールは、コードが実行される必要がなかったため、行き詰まったときにそこにあります。
なぜこれが1つのアイデアであり、複数ではないのか
クラッシュを生き延びる依存関係グラフ、マップ内の編集ドリルダウン、ファイル間のナビゲーション、1行の差分。外部から見ると、これらは別々の機能のように見えます。それらは、解析されたソースを真実の源として扱い、すべてのサーフェスをそのASTのビューにすることを、異なる角度から見た同じ決定です。キャンバスはASTのビューです。プロップインスペクターはASTのビューです。依存関係グラフは、ファイル間のASTのビューです。それらのどれも、正常なレンダリングに依存しません。なぜなら、それらのどれも実行時に構築されていないからです。これはファイバーツリーにフックするよりも構築が難しいものです。そして、それは実行時、そしてそれに基づいて構築されたすべてが行き詰まった瞬間に、ツールの寿命を延ばすものです。
→試してみてください。プロジェクトを開き、意図的に深いインポートを壊してみて、構造がまだレンダリングされるのを見てください。
CrossUI Studioについて—React & MUI用のビジュアルIDE。コードとキャンバスは同じAST上で双方向に同期します。コードを編集するとキャンバスがライブで更新されます。キャンバス上の要素をクリックすると、そのプロップを視覚的に編集でき、コードは外科的な1行の差分で変更されます。ビルドやlocalhostは不要です。ブラウザで動作し、実際のGitリポジトリまたはローカルフォルダで機能し、ベンダーロックインはありません。無料でお試しください→studio.crossui.com
関連記事
ビジュアルUI編集のためにエクスポート&フォークモデルを却下した理由
壊れたインポートを見つけるだけでなく、それをバイパスする。