Create a Single Page Application with Symfony and Vue.js

December 18, 2018
Written by
Onwuka Gideon
Contributor
Opinions expressed by Twilio contributors are their own

symfony-vue-js-single-page-app-cover-photo.png

Symfony is one of the better PHP frameworks for speeding up the creation and maintenance of web applications. When coupled with Vue.js, a JavaScript framework for building user interfaces, Symfony becomes a major contender for powering sophisticated Twilio Single-Page Applications.

In this tutorial, I will walk you through how to set up a Symfony and Vue.js application coupled together for utilizing the Twilio API. Symfony will handle all the backend operations while Vue.js will take care of the frontend DOM rendering.

If you are building an app using the Twilio API, you will need to generate a token. At the end of this tutorial, you should be able to generate this token from our Symfony application.

Prerequisite

This tutorial uses the following:

Set up the Project

First, open up a terminal and make sure you have PHP installed by typing the below command:

$ php --version

This should print out the version of PHP you have installed, otherwise, you need to install PHP. We are using Symfony 4.2 to build this app which requires PHP 7.1 or higher to run. If you don’t have version 7.1 or above installed, you can view this tutorial to install/upgrade.

Next, make sure you have Composer installed on your machine:

$ composer --version

If the command does not print out the version of the Composer that you have installed, this means you need to install Composer. You can do that here.

Next, create a new folder that will contain the files of the project in any convenient location on your system and then change your directory to the folder:

$ mkdir symfony-vue && cd symfony-vue                                                                                                      

Create a Symfony Project

Next, initialize a Symfony project through Composer:

$ composer create-project symfony/website-skeleton .                                                                          

This will download some dependencies into the project folder and generate the basic directories and files we need to get started.

Now start the server:

$ php -S localhost:9030 -t public

If everything goes well, the app will now be accessible from http://localhost:9030. Open your browser and navigate to the URL. You should see a welcome page like so:





Remember not to close the terminal so that we can observe changes while we build. Open a new terminal and add a package that will enable us to use annotations to create our routes:
$ composer require annotations

Get your Twilio API keys

To start using the Twilio API, we need to get our API keys from our Twilio account.

We will need two values from our account:

If it doesn’t exist, create a new file named .env in the root folder of the project and then add the following API keys to it:

ACCOUNT_SID=Account SID
AUTH_TOKEN=AUTH TOKEN

Make sure to replace Account SID and AUTH TOKEN placeholders with your actual API keys. If you are using an API that requires more keys, you can add it to this file and reference it from the Symfony app.

Add Vue to the Project

By default, Vue is not added to the default installation. We need to add it ourselves. We will now include Vue in our project by using Weback via Symfony’s Webpack Encore wrapper; A simpler way to integrate Webpack into Symfony applications. Install WebPack Encore by executing the below command:

$ composer require encore

Next, install the dependencies:

$ yarn install

Now let’s install the required packages for Vue.js:

$ yarn add vue vue-loader@^15.0.11 vue-template-compiler --dev

Then update the webpack.config.js file as follows:

var Encore = require('@symfony/webpack-encore');

Encore
    // directory where compiled assets will be stored
    .setOutputPath('public/build/')
    // public path used by the web server to access the output path
    .setPublicPath('/build')
    .enableVueLoader()

    /*
     * ENTRY CONFIG
     *
     * Add 1 entry for each "page" of your app
     * (including one that's included on every page - e.g. "app")
     *
     * Each entry will result in one JavaScript file (e.g. app.js)
     * and one CSS file (e.g. app.css) if you JavaScript imports CSS.
     */
    .addEntry('app', './assets/js/app.js')
    //.addEntry('page1', './assets/js/page1.js')

    // will require an extra script tag for runtime.js
    // but, you probably want this, unless you're building a single-page app
    .enableSingleRuntimeChunk()

    /*
     * FEATURE CONFIG
     *
     * Enable & configure other features below. For a full
     * list of features, see:
     * https://symfony.com/doc/current/frontend.html#adding-more-features
     */
    .cleanupOutputBeforeBuild()
    .enableBuildNotifications()
    .enableSourceMaps(!Encore.isProduction())
    // enables hashed filenames (e.g. app.abc123.css)
    .enableVersioning(Encore.isProduction())
;

module.exports = Encore.getWebpackConfig();

We enabled the Vue loader by adding the .enableVueLoader() line so that any .vue file can be compiled.

Finally, run the dev server:

$ yarn encore dev-server --hot

Don’t close the terminal so that all changes we make to the .vue files will be detected and updated automatically.

Create the Single Page Application

We'll create a main component for the app to host our other components. We will name the file App.vue.

First, create a folder named components in the assets/js folder. Then, create a new file named App.vue in the components folder you just created. Then add a basic Vue component skeleton to the App.vue file:

<template>
   <!-- Your HTML tags-->
   <h2 class="center"> Ahoy! </h2>
</template>

<script>
   // Your JavaScript code
  console.log("Loaded")
</script>

<style>
  /* Your styles */
  .center {
     Text-align: center;
  }
</style>

This is the basic structure of what a single-file component looks like. We placed the HTML markup in the <template> section, our JavaScript code in the <script> section, and our styles will be in the <styles> section.

Next, include the component in the assets/js/app.js file:

import Vue from 'vue';
import App from './components/App';

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

In the code above, we first imported Vue. Then we required the App.vue component file we created. Lastly, we created a Vue instance to target an app element in the body of the HTML.

Create a Landing Page

We need a page where we can add our client interface. Create a new file named HomeController.php in the src/Controller folder and add the code below to it:

    // src/Controller/HomeController.php

    <?php
    
    namespace App\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\Routing\Annotation\Route;
    use Symfony\Component\HttpFoundation\Request;
    
    class HomeController extends AbstractController
    {
         /**
         * @Route("/")
         */
        public function index()
        {
            return $this->render('index.html.twig');
        }
    }

In the above code, we created a new route using the annotation @Route("/"), which will render an index.html.twig file in the templates folder.

NOTE: If you are getting an error similar to - “Namespace declaration statement has to be the very first statement in the script”, make sure there is no trailing space before the ‘<?php’ tag.

Next, update the base.html.twig file in the templates folder, which is the base layout with the markup below:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title>
        {% block stylesheets %}
            {{ encore_entry_link_tags('app') }}
        {% endblock %}
    </head>
    <body>
        {% block body %}{% endblock %}
        {% block javascripts %}
            {{ encore_entry_script_tags('app') }}
        {% endblock %}
    </body>
</html>

Next, create a new file named index.html.twig in the templates folder, and add the markup below to it:

{% extends 'base.html.twig' %}

{% block title %} Welcome !{% endblock %}
{% block body %}
<div class="example-wrapper" id="app">
    <app></app>
</div>
{% endblock %}

Note the <app></app> tag. This is the App.vue component we included in the assets/js/app.js file, which is going to render the part where Vue will watch over.

Now if you reload the app - http://localhost:9030, you will see that the page now renders the src/components/App.vue component with the message "Ahoy".

Install the Twilio PHP SDK

Most Twilio products come with a server-side SDK which is mostly used for generating tokens. Now let's add the PHP SDK. Install it via Composer using:

$ composer require twilio/sdk

With this, you can now generate a token using the key in the .env file. We are now ready to start building our Twilio-powered application.

Conclusion

In this tutorial, we created a Single Page Application with Symfony and Vue to support the creation of a Twilio app. You can now use the API Keys in the .env file to begin building with Twilio and signing API requests.

You can also get the complete code on GitHub.

Onwuka Gideon is a Full-stack Software developer with years of experience developing web applications. You can reach him on Twitter or Github.