├── .eslintrc.cjs ├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc.json ├── .vscode └── extensions.json ├── README.md ├── index.html ├── jsconfig.json ├── package-lock.json ├── package.json ├── postcss.config.js ├── public └── favicon.ico ├── src ├── App.vue ├── assets │ ├── base.scss │ ├── logo.svg │ ├── main.scss │ └── tailwind.scss ├── components │ ├── HelloWorld.vue │ ├── TheWelcome.vue │ ├── WelcomeItem.vue │ └── icons │ │ ├── IconCommunity.vue │ │ ├── IconDocumentation.vue │ │ ├── IconEcosystem.vue │ │ ├── IconSupport.vue │ │ └── IconTooling.vue ├── main.js ├── router │ └── index.js ├── stores │ └── counter.js └── views │ ├── AboutView.vue │ └── HomeView.vue ├── tailwind.config.js ├── vite.config.dev.mjs └── vite.config.prod.mjs /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require('@rushstack/eslint-patch/modern-module-resolution') 3 | 4 | module.exports = { 5 | root: true, 6 | env: { 7 | node: true 8 | }, 9 | extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-prettier'] 10 | } 11 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [richardevcom] 2 | custom: ['buymeacoffee.com/richardevcom', 'revolut.me/richardevcom'] 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "semi": false, 4 | "tabWidth": 2, 5 | "singleQuote": true, 6 | "printWidth": 100, 7 | "trailingComma": "none" 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "bradlc.vscode-tailwindcss", 4 | "Vue.volar", 5 | "dbaeumer.vscode-eslint", 6 | "esbenp.prettier-vscode" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [![](https://img.shields.io/static/v1?label=Sponsor+%F0%9F%91%89&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/richardevcom) Vue 3 boilerplate - Vite, Pinia, Vue Router & Tailwind CSS 2 | 3 | This boilerplate was created as part of my [custom Vue 3 boilerpalte tutorial](https://medium.com/@richardevcom/custom-vue3-boilerplate-9635806acde3). It will help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 40 | 41 | 42 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | }, 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@richardev/vue3-boilerplate", 3 | "description": "Quick boilerplate for your next project, containing - Vite, Vuex, Vue Router & Tailwind CSS. This was created as part of my tutorial series.", 4 | "private": false, 5 | "type": "module", 6 | "version": "1.1.1", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/richardevcom/vue3-boilerplate.git" 10 | }, 11 | "scripts": { 12 | "dev": "vite --config='vite.config.dev.mjs'", 13 | "build": "vite build --config='vite.config.prod.mjs'", 14 | "preview": "vite preview --config='./vite.config.prod.mjs'", 15 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore", 16 | "format": "prettier --write src/" 17 | }, 18 | "dependencies": { 19 | "pinia": "^2.1.7", 20 | "vue": "^3.4.29", 21 | "vue-router": "^4.3.3" 22 | }, 23 | "devDependencies": { 24 | "@rushstack/eslint-patch": "^1.8.0", 25 | "@vitejs/plugin-vue": "^5.0.5", 26 | "@vue/eslint-config-prettier": "^9.0.0", 27 | "autoprefixer": "^10.4.19", 28 | "cssnano": "^7.0.4", 29 | "eslint": "^8.57.0", 30 | "eslint-plugin-vue": "^9.23.0", 31 | "postcss": "^8.4.40", 32 | "prettier": "^3.2.5", 33 | "sass": "^1.77.8", 34 | "tailwindcss": "^3.4.7", 35 | "vite": "^5.3.1", 36 | "vite-plugin-vue-devtools": "^7.3.1" 37 | }, 38 | "keywords": [ 39 | "vue", 40 | "vue3", 41 | "vuejs", 42 | "vue3js", 43 | "boilerplate", 44 | "template", 45 | "router", 46 | "vuerouter", 47 | "vue-router", 48 | "tailwind", 49 | "tailwindcss", 50 | "tailwind-css", 51 | "pinia", 52 | "svg", 53 | "vue 3 boilerplate", 54 | "vue3 boilerplate", 55 | "vue 3 skeleton", 56 | "vue3 skeleton", 57 | "vue 3 starter", 58 | "vue3 starter", 59 | "vue 3 webpack boilerplate", 60 | "vue3 webpack boilerplate", 61 | "vue 3 webpack skeleton", 62 | "vue3 webpack skeleton", 63 | "vue 3 webpack starter", 64 | "vue3 webpack starter", 65 | "vue3 enterprise boilerplate", 66 | "vue 3 enterprise boilerplate", 67 | "vue3 enterprise skeleton", 68 | "vue 3 enterprise skeleton", 69 | "vue3 enterprise starter", 70 | "vue 3 enterprise starter" 71 | ], 72 | "author": "richardevcom (https://github.com/richardevcom/)" 73 | } 74 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/richardevcom/vue3-boilerplate/5f9c44b170347c833d26f8d7098fe1342553f430/public/favicon.ico -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 22 | 23 | 86 | -------------------------------------------------------------------------------- /src/assets/base.scss: -------------------------------------------------------------------------------- 1 | /* color palette from */ 2 | :root { 3 | --vt-c-white: #ffffff; 4 | --vt-c-white-soft: #f8f8f8; 5 | --vt-c-white-mute: #f2f2f2; 6 | 7 | --vt-c-black: #181818; 8 | --vt-c-black-soft: #222222; 9 | --vt-c-black-mute: #282828; 10 | 11 | --vt-c-indigo: #2c3e50; 12 | 13 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); 14 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); 15 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); 16 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); 17 | 18 | --vt-c-text-light-1: var(--vt-c-indigo); 19 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66); 20 | --vt-c-text-dark-1: var(--vt-c-white); 21 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); 22 | } 23 | 24 | /* semantic color variables for this project */ 25 | :root { 26 | --color-background: var(--vt-c-white); 27 | --color-background-soft: var(--vt-c-white-soft); 28 | --color-background-mute: var(--vt-c-white-mute); 29 | 30 | --color-border: var(--vt-c-divider-light-2); 31 | --color-border-hover: var(--vt-c-divider-light-1); 32 | 33 | --color-heading: var(--vt-c-text-light-1); 34 | --color-text: var(--vt-c-text-light-1); 35 | 36 | --section-gap: 160px; 37 | } 38 | 39 | @media (prefers-color-scheme: dark) { 40 | :root { 41 | --color-background: var(--vt-c-black); 42 | --color-background-soft: var(--vt-c-black-soft); 43 | --color-background-mute: var(--vt-c-black-mute); 44 | 45 | --color-border: var(--vt-c-divider-dark-2); 46 | --color-border-hover: var(--vt-c-divider-dark-1); 47 | 48 | --color-heading: var(--vt-c-text-dark-1); 49 | --color-text: var(--vt-c-text-dark-2); 50 | } 51 | } 52 | 53 | *, 54 | *::before, 55 | *::after { 56 | box-sizing: border-box; 57 | margin: 0; 58 | font-weight: normal; 59 | } 60 | 61 | body { 62 | min-height: 100vh; 63 | color: var(--color-text); 64 | background: var(--color-background); 65 | transition: 66 | color 0.5s, 67 | background-color 0.5s; 68 | line-height: 1.6; 69 | font-family: 70 | Inter, 71 | -apple-system, 72 | BlinkMacSystemFont, 73 | 'Segoe UI', 74 | Roboto, 75 | Oxygen, 76 | Ubuntu, 77 | Cantarell, 78 | 'Fira Sans', 79 | 'Droid Sans', 80 | 'Helvetica Neue', 81 | sans-serif; 82 | font-size: 15px; 83 | text-rendering: optimizeLegibility; 84 | -webkit-font-smoothing: antialiased; 85 | -moz-osx-font-smoothing: grayscale; 86 | } 87 | -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/main.scss: -------------------------------------------------------------------------------- 1 | @import './tailwind.scss'; 2 | @import './base.scss'; 3 | 4 | #app { 5 | max-width: 1280px; 6 | margin: 0 auto; 7 | padding: 2rem; 8 | font-weight: normal; 9 | } 10 | 11 | a, 12 | .green { 13 | text-decoration: none; 14 | color: hsla(160, 100%, 37%, 1); 15 | transition: 0.4s; 16 | padding: 3px; 17 | } 18 | 19 | @media (hover: hover) { 20 | a:hover { 21 | background-color: hsla(160, 100%, 37%, 0.2); 22 | } 23 | } 24 | 25 | @media (min-width: 1024px) { 26 | body { 27 | display: flex; 28 | place-items: center; 29 | } 30 | 31 | #app { 32 | display: grid; 33 | grid-template-columns: 1fr 1fr; 34 | padding: 0 2rem; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/assets/tailwind.scss: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | 21 | 45 | -------------------------------------------------------------------------------- /src/components/TheWelcome.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 89 | -------------------------------------------------------------------------------- /src/components/WelcomeItem.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 87 | -------------------------------------------------------------------------------- /src/components/icons/IconCommunity.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/icons/IconDocumentation.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/icons/IconEcosystem.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/icons/IconSupport.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { createPinia } from 'pinia' 3 | 4 | import App from './App.vue' 5 | import router from './router' 6 | 7 | import './assets/main.scss' 8 | 9 | const app = createApp(App) 10 | 11 | app.use(createPinia()) 12 | app.use(router) 13 | 14 | app.mount('#app') 15 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | import HomeView from '../views/HomeView.vue' 3 | 4 | const router = createRouter({ 5 | history: createWebHistory(import.meta.env.BASE_URL), 6 | routes: [ 7 | { 8 | path: '/', 9 | name: 'home', 10 | component: HomeView 11 | }, 12 | { 13 | path: '/about', 14 | name: 'about', 15 | // route level code-splitting 16 | // this generates a separate chunk (About.[hash].js) for this route 17 | // which is lazy-loaded when the route is visited. 18 | component: () => import('../views/AboutView.vue') 19 | } 20 | ] 21 | }) 22 | 23 | export default router 24 | -------------------------------------------------------------------------------- /src/stores/counter.js: -------------------------------------------------------------------------------- 1 | import { ref, computed } from 'vue' 2 | import { defineStore } from 'pinia' 3 | 4 | export const useCounterStore = defineStore('counter', () => { 5 | const count = ref(0) 6 | const doubleCount = computed(() => count.value * 2) 7 | function increment() { 8 | count.value++ 9 | } 10 | 11 | return { count, doubleCount, increment } 12 | }) 13 | -------------------------------------------------------------------------------- /src/views/AboutView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /src/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: {} 6 | }, 7 | plugins: [] 8 | } 9 | -------------------------------------------------------------------------------- /vite.config.dev.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | import vueDevTools from 'vite-plugin-vue-devtools' 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [vue(), vueDevTools()], 10 | resolve: { 11 | alias: { 12 | '@': fileURLToPath(new URL('./src', import.meta.url)) 13 | } 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /vite.config.prod.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | logLevel: 'silent', 9 | plugins: [vue()], 10 | resolve: { 11 | alias: { 12 | '@': fileURLToPath(new URL('./src', import.meta.url)) 13 | } 14 | } 15 | }) 16 | --------------------------------------------------------------------------------