DEV Community

Cristian Pallarés
Cristian Pallarés

Posted on • Edited on

Create a SPA with Laravel and Nuxt

In this tutorial we'll use Laravel as an API and Nuxt as a Single Page Application. They can work together, but it's not an easy task at first. If you already tried, getting HMR to seamlessly work is a pain! For that reason I created laravel-nuxt and laravel-nuxt-js.

There are more reasons to use these packages, such as when using Laravel Passport and the CreateFreshApiToken. The middleware will create an api_token cookie on web routes that use the get http verb, and that's a problem if you're not serving your SPA from within Laravel.

Getting started

Install Laravel

Let's start with fresh new Laravel installation:

composer create-project laravel/laravel spa
Enter fullscreen mode Exit fullscreen mode

Go inside the spa directory with your terminal.

Install laravel-nuxt (for PHP)

# cd spa
composer require pallares/laravel-nuxt
Enter fullscreen mode Exit fullscreen mode

This package will be autodiscovered. If you're using old versions of Laravel, just add the service provider in config/app.php file:

<?php
return [
    // ...
    'providers' => [
        // ...
        Pallares\LaravelNuxt\LaravelNuxtServiceProvider::class,
    ],
];
Enter fullscreen mode Exit fullscreen mode

Add a fallback route that will render the SPA page in routes/web.php file. Be sure to remove the default route that comes with the framework:

<?php
// Route::get('/', function () {
//     return view('welcome');
// });

Route::get(
    '{uri}',
    '\\'.Pallares\LaravelNuxt\Controllers\NuxtController::class
)->where('uri', '.*');
Enter fullscreen mode Exit fullscreen mode

Now, your backend is ready to serve the compiled assets that Nuxt will generate for you. Every route that would return a 404 now will serve our SPA page.

Install laravel-nuxt (for JS)

It's time to install the JS package. Replace your package.json file with this:

{
    "private": true,
    "scripts": {
        "start": "laravel-nuxt dev",
        "build": "laravel-nuxt build"
    },
    "dependencies": {
        "laravel-nuxt": "^1.0.0"
    }
}
Enter fullscreen mode Exit fullscreen mode

Install the dependencies:

npm install
Enter fullscreen mode Exit fullscreen mode

The laravel-nuxt package will install Nuxt for you, along with Vue, vue-router, @nuxtjs/axios, etc. Let's create the nuxt.config.js file:

const laravelNuxt = require("laravel-nuxt");

module.exports = laravelNuxt({
  // Options such as mode, srcDir and generate.dir are already handled for you.
  modules: [],
  plugins: [],
});
Enter fullscreen mode Exit fullscreen mode

From now on, Nuxt will look for the source files in the resources/nuxt directory.

Create a hello world route in resources/nuxt/pages/index.vue:

<template>
  <h1>Hello {{ name }}!</h1>
</template>

<script>
export default {
  data: () => {
    return { name: 'world' };
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

Finally, run:

npm start
Enter fullscreen mode Exit fullscreen mode

Go to http://localhost:8000. You should see this: hello-world-picture

That's it! Laravel artisan's server and Nuxt's dev server are up and working together transparently. Try editing your home page now, it's very enjoyable to see the live reload in action.

Under the hood, Nuxt's dev server is proxying every call to the Laravel's server, including the SPA rendering. Since @nuxtjs/axios module is included (and proxied, too), you can make API calls normally.

Calling the API from the SPA

The SPA will surely need to call our API, so let's add a route to routes/api.php to retrieve the user information:

<?php
Route::get('me', function () {
    // Let's return fake information.
    return [
        'name' => 'John Doe',
    ];
});
Enter fullscreen mode Exit fullscreen mode

Now, edit resources/nuxt/pages/index.vue:

<template>
  <h1>Hello {{ user.name }}!</h1>
</template>

<script>
export default {
    // https://github.com/nuxt-community/axios-module
    async asyncData({ app }) {
        const user = await app.$axios.$get('api/me');
        return { user };
    },
};
</script>
Enter fullscreen mode Exit fullscreen mode

Voila! Your page should now look like this!

api-call-picture

In order to keep the tutorial simple, we aren't using any kind of authentication here. Integrating Passport should be almost trivial here.

Deployment

If you want to deploy your application, just run npm run build. The compiled assets will be placed in the public/_nuxt directory.

You can preview your final app with the well known artisan command php artisan serve.

You may want to add the .nuxt and public/_nuxt directories to your .gitignore.

Final thoughts

This is my first tutorial. I hope everything is clear and concise! Please, don't hesitate to ask questions here or create issues in the laravel-nuxt repositories. Thanks!

Latest comments (55)

Collapse
 
huypham55 profile image
Phạm Đức Huy • Edited

It's not working for me. When I run npm start and open localhost:8000, it shows Error occured while trying to proxy to: 127.0.0.1:8000/ . There was no other process that occupying that port. What could be the problem? ([HPM] Error occurred while trying to proxy request /favicon.ico from 127.0.0.1:8000 to 127.0.0.1:8001 (ECONNREFUSED) (nodejs.org/api/errors.html#errors_...)

Collapse
 
kousar2334 profile image
Kousar Rahman

Hi I have build a application with laravel + nuxt js using pallares/laravel-nuxt package but after deploy this app it take too much time to load and show a preloader , how speed up this app .
this this the app url :
zanaj.com

Collapse
 
jenueldev profile image
Jenuel Oras Ganawed

any update on this? for 2021?

Collapse
 
ramirezfer772 profile image
ramirezfer772

Hi, I'm having a problem compiling tailwind runnning npm run build, however I can see all the tailwind stuff with nuxt running npm start, I configured the nuxt.config.js file with buildModules: ['@nuxtjs/tailwindcss'], but unable to compile tailwind in the public/_nuxt, Do you have any idea how to have tailwind styles in with npm run build? Thank you, amazing work anyway.

Collapse
 
tol64 profile image
Anatoli

If I add the universal mode to the nuxt.config.js file, the spa mode still remains when the application starts (npm run start).

What does it take to get the SSR to turn on?

Collapse
 
keetamhoang profile image
keetamhoang

hello, Have you solved this problem yet?

Collapse
 
jamalroger profile image
BELHARRADI JAMAL

how to use mutiple nuxt projects ??

Collapse
 
skyrpex profile image
Cristian Pallarés

The package targets one Nuxt project per Laravel API. I suggest using Laravel Sanctum now, which handles SPA authentication for you easily (with support for any number of projects).

Collapse
 
lordroseman profile image
lordroseman

Hi, why I cant add vuetify in this laravel-nuxt? After I follow your instructions, I added nuxt/vuetify by running:

"npm install @nuxtjs/vuetify -D" 

then I add the buildModules in nuxt.config.js it looks like this:

const laravelNuxt = require("laravel-nuxt");

module.exports = laravelNuxt({
    // Options such as mode, srcDir and generate.dir are already handled for you.
    modules: [],
    plugins: [],
    buildModules: [
        // Simple usage
        '@nuxtjs/vuetify',
    ]
});


`

then I run: npm start and it gives me error:

`

[laravel] Laravel development server started: http://127.0.0.1:8001
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ start: `laravel-nuxt dev`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\HP\AppData\Roaming\npm-cache\_logs\2020-02-15T04_21_37_327Z-debug.log

What did I do wrong? Can you please help me? Thanks! :D

Collapse
 
thisisntmyid profile image
ThisIsntMyId

Can I still use this in 2019?

Collapse
 
renztoygwapo profile image
Florence Comajes

is it fully support on deploying to vapor ?

Collapse
 
skyrpex profile image
Cristian Pallarés

I think it should work out of the box, providing that you run the build script.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.