Symfony advanced tutorial. Frontend setup and configuration. Part 3
3 min read

Symfony advanced tutorial. Frontend setup and configuration. Part 3

Symfony advanced tutorial. Frontend setup and configuration. Vue.js Vuex Vue Router, JWT authentication bundle configuration. Webpack encore bundle configuration.
Symfony advanced tutorial. Frontend setup and configuration. Part 3

In this part, I will set up Vue 3 and Vuex store and a JWT authentication bundle.
First of all, I need to install the Webpack encore bundle(plus MakerBundle):

composer require symfony/webpack-encore-bundle
composer require --dev symfony/maker-bundle
npm install
yarn install

Suppose you have it, cool. Now let's add Vue, Vuex store, and Vue Router.

npm install vue@next
npm install vue-router@next --save
npm install -D @vue/compiler-sfc
npm install -g @vue/cli
vue upgrade --next
npm install vuex@next --save
yarn add vue-loader@^16.1.0 --dev

Also, you can install chrome dev tools for VUE(it helps with debugging).

Now I need one more bundle for JWT authentication

composer require "lexik/jwt-authentication-bundle"

After installation, I need to generate SSL keys:

bin/console lexik:jwt:generate-keypair

And update security.YAML file with the following:

        login:
            pattern: ^/api/login
            stateless: true
            json_login:
                check_path: /api/login_check # or api_login_check as defined in config/routes.yaml
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
        api:
            pattern: ^/api
            stateless: true

I don't have a User Entity yet. Well, I can use FOSUserBundle, but it's too much for this kind of project. So I am going to create a simple user entity:

./bin/console make:user
User Entity

Next run migration:

php bin/console make:migration
$ php bin/console doctrine:migrations:migrate

At first, I wanted to use foundation, but when I saw that it uses jquery, I changed my mind and decided to go with the tailwind(strange? - maybe, but it is what it is).
Install Tailwind CSS

npm i tailwindcss postcss-loader autoprefixer

create postcss.config.js in the main folder:

let tailwindcss = require('tailwindcss');

module.exports = {
        plugins: [
            tailwindcss('./tailwind.config.js'),
            require('autoprefixer'),
            require('postcss-import')
        ]
}

Create tailwind.css file in /assets/styles/tailwind.css

@tailwind base;

@tailwind components;

@tailwind utilities;

update Webpack configuration with new tailwind CSS, add these lines:

    Encore
    //.......
    .enableVueLoader()
    .addStyleEntry('tailwind', './assets/styles/tailwind.css')
    // enable post css loader
    .enablePostCssLoader((options) => {
        options.postcssOptions = {
            config: './postcss.config.js'
        };
    })

Don't forget to update your base.html.twig file, add this:

        {% block stylesheets %}
            {{ encore_entry_link_tags('tailwind') }}
        {% endblock %}

Lets build our first component.

Now let's create a basic Vue project structure.

Please create the following folders and files in your assets/js folder:

Vue.js project structure

main.js - our entry js file.

import '../styles/app.css';
import {createApp} from 'vue';
import App from './App';
import router from './router/router';
import store from './store/index';


createApp(App)
    .use(router)
    .use(store)
    .mount('#app')

App.vue - the main component, for now, it's a pretty simple file:

<template>
  <div>
    <router-view>
      <home />
    </router-view>
  </div>
</template>

<script>
import Home from "./components/Home.vue";
export default {
  name: "App",
  components: {
    Home
  }
};
</script>

/router/router.js - contains our routes;  I created only one route but will add more later.

import Home from '../components/Home.vue'
import {createRouter, createWebHistory} from 'vue-router'

export default createRouter({
    history: createWebHistory(),
    routes: [
        {
            name: 'home',
            path: '/',
            component: Home
        }
    ]
})

store/index.js - Vuex store. Nothing special, I will show what we are going to do with this in the next chapter.

import {createStore} from 'vuex'

export default createStore({
    state() {
        return {
            data: 1
        }
    }
})

And of course our first component - Home.vue

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

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

One more thing, update your FrontendController Index action:

    #[Route('/', name: 'frontend')]
    #[Route('/{route}', name: 'vue', requirements: ['route' => '^.+'])]
    public function index(): Response
yarn encode dev --watch

Voila, and we are done!

In the next chapter, I will build a login/sign-up form with basic authentication.

Back to Part 2