[Gatsby]SSR 部分で window オブジェクトを参照するとビルドできない問題(鬼滅風)


SSR 部分で window を参照しているとビルドに失敗する

Gatsby はビルド時にページを生成するのですが、ページ内に window.innerwidthとか参照しているとエラーで落ちます。

"window" is not available during server side rendering.

See our docs page for more info on this error: https://gatsby.dev/debug-html



  ReferenceError: window is not defined

node でページ生成してるのだから window オブジェクトがないことは当然だ。

window の参照なんかでビルド失敗してんじゃねーよ!!あああ💢

怒っても 公式みても github みても解決しないので、この超めんどくさい問題の対応方法を考えてみました。

一回 state にいれるようにする

class Index extends Component {
  constructor(props) {
    super(props)
    this.state = {
      width: 0, // or your default width here
    }
  }
  componentDidMount() {
    this.handleWindowSizeChange() // Set width
    window.addEventListener('resize', this.handleWindowSizeChange)
  }

  componentWillMount() {
    // Don’t use this as the API is deprecated
  }

  // make sure to remove the listener
  // when the component is not mounted anymore
  componentWillUnmount() {
    window.removeEventListener('resize', this.handleWindowSizeChange)
  }

  handleWindowSizeChange = () => {
    this.setState({ width: window.innerWidth })
  }

  // rest of code
}

issue で議論されてました。
state にいれるの手間だし、おそくなるのでないなーって感じです。

SSR のときはそのコンポーネントをマウントしない。

MUI に NoSSR が用意されており、こちらを使うと、
SSR のときはそのコンポーネントをマウントしないとすることができます。

MUI 以外にも似たような仕組みがあると思います。

import { NoSsr, List, ListItem, Tooltip } from "@material-ui/core";

略
         <NoSsr>
          <Tooltip
            id="instagram-twitter"
            title="Follow us on twitter"
            placement={window && window.innerWidth > 959 ? "top" : "left"}
            classes={{ tooltip: classes.tooltip }}
          >
            <Button
              href="https://twitter.com/CreativeTim?ref=creativetim"
              target="_blank"
              color="transparent"
              className={classes.navLink}
            >
              <i className={classes.socialIcons + " fab fa-twitter"} />
            </Button>
          </Tooltip>
         </NoSsr>

これは window 以外の問題も解決できるのでこれはこれでありです。

そもそもコード書き換えない、Polyfill 的なもの

window の解決ぐらいもっと楽にできないの?!しっかりしてよ〜たんじろおお〜!

ありました。もっとベターなアプローチが。

こちらをimportすると window の参照で落ちないようようになります。
addEventListener も動作します。

import { window } from 'ssr-window';


      <ListItem className={classes.listItem}>
        <Tooltip
          id="instagram-tooltip"
          title="Follow us on instagram"
          placement={window && window.innerWidth > 959 ? "top" : "left"}
          classes={{ tooltip: classes.tooltip }}
        >
          <Button
            color="transparent"
            href="https://www.instagram.com/CreativeTimOfficial?ref=creativetim"
            target="_blank"
            className={classes.navLink}
          >
            <i className={classes.socialIcons + " fab fa-instagram"} />
          </Button>
        </Tooltip>

とかかいても落ちません。

最近ぜんいつのキャラがおもしすぎて

SSRのフレームワークの中でやってくれないの?!だめだよ!もっと楽させてよ!

とか思っちゃいました。