Symfony 4.3 + Vue + VueRouter = SPA

Rory Womack
4 min readJul 14, 2019

--

Recently while working on a project I found this tutorial by Aiden Koh. It is a wonderful integration of Vue with Laravel that should absolutely be read by anyone looking to make that implementation.

I found however when working on a personal project no such article which so concisely describes this same process when working with Symfony.

Assumptions

  1. A fundamental understanding of Symfony 4.3
  2. A fundamental understanding of Vue
  3. A fundamental understanding of Encore

Installing Symfony

First you will need to install the Symfony Client a wonderful tool that has been added in new versions of Symfony to negate the need for running commands via composer.

Head over to symfony.com and follow the instructions for your operating system.

Once you have installed the Symfony Client you will be able to create a new project.

$ symfony new --full my_project

Installing Encore

Symfony helpfully has access to a component called Encore which is a wrapper around webpack allowing you to easily integrate it into your project.

$ composer require symfony/webpack-encore-bundle

Make sure to run npm install after this process completes to install the required node modules that have been added to your package.json

Unfortunately Vue is not enabled by default but don’t worry it’s a relatively easy process to enable it.

Add the following to your webpack.config.js along with the rest of the enablers.

//enable VueJs
.enableVueLoader()

Once you have completed that addition you will need to install some npm modules to support it.

$ npm install vue-loader@^15.0.11 vue-template-compiler --save-dev
$ npm install @symfony/webpack-encore vue vue-router vuetify

This will enable Encore to understand and compile your Vue templates.

Twig Templates

First create your base template.

//templates/base.html.twig<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Home{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>

Next create your initial app template

//templates/app.html.twig{% extends 'base.html.twig' %}
{% block stylesheets %}
{{ encore_entry_link_tags('app') }}
{% endblock %}
{% block content %}
<div id="app">
</div>
{% endblock %}
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
{% endblock %}While this is a tutorial for an SPA it is important to remember that application demands change over time. Setting your templates up in this manner gives your application room to expand, for instance, into a collection of micro applications. It’s important in application development to be in the here and now but also remain flexible enough to meet future requirements.

Symfony Routing

In order to allow this to function as an SPA it is necessary to create a routing profile for Symfony to make sure that your Vue app is in control of the routing.

// config/routes.yamlindex:
path: /{wildcard}
controller: App\Controller\BaseController::index
requirements:
wildcard: .*

Base Controller

Now let’s create the controller referenced in the route above.

// src/Controller.BaseController.php<?php

namespace
App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class BaseController extends AbstractController
{
public function index()
{
return $this->render('app.html.twig');
}
}

With Symfony’s router now pointing to the template you created earlier it’s time to focus on Vue.

Modifying app.js

Add the following lines to your app.js file.

// assets/js/app.jsimport Vue from 'vue';
import Vuetify from 'vuetify';

import Routes from './routes.js';

import App from './views/App';

Vue.use(Vuetify);

const app = new Vue({
el: '#app',
router: Routes,
render: h => h(App),
});

export default app;

Directory Structure

Create a directory structure that looks like this.

|assets
|--js
| |--components
| |--layouts
| |--pages
| |--stores
| |--views

Vue Components

First create /assets/js/views/App.vue

<template>
<v-app>
<v-content>
<v-container fluid>
<router-view></router-view>
</v-container>
</v-content>
</v-app>
</template>

<script>
export default {
name: "App"
}
</script>

<style scoped>

</style>

This will be the primary point of access to your Vue application.

Now create /assets/js/components/Home.vue

<template>
<div>
Home
</div>
</template>

<script>
export default {
name: "Home"
}
</script>

<style scoped>

</style>

Vue Router Setup

Create /assets/js/routes.js

import Vue from 'vue';
import VueRouter from 'vue-router';

import Home from './components/Home';

Vue.use(VueRouter);

const router = new VueRouter({
mode: 'history',
routes:[
{path:'/', name:'home', component:Home}
]
});

export default router;

This will give you access to you initial component and this pattern should be observed when adding additional routers.

In order to access your routes from any component add the following code

<router-link to="<my_route>">My Component</router-link>

Compiling and Watching

During development to save time you can ask Encore to watch your javascript for changes with the following command

$ npm run watch

Depending on whether or not you are compiling for development or production deployment run one of the following two commands.

$ npm run dev$ npm run build

Symfony Web Server

Finally run the symfony webserver and navigate to http://127.0.0.1:8000 in your browser

$ symfony server:start

You should see the following if you have done everything correctly:

Let me know what you think in the comments!

--

--

Rory Womack

A software developer with 10 years of experience in online advertisment, government applications, and healthcare related communications and billing.