Creating a project template using Laravel, Vue 3 and Tailwind - Part 1

Nolan Nordlund

Nolan Nordlund

Laravel has recently added a couple cool new tech stacks to the ecosystem, Livewire and Inertia. Both have a lot of potential and can be great next steps for people looking to get some more interactivity in their Laravel projects but who may feel that a full fledged JS framework is daunting. About a year before Laravel introduced the new stacks, I decided to take the plunge on Vue. Even with great options like Livewire and Inertia, I would highly recommend a Vue deep dive.

Since learning Vue, I have found myself doing lots of tinkering on fun weekend ideas. Often a new idea means a fresh install and rather than spending all of my tinkering time installing packages and setting up build processes, I decided my next tinkering project would be a series of Laravel + Vue 3 templates. For the most basic of ideas, all I really want is Laravel with Vue integrated. Often times I'm using a project like this to test a new technique or package rather than actually work on an app idea. If I want to rapidly prototype a simple app and I'm not too concerned about the UX of the project, I'll add a simple authentication system and testing tools. And finally for the projects that I think might actually turn into something useful, I like to set up a SPA.

I'll show you how I put each of my project templates together and you'll find links to the Github repos if you would rather just download it and get started with one of your own creations.

Setting up a basic project template

The goal here is to have something that I can clone and immediately have access to some of the basic tools that I want in all of my projects. Again, the uses for this basic template are just experimenting with new techniques or packages so my needs are pretty low.

Installing Laravel

Let's start with a fresh install of Laravel. If you have the installer, it is incredibly simple.

laravel new template

If you don't have the Laravel installer, check out the docs to get started.

Integrating Vue 3

While Vue 3 was officially release back in September of 2020, it still needs to be installed using the next tag.

npm install vue@next

Now that we have added Vue to our project, we'll create an instance and mount it to one of our blade templates.

// resources/js/app.js
require("./bootstrap");

import { createApp } from "vue";

const app = createApp({});

app.mount("#app");
// resources/views/welcome.blade.php
...
<body>
    <div id="app" class="flex items-center bg-gray-100 min-h-screen">

    </div>
    <script src="{{ asset('js/app.js') }}"></script>
</body>
...

We'll need to also update our JS build process to correctly process our Vue 3 files. I prefer using BrowserSync when I'm developing and Laravel Mix makes it simple to add. We'll make use of the APP_URL setting in the .env file.

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

mix.browserSync({
    proxy: process.env.APP_URL,
    notify: false
});
mix.js('resources/js/app.js', 'public/js').vue();
mix.postCss('resources/css/app.css', 'public/css', [
        //
    ]);

Run the build and we'll have a functioning Vue instance but we won't see anything just yet. Mix will likely also install some extra packages and need to be ran a second time.

npm install && npm run dev

Next we'll add a simple component so we have something to display. Create a new folder for components in resources/js and then we'll create our simple component, Home.vue.

// resources/js/components/Home.vue
<template>
    <div>
        <h1>
            Basic template
        </h1>
        <p>
            Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ad, expedita? Officiis autem, omnis hic similique facere tempora culpa animi quisquam commodi illum sapiente error fugiat? Nobis, architecto? Sapiente, laborum sint!    
        </p>
    </div>
</template>

<script>
export default {};
</script>
// resources/js/app.js
require("./bootstrap");

import { createApp } from "vue";
import Home from "./components/Home.vue";

const app = createApp({
  components: {
    Home
  }
});

app.mount("#app");
// resources/views/welcome.blade.php
...
<body>
    <div id="app" class="flex items-center bg-gray-100 min-h-screen">
        <home />
    </div>
    <script src="{{ asset('js/app.js') }}"></script>
</body>
...

Adding TailwindCSS for styling

For the fastest prototyping, TailwindCSS is an excellent choice to style our views. It is a utility framework which might feel wrong if you strive to minimize the number of classes you use in your HTML. If try it, I'm sure you'll love it. It is what I used to build my site as well as several others. As a developer with mostly backend experience, Tailwind really helped to demystify all things CSS.

One of Tailwind's most powerful features is the advanced configuration and theme customization. We can install and get a basic setup with the following commands.

npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwind init

You'll have a tailwind.config.js file in the root of your project for you to customize tailwind to your heart's content. One more update for webpack and we'll add the Tailwind styling to our app.css file.

// webpack.mix.js
...
mix.postCss('resources/css/app.css', 'public/css', [
        require('tailwindcss'),
    ]);
// resources/css/app.css
@tailwind base;
@tailwind components;
@tailwind utilities;

The welcome view comes with some styles defined directly inside of style tags within the head of the view. Remove the styles and replace them with a link to our app.css file.

// resources/views/welcome.blade.php
...
<head>
    ...
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    ...
</head>
...

Finally, let's make some updates to the styling of our Home component.

// resources/js/components/Home.vue
<template>
    <div class="w-1/2 bg-white rounded-lg shadow-lg mx-auto p-4">
        <h1 class="text-2xl text-gray-700 text-center mb-4">
            Home component
        </h1>
        <p>
            Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ad, expedita? Officiis autem, omnis hic similique facere tempora culpa animi quisquam commodi illum sapiente error fugiat? Nobis, architecto? Sapiente, laborum sint!
        </p>
    </div>
</template>

<script>
export default {};
</script>

Conclusion and next steps

Overall, pretty simple but it is nice to save the steps ever time we want to do some experimenting. You can grab the source from Github for yourself. Next time, we'll add Laravel Breeze for some simple authentication and set up our TDD workflow as well.