Getting started with Vue 3 composition API in typescript with Laravel Mix from scratch

Laravel is one of the most loved web frameworks by the developers. It makes development so easier and fun. VueJs is one of the most loved JavaScript and rapidly growing Web Framework. This article will cover steps on implement Vue 3 in TypeScript with Laravel Mix and Composition API from scratch.
Let’s get started:
Many developers love TypeScript. The reason is it simplifies JavaScript code, as it adds the readability and writability and makes easier to debug. It gives us all the benefits of the modern JavaScript (ES6 & beyond) also can help us to avoid painful bugs that developers commonly run into when writing JavaScript by type checking the code.
We can start by scaffolding a new laravel app using the command:
laravel new laravue3-ts
Let’s get into this directory and install the required dependencies:
yarn add vue@next vue-loader@next @vue/compiler-sfc
yarn add ts-loader typescript --dev
Now, let’s generate a tsconfig.json
file in the root directory with the following contents on it. (Please refer to the official documentation https://v3.vuejs.org/guide/typescript-support.html#typescript-support.)
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
// this enables stricter inference for data properties on `this`
"strict": true,
"jsx": "preserve",
"moduleResolution": "node"
}
}
Now, let’s generate shims-vue.d.ts
file inside resources directory which stores the type defination for .vue files with the following content:
declare module '*.vue' { import type { DefineComponent } from 'vue' const component: DefineComponent<{}, {}, any> export default component}
Now, we need to make changes on our webpack.mix.js file:
const mix = require("laravel-mix");mix.ts("resources/js/app.ts", "public/js").vue({ version: 3 });
Now, let’s add a few components insides resources/js/components
directory:
Welcome.vue:
<template>
Hello {{ name }} welcome to my app.
<hr />
<counter></counter>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import Counter from "./Counter.vue";export default defineComponent({
components: {
Counter,
},
setup() {
const name = ref<string>("Bijaya");
return {
name,
};
},
});
</script>
Counter.vue:
<template>
<button @click.prevent="decrement">-</button>
{{ count }}
<button @click.prevent="increment">+</button>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";export default defineComponent({
name: "counter",
setup() {
const count = ref<number>(0);
const increment = ():number => {
return count.value++;
};
const decrement = ():number => {
return count.value--;
};
return {
count,
increment,
decrement,
};
},
});
</script>
Great, now that we have added the components, now lets rename the default resources/js/app.js
to app.ts
and update the contents to have following:
import { createApp } from "vue";
import Welcome from "./components/Welcome.vue";const app = createApp({
components: {
Welcome,
},
}).mount("#app");
Finally, let’s update the resources/welcome.blade.php
file with following contents:
<body>
<div id="app">
<welcome />
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
We are rendering a welcome component in the blade file which will show the welcome message along with a counter component that we added.
Now we can compile all of the assets using command: yarn dev
Boot the laravel server: php artisan serve
and then access: http://localhost:8000
which will render the following output:

Please watch my video on youtube for detailed explanation: