作り方とセキュリティについてJavaScriptTweet一年前に以下の記事を書いて、その後放置していたら多くのライブラリのメジャーリリースで完全に動かなくなってしまったのでリニューアルしました。blog.hiroppy.me以下のセクションで説明していきますが、コードを読んだほうが早いです。WorkerGraphQLおわりリポジトリgithub.comこのリポジトリはこれを見れば様々な実装の動く土俵を作れるというのを目的としています。環境構築ですら毎回忘れるので。冗長に書いてある部分も多いですが、今後も新しい必要な実装を小さく追加していく予定です。動きを確認したい人は、cloneして手元で動かしてみてください。技術スタックこれはあくまでもサンプルなので、sagaとapolloが混じってますが実際はどちらかで大丈夫です。sagaで設計していて、apollo-stateは使わずあくまでもqueryとmutationのみです。主要なライブラリは以下のとおりです。Rendering注目するべき点はloadable-componentsの大幅なアルゴリズム改善だと思っています。これにより、パフォーマンスは改善されました。loadable-componentsgithub.com未だ、ReactのほうがSSRに対応していないため、引き続きreact-loadableやloadable-componentsは必要となります。SuspenseはSSR対応進めています。github.comメジャーバージョンでreact-loadableと同様にwebpackを使いassetsのmapを作成するようになりました。これにより、SSRの処理が高速化されました。babel-pluginに依存しないと動かないため、babel-preset-typescriptをこのライブラリでは使っています。データの送り方SSRで取得したデータはStoreを構築し、それをクライアントサイドにHTML経由で渡します。以下のようにdata属性を使い、scriptタグ経由で渡すのがいいと自分も思っています。data-json="${preloadedState}"></script>このpreloadedStateはエスケープ処理が必要なので注意してください。GitHubuseEffectSSRでは、componentDidMount前までしか実行されません。hooksではuseEffectは呼び出されずFCにはconstructorは存在しません。どこに初期化処理とかあれば書けばいいのかベストプラクティスは自分はわかりません。}今はこんなふうに書いているけど気持ち悪いので辞めたい。副作用の操作をredux-sagaでこのサンプルは行っています。hooksreactにhooksが入ったことにより、react-routerやredux、apolloのhooks対応されました。GitHubreduxreduxはhooksが入ったことにより大きな変更があります。それは、presentationalとcontainerという単語が無くなりそうです。github.com今までのreduxは、presentationalとcontainerで責務(関心事)が別れていました。それは自分にとってはきれいだと思っていました、presentationalでstoreからくる値はpropsを渡す感じ。hooksが入ったことにより、dispatchをpresentationalから呼ぶことになったのでcontainerも必要ないです。apolloapolloは本当にきれいに書くことができるようになり満足しています。移行記事は以下を参考にしてください。GitHubはぁ、きれい。(saga捨てたい顔)redux-sagasagaが行うこととして、クライアントサイドとサーバーサイドで一点異なる点があります。それは、sagaのプロセスをサーバーサイドの場合停止させないといけなく、そうしないとクライアントにhtmlを返せません。以下のように止めるようにします。GitHub自分がSPAで実装を行うときは、sagaを2ライン走らせます。GitHubこれらが終わり次第、ENDを呼ぶ構築が一番いいと思います。ShellPWAと少し被りますが、sagaとの話もあるのでここで。react-routerでパスに応じたcomponentsはここに流れてきます。このコンポーネントが上位階層で、ここでheaderだけのレンダリング(App)と共通処理(appProcess)を行います。いうファイル名にします。developer.mozilla.org仕様w3c.github.iowebpack-pwa-manifestを使い、生成します。screen等はデバッグしづらいので、もし原因がわからなかったらchrome://flags/#bypass-app-banner-engagement-checksをオンにすると幸せになります。screenはこんな感じになります。WorkerWorkboxを使います。cacheを優先する。GitHub後ほど、説明しますが、CSPには注意してください。service-workerからのアクセスはconnectとなります。AuditsExpressのhttp/2対応がマージされれば全部100になります。Policydeveloper.mozilla.orgCSPとは、XSSを防ぐために信頼したものしかブラウザが実行しないように制御できます。headerからContent-Security-Policyの属性を照会し一致するものだけを実行します。connect等幅広く設定できます。fontとreadmeのバッジで使われるshieldsを許可しています。GitHubこのように指定したところへのアクセスだけを許可することよりXSSに対して強固なwebアプリケーションが作成できます。このアプリケーションでは、nonce方式を説明していきます。nonce="ZmZIaTAyQ25rZ2FxVERUVVI4VUhBTUVJc29uTV9leUo="></script>もっと詳しく知りたい方はPixivの記事が詳しいので読むと良さそうです。importの対応の難しさが上げられます。importの場合、nonceが存在しないためです。CSPには、level3とlevel2が存在し、level3にはstrict-dynamicという仕組みがありそれがこの問題を解決します。strict-dynamicでは、nonce付きの実行されたスクリプトの子供はnonceが無くても実行可能となります。importは解決が行なえません。__webpack_nonce__を使えば、動きますがnonceは本来毎アクセス時にhashを生成しないと攻撃者に推測される可能性があるため、ビルド時ではいけなく根本的な解決ではありません。workerからの問い合わせはconnect-srcとなります。以下のように、styleSrcやfontSrcと同じurlがconnectSrcに書いてあるのがわかります。["'self'"]};GraphQLGraphQLはスキーマが自由であるため、サーバーへの負荷対策を行う必要があります。入れ子の深い不正クエリーが送られてきたときにはサーバー側の処理に負荷がかかる可能性があるため、その処理に到達させる前に弾く必要があります。DoSを防ぐためにも必ず入れる対策がこの対策です。有名な方法は以下のとおりです。指定したクエリの深さ以下を通過させる重み(コスト)制限クエリーに重さ(深さ含む)付けをし、それの合計値が指定値以下の場合は通過させるこのサンプルでは、重み制限を使用しています。今回は使ってないですがgraphql-validation-complexityであれば以下の計算式となります。listFactorgithub.com今回は、graphql-query-complexityを使っています。GitHubGraphQLはプロダクションでリリースするときには必ず、このような対策が必要となります。おわり長文になりましたが、機能追加等のPR/Issue歓迎しています。Sponsorsもよろしくおねがいします。作り方とセキュリティについてTweet関連記事2019-06-24Markdownだけでスライドを作るCLIの大規模アップデートをしたFusumaの大規模アップデートです。週間)JavaScriptが好き。Node.jsとwebpackのコミッター。月別アーカイブはてなブログをはじめよう!about_hiroppyさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。