Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ReactベースのSPA開発で開発者が気をつけたいSEOのお話
Search
Yoshinobu Wakamatsu
August 21, 2019
Technology
2
1.6k
ReactベースのSPA開発で開発者が気をつけたいSEOのお話
【シューマイ】Tech Lead Engineerから最新技術を学べ!React編
https://shuuu-mai.connpass.com/event/140002/
Yoshinobu Wakamatsu
August 21, 2019
Tweet
Share
More Decks by Yoshinobu Wakamatsu
See All by Yoshinobu Wakamatsu
金融領域におけるサービス開発の進め方
yshnb
0
610
資産運用スタートアップの開発で採用した、PlayによるClean Arcitectureでの設計・開発事例
yshnb
5
910
Fundsのアーキテクチャについて
yshnb
0
210
ScalaによるDDDライクなプロダクト開発
yshnb
0
470
Applivの開発体制から考える、理想の開発体制とは?
yshnb
2
10k
Other Decks in Technology
See All in Technology
Terraform CI/CD パイプラインにおける AWS CodeCommit の代替手段
hiyanger
1
240
OCI Vault 概要
oracle4engineer
PRO
0
9.7k
OCI Network Firewall 概要
oracle4engineer
PRO
0
4.1k
SSMRunbook作成の勘所_20241120
koichiotomo
1
110
iOS/Androidで同じUI体験をネ イティブで作成する際に気をつ けたい落とし穴
fumiyasac0921
1
110
インフラとバックエンドとフロントエンドをくまなく調べて遅いアプリを早くした件
tubone24
1
430
New Relicを活用したSREの最初のステップ / NRUG OKINAWA VOL.3
isaoshimizu
2
570
誰も全体を知らない ~ ロールの垣根を超えて引き上げる開発生産性 / Boosting Development Productivity Across Roles
kakehashi
1
220
IBC 2024 動画技術関連レポート / IBC 2024 Report
cyberagentdevelopers
PRO
0
110
Platform Engineering for Software Developers and Architects
syntasso
1
510
データプロダクトの定義からはじめる、データコントラクト駆動なデータ基盤
chanyou0311
2
280
Why does continuous profiling matter to developers? #appdevelopercon
salaboy
0
180
Featured
See All Featured
Making Projects Easy
brettharned
115
5.9k
For a Future-Friendly Web
brad_frost
175
9.4k
Rails Girls Zürich Keynote
gr2m
94
13k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
1.9k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
Designing the Hi-DPI Web
ddemaree
280
34k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
YesSQL, Process and Tooling at Scale
rocio
169
14k
The Cost Of JavaScript in 2023
addyosmani
45
6.7k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.3k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
28
2k
Transcript
ReactベースのSPA開発で 開発者が気をつけたいSEOのお話 株式会社クラウドポート IT・業務管理部⻑/エンジニア 若松 慶信
Introduction 2019/8/21 2
⾃⼰紹介 株式会社クラウドポート IT・業務管理部⻑/エンジニア 若松 慶信 2019/8/21 3 • クラウドポートのFundsではフロントエンド含む開発・運⽤全般を担当 •
SEOについては前職で経験
資産形成をしたい個⼈とお⾦を借りたい企業を結ぶ、 「貸付ファンド」のオンラインマーケット 第⼆種⾦融商品取引業者のクラウドポートが運営
None
2019/8/21 6 今回のテーマについて
2019/8/21 7 Reactなどを使うモダンなフロントエンド開発での SEOに関する情報は少ない・・・
FundsでのReactの使い⽅を SEOという視点からお話します 2019/8/21 8 ※SEOの話多めです
SEOとフロントエンドエンジニアの役割 2019/8/21 9
SEO(検索エンジン最適化)とは Webサイトが検索エンジンで⾒つかりやすくすること 2019/8/21 10
SEOに取り組む上での基本的な考え⽅ • ベストエフォートで取り組み、結果が出るのを待つ • 銀の弾丸はない 2019/8/21 11
今回はフロントエンドエンジニアの役割にフォーカスした話をします 2019/8/21 12
SEOにおけるフロントエンドエンジニアの役割 クローラーが正しくWebサイトを解釈できるようにし サイトが正当な評価を受けられるようにする 2019/8/21 13
「正当な評価を受けられる」とは︖ 2019/8/21 14
正当な評価を受けられないケースの例 • クローラーが正しくレンダリングできない • ページ間の関係性をリンクで伝えられていない • 複数のURLで同じコンテンツを表⽰できてしまう • 存在しないページなのに、200でコンテンツが表⽰できてしまう 2019/8/21
15
SEOにおけるフロントエンドエンジニアの役割 クローラーが正しくWebサイトを解釈できるようにし サイトが正当な評価を受けられるようにする 2019/8/21 16
SEOにおけるフロントエンドエンジニアの役割 クローラーが正しくWebサイトを解釈できるようにし サイトが正当な評価を受けられるようにする 2019/8/21 17 エンジニアの考慮不⾜で機会損失を⽣まないことが重要
SEOを考慮したレンダリング⼿法の選択 2019/8/21 18
レンダリング (今回の⽂脈では) HTMLとJavaScriptからブラウザ上へ描画するための DOMツリーを構築すること 2019/8/21 19
レンダリング 正しくレンダリングさせることは、正当な評価を受ける必要条件の1つ 2019/8/21 20
Googlebotのレンダリング能⼒ • (〜2019/5)Chrome 41 程度のレンダリング能⼒ • ES6などのシンタックスは未サポートでpolyfillが必要 • (2019/5〜現在)最新のChromium エンジンを適⽤可能に
• ES6などにも対応 • クローラー向けのpolyfillは不要になっている 2019/8/21 21
2019/8/21 22
SPAの主なレンダリング⽅式 • CSR (Client Side Rendering) • ブラウザ上でJavaScriptによりレンダリングする⽅式 • SSG
(Static Site Generator) • ビルド時に静的なHTMLを出⼒する⽅式 • Dynamic Rendering • ⼀般のユーザー向けにはCSRを適⽤する • クローラー向けの配信に限りレンダリング済みの結果を返す • SSR (Server Side Rendering) • コンテンツ配信時にサーバサイドでレンダリングする⽅式 • Rehydration により継続して CSR でレンダリングできるようにすることも多い • ⾯倒だが確実性はある 2019/8/21 23
SSRは必要か︖ • レンダリングの問題に限ればSSRは必須ではない • SSRでなければ対応できない問題もある 2019/8/21 24
SSRでなければできないこと • ステータスコードを適切に返す • ページ単位のURL正規化/ソフト404エラーの防⽌に必要 • メタ要素 (title, meta, link
タグなど)を確実に認識させる • URL正規化で使⽤する rel=canonical はSSR以外では解釈されない • その他のメタ要素もサーバサイドでレンダリングして返すことが望ましい • 頻繁に更新されるコンテンツ • JavaScriptを使⽤するレンダリングは遅い(次に説明) • これはDynamic Renderingでも対応できる 2019/8/21 25
引⽤元: https://developers.google.com/search/docs/guides/javascript-seo-basics GoogleがJavaScriptをレンダリングするプロセス JavaScriptのレンダリングには このプロセスが追加で必要 レンダリングされるまで時間を要する 2019/8/21 26
SEOを考慮したレンダリング⼿法の選択 ⾃然検索流⼊が重要な集客チャネルかどうか︖に注⽬する 2019/8/21 27
SEOを考慮したレンダリング⼿法の選択 ⾃然検索流⼊が重要 ⾃然検索流⼊はあまり重要ではない サイトの例 • Webメディア • ECサイト/マーケットプレイス • ポータルサイト
• コーポレートサイト • 会員登録が必須のサイト • 他の集客チャネルがメインのサイト 採⽤する アプローチ SSRを採⽤することが望ましい SSRを採⽤するかはUX次第 2019/8/21 28
Fundsの集客チャネルと要件 ⾃然検索流⼊が重要 ⾃然検索流⼊はあまり重要ではない サイトの例 • Webメディア • ECサイト/マーケットプレイス • ポータルサイト
• コーポレートサイト • 会員登録が必須のサイト • 他の集客チャネルがメインのサイト 採⽤する アプローチ SSRを採⽤することが望ましい SSRを採⽤するかはUX次第 2019/8/21 29 ⾃然検索流⼊は主要な集客チャネルではないが、機会損失がないようにしたい + UXも考慮してSSRを採⽤
Fundsのフロントエンド概要 2019/8/21 30
Fundsのフロントエンド概要 Service app (JavaScript on Browser) Service API (Scala) Service
app (Node.js) on Server on Browser ClientとServerの双⽅で動作するIsomorphicなアプリケーション 2019/8/21 31
Fundsのフロントエンド概要 • ES6 + Flow(TypeScript移⾏したい) • React + Redux •
WebpackでPC⽤, SP⽤, SSR⽤に3種類のビルドを⽣成 • Node.js + Express での SSR(Next.js など使⽤せず) 2019/8/21 32
3種類のビルド⽣成 • 単⼀のコードベースからPC⽤とSP⽤のビルドを⽣成 • またNode.jsでの実⾏⽤にSSR⽤のビルドを別に⽣成 source code build (PC) build
(SP) build (server) webpack 2019/8/21 33
clientではPC/SPでentrypointを分離 (webpack.client.config.js) client/server⽤の設定 (webpack.config.js) 3種類のビルド⽣成: Webpackの設定(抜粋) 2019/8/21 34 const client
= require('./webpack.client.config’); const server = require('./webpack.server.config’); module.exports = [client, server]; entry: { appPc: [ './src/funds_pc.jsx’, ], appSp: [ './src/funds_sp.jsx’, ], }, …
Dynamic Serving(動的な配信) PC・SPで異なるコンテンツを表⽰する⽅式 Server Browser (PC) Browser (SP) HTML (for
SP) request request HTML (for PC) 2019/8/21 35
Dynamic Serving(動的な配信) UserAgent⽂字列を識別して、PC/SPのレンダリング内容を分離 // モバイル判定 const isMobile = (req) =>
{ const md = new MobileDetect(req.headers['user-agent']); return !!md.mobile() && !md.tablet(); }; // モバイル判定結果に応じてレンダリングするコンポーネントを変更 <StaticRouter location={location} context={context}> {isMobile(req) ? <AppSP /> : <AppPC />} </StaticRouter> 2019/8/21 36
ReactでのSEOを加味したアプローチ例 2019/8/21 37
エンジニアが注意すべきSEO上のポイントの⼀例 • レンダリング • 正しく有効なマークアップ • ステータスコードの制御 • URL正規化 •
ページの表⽰速度 • モバイルフレンドリー化 • 構造化データ (ほかにもあるよ) 2019/8/21 38
今回お話するトピック • レンダリング • 正しく有効なマークアップ • ステータスコードの制御 • URL正規化 •
ページの表⽰速度 • モバイルフレンドリー化 • 構造化データ 2019/8/21 39
今回お話するトピック • レンダリング • 正しく有効なマークアップ • ステータスコードの制御 • URL正規化 •
ページの表⽰速度 • モバイルフレンドリー化 • 構造化データ 2019/8/21 40
レンダリング • FundsではReactでSSR • SSR時のstateをクライアント側でRehydrationし CSRできるようにしている 2019/8/21 41
SSR with Rehydration FundsではReactのSSRにRehydrationでCSRを組み合わせています Browser Server state state API ②更新されたredux
stateで renderToString ①レンダリングに 必要な情報取得 ③クライアントサイドに stateを引き継ぎ ④ブラウザ上で差分更新 2019/8/21 42
SSR with Rehydration // react-redux の Providerでreactとredux stateを結合 const provider
= ( <Provider store={store}> <StaticRouter location={location} context={context}> ... </StaticRouter> </Provider> ); // サーバサイドでレンダリング const renderedContent = renderToString(provider); ... // レンダリングしたコンテンツを埋め込み <div id="app">${renderedContent}</div> ②更新されたredux stateを注⼊しrenderToString on Server 2019/8/21 43
SSR with Rehydration // state はrenderToStringで使⽤したRedux State const state =
store.getState(); const serializedState = JSON.stringify(state); // SSRでレンダリングしておきクライアントサイドで利⽤ <script type="text/javascript">var __CWP_INITIAL_STORE=${serializedState};</script> // クライアントサイドでは以下のようにロード const store = configureStore(window.__CWP_INITIAL_STORE, history); ③クライアントサイドにstateを引き継ぎ on Server on Browser 2019/8/21 44
SSR with Rehydration FundsではReactのSSRにRehydrationでCSRを組み合わせています Browser Server state state API ②更新されたredux
stateで renderToString ①レンダリングに 必要な情報取得 ③クライアントサイドに stateを引き継ぎ ④ブラウザ上で差分更新 2019/8/21 45
今回お話するトピック • レンダリング • 正しく有効なマークアップ • ステータスコードの制御 • URL正規化 •
ページの表⽰速度 • モバイルフレンドリー化 • 構造化データ 2019/8/21 46
ソフト404エラー • ステータスコード200で、エラー⾵のページを表⽰している状態 • クローラーは404ページであることを認識できない 404 HTTP上では・・・ HTTP/2 200 Content-Encoding:
gzip Accept-Ranges: bytes Cache-Control: max-age=604800 Content-Type: text/html; charset=UTF-8 … 2019/8/21 47
SPA固有の404ページに関する問題 SPAでは⼀度200で返したHTML・JavaScriptから CSRでレンダリングするため、ステータスコードを404に設定できない 404 CSR前のページを表⽰ この時点で200 ⾒た⽬が404⾵のページをレンダリング 実際はステータスコード200 2019/8/21 48
Fundsの404ページ ステータスコード404で404ページを表⽰(あたりまえですが・・・) 2019/8/21 49
Fundsの404ページ ステータスコードに対応するフィールドをredux state上に定義 SSR時にredux stateを参照しステータスコードを変更する ステータス変更⽤のredux action⽣成 ステータスコードに対応するフィールドを更新 SSR時にstateからステータスコードを変更 Fundsで404ページを表⽰する場合の流れ
2019/8/21 50
今回お話するトピック • レンダリング • 正しく有効なマークアップ • ステータスコードの制御 • URL正規化 •
ページの表⽰速度 • モバイルフレンドリー化 • 構造化データ 2019/8/21 51
重複コンテンツとURL制御 複数のURLで同じコンテンツにアクセス可能だと、 本来得られるべき適切な評価が得られない ページ ページ /cat /cat/hoge ページ /cat/fuga ミスなのか、本当に表⽰したいページが複数あるのかわからない
2019/8/21 52
重複コンテンツとURL制御 まずは正しいURL以外でアクセスできないようにするのが原則 ページ ページ /cat /cat/hoge ページ /cat/fuga 2019/8/21 53
重複コンテンツとURL制御 • react-router でURLに対応するコンポーネントを選択 • できる限りexactを指定 import { Route, Switch
} from 'react-router’; return ( <Switch> <Route exact // exact を指定することで /cat/hoge などはマッチしない path="/cat” component={CatPage} /> ... 2019/8/21 54
URL正規化 クエリパラメータの有無など、複数のURLでアクセス可能になる場合もある ページ /cat/1 ページ /cat/1?foo=1 2019/8/21 55
URL正規化 ステータスコード 301でリダイレクト ページ /cat/1 ページ /cat/1?foo=1 正しいURLの場所をHTTP Responseで明⽰ リソースが直接参照できるURLを1つに限定する(URL正規化)
HTTP/1.1 301 Location: /cat/1 2019/8/21 56
rel=canonical によるURL正規化 301リダイレクトの代わりに rel=canonical で正しいURLを指定することで評価の分散を防⽌ ページ /cat/1 ページ /cat/1?foo=1 クローラーは
/cat/1 の⽅をインデックスすべきURLと解釈し /cat/1?foo=1 はインデックスしない <link rel="canonical” href="https://example.com/cats/1"> 2019/8/21 57
react-helmetでのメタ情報設定 // Helmet (react-helmet) import Helmet from 'react-helmet’; ... return
( <Helmet title=“ファンドを探す” meta={[ { name: 'description’, content: 'Funds(ファンズ)のファンド⼀覧ページです。', }, react-helmet はメタ要素を挿⼊するためのライブラリ <Helmet>で定義すると ⾃動的に <head /> 内へ含めてくれる 2019/8/21 58
rel=canonical によるURL正規化 rel=canonicalを指定する場合も react-helmet を使⽤ // Helmet (react-helmet) import Helmet
from 'react-helmet’; ... return ( <Helmet link={[ { ref: ‘canonical’, href: ‘https://funds.jp/fund/list', }, 2019/8/21 59
react-helmet で設定可能なメタ要素の例 • title • meta description • SERPs(検索結果のページ)に表⽰される内容には影響する •
meta robots • OGP • og:image など。Facebookなどでのシェアの際に有効 • Twitter Cards • Twitterでのシェアの際の表⽰ • rel=canonical • URL正規化で使⽤ このあたりの指定は SSR or Dynamic Renderingが必要 2019/8/21 60
まとめ 公開サイトを開発するフロントエンドエンジニアなら SEOについても知っておこう 2019/8/21 61