Frontend Development

Vue.js: A Beginner to Advanced Guide for Progressive Web Apps

By the Domain India teamPublished 8 min read
Knowledge base article
Contents (9 sections)

Vue.js is a JavaScript framework for building user interfaces, from a single interactive widget on an existing page to a full single-page application (SPA) or an installable progressive web app (PWA). This guide uses Vue 3 and today's standard tools: create-vue with Vite, the Composition API, Vue Router and Pinia. It ends with how to build your app and put it online.

Key takeaways

Start a Vue 3 project with npm create vue@latest (Vite-based; Vue CLI is in maintenance mode). Write components with script setup and the Composition API, use Vue Router for pages and Pinia for shared state, and add PWA features with vite-plugin-pwa. npm run build produces static files you can upload to any web host, with one rewrite rule for SPA routing.

1. What Vue is good for

Vue is "progressive": you can add it to one part of a page, or build an entire app with it.

  • Interactive widgets on existing sites: calculators, filters, forms.
  • Single-page apps: dashboards, admin panels, customer portals.
  • Progressive web apps: apps that install to a phone's home screen and keep working on a poor connection.

Vue was created by Evan You and first released in 2014. Vue 3 is the current major version; Vue 2 reached end of life at the end of 2023, so new projects should not use it.

2. Set up a project

You need a current Node.js LTS release (22 or 24) on your own computer. See Installing Node.js and npm on your local machine.

  1. Create the project.
    Run npm create vue@latest and answer the prompts. Say yes to Vue Router and Pinia if you are building an app; TypeScript, ESLint and testing are optional.
  2. Install dependencies.
    cd into the new folder and run npm install.
  3. Start the dev server.
    Run npm run dev and open the address it prints, usually http://localhost:5173. Changes appear in the browser as you save.
Vue CLI and Vuex are legacy

Older tutorials use vue create (Vue CLI), npm run serve and Vuex. Vue CLI is in maintenance mode and Vite replaced it; Pinia is the official state library. Use create-vue and Pinia for new work.

For a quick experiment with no build step, you can also load Vue from a CDN in a plain HTML file:

html
<div id="app">{{ message }}</div>
<script type="module">
  import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.prod.js'
  createApp({
    setup() {
      const message = ref('Hello, Vue!')
      return { message }
    }
  }).mount('#app')
</script>

3. Core ideas: components, reactivity and templates

A Vue app is made of single-file components (.vue files) that hold a template, logic and styles together. With a script setup block, anything you declare is available in the template.

vue
<script setup>
import { ref, computed } from 'vue'

const name = ref('')
const count = ref(0)
const greeting = computed(() => name.value ? `Hello, ${name.value}!` : 'Type your name')
</script>

<template>
  <input v-model="name" placeholder="Your name" />
  <p>{{ greeting }}</p>
  <button @click="count++">Clicked {{ count }} times</button>
</template>
  • ref() makes a value reactive: when it changes, the page updates. In the script you read it as name.value; in the template you just write name.
  • computed() derives a value that updates automatically.
  • v-model binds a form field to data in both directions.

The directives you will use most:

DirectiveDoesExample
v-if / v-elseShow or hide an elementv-if="loggedIn"
v-forRepeat an element for each itemv-for="item in items" :key="item.id"
v-bind (short :)Bind an attribute to data:src="imageUrl"
v-on (short @)Listen for an event@click="save"
v-modelTwo-way form bindingv-model="email"

4. Props and events between components

A parent passes data down with props; a child sends messages up with events.

vue
<!-- AppButton.vue -->
<script setup>
defineProps({ label: String })
const emit = defineEmits(['press'])
</script>

<template>
  <button @click="emit('press')">{{ label }}</button>
</template>
vue
<!-- Parent -->
<AppButton label="Save" @press="saveForm" />

5. Pages with Vue Router

Vue Router maps URLs to components, so moving between pages does not reload the browser.

js
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

export default createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: HomeView },
    { path: '/about', component: () => import('../views/AboutView.vue') },
  ],
})

The arrow-function import loads the About page only when someone visits it, which keeps the first download small. createWebHistory() gives clean URLs like /about, which need one server rule when you deploy (section 8).

6. Shared state with Pinia

When several components need the same data, such as a cart or the signed-in user, put it in a Pinia store.

js
// src/stores/cart.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCartStore = defineStore('cart', () => {
  const items = ref([])
  const total = computed(() => items.value.reduce((sum, i) => sum + i.price, 0))
  function add(item) { items.value.push(item) }
  return { items, total, add }
})

Any component can then call const cart = useCartStore() and use cart.add(...) and cart.total.

7. Reusing logic: composables and directives

Composables replace the old mixins. A composable is a function that uses Vue's reactivity and returns what a component needs:

js
// src/composables/useFetch.js
import { ref } from 'vue'

export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)
  fetch(url)
    .then(r => r.ok ? r.json() : Promise.reject(r.status))
    .then(json => (data.value = json))
    .catch(e => (error.value = e))
  return { data, error }
}

Custom directives handle low-level DOM behaviour. Inside a script setup block, any variable named vSomething becomes the directive v-something:

vue
<script setup>
const vFocus = { mounted: (el) => el.focus() }
</script>

<template>
  <input v-focus />
</template>

8. Turn it into a progressive web app

A PWA needs a web app manifest, a service worker and HTTPS. With Vite, the vite-plugin-pwa package generates both files for you.

js
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
  plugins: [
    vue(),
    VitePWA({
      registerType: 'autoUpdate',
      manifest: {
        name: 'My Vue App',
        short_name: 'VueApp',
        theme_color: '#1f6feb',
        icons: [
          { src: 'icon-192.png', sizes: '192x192', type: 'image/png' },
          { src: 'icon-512.png', sizes: '512x512', type: 'image/png' },
        ],
      },
    }),
  ],
})

Install it with npm install -D vite-plugin-pwa, put the icons in public/, and rebuild. Test in Chrome DevTools under Application › Manifest and Service workers, and run a Lighthouse check.

Service workers need HTTPS

Browsers only register service workers on HTTPS (or localhost). Make sure SSL is active on your domain before you test installation on a phone.

9. Build and deploy on Domain India

Run npm run build on your own computer. Vite writes a dist/ folder of plain HTML, CSS and JavaScript. A front-end-only Vue app is static, so it runs on any Domain India shared hosting plan:

  1. Build locally.
    Run npm run build, and set base in vite.config.js if the app will live in a subfolder.
  2. Upload the contents of dist/
    to public_html (or the subfolder) with File Manager or FTP. See What settings do I need to upload my website.
  3. Add the SPA rewrite rule
    below as .htaccess in the same folder, so links like /about work when opened directly.
  4. Check SSL
    is active, then test in a private window.
apache
RewriteEngine On
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

mod_rewrite is loaded and .htaccess is allowed on our cPanel, DirectAdmin and Webuzo servers. On cPanel, a front-end cache can keep serving the previous index.html for up to two hours after you upload a new build; add ?t=123 to the address to check the new version.

Need a back end? A Node.js API (Express, Fastify, Nest) fits the App Platform, which detects Node.js apps automatically; see Getting started with the App Platform. Shared hosting can also run Node.js apps through the panel's Node.js tool; see Deploy a Node.js app on shared hosting. For full control, a VPS is self-managed with root access.

Should I use Vue CLI or Vite for a new Vue project?

Use Vite through create-vue, by running npm create vue@latest. Vue CLI is in maintenance mode and is not recommended for new projects.

Should I use Vuex or Pinia?

Pinia. It is the official state management library for Vue 3, with a simpler API and full TypeScript support. Vuex is only for maintaining older apps.

Options API or Composition API?

Both work in Vue 3. The Composition API with script setup is the recommended default for new code because it makes logic easier to reuse through composables.

How do I make a Vue app a PWA?

Add vite-plugin-pwa to your Vite config with a manifest and icons, rebuild, and serve the app over HTTPS. The plugin generates the service worker and manifest for you.

Why do my Vue routes show a 404 after I upload the app?

With history mode, the server must send every unknown path to index.html. On Apache hosting, add an .htaccess rewrite rule that serves index.html when the requested file or folder does not exist.

Can I host a Vue app on Domain India shared hosting?

Yes. Build it locally with npm run build and upload the contents of the dist folder to public_html. A Node.js back end can run on the App Platform or through the panel's Node.js tool.

Ready to put your Vue app online? Upload the build to cPanel hosting, or deploy its Node.js API on the App Platform.

Put your Vue app online

Static Vue builds run on any shared hosting plan, and Node.js back ends deploy on the App Platform with free SSL.

See the App Platform

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app
Vue.js 3 Guide: Vite, Pinia, Router and PWA | Domain India