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.
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.
- Create the project.Run
npm create vue@latestand answer the prompts. Say yes to Vue Router and Pinia if you are building an app; TypeScript, ESLint and testing are optional. - Install dependencies.
cdinto the new folder and runnpm install. - Start the dev server.Run
npm run devand open the address it prints, usually http://localhost:5173. Changes appear in the browser as you save.
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:
<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.
<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 asname.value; in the template you just writename.computed()derives a value that updates automatically.v-modelbinds a form field to data in both directions.
The directives you will use most:
| Directive | Does | Example |
|---|---|---|
| v-if / v-else | Show or hide an element | v-if="loggedIn" |
| v-for | Repeat an element for each item | v-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-model | Two-way form binding | v-model="email" |
4. Props and events between components
A parent passes data down with props; a child sends messages up with events.
<!-- AppButton.vue -->
<script setup>
defineProps({ label: String })
const emit = defineEmits(['press'])
</script>
<template>
<button @click="emit('press')">{{ label }}</button>
</template><!-- 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.
// 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.
// 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:
// 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:
<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.
// 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.
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:
- Build locally.Run
npm run build, and setbaseinvite.config.jsif the app will live in a subfolder. - Upload the contents of
dist/topublic_html(or the subfolder) with File Manager or FTP. See What settings do I need to upload my website. - Add the SPA rewrite rulebelow as
.htaccessin the same folder, so links like/aboutwork when opened directly. - Check SSLis active, then test in a private window.
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.
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