Blitzにtwin.macroを導入する

Blitzにtwin.macroを導入する

2021年08月18日

BlitzTailwind CSS
Blitz+twin.macro

はじめに

今回はBlitzにtwin.macroを導入する方法をメモしておきます。

twin.macroの良さを知ってからいつもとりあえずtwin.macroを入れられないかを考えています。

デザインはできないので他はあまり知らないですけど、twin.macroとはprogrammaticで仲良くなれそうだと思っています。

結論からいうとNext.jsへの導入方法とほとんど変わりません。

今回もemotionを使う方向で進めていきます。

環境

  • Node 15.11.0
  • yarn 1.22.10
  • Blitz 0.39.0

プロジェクトの作成

$ blitz new blitz-twin
$ cd blitz-twin

Pick a form library (you can switch to something else later if you want) とフォームのライブラリを聞かれますがとりあえずReact Final Formを選択しておきます。

依存関係のインストール

公式に他のライブラリやフレームワークでの導入方法がありますが、 あまり大差はないかなと思っています。お決まりですかね。

$ yarn add @emotion/css @emotion/react @emotion/server @emotion/styled @emotion/client

$ yarn add -D @emotion/babel-plugin babel-plugin-macros twin.macro tailwindcss 

twin.macroの設定をpackage.jsonの追加する。

twin.macroはbabelマクロを使用しますのでその設定を記述します。

こちらはお好みですがbabel-plugin-macros.config.jsに書く方法もあります。

記述量が少ないのでpackage.jsonに書いてしまっていいのかなと思っています。

package.json

{
    ...
+    "babelMacros": {
+        "twin": {
+            "preset": "emotion"
+        }
+    }
}

babel.config.jsの修正

こちらは悩んだところですが、以下の様な記述でOKでした。

babel.config.js

module.exports = {
-  presets: ["blitz/babel"],
-  plugins: [],
+  presets: [
+    [
+      "blitz/babel",
+      {
+        "preset-react": {
+          runtime: "automatic",
+          importSource: "@emotion/react"
+        }
+      }
+    ]
+  ],
+ plugins: ["@emotion/babel-plugin", "babel-plugin-macros"],
}

グローバルのスタイルの追加

ブラウザ間の表示を揃えるためにtwin.macroが提供してくれているグローバルのスタイルを追加します。

リセットCSSとかサニタイズCSSとか呼ばれているものですかね。

Next.jsと同様に_app.tsxに記述することでグローバルにスタイルを適応することができます。

src/pages/_app.tsx

import {
  AppProps,
  ErrorBoundary,
  ErrorComponent,
  AuthenticationError,
  AuthorizationError,
  ErrorFallbackProps,
  useQueryErrorResetBoundary,
} from "blitz"
+ import { GlobalStyles } from "twin.macro"
import LoginForm from "app/auth/components/LoginForm"

export default function App({ Component, pageProps }: AppProps) {
  const getLayout = Component.getLayout || ((page) => page)

  return (
    <ErrorBoundary
      FallbackComponent={RootErrorFallback}
      onReset={useQueryErrorResetBoundary().reset}
    >
 +      <GlobalStyles />
      {getLayout(<Component {...pageProps} />)}
    </ErrorBoundary>
  )
}
...

twin.macro用の型定義ファイルを追加する。

twin.macroはjsx,tsx内でtw,styled,cssといったattributeを使用しますのでそちらの型定義を追加します。

直下にtypes.tsが配置されていたので今回はこちらも直下に配置します。

twin.d.ts

import 'twin.macro'
import { css as cssImport } from '@emotion/react'
import { CSSInterpolation } from '@emotion/serialize'
import styledImport from '@emotion/styled'

declare module 'twin.macro' {
  // The styled and css imports
  const styled: typeof styledImport
  const css: typeof cssImport
}

declare module 'react' {
  // The css prop
  interface HTMLAttributes<T> extends DOMAttributes<T> {
    css?: CSSInterpolation
  }
  // The inline svg css prop
  interface SVGProps<T> extends SVGProps<SVGSVGElement> {
    css?: CSSInterpolation
  }
}

ちらつきの防止

上記までの設定でtwin.macroが使えるようになっていますが、初期レンダリング時にちらつく場合は以下のように記述することによって、 重要なスタイルを抜き出して最初に読み込むようにしてくれます。

src/pages/_document.tsx

- import {Document, Html, DocumentHead, Main, BlitzScript /*DocumentContext*/} from 'blitz'
+ import {Document, Html, DocumentHead, Main, BlitzScript, DocumentContext} from 'blitz'
+ import { extractCritical } from "@emotion/server"

class MyDocument extends Document {
-  // Only uncomment if you need to customize this behaviour
-  // static async getInitialProps(ctx: DocumentContext) {
-  //   const initialProps = await Document.getInitialProps(ctx)
-  //   return {...initialProps}
-  // }
+  static async getInitialProps(ctx: DocumentContext) {
+    const initialProps = await Document.getInitialProps(ctx)
+    const page = await ctx.renderPage()
+    const styles = extractCritical(page.html)
+    return {
+      ...initialProps,
+      ...page,
+      styles: (
+        <>
+          {initialProps.styles}
+          <style
+            data-emotion-css={styles.ids.join(' ')}
+            dangerouslySetInnerHTML={{ __html: styles.css }}
+          />
+        </>
+      )
+    }
+  }
...
}

export default MyDocument

おわりに

Blitzもtwin.macroもとても良いなと思っているので合わせられるのが嬉しいです。 twin.macroの導入方法ですが一部不明な部分もありますのでそちらも調べたいなと思っています。

参考



ホーム記事一覧プライバシーポリシーお問い合わせ
© 2024 luku.work