<div id="app">{{ message }}</div> <script src="https://unpkg.com/vue@3"></script> <script> const app = Vue.createApp({ data() { return { message: 'Hello Vue!' } } }).mount('#app') </script>1.2 Vue.js Features
<template> <div>{{ greeting }}</div> </template> <script> export default { data() { return { greeting: 'Vue is reactive!' } } } </script>1.3 Setting up Vue.js
<!-- CDN setup --> <script src="https://unpkg.com/vue@3"></script> <div id="app">{{ message }}</div>1.4 Vue Instance
<script> const app = Vue.createApp({ data() { return { count: 0 } }, methods: { increment() { this.count++ } } }).mount('#app') </script>1.5 Template Syntax
<div id="app"> <p>{{ message }}</p> <button v-on:click="sayHi">Say Hi</button> </div> <script> const app = Vue.createApp({ data() { return { message: 'Hello!' } }, methods: { sayHi() { alert(this.message) } } }).mount('#app') </script>1.6 Data Binding
<div id="app"> <input v-model="name" placeholder="Enter name"> <p>Hello, {{ name }}!</p> </div> <script> const app = Vue.createApp({ data() { return { name: '' } } }).mount('#app') </script>1.7 Directives
<ul> <li v-for="item in items" :key="item.id">{{ item.name }}</li> </ul> <script> const app = Vue.createApp({ data() { return { items: [ { id: 1, name: 'Apple' }, { id: 2, name: 'Banana' } ] } } }).mount('#app') </script>1.8 Event Handling
<button @click="increment">Clicked {{ count }} times</button> <script> const app = Vue.createApp({ data() { return { count: 0 } }, methods: { increment() { this.count++ } } }).mount('#app') </script>1.9 Computed Properties
<div>Full Name: {{ fullName }}</div> <script> const app = Vue.createApp({ data() { return { firstName: 'John', lastName: 'Doe' } }, computed: { fullName() { return this.firstName + ' ' + this.lastName } } }).mount('#app') </script>1.10 Lifecycle Hooks
<script> const app = Vue.createApp({ data() { return { message: 'Hi' } }, mounted() { console.log('Component mounted!') } }).mount('#app') </script>
<template> <div>Hello from a component!</div> </template> <script> export default { name: 'MyComponent' } </script>2.2 Registering Components
<script> const MyComponent = { template: '<div>Hi!</div>' } Vue.createApp({}) .component('my-component', MyComponent) .mount('#app') </script>2.3 Props
<template> <div>Hello, {{ name }}!</div> </template> <script> export default { props: ['name'] } </script>2.4 Emitting Events
<template> <button @click="$emit('increment')">Increment</button> </template>2.5 Slots
<template> <div> <slot>Default content</slot> </div> </template>2.6 Dynamic Components
<component :is="currentTab"></component> <script> export default { data() { return { currentTab: 'home' } } } </script>2.7 Async Components
<script> const AsyncComp = () => import('./MyComponent.vue') export default { components: { AsyncComp } } </script>2.8 Provide/Inject
<script> export default { provide() { return { color: 'blue' } } } </script> <script> export default { inject: ['color'] } </script>2.9 Component Lifecycle
<script> export default { mounted() { console.log('Component mounted') }, unmounted() { console.log('Component removed') } } </script>2.10 Functional Components
<script> export default { functional: true, render(h) { return h('div', 'I am functional!') } } </script>
<div v-if="isVisible">Visible Content</div>3.2 Conditional Rendering (v-if)
<div v-if="loggedIn">Welcome back!</div>3.3 List Rendering (v-for)
<li v-for="item in items" :key="item.id">{{ item.name }}</li>3.4 Attribute Binding (v-bind)
<img :src="imageUrl" alt="Image">3.5 Two-Way Binding (v-model)
<input v-model="username" placeholder="Enter username"> <p>Hello, {{ username }}!</p>3.6 Event Handling (v-on)
<button @click="submitForm">Submit</button>3.7 Modifiers
<form @submit.prevent="onSubmit"></form>3.8 Computed vs Watchers
<script> computed: { reversed() { return this.text.split('').reverse().join('') } }, watch: { text(newVal) { console.log('Text changed:', newVal) } } </script>3.9 Dynamic Class & Style Binding
<div :class="{ active: isActive }" :style="{ color: textColor }">Styled Text</div>3.10 Key Attribute
<li v-for="item in list" :key="item.id">{{ item.name }}</li>
<button @click="greet">Greet</button> <script> methods: { greet() { alert('Hello from method!') } } </script>4.2 Computed Properties Overview
<div>Full Name: {{ fullName }}</div> <script> computed: { fullName() { return this.firstName + ' ' + this.lastName } } </script>4.3 Difference: Methods vs Computed
<!-- Use computed for derived state --> <div>Reversed: {{ reversedText }}</div> <script> computed: { reversedText() { return this.text.split('').reverse().join('') } } </script>4.4 Using Watchers
<script> watch: { searchQuery(newVal) { this.fetchResults(newVal) } } </script>4.5 Passing Arguments to Methods
<button @click="sayHello('Vue')">Say Hello</button> <script> methods: { sayHello(name) { alert('Hello, ' + name) } } </script>4.6 Method Binding with Parameters
<button @click="() => addItem(item)">Add</button>4.7 Methods in Templates
<div>{{ formatDate(date) }}</div> <script> methods: { formatDate(d) { return new Date(d).toLocaleDateString() } } </script>4.8 Computed Setters
<script> computed: { fullName: { get() { return this.firstName + ' ' + this.lastName }, set(value) { const names = value.split(' ') this.firstName = names[0] this.lastName = names[1] } } } </script>4.9 Watch Deep and Immediate Options
<script> watch: { user: { handler(newVal) { console.log(newVal) }, deep: true, immediate: true } } </script>4.10 Debouncing with Watchers
<script> watch: { searchQuery: _.debounce(function(newVal) { this.fetchResults(newVal) }, 500) } </script>
<script> import { createRouter, createWebHistory } from 'vue-router' import Home from './components/Home.vue' const routes = [ { path: '/', component: Home } ] const router = createRouter({ history: createWebHistory(), routes }) export default router </script>5.2 Setting up Vue Router
<script> import { createApp } from 'vue' import App from './App.vue' import router from './router' createApp(App) .use(router) .mount('#app') </script>5.3 Defining Routes
const routes = [ { path: '/about', component: About }, { path: '/user/:id', component: User } ]5.4 Navigation Methods
this.$router.push('/about')5.5 Route Parameters
const userId = this.$route.params.id5.6 Vuex State Management
import { createStore } from 'vuex' const store = createStore({ state() { return { count: 0 } }, mutations: { increment(state) { state.count++ } } }) export default store5.7 Using Vuex in Components
<script> computed: { count() { return this.$store.state.count } }, methods: { increment() { this.$store.commit('increment') } } </script>5.8 Modules in Vuex
const moduleA = { state() { return { value: 1 } }, mutations: { increment(state) { state.value++ } } }5.9 Alternatives to Vuex
import { defineStore } from 'pinia' export const useStore = defineStore('main', { state: () => ({ count: 0 }), actions: { increment() { this.count++ } } })5.10 Navigation Guards
router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !isLoggedIn()) { next('/login') } else { next() } })
<input v-model="username" placeholder="Enter username"> <p>Username: {{ username }}</p>6.2 Input Bindings
<input type="checkbox" v-model="isChecked"> <input type="radio" v-model="picked" value="A">6.3 Modifiers in Forms
<input v-model.lazy="text"> <input v-model.trim="text"> <input v-model.number="age">6.4 Form Submission
<form @submit.prevent="submitForm"> <input v-model="email"> <button type="submit">Submit</button> </form>6.5 Basic Validation
<script> methods: { submitForm() { if (!this.email) alert('Email required') else alert('Form submitted') } } </script>6.6 Using Vuelidate
<script> import { required, email } from '@vuelidate/validators' export default { validations: { email: { required, email } } } </script>6.7 Using Vue Formulate
<FormulateInput name="email" label="Email" type="email" validation="required|email" />6.8 Custom Validation
<script> methods: { validateAge(value) { return value >= 18 || 'Must be 18 or older' } } </script>6.9 Showing Validation Errors
<span v-if="error">{{ error }}</span>6.10 Form Reset
<script> methods: { resetForm() { this.username = '' this.email = '' } } </script>
<script> app.directive('focus', { mounted(el) { el.focus() } }) </script>7.2 Registering Custom Directives
<script> app.directive('highlight', { beforeMount(el) { el.style.backgroundColor = 'yellow' } }) </script>7.3 Directive Lifecycle Hooks
<script> app.directive('tooltip', { mounted(el) { el.setAttribute('title', 'Tooltip text') }, unmounted(el) { // cleanup } }) </script>7.4 Directive Arguments & Modifiers
<div v-highlight:color.red>Colored Background</div> <script> app.directive('highlight', { beforeMount(el, binding) { el.style.backgroundColor = binding.arg || 'blue' if (binding.modifiers.red) el.style.color = 'red' } }) </script>7.5 Creating Plugins
<script> const MyPlugin = { install(app) { app.config.globalProperties.$myMethod = () => alert('Plugin method') } } app.use(MyPlugin) </script>7.6 Using Plugins
<script> export default { mounted() { this.$myMethod() } } </script>7.7 Plugin Options
<script> const MyPlugin = { install(app, options) { console.log('Options:', options) } } app.use(MyPlugin, { debug: true }) </script>7.8 Writing Reusable Plugins
<script> const MyPlugin = { install(app) { app.component('MyButton', { /* component code */ }) app.directive('focus', { /* directive code */ }) } } </script>7.9 Publishing Plugins
npm publish7.10 Using Third-party Plugins
import VueToast from 'vue-toastification' app.use(VueToast)
<script setup> import { ref } from 'vue' const count = ref(0) </script>8.2 Reactive State with ref
<script setup> import { ref } from 'vue' const message = ref('Hello!') message.value = 'Hi!' </script>8.3 Reactive Objects with reactive
<script setup> import { reactive } from 'vue' const state = reactive({ count: 0 }) state.count++ </script>8.4 Computed with Composition API
<script setup> import { ref, computed } from 'vue' const first = ref('John') const last = ref('Doe') const fullName = computed(() => first.value + ' ' + last.value) </script>8.5 Watchers with Composition API
<script setup> import { ref, watch } from 'vue' const count = ref(0) watch(count, (newVal, oldVal) => { console.log('Count changed:', newVal) }) </script>8.6 Lifecycle Hooks in Composition API
<script setup> import { onMounted } from 'vue' onMounted(() => { console.log('Component mounted') }) </script>8.7 Provide and Inject in Composition API
<script setup> import { provide, inject } from 'vue' provide('color', 'blue') const color = inject('color') </script>8.8 Template Refs
<template> <input ref="inputEl"> </template> <script setup> import { ref, onMounted } from 'vue' const inputEl = ref(null) onMounted(() => inputEl.value.focus()) </script>8.9 Using Emits
<script setup> const emit = defineEmits(['increment']) function handleClick() { emit('increment') } </script>8.10 Composables
<script> import { ref } from 'vue' export function useCounter() { const count = ref(0) function increment() { count.value++ } return { count, increment } } </script>
<!-- Jest is popular for unit tests -->9.2 Unit Testing with Vue Test Utils
import { mount } from '@vue/test-utils' import MyComponent from '@/components/MyComponent.vue' test('renders message', () => { const wrapper = mount(MyComponent) expect(wrapper.text()).toContain('Hello') })9.3 Writing Test Cases
test('button click increments count', () => { const wrapper = mount(Counter) wrapper.find('button').trigger('click') expect(wrapper.vm.count).toBe(1) })9.4 Snapshot Testing
expect(wrapper.html()).toMatchSnapshot()9.5 End-to-End Testing with Cypress
describe('Login flow', () => { it('logs in successfully', () => { cy.visit('/login') cy.get('input').type('user') cy.get('button').click() cy.url().should('include', '/dashboard') }) })9.6 Debugging Vue Apps
console.log(this.someData)9.7 Handling Errors Gracefully
app.config.errorHandler = (err, vm, info) => { console.error(err, info) }9.8 Mocking Dependencies
jest.mock('axios')9.9 Performance Profiling
Vue.config.performance = true9.10 Testing Best Practices
test('does something', () => { expect(true).toBe(true) })
Vue.config.performance = true10.2 Lazy Loading Components
const AsyncComp = () => import('./AsyncComp.vue')10.3 Virtual Scrolling
<virtual-list :items="bigList"></virtual-list>10.4 Debounce & Throttle
methods: { onScroll: _.throttle(function() { console.log('Scrolled') }, 200) }10.5 Use Key Attribute Wisely
<li v-for="item in items" :key="item.id">{{ item.name }}</li>10.6 Optimize Computed Properties
computed: { filteredList() { return this.list.filter(item => item.active) } }10.7 Avoid Watchers if Possible
computed: { total() { return this.items.reduce((sum, i) => sum + i.price, 0) } }10.8 Server-Side Rendering
npm install vue-server-renderer10.9 Using Web Workers
const worker = new Worker('worker.js')10.10 Performance Tools
Vue.config.devtools = true
const AsyncComp = () => import('./AsyncComp.vue')11.2 Dynamic & Async Component Usage
<component :is="currentComponent"></component>11.3 Render Functions
render() { return h('div', this.message) }11.4 Scoped Slots
<slot :user="user"></slot>11.5 Functional Components
export default { functional: true, render(h, ctx) { return h('div', ctx.props.text) } }11.6 Mixins
const myMixin = { created() { console.log('Mixin created') } }11.7 Custom Events & $emit
this.$emit('customEvent', payload)11.8 Provide/Inject API
provide() { return { color: 'red' } } inject: ['color']11.9 Dynamic Async Components with Suspense
<Suspense> <template #default> <AsyncComp /> </template> <template #fallback> Loading... </template> </Suspense>11.10 Teleport
<teleport to="body"> <div class="modal">Modal Content</div> </teleport>
<transition name="fade"> <div v-if="show">Fade me</div> </transition>12.2 Transition Classes
.fade-enter-active { transition: opacity 0.5s; } .fade-enter-from { opacity: 0; } .fade-enter-to { opacity: 1; }12.3 JavaScript Hooks
<transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> </transition>12.4 List Transitions (v-for)
<transition-group name="list"> <li v-for="item in items" :key="item.id">{{ item.name }}</li> </transition-group>12.5 Using Animate.css with Vue
<transition enter-active-class="animate__animated animate__bounce"> <div v-if="show">Bounce!</div> </transition>12.6 Custom Animation with GSAP
import { gsap } from 'gsap' methods: { enter(el, done) { gsap.fromTo(el, {opacity: 0}, {opacity: 1, duration: 1, onComplete: done}) } }12.7 Staggered Transitions
.list-enter-active > * { transition-delay: calc(var(--index) * 100ms); }12.8 Transition Modes
<transition mode="out-in"></transition>12.9 Animating Route Changes
<transition name="fade"> <router-view /> </transition>12.10 Performance Tips
.fade-enter-active { transition: transform 0.3s ease; }
npm install vue-i18n13.2 Setting Up Vue i18n
import { createI18n } from 'vue-i18n' const messages = { en: { welcome: 'Welcome' }, fr: { welcome: 'Bienvenue' } } const i18n = createI18n({ locale: 'en', messages, }) app.use(i18n)13.3 Using $t for Translation
<p>{{ $t('welcome') }}</p>13.4 Changing Locale
this.$i18n.locale = 'fr'13.5 Pluralization
messages: { en: { apple: 'apple | apples' } }13.6 Date & Number Formatting
this.$d(new Date(), 'short')13.7 Lazy Loading Language Packs
import('locales/fr.json').then(...)13.8 Fallback Locale
fallbackLocale: 'en'13.9 Custom Directives for i18n
<div v-t="'welcome'"></div>13.10 Integrating with Vue Router
router.beforeEach((to, from, next) => { const lang = to.params.lang || 'en' i18n.locale = lang next() })
npm install vue-server-renderer14.2 Setting up SSR
import { renderToString } from '@vue/server-renderer' const app = createSSRApp(App) const html = await renderToString(app)14.3 Hydration
createApp(App).mount('#app')14.4 Benefits of SSR
console.log('SSR benefits')14.5 SSR with Nuxt.js
npx create-nuxt-app my-nuxt-app14.6 Data Fetching in SSR
export default { asyncData() { return fetchData() } }14.7 Handling State Transfer
app.$store.replaceState(window.__INITIAL_STATE__)14.8 Caching Strategies
const cache = new LRUCache()14.9 SSR Security Considerations
app.use(helmet())14.10 Debugging SSR
console.error('SSR error', error)
npm install -g @vue/cli vue create my-project15.2 Vue Router
import { createRouter, createWebHistory } from 'vue-router' const routes = [{ path: '/', component: Home }] const router = createRouter({ history: createWebHistory(), routes }) app.use(router)15.3 Vuex
import { createStore } from 'vuex' const store = createStore({ state() { return { count: 0 } }, mutations: { increment(state) { state.count++ } } }) app.use(store)15.4 Vue Devtools
Install from browser store15.5 Vue Test Utils
import { mount } from '@vue/test-utils'15.6 Vite
npm init vite@latest my-vue-app -- --template vue15.7 ESLint & Prettier
npm install eslint prettier --save-dev15.8 Storybook
npx sb init15.9 Nuxt.js
npm install nuxt15.10 Pinia
import { createPinia } from 'pinia' const pinia = createPinia() app.use(pinia)
import { reactive, ref } from 'vue' const state = reactive({ count: 0 }) const number = ref(10)16.2 Computed Properties with Composition API
import { computed } from 'vue' const double = computed(() => state.count * 2)16.3 Watchers in Composition API
import { watch } from 'vue' watch(() => state.count, (newVal, oldVal) => { console.log(newVal, oldVal) })16.4 Lifecycle Hooks in Setup
import { onMounted } from 'vue' onMounted(() => { console.log('Component mounted') })16.5 Provide/Inject with Composition API
import { provide, inject } from 'vue' provide('key', reactiveData) const data = inject('key')16.6 Using Template Refs
import { ref, onMounted } from 'vue' const inputRef = ref(null) onMounted(() => { inputRef.value.focus() })16.7 Custom Composition Functions
function useCounter() { const count = ref(0) const increment = () => count.value++ return { count, increment } }16.8 Reactive vs. Ref
const obj = reactive({ a: 1 }) const num = ref(1)16.9 Async Setup & Suspense
setup: async () => { const data = await fetchData() return { data } }16.10 TypeScript with Composition API
import { ref } from 'vue' const message = ref<string>('Hello')
const moduleA = { state: { count: 0 }, mutations: { increment(state) { state.count++ } } } const store = createStore({ modules: { a: moduleA } })17.2 Namespaced Modules
const moduleB = { namespaced: true, state: { value: 10 } }17.3 Vuex Actions with Async
actions: { async fetchData({ commit }) { const data = await api.getData() commit('setData', data) } }17.4 Vuex Getters
getters: { doubleCount(state) { return state.count * 2 } }17.5 Committing Mutations
store.commit('increment')17.6 Dispatching Actions
store.dispatch('fetchData')17.7 Using mapState and mapActions
import { mapState, mapActions } from 'vuex' computed: { ...mapState(['count']) }, methods: { ...mapActions(['increment']) }17.8 Plugins in Vuex
const myPlugin = store => { store.subscribe((mutation, state) => { console.log(mutation.type) }) }17.9 Strict Mode
const store = createStore({ strict: true })17.10 Testing Vuex Stores
test('mutation increments count', () => { const state = { count: 0 } mutations.increment(state) expect(state.count).toBe(1) })
const routes = [ { path: '/user/:id', component: User } ]18.2 Nested Routes
const routes = [ { path: '/parent', component: Parent, children: [ { path: 'child', component: Child } ] } ]18.3 Named Views
const routes = [ { path: '/', components: { default: DefaultComp, sidebar: SidebarComp } } ]18.4 Navigation Guards
router.beforeEach((to, from, next) => { if (to.meta.requiresAuth) next('/login') else next() })18.5 Lazy Loading Routes
const routes = [ { path: '/about', component: () => import('./About.vue') } ]18.6 Scroll Behavior
const router = createRouter({ scrollBehavior() { return { top: 0 } } })18.7 Route Meta Fields
{ path: '/admin', meta: { requiresAuth: true } }18.8 Programmatic Navigation
this.$router.push('/home')18.9 Route Props
{ path: '/user/:id', props: true }18.10 Navigation Failures Handling
this.$router.push('/home').catch(err => {})
import { useStore } from 'vuex' setup() { const store = useStore() store.commit('increment') }19.2 Using Router in Composition API
import { useRouter, useRoute } from 'vue-router' setup() { const router = useRouter() const route = useRoute() }19.3 Navigation in Setup
router.push('/dashboard')19.4 Reactive Route Params
watch(() => route.params.id, (newId) => { fetchData(newId) })19.5 Vuex Actions with Composition API
store.dispatch('fetchData')19.6 Mapping Vuex State
const count = computed(() => store.state.count)19.7 Handling Route Guards
router.beforeEach((to, from, next) => { if (!isAuthenticated) next('/login') else next() })19.8 Async Data Fetching on Route Change
watch(() => route.params.id, fetchData)19.9 Using Suspense with Router
<Suspense><router-view /></Suspense>19.10 Testing Components with Vuex & Router
const store = createStore(...) const router = createRouter(...) mount(Component, { global: { plugins: [store, router] } })
npm run build20.2 Environment Variables
VUE_APP_API_URL=https://api.example.com20.3 Deploying to Netlify
git push origin main Connect repo in Netlify dashboard20.4 Deploying to Vercel
vercel --prod20.5 Performance Audits
lighthouse https://myapp.com20.6 Code Splitting
const AsyncComp = () => import('./AsyncComp.vue')20.7 Lazy Loading Routes & Components
const routes = [{ path: '/about', component: () => import('./About.vue') }]20.8 SEO Optimization
20.9 Security Best Practices
20.10 Monitoring & Analytics
gtag('config', 'GA_TRACKING_ID')
import { mount } from '@vue/test-utils' import MyComponent from '@/components/MyComponent.vue' const wrapper = mount(MyComponent) expect(wrapper.text()).toContain('Hello')21.2 Using Jest with Vue
npm install --save-dev jest vue-jest @vue/test-utils21.3 Snapshot Testing
expect(wrapper.html()).toMatchSnapshot()21.4 Mocking Vuex Store
import { createStore } from 'vuex' import { mount } from '@vue/test-utils' import MyComponent from '@/components/MyComponent.vue' const store = createStore({ state: { count: 1 } }) const wrapper = mount(MyComponent, { global: { plugins: [store] } }) expect(wrapper.text()).toContain('1')21.5 Testing Router Navigation
import { createRouter, createWebHistory } from 'vue-router' import { mount } from '@vue/test-utils' const router = createRouter({ history: createWebHistory(), routes: [{ path: '/', component: {} }] }) const wrapper = mount(MyComponent, { global: { plugins: [router] } }) router.push('/') await router.isReady() expect(wrapper.html()).toContain('Welcome')21.6 Debugging Tools
console.log(this.$data)21.7 Error Handling
export default { errorCaptured(err, vm, info) { console.error('Error:', err) } }21.8 Handling Async Tests
test('fetches data', async () => { await wrapper.vm.fetchData() expect(wrapper.text()).toContain('Data loaded') })21.9 End-to-End Testing
npx cypress open21.10 Performance Profiling
performance.mark('start') // Run Vue component render or logic here performance.mark('end') performance.measure('myMeasure', 'start', 'end')
import { reactive } from 'vue' const state = reactive({ count: 0 })22.2 Pinia
import { createPinia, defineStore } from 'pinia' const useStore = defineStore('main', { state: () => ({ count: 0 }), actions: { increment() { this.count++ } } }) app.use(createPinia())22.3 Using Vue Observable
import { reactive } from 'vue' const state = reactive({ value: 0 })22.4 Local Storage for State
localStorage.setItem('count', state.count) state.count = Number(localStorage.getItem('count')) || 022.5 Using provide/inject for State
import { provide, inject, reactive } from 'vue' const state = reactive({ count: 0 }) provide('state', state) // In child component const state = inject('state')22.6 Comparing Vuex vs Pinia
console.log('Pinia is modular, simpler; Vuex has bigger community and plugins')22.7 MobX with Vue
import { observable } from 'mobx' const state = observable({ count: 0 })22.8 Zustand & Other Alternatives
import create from 'zustand' const useStore = create(set => ({ count: 0, increment: () => set(state => ({ count: state.count + 1 })) }))22.9 Best Practices for State Management
state: { users: [], posts: [] }22.10 Debugging State
console.log(state)
import { ref } from 'vue' function useToggle() { const isOn = ref(false) function toggle() { isOn.value = !isOn.value } return { isOn, toggle } }23.2 Separation of Concerns
const { data, fetchData } = useApi()23.3 Reusing Reactive State
import { reactive } from 'vue' const sharedState = reactive({ count: 0 })23.4 Use of Watchers & Effects
import { watch } from 'vue' watch(count, (val) => { console.log('Count changed:', val) })23.5 Handling Side Effects
import { onMounted } from 'vue' onMounted(() => { fetchData() })23.6 Providing & Injecting Composables
import { provide } from 'vue' provide('auth', useAuth())23.7 Async Composables
import { ref } from 'vue' async function useData() { const data = ref(null) data.value = await fetchApi() return { data } }23.8 Error Handling in Composables
try { await fetch() } catch(e) { console.error(e) }23.9 Testing Composables
import { nextTick } from 'vue' // Write unit tests that call composables and assert outputs23.10 Documentation & Naming
function useUser() { // ... }
export default { install(app) { // Plugin code here } }24.2 Creating a Simple Plugin
export default { install(app) { app.config.globalProperties.$myMethod = () => console.log('Hello from plugin') } }24.3 Using Plugins in Vue
import MyPlugin from './MyPlugin' app.use(MyPlugin)24.4 Plugin Options
app.use(MyPlugin, { option: true })24.5 Plugin Lifecycle Hooks
app.mixin({ mounted() { console.log('Component mounted') } })24.6 Global Components in Plugins
app.component('MyButton', MyButton)24.7 Directives in Plugins
app.directive('focus', { mounted(el) { el.focus() } })24.8 Composables in Plugins
export function usePluginFeature() { // composable logic }24.9 Publishing Plugins
npm publish24.10 Best Practices
console.log('Use scoped names and avoid globals')
<button aria-label="Close">X</button>25.2 Semantic HTML
<nav> <ul> <li>Home</li> <li>About</li> </ul> </nav>25.3 ARIA Roles and Attributes
<div role="alert">Error occurred!</div>25.4 Keyboard Navigation
<button @keydown.enter="submit">Submit</button>25.5 Focus Management
methods: { focusInput() { this.$refs.input.focus() } }25.6 Using Vue-A11y Libraries
npm install vue-a11y-dialog25.7 Testing Accessibility
npm install @axe-core/vue25.8 Responsive Design and A11y
@media (max-width: 600px) { /* Responsive styles */ }25.9 Color Contrast
color: #000000; background-color: #ffffff;25.10 Documentation & Guidelines
https://www.w3.org/WAI/standards-guidelines/wcag/
npm install vue-i18n26.2 Setting up vue-i18n
import { createI18n } from 'vue-i18n' const i18n = createI18n({ locale: 'en', messages }) app.use(i18n)26.3 Defining Messages
const messages = { en: { welcome: 'Welcome' }, fr: { welcome: 'Bienvenue' } }26.4 Using $t for Translation
<p>{{ $t('welcome') }}</p>26.5 Changing Locale Dynamically
i18n.global.locale = 'fr'26.6 Pluralization
messages: { en: { car: 'car | cars' } }26.7 Date & Number Formatting
i18n.global.dtf('en').format(new Date())26.8 Lazy Loading Language Packs
import('locales/fr.json').then(...)26.9 Custom Directives for i18n
app.directive('t', { mounted(el, binding) { el.textContent = i18n.global.t(binding.value) }})26.10 Testing i18n
jest.mock('vue-i18n', () => ({ t: key => key }))
<transition name="fade"> <div v-if="show">Hello</div> </transition>27.2 CSS Transition Classes
.fade-enter-active { transition: opacity 0.5s; } .fade-leave-active { transition: opacity 0.5s; }27.3 JavaScript Hooks
<transition @before-enter="beforeEnter" @enter="enter" @leave="leave" >27.4 List Transitions
<transition-group name="list"> <div v-for="item in items" :key="item.id">{{ item.text }}</div> </transition-group>27.5 Using Third-Party Libraries
import gsap from 'gsap' gsap.to('.box', { x: 100, duration: 1 })27.6 Transition Modes
<transition mode="out-in"> ... </transition>27.7 Custom Animation Classes
@keyframes bounce { 0%, 100% { transform: translateY(0) } 50% { transform: translateY(-30px) } }27.8 Handling Animation Interruptions
@keyframes fadeOut { ... }27.9 Accessibility & Animations
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }27.10 Debugging Animations
document.querySelector('.box').style.animationPlayState = 'paused'
npm install vue-server-renderer28.2 Setting up SSR
// server.js const express = require('express') const { createRenderer } = require('vue-server-renderer') const Vue = require('vue') const server = express() const renderer = createRenderer() server.get('*', (req, res) => { const app = new Vue({ data: { url: req.url }, template: `<div>Hello SSR! URL is: {{ url }}</div>` }) renderer.renderToString(app, (err, html) => { if (err) { res.status(500).end('Server Error') return } res.end(` <!DOCTYPE html> <html lang="en"> <head><title>Vue SSR</title></head> <body>${html}</body> </html> `) }) }) server.listen(8080) console.log('Server running at http://localhost:8080')28.3 Creating App Entry for SSR
// app.js const { createSSRApp } = require('vue') module.exports = function createApp() { const app = createSSRApp({ data() { return { message: 'Hello from SSR app!' } }, template: '<div>{{ message }}</div>' }) return app }28.4 Hydration
// main.js (client entry) import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) // Hydrate: attach Vue to existing server-rendered markup app.mount('#app') // Vue 3 hydrates automatically if markup exists28.5 Data Prefetching
export default { async asyncData() { // Pretend fetching data from API const data = await fetch('https://api.example.com/data').then(res => res.json()) return { items: data } }, data() { return { items: [] } }, template: '<ul><li v-for="item in items" :key="item.id">{{ item.name }}</li></ul>' }28.6 Cache Strategies
// server.js cache example const LRU = require('lru-cache') const cache = new LRU({ max: 100, maxAge: 1000 * 60 * 15 }) // 15 minutes cache server.get('*', (req, res) => { const cachedPage = cache.get(req.url) if (cachedPage) { return res.end(cachedPage) } // render app ... renderer.renderToString(app, (err, html) => { if (!err) { cache.set(req.url, html) } res.end(html) }) })28.7 Handling Routing with SSR
// router.js (example) import { createRouter, createMemoryHistory } from 'vue-router' const routes = [ { path: '/', component: Home }, { path: '/about', component: About } ] export function createSSRRouter() { return createRouter({ history: createMemoryHistory(), routes, }) } // server.js const router = createSSRRouter() router.push(req.url) router.isReady().then(() => { const app = createApp() app.use(router) // render... })28.8 Dealing with State Transfer
// In server render: const state = { user: 'John Doe', loggedIn: true } renderer.renderToString(app, (err, html) => { res.end(` <div id="app">${html}</div> <script> window.__INITIAL_STATE__ = ${JSON.stringify(state)} </script> `) }) // In client entry: const state = window.__INITIAL_STATE__ const app = createApp() app.provide('initialState', state) app.mount('#app')28.9 Error Handling in SSR
renderer.renderToString(app, (err, html) => { if (err) { if (err.code === 404) { res.status(404).end('Page Not Found') } else { res.status(500).end('Internal Server Error') } } else { res.end(html) } })28.10 Deploying SSR Apps
# Use pm2 to start server in production pm2 start server.js --name vue-ssr-app # Check logs pm2 logs vue-ssr-app
function sanitize(input) { const div = document.createElement('div') div.textContent = input return div.innerHTML } // Usage: const userInput = '<script>alert("XSS")</script>' const safeInput = sanitize(userInput) console.log(safeInput) // <script>alert("XSS")</script>29.2 Content Security Policy (CSP)
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self'">29.3 Sanitizing Inputs
import DOMPurify from 'dompurify' const dirty = '<img src=x onerror=alert(1)>' const clean = DOMPurify.sanitize(dirty) console.log(clean) // <img src="x">29.4 Avoiding Inline JavaScript
<!-- Good: External JS file --> <script src="app.js"></script> <!-- Bad: Inline script --> <script>alert('Hello')</script>29.5 Safe Event Handling
<button @click="handleClick">Click Me</button> methods: { handleClick() { alert('Button clicked safely') } }29.6 Authentication & Authorization
router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !isUserLoggedIn()) { next('/login') } else { next() } })29.7 Securing Vuex State
const store = createStore({ state: { token: null // don't store sensitive info permanently here }, mutations: { setToken(state, token) { state.token = token } } })29.8 HTTPS & Secure Headers
// Express example with helmet middleware const helmet = require('helmet') app.use(helmet()) // sets secure headers automatically29.9 Dependency Audits
npm audit npm audit fix29.10 Keeping Up-to-Date
npm update vue npm outdated
const AsyncComp = () => import('./AsyncComp.vue') // Usage in template: // <AsyncComp />30.2 Debouncing Input
function debounce(fn, delay) { let timeout return (...args) => { clearTimeout(timeout) timeout = setTimeout(() => fn(...args), delay) } } // Usage const debouncedSearch = debounce(() => { console.log('Search triggered') }, 300)30.3 Virtual Scrolling
<template> <virtual-scroller :items="items"></virtual-scroller> </template> <script> import VirtualScroller from 'vue-virtual-scroller' export default { components: { VirtualScroller }, data() { return { items: Array(1000).fill().map((_, i) => 'Item ' + i) } } } </script>30.4 Memoization
import { computed } from 'vue' const expensiveFn = (data) => { // some heavy calculation return data.reduce((a, b) => a + b, 0) } const data = [1, 2, 3, 4, 5] const result = computed(() => expensiveFn(data)) console.log(result.value) // 1530.5 Using Web Workers
// worker.js self.onmessage = function(e) { const result = e.data * 2 self.postMessage(result) } // main.js const worker = new Worker('worker.js') worker.onmessage = (e) => console.log('Result from worker:', e.data) worker.postMessage(10)30.6 Optimizing Reactivity
import { shallowReactive } from 'vue' const state = shallowReactive({ user: { name: 'Alice', age: 30 } }) // Changes to nested objects won't trigger reactivity state.user.name = 'Bob' // won't trigger updates30.7 Reducing Watchers
import { watchEffect } from 'vue' watchEffect(() => { console.log('Reactive effect runs') // Avoid watching too many variables unnecessarily })30.8 Server-Side Caching
const cache = new Map() function renderPage(url) { if (cache.has(url)) { return cache.get(url) } const html = renderApp(url) cache.set(url, html) return html }30.9 Tree Shaking
# In package.json scripts "build": "vue-cli-service build --modern --target app --report --tree-shake"30.10 Profiling Performance
performance.mark('start') // ... some Vue rendering or code ... performance.mark('end') performance.measure('myMeasurement', 'start', 'end') const measures = performance.getEntriesByName('myMeasurement') console.log(measures)