問題
Gatsbyで作ったサイトにアクセスする際、HTMLは読み込まれるもののCSSが適応されてない状態で表示され、1秒ほど遅れてCSSが適応される現象が起きました。
大きな問題ではないものの、綺麗ではないし、そもそもなぜこんな現象が起きるのでしょうか。
少し調べてみるとGatsbyの公式repositoryでもissueとして何件か上がっていたり、長い間解決できてない人もチラホラみかけます。
Gatsby: v3.2.1
Styled components: v5.3
考えられる原因と解決策
考えられる原因は2つありますが、どちらも根本は同じで、CSSがSSR(server side rendering)されていないことが原因です。
1. 適切なプラグインをインストールしていない
単純なパターンはこれです。
Styled componentsを使う場合、以下の2つのパッケージをインストールして使いますが、
- styled-components
- babel-plugin-styled-components
GatsbyでStyled componentsを使う場合はgatsby-plugin-styled-componentもインストールし、gatsby-config.jsで設定する必要があります。
npm install --save gatsby-plugin-styled-component
or
yarn add gatsby-plugin-styled-component
// gatsby-config.js
module.exports = {
plugins: [
`gatsby-plugin-styled-components`,
]
}
このプラグインはGatsbyがSSRする際にStyled componentsに対応するためのものです。
2. SSRする際にCSSが含まれていない
CSSリセットやグローバルCSSをgatsby-browser.jsで設定している人はこれが原因かもしれません。
// gatsby-browser.js
import { CSSReset } from ''
import { GlobalCSS } from ''
export const wrapPageElement = ({ element }) => {
return (
<>
<CSSReset />
<GlobalCSS />
{element}
</>
)
}
このように設定すること自体は何も問題ないのですが、gatsby browser APIはブラウザでしか実行されません。
各ページはGatsbyによりSSRされ、事前に静的ファイルが生成されます。その際にGatsbyがCSSリセットファイルやグローバルCSSファイルの存在を知らないため、それらのCSSが組み込まれていないページが生成されるわけです。
その後ページが読み込まれる時になってやっとgatsby browser APIが実行され、CSSリセットファイルなどが読み込まれるので上記のgifのような現象になります。
解決方法は簡単で、gatsby server rendering APIを設定するためのgatsby-ssr.jsに同様のことを記述するだけです。
// gatsby-ssr.js
import { CSSReset } from ''
import { GlobalCSS } from ''
export const wrapPageElement = ({ element }) => {
return (
<>
<CSSReset />
<GlobalCSS />
{element}
</>
)
}
これでGatsbyがSSRする際にCSSリセットファイルなども読み込んだ上で静的ファイルが生成されるので、CSSの奇妙な読み込みラグは生まれません。