転職したらスマレジだった件

スマレジのエンジニアやまてのテックブログです。マジレス大歓迎です。

Laravel Sail を活用した Laravel 10 と React 18 の SPA 開発環境の構築手順

スマレジのテックファーム(SES 部門)で Web 系エンジニアとして働いている やまて(@r_yamate) と申します。

2023 年 4 月からは、スマレジの関連アプリの開発業務を担当しています。触ったことのなかった Flutter での開発を担当(React も少々)することになり、日々奮闘中です。開発しているアプリはモニター利用も始まり、開発の醍醐味を味わえていて楽しいです。

はじめに

今回は、Laravel 10React 18 を使用した SPA 開発環境を Laravel Sail を活用して構築手順について、ハンズオンの記録をまとめます。

laravel.com

ja.react.dev

以下の記事を参考にさせていただき、ハンズオンで実行した記録です。

qiita.com

目次

開発環境

バックエンド

  • Laravel 10(Laravel Sail, Vite)
  • MySQL 8

フロントエンド

  • React 18
  • Sass
  • TypeScript

Laravel Sail とは

Laravel Sail は Docker ベースの開発環境を簡単に構築できるツールです。

readouble.com

1. Laravel の開発環境構築

Laravel の開発環境を構築します。

laravel.com

Docker Desktop が必要です。

www.docker.com

1-1. 新規 Laravel プロジェクトの作成

以下のコマンドで、新規プロジェクトを作成します。

curl -s "https://laravel.build/sample-app?with=mysql" | bash
  • コマンド実行時ログ

      # r_yamate @ srC02T54QWH03M in ~/development [18:14:43]
      $ curl -s "https://laravel.build/sample-app?with=mysql" | bash
      latest: Pulling from laravelsail/php82-composer
      Digest: sha256:37549f980be6146efcb16b0dc352644edfc5cca32b9862494631eb197ef89737
      Status: Image is up to date for laravelsail/php82-composer:latest
    
         _                               _
        | |                             | |
        | |     __ _ _ __ __ ___   _____| |
        | |    / _` | '__/ _` \ \ / / _ \ |
        | |___| (_| | | | (_| |\ V /  __/ |
        |______\__,_|_|  \__,_| \_/ \___|_|
    
         WARN  TTY mode requires /dev/tty to be read/writable.
    
          Creating a "laravel/laravel" project at "./sample-app"
          Installing laravel/laravel (v10.2.9)
            - Downloading laravel/laravel (v10.2.9)
            - Installing laravel/laravel (v10.2.9): Extracting archive
          Created project in /opt/sample-app
          > @php -r "file_exists('.env') || copy('.env.example', '.env');"
          Loading composer repositories with package information
          Updating dependencies
          Lock file operations: 110 installs, 0 updates, 0 removals
            - Locking brick/math (0.11.0)
            - Locking dflydev/dot-access-data (v3.0.2)
        - Locking doctrine/inflector (2.0.8)
        - Locking doctrine/lexer (3.0.0)
        - Locking dragonmantank/cron-expression (v3.3.3)
            - Locking egulias/email-validator (4.0.2)
        - Locking fakerphp/faker (v1.23.0)
        - Locking filp/whoops (2.15.4)
        - Locking fruitcake/php-cors (v1.3.0)
            - Locking graham-campbell/result-type (v1.1.2)
            - Locking guzzlehttp/guzzle (7.8.0)
            - Locking guzzlehttp/promises (2.0.1)
        - Locking guzzlehttp/psr7 (2.6.1)
        - Locking guzzlehttp/uri-template (v1.0.2)
        - Locking hamcrest/hamcrest-php (v2.0.1)
            - Locking laravel/framework (v10.32.1)
            - Locking laravel/pint (v1.13.6)
            - Locking laravel/prompts (v0.1.13)
            - Locking laravel/sail (v1.26.0)
            - Locking laravel/sanctum (v3.3.2)
            - Locking laravel/serializable-closure (v1.3.3)
        - Locking laravel/tinker (v2.8.2)
        - Locking league/commonmark (2.4.1)
        - Locking league/config (v1.2.0)
        - Locking league/flysystem (3.21.0)
        - Locking league/flysystem-local (3.21.0)
        - Locking league/mime-type-detection (1.14.0)
            - Locking mockery/mockery (1.6.6)
        - Locking monolog/monolog (3.5.0)
        - Locking myclabs/deep-copy (1.11.1)
            - Locking nesbot/carbon (2.71.0)
            - Locking nette/schema (v1.2.5)
        - Locking nette/utils (v4.0.3)
        - Locking nikic/php-parser (v4.17.1)
        - Locking nunomaduro/collision (v7.10.0)
            - Locking nunomaduro/termwind (v1.15.1)
        - Locking phar-io/manifest (2.0.3)
        - Locking phar-io/version (3.2.1)
        - Locking phpoption/phpoption (1.9.2)
        - Locking phpunit/php-code-coverage (10.1.8)
        - Locking phpunit/php-file-iterator (4.1.0)
            - Locking phpunit/php-invoker (4.0.0)
        - Locking phpunit/php-text-template (3.0.1)
            - Locking phpunit/php-timer (6.0.0)
        - Locking phpunit/phpunit (10.4.2)
        - Locking psr/clock (1.0.0)
            - Locking psr/container (2.0.2)
            - Locking psr/event-dispatcher (1.0.0)
            - Locking psr/http-client (1.0.3)
            - Locking psr/http-factory (1.0.2)
        - Locking psr/http-message (2.0)
        - Locking psr/log (3.0.0)
        - Locking psr/simple-cache (3.0.0)
        - Locking psy/psysh (v0.11.22)
            - Locking ralouphie/getallheaders (3.0.3)
        - Locking ramsey/collection (2.0.0)
            - Locking ramsey/uuid (4.7.5)
        - Locking sebastian/cli-parser (2.0.0)
        - Locking sebastian/code-unit (2.0.0)
        - Locking sebastian/code-unit-reverse-lookup (3.0.0)
        - Locking sebastian/comparator (5.0.1)
            - Locking sebastian/complexity (3.1.0)
        - Locking sebastian/diff (5.0.3)
        - Locking sebastian/environment (6.0.1)
            - Locking sebastian/exporter (5.1.1)
        - Locking sebastian/global-state (6.0.1)
        - Locking sebastian/lines-of-code (2.0.1)
        - Locking sebastian/object-enumerator (5.0.0)
        - Locking sebastian/object-reflector (3.0.0)
            - Locking sebastian/recursion-context (5.0.0)
        - Locking sebastian/type (4.0.0)
        - Locking sebastian/version (4.0.1)
        - Locking spatie/backtrace (1.5.3)
        - Locking spatie/flare-client-php (1.4.3)
            - Locking spatie/ignition (1.11.3)
            - Locking spatie/laravel-ignition (2.3.1)
            - Locking symfony/console (v6.3.8)
        - Locking symfony/css-selector (v6.3.2)
        - Locking symfony/deprecation-contracts (v3.4.0)
            - Locking symfony/error-handler (v6.3.5)
            - Locking symfony/event-dispatcher (v6.3.2)
        - Locking symfony/event-dispatcher-contracts (v3.4.0)
        - Locking symfony/finder (v6.3.5)
        - Locking symfony/http-foundation (v6.3.8)
            - Locking symfony/http-kernel (v6.3.8)
        - Locking symfony/mailer (v6.3.5)
            - Locking symfony/mime (v6.3.5)
        - Locking symfony/polyfill-ctype (v1.28.0)
            - Locking symfony/polyfill-intl-grapheme (v1.28.0)
        - Locking symfony/polyfill-intl-idn (v1.28.0)
        - Locking symfony/polyfill-intl-normalizer (v1.28.0)
            - Locking symfony/polyfill-mbstring (v1.28.0)
        - Locking symfony/polyfill-php72 (v1.28.0)
        - Locking symfony/polyfill-php80 (v1.28.0)
        - Locking symfony/polyfill-php83 (v1.28.0)
        - Locking symfony/polyfill-uuid (v1.28.0)
        - Locking symfony/process (v6.3.4)
        - Locking symfony/routing (v6.3.5)
            - Locking symfony/service-contracts (v3.4.0)
        - Locking symfony/string (v6.3.8)
        - Locking symfony/translation (v6.3.7)
            - Locking symfony/translation-contracts (v3.4.0)
        - Locking symfony/uid (v6.3.8)
            - Locking symfony/var-dumper (v6.3.8)
        - Locking symfony/yaml (v6.3.8)
        - Locking theseer/tokenizer (1.2.2)
        - Locking tijsverkoyen/css-to-inline-styles (2.2.6)
        - Locking vlucas/phpdotenv (v5.6.0)
        - Locking voku/portable-ascii (2.0.1)
        - Locking webmozart/assert (1.11.0)
          Writing lock file
          Installing dependencies from lock file (including require-dev)
          Package operations: 110 installs, 0 updates, 0 removals
            - Downloading doctrine/inflector (2.0.8)
            - Downloading doctrine/lexer (3.0.0)
            - Downloading symfony/polyfill-ctype (v1.28.0)
            - Downloading webmozart/assert (1.11.0)
            - Downloading dragonmantank/cron-expression (v3.3.3)
            - Downloading symfony/deprecation-contracts (v3.4.0)
            - Downloading fakerphp/faker (v1.23.0)
            - Downloading symfony/polyfill-php80 (v1.28.0)
            - Downloading symfony/polyfill-php83 (v1.28.0)
            - Downloading symfony/polyfill-mbstring (v1.28.0)
            - Downloading symfony/http-foundation (v6.3.8)
            - Downloading fruitcake/php-cors (v1.3.0)
            - Downloading psr/http-message (2.0)
            - Downloading psr/http-client (1.0.3)
            - Downloading ralouphie/getallheaders (3.0.3)
            - Downloading psr/http-factory (1.0.2)
            - Downloading guzzlehttp/psr7 (2.6.1)
            - Downloading guzzlehttp/promises (2.0.1)
            - Downloading guzzlehttp/guzzle (7.8.0)
            - Downloading guzzlehttp/uri-template (v1.0.2)
            - Downloading laravel/pint (v1.13.6)
            - Downloading symfony/polyfill-intl-normalizer (v1.28.0)
            - Downloading symfony/polyfill-intl-grapheme (v1.28.0)
            - Downloading symfony/string (v6.3.8)
            - Downloading symfony/service-contracts (v3.4.0)
            - Downloading symfony/console (v6.3.8)
            - Downloading voku/portable-ascii (2.0.1)
            - Downloading phpoption/phpoption (1.9.2)
            - Downloading graham-campbell/result-type (v1.1.2)
            - Downloading vlucas/phpdotenv (v5.6.0)
            - Downloading symfony/css-selector (v6.3.2)
            - Downloading tijsverkoyen/css-to-inline-styles (2.2.6)
            - Downloading symfony/var-dumper (v6.3.8)
            - Downloading symfony/polyfill-uuid (v1.28.0)
            - Downloading symfony/uid (v6.3.8)
            - Downloading symfony/routing (v6.3.5)
            - Downloading symfony/process (v6.3.4)
            - Downloading symfony/polyfill-php72 (v1.28.0)
            - Downloading symfony/polyfill-intl-idn (v1.28.0)
            - Downloading symfony/mime (v6.3.5)
            - Downloading psr/event-dispatcher (1.0.0)
            - Downloading symfony/event-dispatcher-contracts (v3.4.0)
            - Downloading symfony/event-dispatcher (v6.3.2)
            - Downloading psr/log (3.0.0)
            - Downloading egulias/email-validator (4.0.2)
            - Downloading symfony/mailer (v6.3.5)
            - Downloading symfony/error-handler (v6.3.5)
            - Downloading symfony/http-kernel (v6.3.8)
            - Downloading symfony/finder (v6.3.5)
            - Downloading ramsey/collection (2.0.0)
            - Downloading brick/math (0.11.0)
            - Downloading ramsey/uuid (4.7.5)
            - Downloading psr/simple-cache (3.0.0)
            - Downloading nunomaduro/termwind (v1.15.1)
            - Downloading symfony/translation-contracts (v3.4.0)
            - Downloading symfony/translation (v6.3.7)
            - Downloading psr/clock (1.0.0)
            - Downloading nesbot/carbon (2.71.0)
            - Downloading monolog/monolog (3.5.0)
            - Downloading league/mime-type-detection (1.14.0)
            - Downloading league/flysystem (3.21.0)
            - Downloading league/flysystem-local (3.21.0)
            - Downloading nette/utils (v4.0.3)
            - Downloading nette/schema (v1.2.5)
            - Downloading dflydev/dot-access-data (v3.0.2)
            - Downloading league/config (v1.2.0)
            - Downloading league/commonmark (2.4.1)
            - Downloading laravel/serializable-closure (v1.3.3)
            - Downloading laravel/prompts (v0.1.13)
            - Downloading laravel/framework (v10.32.1)
            - Downloading symfony/yaml (v6.3.8)
            - Downloading laravel/sail (v1.26.0)
            - Downloading laravel/sanctum (v3.3.2)
            - Downloading nikic/php-parser (v4.17.1)
            - Downloading psy/psysh (v0.11.22)
            - Downloading laravel/tinker (v2.8.2)
            - Downloading hamcrest/hamcrest-php (v2.0.1)
            - Downloading mockery/mockery (1.6.6)
            - Downloading filp/whoops (2.15.4)
            - Downloading nunomaduro/collision (v7.10.0)
            - Downloading sebastian/version (4.0.1)
            - Downloading sebastian/type (4.0.0)
            - Downloading sebastian/recursion-context (5.0.0)
            - Downloading sebastian/object-reflector (3.0.0)
            - Downloading sebastian/object-enumerator (5.0.0)
            - Downloading sebastian/global-state (6.0.1)
            - Downloading sebastian/exporter (5.1.1)
            - Downloading sebastian/environment (6.0.1)
            - Downloading sebastian/diff (5.0.3)
            - Downloading sebastian/comparator (5.0.1)
            - Downloading sebastian/code-unit (2.0.0)
            - Downloading sebastian/cli-parser (2.0.0)
            - Downloading phpunit/php-timer (6.0.0)
            - Downloading phpunit/php-text-template (3.0.1)
            - Downloading phpunit/php-invoker (4.0.0)
            - Downloading phpunit/php-file-iterator (4.1.0)
            - Downloading theseer/tokenizer (1.2.2)
            - Downloading sebastian/lines-of-code (2.0.1)
            - Downloading sebastian/complexity (3.1.0)
            - Downloading sebastian/code-unit-reverse-lookup (3.0.0)
            - Downloading phpunit/php-code-coverage (10.1.8)
            - Downloading myclabs/deep-copy (1.11.1)
            - Downloading phpunit/phpunit (10.4.2)
            - Downloading spatie/backtrace (1.5.3)
            - Downloading spatie/flare-client-php (1.4.3)
            - Downloading spatie/ignition (1.11.3)
            - Downloading spatie/laravel-ignition (2.3.1)
            - Installing doctrine/inflector (2.0.8): Extracting archive
            - Installing doctrine/lexer (3.0.0): Extracting archive
            - Installing symfony/polyfill-ctype (v1.28.0): Extracting archive
            - Installing webmozart/assert (1.11.0): Extracting archive
            - Installing dragonmantank/cron-expression (v3.3.3): Extracting archive
            - Installing symfony/deprecation-contracts (v3.4.0): Extracting archive
            - Installing psr/container (2.0.2): Extracting archive
            - Installing fakerphp/faker (v1.23.0): Extracting archive
            - Installing symfony/polyfill-php80 (v1.28.0): Extracting archive
            - Installing symfony/polyfill-php83 (v1.28.0): Extracting archive
            - Installing symfony/polyfill-mbstring (v1.28.0): Extracting archive
            - Installing symfony/http-foundation (v6.3.8): Extracting archive
            - Installing fruitcake/php-cors (v1.3.0): Extracting archive
            - Installing psr/http-message (2.0): Extracting archive
            - Installing psr/http-client (1.0.3): Extracting archive
            - Installing ralouphie/getallheaders (3.0.3): Extracting archive
            - Installing psr/http-factory (1.0.2): Extracting archive
            - Installing guzzlehttp/psr7 (2.6.1): Extracting archive
            - Installing guzzlehttp/promises (2.0.1): Extracting archive
            - Installing guzzlehttp/guzzle (7.8.0): Extracting archive
            - Installing guzzlehttp/uri-template (v1.0.2): Extracting archive
            - Installing laravel/pint (v1.13.6): Extracting archive
            - Installing symfony/polyfill-intl-normalizer (v1.28.0): Extracting archive
            - Installing symfony/polyfill-intl-grapheme (v1.28.0): Extracting archive
            - Installing symfony/string (v6.3.8): Extracting archive
            - Installing symfony/service-contracts (v3.4.0): Extracting archive
            - Installing symfony/console (v6.3.8): Extracting archive
            - Installing voku/portable-ascii (2.0.1): Extracting archive
            - Installing phpoption/phpoption (1.9.2): Extracting archive
            - Installing graham-campbell/result-type (v1.1.2): Extracting archive
            - Installing vlucas/phpdotenv (v5.6.0): Extracting archive
            - Installing symfony/css-selector (v6.3.2): Extracting archive
            - Installing tijsverkoyen/css-to-inline-styles (2.2.6): Extracting archive
            - Installing symfony/var-dumper (v6.3.8): Extracting archive
            - Installing symfony/polyfill-uuid (v1.28.0): Extracting archive
            - Installing symfony/uid (v6.3.8): Extracting archive
            - Installing symfony/routing (v6.3.5): Extracting archive
            - Installing symfony/process (v6.3.4): Extracting archive
            - Installing symfony/polyfill-php72 (v1.28.0): Extracting archive
            - Installing symfony/polyfill-intl-idn (v1.28.0): Extracting archive
            - Installing symfony/mime (v6.3.5): Extracting archive
            - Installing psr/event-dispatcher (1.0.0): Extracting archive
            - Installing symfony/event-dispatcher-contracts (v3.4.0): Extracting archive
            - Installing symfony/event-dispatcher (v6.3.2): Extracting archive
            - Installing psr/log (3.0.0): Extracting archive
            - Installing egulias/email-validator (4.0.2): Extracting archive
            - Installing symfony/mailer (v6.3.5): Extracting archive
            - Installing symfony/error-handler (v6.3.5): Extracting archive
            - Installing symfony/http-kernel (v6.3.8): Extracting archive
            - Installing symfony/finder (v6.3.5): Extracting archive
            - Installing ramsey/collection (2.0.0): Extracting archive
            - Installing brick/math (0.11.0): Extracting archive
            - Installing ramsey/uuid (4.7.5): Extracting archive
            - Installing psr/simple-cache (3.0.0): Extracting archive
            - Installing nunomaduro/termwind (v1.15.1): Extracting archive
            - Installing symfony/translation-contracts (v3.4.0): Extracting archive
            - Installing symfony/translation (v6.3.7): Extracting archive
            - Installing psr/clock (1.0.0): Extracting archive
            - Installing nesbot/carbon (2.71.0): Extracting archive
            - Installing monolog/monolog (3.5.0): Extracting archive
            - Installing league/mime-type-detection (1.14.0): Extracting archive
            - Installing league/flysystem (3.21.0): Extracting archive
            - Installing league/flysystem-local (3.21.0): Extracting archive
            - Installing nette/utils (v4.0.3): Extracting archive
            - Installing nette/schema (v1.2.5): Extracting archive
            - Installing dflydev/dot-access-data (v3.0.2): Extracting archive
            - Installing league/config (v1.2.0): Extracting archive
            - Installing league/commonmark (2.4.1): Extracting archive
            - Installing laravel/serializable-closure (v1.3.3): Extracting archive
            - Installing laravel/prompts (v0.1.13): Extracting archive
            - Installing laravel/framework (v10.32.1): Extracting archive
            - Installing symfony/yaml (v6.3.8): Extracting archive
            - Installing laravel/sail (v1.26.0): Extracting archive
            - Installing laravel/sanctum (v3.3.2): Extracting archive
            - Installing nikic/php-parser (v4.17.1): Extracting archive
            - Installing psy/psysh (v0.11.22): Extracting archive
            - Installing laravel/tinker (v2.8.2): Extracting archive
            - Installing hamcrest/hamcrest-php (v2.0.1): Extracting archive
            - Installing mockery/mockery (1.6.6): Extracting archive
            - Installing filp/whoops (2.15.4): Extracting archive
            - Installing nunomaduro/collision (v7.10.0): Extracting archive
            - Installing sebastian/version (4.0.1): Extracting archive
            - Installing sebastian/type (4.0.0): Extracting archive
            - Installing sebastian/recursion-context (5.0.0): Extracting archive
            - Installing sebastian/object-reflector (3.0.0): Extracting archive
            - Installing sebastian/object-enumerator (5.0.0): Extracting archive
            - Installing sebastian/global-state (6.0.1): Extracting archive
            - Installing sebastian/exporter (5.1.1): Extracting archive
            - Installing sebastian/environment (6.0.1): Extracting archive
            - Installing sebastian/diff (5.0.3): Extracting archive
            - Installing sebastian/comparator (5.0.1): Extracting archive
            - Installing sebastian/code-unit (2.0.0): Extracting archive
            - Installing sebastian/cli-parser (2.0.0): Extracting archive
            - Installing phpunit/php-timer (6.0.0): Extracting archive
            - Installing phpunit/php-text-template (3.0.1): Extracting archive
            - Installing phpunit/php-invoker (4.0.0): Extracting archive
            - Installing phpunit/php-file-iterator (4.1.0): Extracting archive
            - Installing theseer/tokenizer (1.2.2): Extracting archive
            - Installing sebastian/lines-of-code (2.0.1): Extracting archive
            - Installing sebastian/complexity (3.1.0): Extracting archive
            - Installing sebastian/code-unit-reverse-lookup (3.0.0): Extracting archive
            - Installing phpunit/php-code-coverage (10.1.8): Extracting archive
            - Installing phar-io/version (3.2.1): Extracting archive
            - Installing phar-io/manifest (2.0.3): Extracting archive
            - Installing myclabs/deep-copy (1.11.1): Extracting archive
            - Installing phpunit/phpunit (10.4.2): Extracting archive
            - Installing spatie/backtrace (1.5.3): Extracting archive
            - Installing spatie/flare-client-php (1.4.3): Extracting archive
            - Installing spatie/ignition (1.11.3): Extracting archive
            - Installing spatie/laravel-ignition (2.3.1): Extracting archive
          55 package suggestions were added by new dependencies, use `composer suggest` to see details.
          Generating optimized autoload files
          > Illuminate\Foundation\ComposerScripts::postAutoloadDump
          > @php artisan package:discover --ansi
    
         INFO  Discovering packages.
    
            laravel/sail     ..........................................................     DONE
            laravel/sanctum     .......................................................     DONE
            laravel/tinker     ........................................................     DONE
            nesbot/carbon     .........................................................     DONE
        nunomaduro/collision     ..................................................     DONE
        nunomaduro/termwind     ...................................................     DONE
            spatie/laravel-ignition     ...............................................     DONE
    
          82 packages you are using are looking for funding.
      Use the `composer fund` command to find out more!
          > @php artisan vendor:publish --tag=laravel-assets --ansi --force
    
         INFO  No publishable resources for tag [laravel-assets].
    
          No security vulnerability advisories found
          > @php artisan key:generate --ansi
    
         INFO  Application key set successfully.
    
         INFO  Application ready! Build something amazing.
    
      Sail scaffolding installed successfully.
         WARN  TTY mode requires /dev/tty to be read/writable.
    
      [+] Running 1/1
       ⠿ mysql Pulled                                                                       2.8s
      [+] Building 3.3s (16/16) FINISHED
       => [internal] load build definition from Dockerfile                                  0.1s
       => => transferring dockerfile: 32B                                                   0.0s
       => [internal] load .dockerignore                                                     0.0s
       => => transferring context: 2B                                                       0.0s
       => [internal] load metadata for docker.io/library/ubuntu:22.04                       2.9s
       => [ 1/11] FROM docker.io/library/ubuntu:22.04@sha256:2b7412e6465c3c7fc5bb21d3e6f19  0.0s
       => [internal] load build context                                                     0.0s
       => => transferring context: 99B                                                      0.0s
       => CACHED [ 2/11] WORKDIR /var/www/html                                              0.0s
       => CACHED [ 3/11] RUN ln -snf /usr/share/zoneinfo/UTC /etc/localtime && echo UTC >   0.0s
       => CACHED [ 4/11] RUN apt-get update     && mkdir -p /etc/apt/keyrings     && apt-g  0.0s
       => CACHED [ 5/11] RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2              0.0s
       => CACHED [ 6/11] RUN groupadd --force -g 20 sail                                    0.0s
       => CACHED [ 7/11] RUN useradd -ms /bin/bash --no-user-group -g 20 -u 1337 sail       0.0s
       => CACHED [ 8/11] COPY start-container /usr/local/bin/start-container                0.0s
       => CACHED [ 9/11] COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf      0.0s
       => CACHED [10/11] COPY php.ini /etc/php/8.2/cli/conf.d/99-sail.ini                   0.0s
       => CACHED [11/11] RUN chmod +x /usr/local/bin/start-container                        0.0s
       => exporting to image                                                                0.1s
       => => exporting layers                                                               0.0s
       => => writing image sha256:e61d59045001df822f1a08d808ca8c3f27967fa59323ebf01871a1c2  0.0s
       => => naming to sail-8.2/app                                                         0.0s
    
      Please provide your password so we can make some final adjustments to your application's permissions.
    
      Password:
    
      Thank you! We hope you build something incredible. Dive in with: cd sample-app && ./vendor/bin/sail up
    
  • アプリケーション名は、任意の名前で作成できます。

  • 例えば、?with=mysql,redis をつけることで、MySQL と Redis を利用できます。
  • ?with= をつけない場合、mysql、redis、meilisearch、mailpit、selenium が設定されます。
  • PostgreSQLを使用する場合は mysqlpgsql に変更します。

laravel.com

1-2. Docker コンテナの起動

以下のコマンドで、Docker コンテナを起動します。

./vendor/bin/sail up
  • コマンド実行時ログ

      # r_yamate @ mbp in ~/development [18:20:58] C:127
      $ cd sample-app
    
      # r_yamate @ mbp in ~/development/sample-app [18:21:05]
      $ ./vendor/bin/sail up
      [+] Running 4/4
       ⠿ Network sample-app_sail              Created                                       0.2s
       ⠿ Volume "sample-app_sail-mysql"       Created                                       0.0s
       ⠿ Container sample-app-mysql-1         Created                                       0.2s
       ⠿ Container sample-app-laravel.test-1  Crea...                                       0.4s
      Attaching to sample-app-laravel.test-1, sample-app-mysql-1
      sample-app-mysql-1         | [Entrypoint] MySQL Docker Image 8.0.32-1.2.11-server
      sample-app-mysql-1         | [Entrypoint] Initializing database
      sample-app-mysql-1         | 2023-11-20T09:21:14.034867Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
      sample-app-mysql-1         | 2023-11-20T09:21:14.041155Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.32) initializing of server in progress as process 17
      sample-app-mysql-1         | 2023-11-20T09:21:14.217630Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
      sample-app-mysql-1         | 2023-11-20T09:21:16.522176Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
      sample-app-laravel.test-1  | 2023-11-20 09:21:18,667 INFO Set uid to user 0 succeeded
      sample-app-laravel.test-1  | 2023-11-20 09:21:18,679 INFO supervisord started with pid 1
      sample-app-laravel.test-1  | 2023-11-20 09:21:19,683 INFO spawned: 'php' with pid 16
      sample-app-mysql-1         | 2023-11-20T09:21:20.076140Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
      sample-app-laravel.test-1  | 2023-11-20 09:21:20,686 INFO success: php entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
    

Web ブラウザで http:// localhost にアクセスし、Laravel のデフォルトページが表示されれば成功です。

Ctrl + C キーで Sail を一度停止します。

1-3. sail コマンドエイリアスの設定

以下のコマンドで、./vendor/bin/sail のエイリアスを設定します。

alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'

laravel.com

以下のコマンドを実行します。

sail up -d
  • コマンド実行時ログ

      # r_yamate @ mbp in ~/development/sample-app [18:23:19] C:130
      $ alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'
    
      # r_yamate @ mbp in ~/development/sample-app [18:29:18]
      $ sail up -d
      [+] Running 2/2
       ⠿ Container sample-app-mysql-1         Started                                       0.8s
       ⠿ Container sample-app-laravel.test-1  Star...                                       3.9s
    

sail up の後に -d をつけていますが、バックグラウンドで Sail を起動するためのオプションです。

http://localhost でアクセスし、同じく Laravel のデフォルトページが表示されれば OK です。

2. React の開発環境構築

React の環境は Laravel 内に設定します。resources ディレクトリ内に ts ディレクトリを作成し、 Laravel に同梱されている node、npm、npx を使用します。

構築した Laravel の開発環境にインストールされた node や npm、npx を確認します。

  • コマンド実行時ログ

      # r_yamate @ mbp in ~/development/sample-app [18:29:27]
      $ sail node --version
      v20.9.0
    
      # r_yamate @ mbp in ~/development/sample-app [18:32:20]
      $ sail npm --version
      10.2.2
    
      # r_yamate @ mbp in ~/development/sample-app [18:32:32]
      $ sail npx --version
      10.2.2
    

2-1. 必要なモジュールのインストール

以下のコマンドを実行し、package.json ファイル内に記述されたパッケージ( Laravel で Vite を使うのに必要なものなど)を一括でインストールします。

sail npm install
sail npm install -D react react-dom @types/react @types/react-dom
sail npm install -D @vitejs/plugin-react

node_modules ディレクトリ と package-lock.json も同時に作成されます。

  • コマンド実行時ログ

      # r_yamate @ mbp in ~/development/sample-app [18:32:35]
      $ sail npm install
      sail npm install -D react react-dom @types/react @types/react-dom
      sail npm install -D @vitejs/plugin-react
    
      added 20 packages, and audited 21 packages in 17s
    
      5 packages are looking for funding
        run `npm fund` for details
    
      found 0 vulnerabilities
    
      added 10 packages, and audited 31 packages in 5s
    
      5 packages are looking for funding
        run `npm fund` for details
    
      found 0 vulnerabilities
    
      added 60 packages, and audited 91 packages in 23s
    
      9 packages are looking for funding
        run `npm fund` for details
    
      found 0 vulnerabilities
    

2-2. TypeScript の導入

以下のコマンドで、TypeScript を導入します。

sail npm install -D typescript
sail npx tsc --init --jsx react-jsx
  • コマンド実行時ログ

      # r_yamate @ mbp in ~/development/sample-app [18:35:19]
      $ sail npm install -D typescript
      sail npx tsc --init --jsx react-jsx
    
      added 1 package, and audited 92 packages in 15s
    
      9 packages are looking for funding
        run `npm fund` for details
    
      found 0 vulnerabilities
    
      Created a new tsconfig.json with:
                                                                                              TS
        target: es2016
        module: commonjs
        jsx: react-jsx
        strict: true
        esModuleInterop: true
        skipLibCheck: true
        forceConsistentCasingInFileNames: true
    
      You can learn more at https://aka.ms/tsconfig
    

tsconfig.json がルートディレクトリに作成されます。

2-3. Vite の設定

vite.config.js の設定を以下のように更新します。

  • 編集:vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react'; // 追加

export default defineConfig({
    plugins: [
        laravel({
            // TypeScriptとSassが使えるように変更
            // input: ['resources/css/app.css', 'resources/js/app.js'],
            input: [
                'resources/sass/app.scss', 
                'resources/ts/index.tsx'
            ],
            refresh: true,
        }),
        react(), // 追加
    ],
});

2-4. index.blade.php の作成

resources/views ディレクトリ内に index.blade.php を作成します。welcome.blade.php は、削除します。

  • 作成:resources/views/index.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>sample-app</title>

        @viteReactRefresh
        @vite(['resources/sass/app.scss', 'resources/ts/index.tsx'])

    </head>

    <body class="antialiased">
        <div id="app"></div>
    </body>
</html>

2-5. index.tsx の作成

resources ディレクトリ内に ts ディレクトリを追加し、index.tsx を作成します。

  • 作成:resources/ts/index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';

const container = document.getElementById('app');
const root = createRoot(container!);

root.render(
  <React.StrictMode>
    <div className="text-blue">
        Hello World!
    </div>
    </React.StrictMode>,
);

2-6. web.php の編集

welcome を index に変更します。

  • 編集:routes/web.php
<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

Route::get('/', function () {
    // return view('welcome');
    return view('index');
});

2-7. Sass の導入

sass のパッケージをインストールします。

sail npm install -D sass
  • コマンド実行時ログ

      # r_yamate @ mbp in ~/development/sample-app [18:37:19]
      $ sail npm install -D sass
    
      added 15 packages, and audited 107 packages in 7s
    
      10 packages are looking for funding
        run `npm fund` for details
    
      found 0 vulnerabilities
    

resources/css/app.css を resources/sass/app.scss に変更し、サンプルでスタイルを設定します。

  • 編集:resources/sass/app.scss
.text-blue {
  color: blue;
}

2-8. React と Sass の動作確認

以下のコマンドを実行します。

sail npm run dev
  • コマンド実行時ログ

      # r_yamate @ mbp in ~/development/sample-app [18:45:10]
      $ sail npm run dev
    
      > dev
      > vite
    
        VITE v4.5.0  ready in 1492 ms
    
        ➜  Local:   http://localhost:5173/
        ➜  Network: http://192.168.32.3:5173/
        ➜  press h to show help
    
        LARAVEL v10.32.1  plugin v0.8.1
    
        ➜  APP_URL: http://localhost
    

http://localhost にアクセスし、青文字で Hello World! と表示されれば成功です。

3. Laravel と React の連携

最後に、Laravel と React の連携を確認します。

3-1. App.tsx の作成

resources/ts ディレクトリ内に App.tsx を作成します。

  • 作成:resources/ts/App.tsx
import React, { useEffect } from 'react';
import axios from 'axios';

const App: React.FC = () => {
    useEffect(()=>{
        const fetchFromLaravel = async () => {
            const res  = await axios.get(`/api/hoge`);
            alert(res.data.hoge)
        };
        fetchFromLaravel();
    }, [])

    return (
        <div className="App"></div>
    );
}

export default App;

3-2. index.tsx の編集

  • 編集:resources/ts/index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App'; // 追加

const container = document.getElementById('app');
const root = createRoot(container!);

root.render(
  <React.StrictMode>
    <div className="text-blue">
        Hello World!
    </div>
    <App /> {/* 追加 */}
    </React.StrictMode>,
);

3-3. api.php の編集

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/

Route::get('/regi', function (Request $request) {
    return response()->json(['regi' => 'Hello Laravel!']);
});

http:// localhost にアクセスし、Alert で Hello Laravel! と表示されれば、Laravel と React の連携は完了です。

Ctrl+C キーで Vite を停止します。

Sail を停止します。

sail down

おわりに

今回は、Laravel 10React 18 を使用した SPA 開発環境を Laravel Sail を活用して構築する手順をまとめました。

ありがとうございました。



枯らさないように。