sagara.inkITエンジニアのまとめノート

Docker+Laravel+React+TypeScript構成のフルスタックパッケージを順を追って構築する【後編:フロントエンド】

Webアプリ開発に慣れない人にとって環境構築は大きなハードルです。 この記事ではサーバーサイドはDockerとLaravel、フロントエンドではReactとTypeScriptを使ったフルスタックパッケージを、ひとつづつ手順を確認しながら構築していきます。 後編ではフロントエンドのReact+TypeScriptの構築を行います。

前編終了時点でのコード

前編の記事は以下からリンクできます。

Docker+Laravel+React+TypeScript構成のフルスタックパッケージを順を追って構築する【前編:サーバーサイド】

また、前編終了時のコードはGitHubで確認できます。

前編での最終形
fullstack-project/
  ├ src/
  |   └ (Laravelのコード)
  ├ docker/
  │   ├ nginx/
  │   │   ├ Dockerfile
  │   │   └ default.conf
  │   ├ php/
  │   │   ├ Dockerfile
  │   │   └ php.ini
  │   └ mysql/
  │       ├ Dockerfile
  │       └ my.conf
  └ docker-compose.yml

3. React環境構築

Laravelを使う場合、ReactやVueなどのフロントエンド開発を手軽に始めるためのパッケージが用意されています。

3-1. Node.jsとnpm

まずは、フロントエンド開発では必須のNode.jsとnpmをDockerコンテナに導入します。phpのDockerfileに記載します。

/docker/php/Dockerfile
FROM php:8.1-fpm-alpine

# install composer
RUN curl -sS https://getcomposer.org/installer | php
RUN mv composer.phar /usr/local/bin/composer

# install packages
RUN apk update
RUN apk add git nodejs npm

# install php extensions
RUN docker-php-ext-install pdo pdo_mysql

apk installコマンドの値にnodejsとnpmを追加します。Dockerfileを編集したのでdocker-compose buildコマンドでビルドします。

console
docker-compose build app
console
docker-compose exec app node -v
v16.15.0

docker-compose exec app npm -v
8.10.0

node -vコマンドおよびnpm -vコマンドでインストールされていることが確認できたら成功です。

ここまでのコード(GitHub)

3-2. MixとUI

Laravel MixはLaravelにデフォルトでインストールされているパッケージで、 モジュールバンドラーのWebpackをラップするパッケージです。 Webpackの設定ファイルであるwebpack.config.jsは構造が複雑になりがちで苦労するのですが、 そのような設定作業に悩まされることなくフロントエンド開発を始めることができます。

Compiling Assets (Mix)

Laravel MixはLaravelプロジェクトにあらかじめ導入されているのでインストールは不要です。

Laravel UI

Laravel UIはフロントエンドのスキャフォールディング(雛形作成)機能で、 ReactやVue、BootStrapの雛形をコマンド1つで作成してくれます。

Laravel UI (GitHub)

console
docker-compose exec app composer require laravel/ui

Laravelには7.xまでLaravel UIに関するドキュメントがありますが、8.x以降は無くなっています。

JavaScript & CSS Scaffolding (7.x)

以下のコマンドを実行することでReactの雛形が作成されます。

console
docker-compose exec app php artisan ui react

コマンドを実行後、Laravelプロジェクトのあるsrc/resources配下にファイルがいくつか追加されます。

php artisan uiコマンド実行後
fullstack-project/
  ├ src/
  |  └ resources/
  |     ├ js/
  |     |  ├ components/
  |     |  |  └ Example.js 
  |     |  ├ app.js
  |     |  └ bootstrap.js
  |     └ sass/
  |        ├ _variables.scss
  |        └ app.scss
  ├ docker/
  └ docker-compose.yml

app.jsを確認すると、Example.jsコンポーネントを要求していることがわかります。

src/resources/js/components/Example.js
import React from 'react';
import ReactDOM from 'react-dom';

function Example() {
  return (
    <div className="container">
      <div className="row justify-content-center">
        <div className="col-md-8">
          <div className="card">
            <div className="card-header">Example Component</div>

            <div className="card-body">I'm an example component!</div>
          </div>
        </div>
      </div>
    </div>
  );
}

export default Example;

if (document.getElementById('example')) {
    ReactDOM.render(<Example />, document.getElementById('example'));
}

さらにExample.jsを確認すると、Exampleコンポーネントの定義と、ExampleコンポーネントをidがexampleのDOM要素に対して描画していることがわかります。

JavaScriptビルド

npm run devコマンドでJavaScriptとCSSをビルドします。

console
docker-compose exec app npm run dev

...
Additional dependencies must be installed. This will only take a moment.
 
Running: npm install resolve-url-loader@^5.0.0 --save-dev --legacy-peer-deps

Finished. Please run Mix again.

初回は、上記のようなメッセージが表示されます。
もう一度npm run devコマンドを実行します。

console
docker-compose exec app npm run dev
...
Laravel Mix v6.0.49                         
✔ Compiled Successfully in 8145ms

Larvelプロジェクトのsrc/public配下にビルドされたファイルが追加されます。

php artisan devコマンド実行後
fullstack-project/
  ├ public/
  |  ├ css/
  |  ├  └ app.css
  |  └ js/
  |     └ app.js
  ├ src/
  ├ docker/
  └ docker-compose.yml

welcome.blade.php

src/views配下にあるwelcome.blade.phpを編集して、Reactコンポーネントを表示するように編集します。

src/views/welcome.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Fullstack Project</title>
    <link rel="stylesheet" href="{{ mix('/css/app.css') }}" />
</head>
<body>
    <div id="example"></div>
    <script src="{{ mix('/js/app.js') }}"></script>
</body>
</html>

link要素にビルドしたcssを、body要素の閉じタグ直前にビルドしたjsを、 そしてbody要素にはexampleをidに持つdiv要素を用意します。

mixメソッドを利用するとLaravelがファイルパスを自動的に指定してくれます。

ブラウザで確認してみる

fig1

ブラウザでlocalhost:8000にアクセスし、Exampleコンポーネントが確認できたら成功です。

ここまでのコード(GitHub)

4. TypeScript環境構築

Reactを用いる場合、同時にTypeScriptを導入することが多いです。 Laravel Mixをすでに導入している場合は、特に負担なくTypeScriptを利用することができます。

4-1. TypeScript

Exampleコンポーネントのファイル名をExample.tsxに変更します。

src/resources/js/components/Example.tsx
import React from 'react';
import ReactDOM from 'react-dom';

function Example(): React.ReactElement {
  return (
    <div className="container">
      <div className="row justify-content-center">
        <div className="col-md-8">
          <div className="card">
            <div className="card-header">Example Component</div>

            <div className="card-body">I'm an example component!</div>
          </div>
        </div>
      </div>
    </div>
  );
}

export default Example;

if (document.getElementById('example')) {
    ReactDOM.render(<Example />, document.getElementById('example'));
}

webpack.mix.jsmix.jsメソッドをmix.tsに変更します。 TypeScriptによる型を使用できるようになります。

src/webpack.config.js
const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.ts('resources/js/app.js', 'public/js')
    .react()
    .sass('resources/sass/app.scss', 'public/css');

npm run devコマンドでJavaScriptとCSSをビルドします。
初回はTypeScriptに関連するnpmパッケージがインストールされます。

console
docker-compose exec app npm run dev

...
Additional dependencies must be installed. This will only take a moment.
 
Running: npm install ts-loader typescript --save-dev --legacy-peer-deps

Finished. Please run Mix again.

もう一度npm run devコマンドを実行します。

console
docker-compose exec app npm run dev

...
ERROR in ./resources/js/components/Example.tsx 
[tsl] ERROR
      TS18002: The 'files' list in config file 'tsconfig.json' is empty.

ERROR in ./resources/js/components/Example.tsx
Module build failed (from ./node_modules/ts-loader/index.js):
Error: error while parsing tsconfig.json
    at Object.loader (/var/www/html/node_modules/ts-loader/dist/index.js:17:18)

webpack compiled with 2 errors and 1 warning

tsconfig.json

Laravel MixのTypescript Supportに記載のある通り、tsconfig.jsonと型パッケージ(@types/*)が必要なので用意します。

tsconfigは公式推奨のものから引っ張ってきます。

src/tsconfig.json
{
  "compilerOptions": {
    "target": "ES2015",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Recommended"
}

さらにReactのJSXを対応できるようにし、さらにvendor配下の検証は除外します。

src/tsconfig.json
{
  "compilerOptions": {
    "target": "ES2015",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "react"
  },
  "exclude": [
    "vendor"
  ],
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Recommended"
}

@types/*

関連する型パッケージをインストールします。

console
docker-compose exec app npm install @types/node @types/react @types/react-dom

ビルドして確認する

console
docker-compose exec app npm run dev

...
Laravel Mix v6.0.49   
                         
✔ Compiled Successfully in 10969ms

TypeScriptでのビルドができるようになりました。

ここまでのコード(GitHub)

完成

Docker+Laravel+React+TypeScript構成の環境が完成しました。
必要に応じてPHP静的解析ツールのphpcsやphpmd、JSのESLintやJS Standardなどを導入してください。

完成形のコード(GitHub)

最終的な構成

最終的な構成(この記事で編集していないLaravelのファイルは省略)
fullstack-project/
  ├ docker/
  │  ├ nginx/
  │  │  ├ Dockerfile
  │  │  └ default.conf
  │  ├ php/
  │  │  ├ Dockerfile
  │  │  └ php.ini
  │  └ mysql/
  │     ├ Dockerfile
  │     └ my.conf
  ├ src/
  ├  ├ public/
  |  |  ├ css/
  |  |  ├  └ app.css
  |  |  └ js/
  |  |     └ app.js
  |  ├ resources/
  |  |  ├ js/
  |  |  |  ├ components/
  |  |  |  |  └ Example.tsx
  |  |  |  ├ app.js
  |  |  |  └ bootstrap.js
  |  |  └ sass/
  |  |     ├ _variables.scss
  |  |     └ app.scss
  |  ├ views/
  |  |  └ welcome.blade.php
  |  ├ .env
  |  ├ tsconfig.json
  |  └ webpack.mix.js
  └ docker-compose.yml