🌱

2022 | Next.js 12 + React 18 + Mantine + TailwindCSS で開発しやすい環境を構築する

2022/08/22に公開

Hi, It's Cray! :D

こんにちは Cray です!

今回は Next.js 12React 18 を中心に、
スタイルにはトレンドの Mantine と、細かな調整がしやすい Tailwind CSS を導入します!

パッケージマネージャーは高速な pnpm を使います。
さらに ESLintPrettier を導入し、インポートを自動で整理します。
開発体験(Developer Experience)の高い環境構築を目指します✌🏻

Packages

今回導入するパッケージです😋

Dependencies

Package Version
nextjs 12.2.5
react 18.2.0
react-dom 18.2.0
@emotion/react ^11.10.0
@emotion/server ^11.10.0
@mantine/core ^5.2.0
@mantine/hooks ^5.2.0
@mantine/next ^5.2.0
@tabler/icons ^1.84.0

Dev Dependencies

Package Version
@types/node 18.7.8
@types/react 18.0.17
@types/react-dom 18.0.6
@typescript-eslint/eslint-plugin ^5.33.1
@typescript-eslint/parser ^5.33.1
autoprefixer ^10.4.8
eslint 8.22.0
eslint-config-next 12.2.5
eslint-config-prettier ^8.5.0
eslint-import-resolver-typescript ^3.4.2
eslint-plugin-import ^2.26.0
eslint-plugin-unused-imports ^2.0.0
postcss ^8.4.16
tailwindcss ^3.1.8
typescript 4.7.4

Guide

pnpm をインストール

いずれかの方法で pnpm をインストールします。
私は node、npm、yarn なども volta で管理しています。

volta intall pnpm
# or
npm install -g pnpm
# or
brew install pnpm

Next.js をセットアップする

1. Next のプロジェクトを生成

Next.js のプロジェクトを TypeScript でセットアップします
実行後、プロジェクト名を訊かれるので入力します。

(Tailwind CSS を同時にインストールするオプションもありますが、 ディレクトリ構成を変えるため、別途インストールします。)

pnpm create next-app --typescript

2. パスを修正

見通しがよくなったり eslint 導入時に指定がしやすくなるので、
生成されたファイルのパスを一部修正します。
src ディレクトリを追加し、pages styles フォルダを移動します。

3. 起動を確認する

セットアップが完了したら、開発サーバーを起動し、アドレスからアプリを確認できます。

cd your-project
pnpm dev

http://localhost:3000

Prettier と ESLint をセットアップする

1. prettierrc

.prettierrc を作成します。
行の文字数は120、セミコロンは省略、タブサイズは2、配列やオブジェクトの末尾のカンマをつける設定にしています。

touch .prettierrc
.prettierrc
{
  "printWidth": 120,
  "semi": false,
  "tabWidth": 2,
  "trailingComma": "all"
}

2. Prettier のパッケージをインストール

同時に Tailwind CSS の整形用のパッケージもインストールしておきます。

pnpm add -D prettier prettier-plugin-tailwindcss

3. パスエイリアスを設定

絶対パスでインポートできるように、tsconfig.jsonでパスエイリアスを設定します。

tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
+   "baseUrl": "./",
+   "paths": {
+     "@/*": ["./src/*"]
+   }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

4. 自動整形用のコマンドを修正

package.jsonのスクリプトを追加、修正しておきます。

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
-   "lint": "next lint"
+   "lint": "next lint --dir src",
+   "lint:fix": "next lint --dir src --fix"
  },
}

5. eslintrc

eslintrc の設定ファイルは json か js を選べますが、今回は管理がしやすい js にします。

.eslintrc.json を削除し、かわりに .eslintrc.js を作成します。

touch .eslintrc.js

ESLint で指定できるインポートの記述順序やルールを指定しています。
外部パッケージ、UI 系の外部パッケージ、コンポーネントの順に、 A to Z で並ぶようにしています。
必要に応じて変更してください。

.eslintrc.js
module.exports = {
  root: true,
  parser: "@typescript-eslint/parser",
  plugins: ["@typescript-eslint", "@typescript-eslint", "import", "unused-imports"],
  extends: [
    "eslint:recommended",
    "next/core-web-vitals",
    "plugin:@typescript-eslint/recommended",
    "plugin:import/recommended",
    "plugin:import/typescript",
    "plugin:import/warnings",
    "prettier",
  ],
  rules: {
    "@typescript-eslint/no-explicit-any": "error",
    "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
    "@typescript-eslint/no-inferrable-types": "off",
    "@typescript-eslint/no-use-before-define": "off",
    "prefer-const": "warn",
    "import/order": [
      "warn",
      {
        "newlines-between": "always",
        alphabetize: { order: "asc" },
        groups: ["builtin", "external", "parent", "sibling", "index", "object", "type"],
        pathGroupsExcludedImportTypes: ["builtin", "object"],
        pathGroups: [
          { pattern: "{@mantine/**,@emotion/**,@tabler/**,@heroicons/**}", group: "parent", position: "before" },
        ],
      },
    ],
    "import/newline-after-import": "warn",
    "unused-imports/no-unused-imports": "warn",
  },
  settings: {
    "import/resolver": {
      typescript: {
        project: "./tsconfig.json",
      },
    },
  },
}

4. VSCode の設定

VSCode で保存したときに、自動で prettier と eslint に従った整形が走るように、設定します。
今回はワークスペースに設定していますが、必要に応じてユーザーに設定してください。

mkdir .vscode && touch .vscode/settings.json
.vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "eslint.alwaysShowStatus": true
}

5. パッケージをインストール

pnpm add -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-unused-imports

6. VSCode プラグインをインストール

以下のプラグインをインストールしておきます。

7. VSCode を再起動し、自動整形を確かめる

インストールが終わったら、VSCode を再起動します。
適当な tsx を保存したときに、自動整形されるようになっていれば OK です。
pnpm lint:fix でまとめて整形することもできます。

これでスタイルを気にせず、快適にコードを書けるようになりました✌🏻


Tailwind CSS をセットアップする

1. Tailwind CSS をインストール

Tailwind CSS を PostCSS プラグインとしてインストールすると webpack、Rollup、Vite、Parcel などのビルドツールとシームレスに統合できます。

init すると tailwind.config.js postcss.config.js が生成されます。

pnpm add -D tailwindcss postcss autoprefixer
pnpm dlx tailwindcss init -p

2. Tailwind CSS のパスを構成する

Tailwind CSS を使用するファイルのパスを content で指定します。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
+ content: ["./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
+ corePlugins: {
+  preflight: false,
+ },
}

3. CSS に Tailwind ディレクティブを追加する

styles/global.css の中身を以下に置き換えます。
おなじディレクトリにある Home.module.css は使用しないので削除してください。

styles/global.css
@tailwind base;
@tailwind components;
@tailwind utilities;

Mantine をセットアップする

1. Mantine 関連のパッケージをインストール

必要なパッケージをインストールします。

pnpm add @mantine/core @mantine/hooks @mantine/next @emotion/server @emotion/react @tabler/icons

2. Mantine の初期セットアップ

_document.tsx _app.tsx ファイルを以下に置き換えてください。

src/pages/_document.tsx
import Document, { Head, Html, Main, NextScript } from "next/document"

import { createGetInitialProps } from "@mantine/next"

const getInitialProps = createGetInitialProps()

export default class _Document extends Document {
  static getInitialProps = getInitialProps

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}
src/pages/_app.tsx
import "@/styles/globals.css"
import { NextPage } from "next"
import { AppProps } from "next/app"
import Head from "next/head"
import { useState } from "react"

import { ColorScheme, ColorSchemeProvider, MantineProvider } from "@mantine/core"

const App: NextPage<AppProps> = ({ Component, pageProps }) => {
  const [colorScheme, setColorScheme] = useState<ColorScheme>("dark")

  const toggleColorScheme = (value?: ColorScheme) =>
    setColorScheme(value || (colorScheme === "dark" ? "light" : "dark"))

  return (
    <>
      <Head>
        <title>Next</title>
        <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
      </Head>
      <MantineProvider
        withGlobalStyles
        withNormalizeCSS
        theme={{
          colorScheme,
        }}
      >
        <ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
          <Component {...pageProps} />
        </ColorSchemeProvider>
      </MantineProvider>
    </>
  )
}

export default App

Mantine + Tailwind CSS を使ったコンポーネントを設置する

Mantine + Tailwind CSS を使ったコンポーネントを設置して、動作を確かめます。

mkdir components && touch components/ColorSchemeToggle.tsx
src/components/ColorSchemeToggle.tsx
import { FC } from "react"

import { useMantineColorScheme, ActionIcon, Group } from "@mantine/core"
import { IconSun, IconMoonStars } from "@tabler/icons"

const ColorSchemeToggle: FC = () => {
  const { colorScheme, toggleColorScheme } = useMantineColorScheme()

  return (
    <Group position="center" my="xl">
      <ActionIcon
        onClick={() => toggleColorScheme()}
        size="lg"
        sx={(theme) => ({
          backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0],
          color: theme.colorScheme === "dark" ? theme.colors.yellow[4] : theme.colors.blue[6],
        })}
      >
        {colorScheme === "dark" ? <IconSun size={18} /> : <IconMoonStars size={18} />}
      </ActionIcon>
    </Group>
  )
}

export default ColorSchemeToggle

index.tsx を以下のように書き換えます。

src/pages/index.tsx
import { NextPage } from "next"

import { Stack } from "@mantine/core"

import ColorSchemeToggle from "@/components/ColorSchemeToggle"

const Home: NextPage = () => {
  return (
    <div>
      <Stack align="center" justify="center" spacing="lg" className="min-h-screen">
        <h1 className="font-extrabold text-gray-600">Welcome to Mantine & Tailwind CSS!</h1>
        <ColorSchemeToggle />
      </Stack>
    </div>
  )
}

export default Home

サンプルでは、Mantine のテーマのカラースキーマを変更できるボタンを設定しています。
ボタンをトグルすると Dark Mode <-> Light Mode の切り替えができれば、 Mantine が機能しています。Welcome to.. の文字が太字で、グレーになっていれば Tailwind CSS が機能しています。

おつかれさまでした🍀

Tail 🐈

今回は、Nextjs を起点に Mantine と Tailwind CSS を組み合わせて、開発しやすい環境を構築してみました。
Mantine と Tailwind CSS はとても自由度が高く使いやすい組み合わせだと思うので、
ぜひ、それぞれのドキュメントをみて、色々なコンポーネントを試してみてください!

最後まで見ていただいてありがとうございました!

Bye! 👋

Refs

https://nextjs.org/docs
https://mantine.dev/pages/getting-started/
https://tailwindcss.com/docs/installation/using-postcss
https://pnpm.io/ja/feature-comparison

Discussion