We'll be using Laravel 5.8. You can see the list of articles in this series here.

Run composer create-project --prefer-dist laravel/laravel address-book to install.

Go ahead and setup your .env file to suit your needs. Also create a .env.testing file that will contain your test configurations (eg a test database).

Let's modify our JS setup as we'll be using VueJS to create our front-end views. Replace the contents of webpack.mix.js with this:

let mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
   .extract(Object.keys(require('./package.json').dependencies || []))
   .sass('resources/sass/app.scss', 'public/css')
   .version();

Modify package.json as shown below and run npm install.

{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.18",
        "bootstrap": "^4.3.1",
        "cross-env": "^5.1",
        "jquery": "^3.2",
        "laravel-mix": "^4.0.15",
        "popper.js": "^1.15.0",
        "resolve-url-loader": "^2.3.1",
        "sass": "^1.18.0",
        "sass-loader": "^7.1.0",
        "vue": "^2.6.10",
        "vue-template-compiler": "^2.6.10",
        "vue-trix": "^0.7.7"
    }
}

Delete the tests/Unit folder.

Install the event-sourcing library by typing composer require spatie/laravel-event-projector:^2.0.0 (requires >= PHP 7.3), and running php artisan vendor:publish --provider="Spatie\EventProjector\EventProjectorServiceProvider" --tag="migrations" and php artisan vendor:publish --provider="Spatie\EventProjector\EventProjectorServiceProvider" --tag="config"

Also install Laravel Passport (which we'll use for API authentication) using composer require laravel/passport.

Add the line below to the boot() method of app/Providers/AppServiceProvider.php  to force all URLs to use the HTTPS scheme. Without that, you might run into issues where assets try to load over HTTP.

if (config('app.env') === 'production') \URL::forceScheme('https');

We'll need a common layout for our views. Let's create resources/views/layouts/app.blade.php and paste the following template into it:

<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Address Book') }}</title>

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
  </head>
  <body>
    <div id="app">
      <nav class="navbar navbar-expand-md navbar-light navbar-laravel">
        <div class="container">
          @guest
          <a class="navbar-brand" href="{{ url('/') }}">
              {{ config('app.name', 'Address Book') }}
          </a>
          @else
          <a class="navbar-brand" href="{{ route('contacts') }}">
              {{ config('app.name', 'Address Book') }}
          </a>
          @endguest
          <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
              <span class="navbar-toggler-icon"></span>
          </button>

          <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <!-- Left Side Of Navbar -->
            <ul class="navbar-nav mr-auto">

            </ul>

            <!-- Right Side Of Navbar -->
            <ul class="navbar-nav ml-auto">
              <!-- Authentication Links -->
              @guest
                <li><a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a></li>
                <li><a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a></li>
              @else
                <li class="nav-item dropdown">
                  <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                      {{ Auth::user()->name }} <span class="caret"></span>
                  </a>

                  <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                    <a class="dropdown-item" href="{{ route('logout') }}"
                       onclick="event.preventDefault();
                         document.getElementById('logout-form').submit();">
                        {{ __('Logout') }}
                    </a>

                    <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                        @csrf
                    </form>
                  </div>
                </li>
              @endguest
            </ul>
          </div>
        </div>
      </nav>

      <main class="py-4">
          @yield('content')
      </main>
    </div>

    <script type="text/javascript" src="{{ asset('js/manifest.js') }}"></script>
    <script type="text/javascript" src="{{ asset('js/vendor.js') }}"></script>
    <script type="text/javascript" src="{{ asset('js/app.js') }}"></script>
  </body>
</html>


We're done with the preparatory steps. In the next article, we'll be implementing user accounts.

You can explore the changes here.