【Next.jsとLaravelのJamstackなWebサービス】Part1:環境構築

環境

  • windows10
  • DockerDesktop for Win 3.5.x
  • Laravel 8.x
  • PHP 8.x
  • node v16.13.1
  • npm 8.1.2
  • Next.js 12.0.7
  • React 17.0.1
  • VsCode
  • gitbash 2.32.0.1

ゴール

  • Laravel側で簡単なAPIを作成し、Nextjs側からデータフェッチできること
  • Next.jsでhtmlをプレレンダリングしてブラウザに表示できること

構成

前提

  • Jamstack
    ・一般的なwebアプリやSPAとは異なり、サーバー側でビルドされた静的なHTMLを取得して、
    ブラウザで表示するだけの構成
    ・動的なデータはサーバーでのビルド時にサーバー側でAPIやDBからデータを取得して
    htmlに組み込む
    ・SEO評価が高いという観点から、Jamstackはブログやコーポレートサイトの作成に向いている
    ・データが更新されたタイミングで都度ビルドデプロイを行うことで最新の状態を維持可能
  • 今回使用するソースコードのリポジトリはこちら
    GitHub - masayan1126/next-laravel-docker
    Contribute to masayan1126/next-laravel-docker development by creating an account on GitHub.

設定手順

開発環境の構築

Docker基盤

ソースコードをクローン

git clone https://github.com/masayan1126/next-laravel-docker.git

カレントをjumstack-sampleに変更

cd next-laravel-docker

各サービスのportを指定

.env.exampleをコピーして.envを作成し、各サービスのポートを指定してください。ご自身のマシンで空いているポートであれば何番でもOKです。

FRONTEND_PORT=
BACKEND_PORT=
DB_PORT=
PHPMYADMIN_PORT=

イメージビルド

docker-compose build

コンテナ起動

docker-compose up -d

フロントエンドの構築

frontendコンテナに入る

docker-compose exec frontend sh

nextjsアプリの作成

npm create next-app

Need to install the following packages:
create-next-app
Ok to proceed? (y) y
✔ What is your project named? … next-web
Creating a new Next.js app in /var/www/next-web.

カレントをnex-webに

cd next-web

ビルドして、開発用サーバーを起動する

npm run dev

wait - compiling / (client and server)...
event - compiled client and server successfully in 1338 ms (189 modules)

ブラウザでhttp://localhost:8020/(frontendの起動port)を表示。ウェルカム画面が表示されていれば、OK

バックエンドの構築

開発用サーバーの起動

backendコンテナに入る

docker-compose exec backend bash

laravelの新規プロジェクト作成

composer create-project laravel/laravel laravel-api

カレントをlaravel-apiに

cd laravel-api

開発用サーバー起動

–hostオプションで、コンテナ外から開発サーバーにアクセスできるようにする必要があるので注意(デフォルトは開発サーバーを起動しているホスト(今回の場合はDockerコンテナ)からしかアクセスを受け付けない)

php artisan serve --host=0.0.0.0

ブラウザでhttp://localhost:9020/(backendの起動port)を表示。ウェルカム画面が表示されていれば、OK

API構築

環境変数としてfrontendのurl等を指定する

api/laravel-api/.env

DB_CONNECTION=mysql
DB_HOST=database
DB_PORT=3306
DB_DATABASE=db_next_laravel
DB_USERNAME=root
DB_PASSWORD=root

FRONTEND_URL=http://localhost:8020

cors.phpに追記

api/laravel-api/config/cors.php

<?php

return[
  'paths'=>['api/*', 'sanctum/csrf-cookie'],
  'allowed_methods'=>['*'],
  'allowed_origins'=>[env('FRONTEND_URL', 'http://localhost')], // 先ほどの環境変数
  'allowed_origins_patterns'=>[],
  ..割愛
  'supports_credentials'=>true, // falseをtrueに変更
];

api/booksを叩くと、本の配列が返ってくる簡易API作成
api/laravel-api/routes/api.php
Route::get("/books", function () {
    return ["book1", "book2", "book3"];
});
ここまでで、環境構築はいったん完了です

動作確認

APIからデータフェッチング

axiosでデータ取得

frontendコンテナ内で実行

npm install axios
frontend/next-web/libs/ にaxios.jsを作成
import Axios from "axios";

const axios = Axios.create({
  baseURL: "http://localhost:9020",
  headers: {
    "X-Requested-With": "XMLHttpRequest",
  },
  withCredentials: true,
});


export default axios;
frontend/next-web/pages/index.js
...割愛
import axios from "../libs/axios";
import React, { useEffect } from 'react';

export default function Home() {
  useEffect(() => {
    axios.get("/api/books").then((res) => {
    const data = res.data;
    console.log(data);
   });
  }, []);
  ...割愛
}
APIから取得したデータがログに出力されていればOK

プレレンダリングする

基本

  • プリレンダリングとは、簡単にいうと事前にサーバー側でHTMLを生成すること
  • サーバー側でhtmlが生成されているかについては、ブラウザ側のjsを無効にして確認するとよい
  • 無効にした状態で、サーバー側で生成されたhtmlを画面上に描画できることがこの記事のゴール
  • ローカルでプリレンダリングを確認するには、以下の手順で行うとよい
    npm run buildしてhtml,js,cssを出力し、npm run startで実行する(buildの結果物は.next/server/pages以下に生成される)
  • npm run devでは、動作確認できないので注意(すべてSSR(Server-side Rendering)になるため)

手順

ブラウザでJsを無効にする

Ctrl + Shift + P からjavascriptと入力し、無効にするを選択

 

この状態でブラウザをリロードすると、下図のようにjavascriptによりhtmlが生成できないため、もとのhtml要素しか表示されていない

Js無効状態でビルドする

Jsは無効にしたまま、frontendのコンテナ内で以下を実行して、本番用ビルドする

npm run build
npm run start

このように、jsとcssがあたった状態でビルドされたhtmlが表示されればOK

ハマりがちなエラー

余談ですが、Next.jsでdocumentやwindowといったクライアントサイドで使用可能なグローバル変数をそのまま使用するとそのような変数は定義されていないとエラーが発生します

理由は簡単で、サーバーサイドでブラウザ用のグローバル変数を使おうとしているためです

Next.jsはサーバーサイド、クライアントサイド両方で動くフレームワーク。そのため、定義したソースはサーバー、ブラウザ両方の環境で実行される可能性があるため、if (process.browser)でブラウザ上で実行する処理であるという判定を入れれば、エラーが生じなくなる

if (process.browser) {
    // windowやdocumentを使う処理を記述
    window.onpopstate = function (e) {
...

Typescriptの導入

frontendコンテナで以下を実行。tsconfig.jsonにデフォルトの設定が書き込まれる(すごい)

/var/www/next-web 

touch tsconfig.json
npm install --dev typescript @types/react @types/node
npm run dev

atomicデザイン用にフォルダ構成を変える

ソースコードのディレクトリをsrc/に変更

tsconfig.jsonを編集して、srcは以下のファイルでソースコードを一元管理できるようにする

{
  "compilerOptions": {
    "target": "es5",
    "baseUrl": "src/", // 追記
    "rootDir": "src/", // 追記

以下のようにディレクトリ構造を変更する

next-web
└src
  └components
  └pages
  └styles
  └libs

index.jsなどをindex.tsxに変更し、ビルドしてエラーがでなければ成功

atomicデザイン用のディレクトリを追加

src直下に以下のようにディレクトリを追加しました

src
└components
  └atomic
    └Atoms
    └Molecules
    └Organisms
    └Pages
  └shared

Tailwind Cssを導入

Installation: Tailwind CSS with Next.js - Tailwind CSS
Documentation for the Tailwind CSS framework.

依存関係のインストール、tailwindcss初期化

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

frontend\next-web\tailwind.config.js

tailwindを使用するファイルの拡張子を指定

module.exports = {
  // 追加
  content: [
    '**/*.ts',
    '**/*.tsx',
    '**/*.jsx',
    '**/*.js'
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

追加

frontend\next-web\src\styles\globals.css

@tailwind base;
@tailwind components;
@tailwind utilities;

styled-componentsを使用している場合のbabelの設定

サーバーサイドでもstyled-componentsが機能するように設定する必要がある

npm install --save-dev babel-plugin-styled-components

or

yarn add -D babel-plugin-styled-components

プロジェクトのルートに.babelrcを作成

{
  "presets": [
    "next/babel"
  ],
  "plugins": [
    [
      "babel-plugin-styled-components",
      {
        "ssr": true,
        "displayName": true,
      }
    ]
  ]
}

以上です。次回以降は何をやるか考えてないですが、何か思いついたら実装して動画にしたいと思います。

タイトルとURLをコピーしました