Fundamentals of Vue 3 Development

Creating a Vue 3 Project

Creating with Vue CLI

Vue CLI is currently in maintenance mode, and the official Vue documentation recommends creating new projects with Vite instead.

Creating with Vite

Vite is a next-generation frontend build tool that offers key benefits:

  • Hot module replacement for fast local development
  • Out-of-the-box support for TypeScript, JSX, and CSS
  • On-demand compilation, no need to wait for the entire application to build before starting development

To create a new project, run the following command in your terminal:

npm init vite@latest

Follow the interactive prompts to complete setup. You can also directly specify your project name and preferred template via command line flags. For a basic Vite + Vue project, run:

# npm 6.x
npm init vite@latest my-vue-app --template vue

# npm 7+ requires an extra double dash
npm init vite@latest my-vue-app -- --template vue

Project Structure for Vite + Vue + TypeScript

  • .vscode
    • extensions.json: VS Code extension recommendation for the project
  • public: Root directory for static assets that don't need processing
  • src: Project source code
    • main.ts: Entry file that imports global styles, mounts the root component to the DOM
    • App.vue: Root component of the application
    • components: Directory for reusable Vue components
    • assets: Directory for processed static assets (images, styles, etc.)
    • vite-env.d.ts: TypeScript declaration file for Vite-specific environment types
  • .gitignore: Git ignore rule configuration
  • index.html: Application entry HTML file
  • package-lock.json: Lock file for dependency versions
  • package.json: Project metadata and dependency manifest
  • README.md: Project introduction and documentation
  • tsconfig.json: TypeScript compiler configuration
  • vite.config.ts: Vite build tool configuration

Core Syntax: Composition API

Vue 2's Options API splits related logic across data, methods, computed, and other options, making it hard to maintain and reuse code when working on large features. Vue 3's Composition API lets you organize related code together logically using functions, improving maintainability for large projects.

The setup Option

setup is a new configuration option introduced in Vue 3, which must be a function. this is undefined inside the setup function, and setup runs before the beforeCreate lifecycle hook from Options API.

Basic usage example:

<script>
export default {
  name: 'UserProfile',
  setup() {
    // Define data and functions here
    let username = 'alex'; // Non-reactive data
    let userAge = 25;

    const updateName = () => {
      username = 'alex2'; // Changes will not trigger UI updates because data is not reactive
    }
    const incrementAge = () => {
      userAge += 1;
    }
    
    return {
      username,
      userAge,
      updateName,
      incrementAge
    }
  }
}
</script>

Vue 3 provides a <script setup> syntax sugar that automatically exposes all top-level variables declared in the script to the template:

<script lang="ts" setup>
// Define data and functions here
let username = 'alex'; // Non-reactive data
let userAge = 25;

const updateName = () => {
  username = 'alex2'; // Changes will not trigger UI updates
}
const incrementAge = () => {
  userAge += 1;
}
</script>

If you need to set a custom component name different from the file name when using <script setup>, follow these steps:

  1. Install the required Vite plugin
npm i vite-plugin-vue-setup-extend -D
  1. Add the plugin to your Vite configuration
import VueSetupExtend from 'vite-plugin-vue-setup-extend'

export default defineConfig({
  plugins: [VueSetupExtend()],
})

Reactive Data

ref: Create Reactive Primitive Values

ref is used to create reactive variables, the syntax is const variable = ref(initialValue). It returns a RefImpl instance (commonly called a ref object), and the value property of the ref object holds the reactive data.

Notes: You need to access the reactive value via variable.value in JavaScript/TypeScript, but you don't need .value directly in Vue templates. ref must be imported from vue first.

Example:

<script setup lang="ts">
    import { ref } from 'vue';

    const username = ref('alex');
    const userAge = ref(25);

    const updateName = () => {
        username.value = 'alex2';
    }
    const incrementAge = () => {
        userAge.value += 1;
    }
</script>

reactive: Create Reactive Reference Types

Use reactive() to wrap object/array/other reference types to get a reactive object. You can access and modify properties directly via object.property. It returns a Proxy instance wrapping the original object.

Notes: reactive provides deep reactivity out of the box, meaning nested properties are also reactive. The main limitation is that reassigning the entire variable to a new object will break reactivity. To work around this, update the existing reactive object with Object.assign(oldReactive, newObject) instead of replacing the variable.

Example:

const product = reactive({
    brand: 'Tesla',
    price: 39999
})
const increasePrice = () => {
    product.price += 1000;
}

ref for Reference Types

When you wrap a reference type with ref, it still returns a RefImpl instance, so you need to access properties via ref.value.property. Under the hood, ref automatically wraps the input reference type with reactive, so RefImpl.value equals the reactive Proxy instance.

Best Practices for Choosing Between ref and reactive

  • Use ref for reactive primitive values
  • Use either ref or reactive for shallow reactive objects
  • Use reactive for deeply nested reactive objects

Auto-Insert .value for ref in VS Code

To enable automatic .value insertion for ref variables, go to VS Code Settings > Extensions > Vue > check the Auto Insert: Dot Value option.

toRef and toRefs

toRefs converts all properties of a reactive object into individual ref variables. This lets you destructure a reactive object while preserving reactivity, and each destructured ref maintains a reference to the original property in the reactive object.

Syntax example:

// Destructure while preserving reactivity
const { name, age, gender, location } = toRefs(userData);

Computed Properties

Computed properties derive new values from existing reactive data. Key differences from regular methods:

  1. Computed properties cache their results based on their dependencies, and only recalculate when dependencies change
  2. Computed properties are reactive, while methods only execute when called
  3. Computed are ideal for derived values that benefit from caching, while methods are best suited for event handlers and one-off actions that don't need caching

Full example:

<template>
  <div class="profile-card">
    First name: <input type="text" v-model="firstName">
    Last name: <input type="text" v-model="lastName">
    Full name: <span>{{ fullName }}</span>
    <button @click="setDefaultFullName">Set Default Name</button>
  </div>
</template>

<script setup lang="ts" name="ProfileCard">
import { ref, computed } from "vue";

const firstName = ref("");
const lastName = ref("");

// Read-only computed
const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`;
});

// Read-write computed with getter and setter
const editableFullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`;
  },
  set(newVal: string) {
    const [first, last] = newVal.trim().split(" ");
    firstName.value = first;
    lastName.value = last;
  }
});

const setDefaultFullName = () => {
  editableFullName.value = "John Doe";
  console.log(editableFullName.value);
}
</script>

Tags: Vue 3 Frontend Development Vite TypeScript javascript

Posted on Thu, 10 Sep 2026 16:31:39 +0000 by playa4real