Next.js + TS + Tailwindで入門してみる

はじめに

最近腹筋ローラーを買って速攻で筋肉痛になりました。The walking deadもやっとシーズン10まで見終わりそうです。

なぜNext.jsを触るのか?

在籍している会社にてNext.jsを使用する流れになり、入門はしたけども忘れてしまったから再度入門して肩慣らしでもしておこう!という気持ちになり、今回触ることにしました。 TSにしているのは、会社ではTSで実装しているため多少いじるにしてもTSの方がいいでしょう!という理由です。

Next.js

nextjs.org

Nuxt.jsより以前から開発が行われているReactのフレームワークです。

公式に物凄い数のexampleが用意されています。

github.com

ゴール

今回は、Next.jsを開発しているVercel社が用意しているサンプルにTailwindを適用してみるの巻です。

参照

kakakakakku.hatenablog.com

今回は、参照記事を元に公式が用意しているexampleのwith-typescriptを使用してみたいとおもいます。

準備

  • nodeのversionは、v14.15.1を使用します。
mkdir next-ts-sample
cd next-ts-sample
npx create-next-app --example with-typescript .
  • installが終わったのでyarn devを実行してみる。下記画像のような表示がされました。

f:id:hironekosun:20201209140713p:plain

  • Next.jsのアプリ全ページにTailwindを使えるようにするためにpages以下に下記fileを作成します。
    • ComponentなどをLayoutなどでラップしてあげるといいです
import './styles/tailwind.css'

function App({ Component, pageProps }) {
    return <Component {...pageProps} />
}

export default App

Tailwind入れる

yarn add -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init --full
touch pages/styles/tailwind.css
  • 作成したtailwind.cssに以下を追加します
@tailwind base;
@tailwind components;
@tailwind utilities;

tailwind.config.jsに追記

  • Purge オプションを使ってビルドサイズの縮小するこができます。
const colors = require('tailwindcss/colors')

module.exports = {
  purge: ['./components/**/*.jsx', './pages/**/*.jsx']

// 省略

postcss.config.jsの作成

module.exports = {
  plugins: ['tailwindcss', 'autoprefixer'],
}

ブラウザで一度確認してみる

  • さきほどまでと様子が違うのでtailwindがあたってそうですね。

f:id:hironekosun:20201209154509p:plain

Tailwindを感じてみよう!

  • pages以下にweather.tsxを作成し以下を記述する
const Weather = () => (
    <div className="min-h-screen flex items-center justify-center">
        <div className="border-solid border-2 flex flex-col bg-white rounded p-4 w-full max-w-xs">
            <div className="font-bold text-xl">Sydney</div>
            <div className="text-sm text-gray-500">Thursday 10 May 2020</div>
            <div className="mt-6 text-6xl self-center inline-flex items-center justify-center rounded-lg text-indigo-400 h-24 w-24">
                <svg className="w-32 h-32" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z"></path></svg>
            </div>
            <div className="flex flex-row items-center justify-center mt-6">
                <div className="font-medium text-6xl">24°</div>
                <div className="flex flex-col items-center ml-6">
                    <div>Cloudy</div>
                    <div className="mt-1">
                        <span className="text-sm"><i className="far fa-long-arrow-up"></i></span>
                        <span className="text-sm font-light text-gray-500">28°C</span>
                    </div>
                    <div>
                        <span className="text-sm"><i className="far fa-long-arrow-down"></i></span>
                        <span className="text-sm font-light text-gray-500">20°C</span>
                    </div>
                </div>
            </div>
            <div className="flex flex-row justify-between mt-6">
                <div className="flex flex-col items-center">
                    <div className="font-medium text-sm">Wind</div>
                    <div className="text-sm text-gray-500">9k/h</div>
                </div>
                <div className="flex flex-col items-center">
                    <div className="font-medium text-sm">Humidity</div>
                    <div className="text-sm text-gray-500">68%</div>
                </div>
                <div className="flex flex-col items-center">
                    <div className="font-medium text-sm">Visibility</div>
                    <div className="text-sm text-gray-500">10km</div>
                </div>
            </div>
        </div>
    </div>
)

export default Weather
  • localhost:3000/weatherにアクセスする f:id:hironekosun:20201209161131p:plain

  • pages以下にcard.tsxを作成し以下を記述する

const Card = () => (
    <section className="flex flex-row flex-wrap mx-auto">
        <div
            className="transition-all duration-150 flex w-full px-4 py-6 md:w-1/2 lg:w-1/3"
        >
            <div
                className="flex flex-col items-stretch min-h-full pb-4 mb-6 transition-all duration-150 bg-white rounded-lg shadow-lg hover:shadow-2xl"
            >
                <div className="md:flex-shrink-0">
                    <img
                        src="https://www.unfe.org/wp-content/uploads/2019/04/SM-placeholder-1024x512.png"
                        alt="Blog Cover"
                        className="object-fill w-full rounded-lg rounded-b-none md:h-56"
                    />
                </div>
                <div className="flex items-center justify-between px-4 py-2 overflow-hidden">
                    <span className="text-xs font-medium text-blue-600 uppercase">
                        Web Programming
                    </span>
                    <div className="flex flex-row items-center">
                        <div
                            className="text-xs font-medium text-gray-500 flex flex-row items-center mr-2"
                        >
                            <svg
                                className="w-4 h-4 mr-1"
                                fill="none"
                                stroke="currentColor"
                                viewBox="0 0 24 24"
                                xmlns="http://www.w3.org/2000/svg"
                            >
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    stroke-width="2"
                                    d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
                                ></path>
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    stroke-width="2"
                                    d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
                                ></path>
                            </svg>
                            <span>1.5k</span>
                        </div>

                        <div
                            className="text-xs font-medium text-gray-500 flex flex-row items-center mr-2"
                        >
                            <svg
                                className="w-4 h-4 mr-1"
                                fill="none"
                                stroke="currentColor"
                                viewBox="0 0 24 24"
                                xmlns="http://www.w3.org/2000/svg"
                            >
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    stroke-width="2"
                                    d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"
                                ></path>
                            </svg>
                            <span>25</span>
                        </div>

                        <div
                            className="text-xs font-medium text-gray-500 flex flex-row items-center"
                        >
                            <svg
                                className="w-4 h-4 mr-1"
                                fill="none"
                                stroke="currentColor"
                                viewBox="0 0 24 24"
                                xmlns="http://www.w3.org/2000/svg"
                            >
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    stroke-width="2"
                                    d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5"
                                ></path>
                            </svg>
                            <span>7</span>
                        </div>
                    </div>
                </div>
                <hr className="border-gray-300" />
                <div className="flex flex-wrap items-center flex-1 px-4 py-1 text-center mx-auto">
                    <a href="#" className="hover:underline">
                        <h2 className="text-2xl font-bold tracking-normal text-gray-800">
                            Ho to Yawn in 7 Days
                        </h2>
                    </a>
                </div>
                <hr className="border-gray-300" />
                <p
                    className="flex flex-row flex-wrap w-full px-4 py-2 overflow-hidden text-sm text-justify text-gray-700"
                >
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Alias, magni
                    fugiat, odit incidunt necessitatibus aut nesciunt exercitationem aliquam
                    id voluptatibus quisquam maiores officia sit amet accusantium aliquid
                    quo obcaecati quasi.
                </p>
                <hr className="border-gray-300" />
                <section className="px-4 py-2 mt-2">
                    <div className="flex items-center justify-between">
                        <div className="flex items-center flex-1">
                            <img
                                className="object-cover h-10 rounded-full"
                                src="https://thumbs.dreamstime.com/b/default-avatar-photo-placeholder-profile-icon-eps-file-easy-to-edit-default-avatar-photo-placeholder-profile-icon-124557887.jpg"
                                alt="Avatar"
                            />
                            <div className="flex flex-col mx-2">
                                <a href="" className="font-semibold text-gray-700 hover:underline">
                                    Fajrian Aidil Pratama
                                </a>
                                <span className="mx-1 text-xs text-gray-600">28 Sep 2020</span>
                            </div>
                        </div>
                        <p className="mt-1 text-xs text-gray-600">9 minutes read</p>
                    </div>
                </section>
            </div>
        </div>
    </section>
)

export default Card
  • localhost:3000/cardにアクセスする f:id:hironekosun:20201209161203p:plain

感想

今回のゴールがあくまでTailwindの適用なのでTSである必要なかったな

フロントのキャッチアップは、目に見えてわかるから楽しい反面、エラーが発生したりすると何を言っているんだって気持ちになるんで億劫になりがちだけど

今後も入門程度でもいいからいろいろ触って経験値だけは積んでいきたいとおもった。

あとVSCodeのフォーマッターがうまく動かず。。。