<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.id
5.6 Vuex State Management
import { createStore } from 'vuex'
const store = createStore({
state() {
return { count: 0 }
},
mutations: {
increment(state) { state.count++ }
}
})
export default store
5.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 publish
7.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 = true
9.10 Testing Best Practices
test('does something', () => {
expect(true).toBe(true)
})
Vue.config.performance = true
10.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-renderer
10.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-i18n
13.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-renderer
14.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-app
14.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-project
15.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 store
15.5 Vue Test Utils
import { mount } from '@vue/test-utils'
15.6 Vite
npm init vite@latest my-vue-app -- --template vue
15.7 ESLint & Prettier
npm install eslint prettier --save-dev
15.8 Storybook
npx sb init
15.9 Nuxt.js
npm install nuxt
15.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 build
20.2 Environment Variables
VUE_APP_API_URL=https://api.example.com
20.3 Deploying to Netlify
git push origin main
Connect repo in Netlify dashboard
20.4 Deploying to Vercel
vercel --prod
20.5 Performance Audits
lighthouse https://myapp.com
20.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-utils
21.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 open
21.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')) || 0
22.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 outputs
23.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 publish
24.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-dialog
25.7 Testing Accessibility
npm install @axe-core/vue
25.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-i18n
26.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-renderer
28.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 exists
28.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 automatically
29.9 Dependency Audits
npm audit
npm audit fix
29.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) // 15
30.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 updates
30.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)