🐥

Next.js + TypeScript + Emotionの開発序盤でつまづいたところ3点

2022/01/30に公開

概要

個人で、タイトルの環境でアプリをつくる際に、いくつかつまづいた箇所があったので、備忘録として残します。

環境

  • next: 12.0.9
  • react: 17.0.2
  • typescript": 4.5.5
  • emotion: 11.0.0
  • @emotion/babel-plugin": 11.7.2
  • @emotion/react": 11.7.1
  • @emotion/styled: 11.6.0

1. 環境変数が読み込めない

dotenvは入れていたのですが、.env.developmentに設定した環境変数を読み込むことができず、はて?となりました。

これはそれぞれの環境変数のあたまにNEXT_PUBLIC_をつけていなかったことが原因でした。Next.jsでは、クライアント側で環境変数を使いたい場合はこの接頭語をつけてあげる必要があるらしく、その対応により無事読み込まれるようになりました。

.env.development
NEXT_PUBLIC_FIREBASE_API_KEY="hoge"
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN="fuga"
NEXT_PUBLIC_FIREBASE_PROJECT_ID="piyo"
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET="hogehoge"
NEXT_PUBLIC_FIREBASE_MESSAGE_SENDER_ID="fugafuga"
NEXT_PUBLIC_FIREBASE_APP_ID="piyopiyo"

こんな感じで。

しか私はFirebaseのinitializeの設定をするにあたり、以下のように環境変数を使用しており、このコードに対して、apiKeyが環境変数からちゃんと渡されていません(大略)というエラーが出ていたわけですが、このコードって特にコンポーネントとか書いていないけどクライアント側としてみなされるの...?と少し疑問も持ちました。

firebase.ts
import firebase from "firebase/compat/app"
import "firebase/compat/auth"
import "firebase/compat/firestore"

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGE_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
}

firebase.initializeApp(firebaseConfig)

export const auth = firebase.auth()
export default firebase

調べきれていないので断言はできませんが、おそらく、環境変数を使用した関数をクライアント側でimportする場合は、結局「クライアント側で環境変数を使用している」と認識されるのかなと思います。上記でexportしたfirebaseをimportしていたページでは、のきなみエラーが出ていたからです。

少し雑な話にはなりますが、とりあえずNext.jsを使ううえでは環境変数にはNEXT_PUBLIC_をつけておくとまちがいないのかなと思います。

2. Emotionが使えない

普通にインストールしただけだと、CSS in JSライブラリであるEmotionを使うとエラーが出てきちゃいました。
それに対して、以下の記事を参考にさせていただき、対応しました。

https://zenn.dev/iwakin999/articles/7a5e11e62ba668
https://qiita.com/xrxoxcxox/items/a5072f3f761e55a272f9

やったことは2つです。

1. babelの設定をする

yarn add @emotion/babel-pluginを実施し、その後トップディレクトリに.babelrcというファイルを作成して以下の設定を書いてあげればOKです。

.babelrc
{
  "presets": [
    [
      "next/babel",
      {
        "preset-react": {
          "runtime": "automatic",
          "importSource": "@emotion/react"
        }
      }
    ]
  ],
  "plugins": ["@emotion/babel-plugin"]
}

2. Emotionの型定義ファイルを読み込む

1をしてあげただけでも正常にCSSがページに反映されるようにはなるのですが、エディタからは引き続き怒られてしまいます。そのエラーはどうやらEmotionのtypesがうまく機能していないためのようなので、型定義ファイルを読み込ませます。

具体的には、トップディレクトリにadditional.d.tsというファイルをつくり、そこに以下を書いてあげるとOKです。

additional.d.ts
/// <reference types="@emotion/react/types/css-prop" />

ファイル名はなんでもいいのですが、Next.jsにはもともとnext-env.d.tsという型定義ファイルがあり、そこに追加した形なのでadditionalです。
ちなみにnext-env.d.tsに直接このディレクティブを書くと、(私の環境では)ビルド時に勝手に消えちゃいます。

3. windowオブジェクトを使っているページをSSRできない

Next.jsにおいてサーバーサイドレンダリングをしているページでは、ブラウザでは使用可能なwindowオブジェクトを使用することができません。使っちゃうとWindow is not definedと出ます。

私の場合は、直接windowオブジェクトを何処かで使用していたわけではないのですが、importしていたライブラリ内で使われていたようです。

要するに、サーバーサイドではなくクライアントサイドでレンダリングしてあげればいいので、以下の設定を加えました。

import dynamic from "next/dynamic"

// import元はレンダリング対象となる実質のコンポーネント
const DynamicComponent = dynamic(() => import("../src/components/editor"), {
  ssr: false,
})

const Article = () => {
  return <DynamicComponent />
}

export default Article

こうすることでSSR(サーバーサイドレンダリング)はオフになり、無事ページを表示することができました。

所感

こうしたところでつまづいたものの、Gatsby.jsなどとちがってNext.jsは、自分でルーティングの設定とかをしなくていいところに感動しました。

参考記事

https://fwywd.com/tech/next-env
https://natural-tearoom.com/window-not-defined/

Discussion

ログインするとコメントできます