Guide to setting up Vue 3 (with example snippets and configuration)

Table of contents

Vue 3.0 was (finally!) released a few weeks back. It is mostly compatible with the old Vue 2 way of doing things... but lots have changed.

I've created a sample app, along with the Vue 3 app source code on github.

The app is quite basic, and is meant just for demonstration purposes. I find tutorials and guides much easier to see when they have a bigger application to refer to, rather than just short snippets.

A quick guide to Vue 3's composition API

There are tons of guides on Vue 3's composition API. I am really excited to start using it in some projects (although I still have some reservations about how useful it will be - but I felt the same about React hooks - and they're really picked up in popularity)

In Vue 2 (and also in Vue 3 as you can still use the options api) you would probably be used to seeing things like this:

 // ...
 export default {
 data() {
   return {
     postTitle: 'a default title',    
   }
 },
 methods: {
    updateTitle(newValue) {
        this.postTitle = newValue;
    }
 },
 computed: {
    numWordsInTitle() {
        return this.postTitle.split(' ').length;
    }
 }
}

And then in your <template> you could reference those data/methods/computed properties:

<template>
 <h1>{{ postTitle }}</h1>
 <p>Post has {{ numWordsInTitle }} words</p>
 <button @click="updateTitle('something new')">Update to 'something new'</button>
</template>

To convert from that 'old' Vue 2 options API to using the Vue 3 composition API, you would instead do the following:

import {defineComponent, ref, computed} from 'vue';

export default defineComponent({
  name: 'BlogSummary',
  components: {},
  props: {
    post: Object,
  },
  setup(props) {
      const postTitle = ref('postTitle');
      const numWordsInTitle = computed(() => postTitle.value.split(' ').length);
      const updateTitle = (newValue) => postTitle.value = newValue;
  
      return { postTitle, numWordsInTitle, updateTitle }
  }
});

The <template>...</template> part would be the same as the above. Anything returned from setup()'s object will be available to use in the <template>.

There is much more that can be said about the composition API. But this is just a brief introduction.

Set up Vue 3 with Sass/SCSS

It is very easy to set up Sass with Vue 3, which I always prefer as it makes writing CSS a little nicer.

Basic setup of Sass in Vue 3 is quite easy: yarn add -D sass-loader sass. I have written more about setting up Sass in Vue 3 here (including global config)

Setting up Vuex in Vue 3

There are some arguments that vuex will not be needed as often, thanks to the (composition API in Vue 3)[/programming-tricks/vue3/vue3-guides/vue-3-composition-api/]. But I think for large applications it will still be a staple part of using Vue.

yarn add vuex

(I'm using 4.0.0, which works with Vue 3)

In your main.js or main.ts file you will need to set it up like this:

import { createApp } from 'vue'
import {createStore} from 'vuex'
import App from './App.vue'; // Your main component

const store = createStore({
    state: {
        posts: [],
    },
    getters: {
        allPosts(state) {
            return state.posts
        },
    },
    mutations: {},
    actions: {},
    modules: {}
})

createApp(App)
    .use(store) // << this is important
    .mount('#app')

Once you have your Vue 3 Vuex config set up, you just need to access the store in your Vue 3 components.

One way to do this is via the composition API:

import {computed, defineComponent} from 'vue';
import {useStore} from "vuex";

export default defineComponent({
  name: 'SinglePost',
  components: {},
  setup() {
    const store = useStore();
    const post = computed(() => store.getters.allPosts.find((post:any) => post.slug === route.params.slug))

    return {
      post,
    }
  },
});

For a more in depth example of using Vuex 4 in Vue 3, I recommend looking at the sample Vue 3 boilerplate app, which includes Vue 3 and Vuex config.

Setting up Vue Router in Vue 3

Vue router works well with Vue 3. To get started you must install it with: yarn add vue-router

Then update your main.ts or main.js to something like this:

import { createApp } from 'vue'
import App from './App.vue'
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import BlogIndex from "@/components/blog/views/BlogIndex.vue";

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'blog.index',
    component: BlogIndex, // without webpack code splitting
  },
  {
    path: '/post/:slug',
    name: 'blog.show',
    // with webpack code splitting (best for larger apps, it can lazy load then):
    component: () => import(/* webpackChunkName: "blog-show" */ '../components/blog/views/SinglePost.vue')
  },
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

createApp(App)
    .use(router) // << important!
    .mount('#app')

For a more in depth example of using vue router in Vue 3, I recommend looking at the sample Vue 3 boilerplate app, which includes Vue 3 and vue router.

Testing in Vue 3 with Vue Test Utils

Testing in Vue 3 with Vue Test Utils is largely similar as it was in Vue 2.

Here is an example of a Vue Test Utils test (using Jest) for a component in Vue 3 which uses <router-link> (Vue Router).

import {mount, RouterLinkStub} from "@vue/test-utils";
import {postFactory} from "@/components/blog/model/Post";
import YourComponent from "@/components/blog/components/YourComponent.vue";

it('emits "deletePost"', emitsDeletePost);

function emitsDeletePost(): void {
    const post = {slug: 'example-slug'};

    const $router = {
        push: jest.fn()
    }
    const $route = {
        params: {
            id: 1
        }
    }

    const wrapper = mount(YourComponent, {
        props: {post},
        global: {
            components: {
                RouterLink: RouterLinkStub
            },
            mocks: {$route, $router}
        }
    })

    const button = wrapper.get('button');
    button.trigger("click");

    expect(wrapper.emitted('deletePost')).toEqual([[post.slug]])
}

Using typescript in Vue 3

Vue 3 fully supports Typescript. The fact that it works so well now with Typescript is one of my favourite new things about Vue 3. It was always a bit hard to get everything typed correctly in Vue 2.

It is still possible to use plain Javascript with Vue 3, if you are not keen on Typescript.

For the configuration to set up Typescript in Vue 3 I would recommend looking at this tsconfig.json. You will also need to yarn add -D typescript (check out package.json in that repo).

Once set up, all you have to do is change <script> to <script lang="ts"> in your .vue files.

TODO - more details oon.

Comments Guide to setting up Vue 3 (with example snippets and configuration)