Closed 168iroha closed 8 months ago
props
とchildren
を入力としてコンポーネントを示すノードのツリーを出力する関数とみたときに副作用とみなせる操作を指すsideEffectLabel
というラベルにより行っているuseSSRData
によりSSRで非同期処理を行った結果を得る場合、
function Component(ctx) {
const data = useSSRData(ctx);
return $('div', { style: data }, ['sample'])
}
SSRでは以下のようなDOMツリーが得られるようにする
<!-- 従来の結果 -->
<div style="">sample</div>
<!-- 改修案における結果 -->
<div style="width: 50%">sample<script class="useSSRData">{ "width": "50%" }</script></div>
ハイドレーションを行うときには以下のようにSSRに関するDOMノードを除去する仕組みさえ用意しておけば、複数のuseSSRData
を行っても問題ない
<!-- ハイドレーション後の状態 -->
<div style="width: 50%">sample</div>
useSSRData
はライブラリとして与えるuseSSRData
を用いていると、子要素の構築が遅延されてしまうため、遅延しないような評価の仕組みが必要
GenStateNode.#mountImpl
でGenStateNode.mount
による構築とみなせるかGenStateNode.write
による構築とみなせるかという区別ができるようにすることで対処可能GenStateNode.mount
とGenStateNode.write
とでuseSSRData
に関する評価順序が入れ替わる可能性があるため、用途はSSRなどと限定する必要がある重要な変更点は以下の通り
onMount
といったライフサイクルフックがノードツリーの構築中に発火することができるPromise
の評価後に発火させることが可能となるため、サーバサイドで取得したデータをDOMノードに後から組み込むことが可能Promise
を評価できるようにした[!NOTE]
GenStateNode.#mountImpl
を非同期関数ではなく、GenStateNode.buildCurrent
の評価に関するジェネレータ関数として実装することにより、マイクロタスクによる評価の遅延を最小限にしつつ、GenStateNode.mount
などを同期的に評価することを可能としている(ジェネレータはasync/await
での実装で内部的に使われているためこのような実装でも問題ない)
useSSRData
を実装するとしたとき、サーバではデータのフェッチ&書き出し、クライアントではデータのデータのフェッチorフェッチされたデータの読み込みのように行う処理が全く異なるため、サーバとクライアントとで処理を切り替える仕組み(エイリアスの作成)が必要
→前提として、webpackなどのモジュールバンドラを用いてバンドルすることになる
→基本方針であるVanilla JSで動作することと乖離が生じてしまうが、AltJSを利用するわけではないためセーフとする
useSSRData
の概要useSSRData
を実装したuseSSRData
をそれぞれ実装し、webpackのaliasを用いてターゲットに応じてリンクをするスクリプトを変更することで実現することを前提としているsample/xx_useSSRData
にサンプルを用意したssg.cjs
とクライアントが読み込むJavaScriptのファイルmain.js
が生成される
node_modules/.bin/webpack
ssg.cjs
に対して以下のようコマンドを実行することでindex.html
が生成されるため、これに対してlocalhostなどでアクセスをすることにより完了する
node ./ssg.cjs
※注意点として、webpackをまともに利用するのは初めてのため、変な記述になっているかもしれない
一先ず、今回の修正により以下の要件はすべて満たすような実装となっている
そのため、適当にリファクタリングをして、結果をdevelop
ブランチにマージしたらissueはクローズする。
※テストについては実施は未定(そのうちやりたいけど、JavaScriptのテスト方法があまり知らないため保留)
- 必ずサーバが非同期処理の結果をクライアントへ与える
- クライアント側では初回の非同期処理の結果はサーバが行った内容を用いる
- 必要なタイミングでクライアント側でも非同期処理を行うことができるようにする
- ハイドレーションが可能であることを保証する
- コンポーネント単位で非同期処理が行われる
今まで副作用では状態の伝播のみを許容していたが、利便性が著しく悪くなるためDOMツリーの属性ノードを除く構造が不変であれば伝播を許容するように変更した
まずはやりたいことだけ整理しておく
背景
要件の整理
※その他、非同期処理の結果のキャッシュの有効期限等の議論も必要だが、本件は非同期処理を行うことが本題であり、いつサーバで非同期処理を行うかは本題ではないため、明示的に取り扱いはしない。ただし、それを可能とするインターフェースの整理は必要