Deploying a Vue single page app on Laravel Forge

Up until recently, our workflow for building a web application has been the following:

  1. Install a fresh new Laravel project
  2. Use the ‘built in’ approach for adding specific frontend behavior with Vue

This basically means that all routing is performed by Laravel and we apply our Javascript on the html generated by the blade views. You can read more about this setup in our post here. Although this is perfectly fine for Laravel applications needing only a little JS behaviour, this approach does not scale well. When the app grows we need to split the client side app into a single page application (SPA), and a server-side part (the API).

Photo by Malte Wingen on Unsplash

In this post I will explain our current setup for a SPA and how we can deploy the app to a server using Laravel Forge. We use Laravel Forge since we use a separate Laravel installation as API which is also deployed using Laravel Forge.

Quick setup of the Vue SPA using Vue CLI 2.x

We use the vue-cli (command line interface) to quickly scaffold the app. I assume you have vue-cli installed globally. If not you can do so by running

npm install -g vue-cli

The vue-cli gives you the init command. Passing it a template (official templates can be found on Github) and a project name (my-project) is all we need to do. Here we choose the widely used webpack template. This sets up everything (Webpack, hot-reload, eslint, unit tests, end-to-end tests and css extraction) for a seamless developer experience. Run the following command

vue init webpack my-project

A series of configuration questions are asked and you can choose whether you need unit tests, integration of ESLint and so on. In the last step you can choose for automatics or manual install of all project dependencies. Choosing manual, you need to run

npm install

to install all dependencies. Then run the development build by executing

npm run dev

Your app is now running locally on http://localhost:8080.

Quick setup of the Vue SPA using Vue CLI 3.x

Recently (Aug 10, 2018), the completely rewritten version of the Vue CLI was released. The new version not only has way more features (including a nice UI in which you can create projects away from the command line), the command to instantiate a new project also slightly changed.

However, first things first, we have to install this new tool. Since it replaces the old version, the installation docs tell us to uninstall the old one first. Hence we run

npm uninstall -g vue-cli npm install -g @vue/cli

To start a new project we simple use the command

vue create my-project

You no longer need to choose a template though since you’ll be prompted to add the features that were previously added to those templates. Simply follow the steps in your command line tool or have a look at the vue create docs.

Once all dependencies are installed, execute the serve component

npm run serve

to compile the app and run it in the browser.

Nice URLs with Vue Router

We use the official Vue Router module for client side routing in the SPA. Out of the box, we have ugly, non SEO friendly URLs with a hash (#) in it. Vue Router makes it easy for us to fix this, but first an intermezzo.

From here I assume you have setup a single page app with a couple of pages and routing via Vue Router!

Configuring Vue Router for nice URLs

To fix the ugly URLs, we need to achieve the following:

  1. Configure Vue Router to use history mode
  2. Add a catch-all fallback route by correctly configuring the server (easier than it sounds!)
  3. Add a catch-all route in the Vue SPA and the corresponding NotFound component.

The first step is a one-liner in router/index.js. You simply add a property to the options object passed to initialize the Router.

// router/index.js 
export default new Router({ 
mode: 'history',

// your routes here

The second step will be treated in the next section when we deploy the app using Laravel Forge.

The third step includes adding a new route to Vue Router, with path: ‘*’ and component ‘NotFound’. Don’t forget to create and import the NotFound component.

// router/index.js 
import Vue from 'vue' 
import Router from 'vue-router'
import Home from '@/components/Home'
import About from '@/components/About'
// Don't forget to import NotFound component 
import NotFound from '@/components/NotFound'
export default new Router({ 
mode: 'history',
routes: [
path: '/',
name: 'home',
component: Home
path: '/about',
name: 'about',
component: About
path: '*',
component: NotFound

Steps for deployment on Laravel Forge

So we have our simple SPA with 2 ‘normal’ pages and a 404 page. You can navigate from the home page to the other one and back and the URL is updated instantly. Try typing a URL that doesn’t exist and make sure that the 404 page is displayed. In addition, navigate forward and backward using the browser’s forward and backward arrows and make sure the URLs are updated as well.

Next it is time to deploy our SPA to production, hence configuring Laravel Forge:

  1. Setup a new site in Laravel Forge
  2. Create the deploy script
  3. Deploy the app

Setup a new site in Laravel Forge

Once you are logged in on your Laravel Forge account, select the desired server. We assume you already have a server setup (setting it up is outside the scope of this post, but we discussed it before on our blog). Then fill out the form at ‘New Site’ as you see in the image below. That is, enter your domain and don’t forget to change the Web Directory from /public to /dist.

The site appears under Active Sites. Click on it and configure the git repository which will be deployed. Once the repository is installed, we have to add the deploy script.

However, as a short sidestep, let’s install an SSL certificate right away. This secures the site and it is free!

Click the menu item SSL from the vertical menu. Choose ‘LetsEncrypt (Beta)’ and let the certificate install and activate itself. In the overview of sites for this server you will see the green lock: site secured!

Deploy script

The deploy script is quite simple. It pulls the code from the online repository (Github/ Bitbucket), installs the dependencies and runs the production build.

cd /home/forge/ 
git pull origin master
npm install
npm run build

However, we still need to “Add a catch-all fallback route by correctly configuring the server”. According to the Vue Router docs, for a Nginx server we just have to add a single line to the nginx configuration file

location / { 
try_files $uri $uri/ /index.html;

Open the Nginx configuration file by clicking on the grey button ‘files’ at the bottom of the page and choose ‘edit nginx configuration’

Halfway the file you see the location block. Replace it with the one above and save the file.

Finally, we have to restart the server to make sure the new configuration will be used. This is done on the server level in Forge, using the grey restart button on the bottom of the page. Just hit ‘Restart Nginx’.

Now you can safely deploy your app by clicking the green button “Deploy now”.

Concluding remarks

In this post we explained how to deploy a Vue SPA through Laravel Forge. We showed how to quickly setup the Vue SPA with nice URLs using the built-in Vue Router module and how to setup the Laravel Forge server for deployment.

Originally published at on September 19, 2018.