# Vue 前端環境相關
相關筆記
{%preview https://hackmd.io/@63Ywhax5TLKtGhFSWnacvQ/rkSzAokSll %}
{%preview https://hackmd.io/@63Ywhax5TLKtGhFSWnacvQ/B1zl12yHlx %}
# 🧰 專案初始化與安裝流程
## 1️⃣ 建立環境(系統框架與開發基礎)
📦 定義:為了讓整個專案能「順利執行、順利開發」的底層工具
- {%preview https://hackmd.io/@63Ywhax5TLKtGhFSWnacvQ/r14DVAtveg %}
- {%preview https://hackmd.io/@63Ywhax5TLKtGhFSWnacvQ/Hkz190tDxl %}
### 🪜 建立 Vue 3 + Vite 專案
```bash
npm create vite@latest
```
接下來依照指示輸入:
✔ Project name: » vite-project(←你想要的專案名稱)
✔ Select a framework: » Vue
✔ Select a variant: » JavaScript
### 💿 接著進入資料夾 vite-project (←你想要的專案名稱)並安裝
```bash
cd vite-project
```
### 📍 Vue 工具函式庫 與 Vite 插件行為檢查工具
```bash
npm i @vueuse/core
npm i -D vite-plugin-inspect
```
📌 用途說明
* `@vueuse/core`:給 Vue 組件內用的函式工具
* 常見像 useMouse()、useDark() 等實用函式,可以幫你快速綁定滑鼠座標、切換深色模式等互動功能。
* `vite-plugin-inspect`:前端開發用的 Vite 插件
### 📍 初始化 Node 專案
```bash
npm init --yes
npm i -D nodemon
```
### 📍 安裝路由
> 無換頁就不需要
```bash
npm i vue-router
```
### 📌 如果沒有的話需手動建立的檔案(.gitignore)
#### 📝 建立檔案.gitignore
> 內容為:要設定讓git忽略的檔案
檔名
```
.gitignore
```
內容(最少)
```
.env
node_modules
dump/*
!dump/.gitkeep
```
### 📍 安裝開發用工具(語法檢查、自動重啟)
> 檢查語法是否符合規則(eslint / oslint / tslint…)
> 檔案變動時自動重啟伺服器(開發用)
```bash
npm init @eslint/config@latest
```
```bash
npm i -D eslint prettier eslint-plugin-prettier eslint-config-prettier eslint-plugin-vue
```
#### 📝 eslint.config.js 內容
##### js 版
檔名
```
eslint.config.js
```
檔案內容(JS版)
```js
import js from '@eslint/js'
import globals from 'globals'
import { defineConfig } from 'eslint/config'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
export default defineConfig([
{
files: ['**/*.{js,mjs,cjs}'],
plugins: { js },
extends: ['js/recommended'],
},
{
files: ['**/*.{js,mjs,cjs}'],
languageOptions: { globals: { ...globals.browser, ...globals.node } },
},
eslintPluginPrettierRecommended,
{
rules: {
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
},
},
])
```
##### ts 版
檔名
```
eslint.config.ts
```
檔案內容(TS版)
```ts
import js from '@eslint/js'
import globals from 'globals'
import pluginVue from 'eslint-plugin-vue'
import tseslint from 'typescript-eslint'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import { defineConfig } from 'eslint/config'
export default defineConfig(
{ ignores: ['dist', 'node_modules'] },
js.configs.recommended,
tseslint.configs.recommended,
...pluginVue.configs['flat/recommended'], // 注意這裡需要展開運算子
{
files: ['**/*.{js,mjs,cjs,ts,vue}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
// 自訂規則
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'vue/multi-word-component-names': 'warn',
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
},
},
eslintPluginPrettierRecommended,
)
```
#### 📝 .prettierrc.json 內容
檔名
```
.prettierrc.json
```
檔案內容
```json
{
"$schema": "https://json.schemastore.org/prettierrc",
"printWidth": 100,
"semi": false,
"singleQuote": true
}
```
---
> 選擇想要的UI框架,ex: [Nuxt UI](https://ui.nuxt.com/getting-started/installation/vue#install-the-nuxt-ui-package) 套件、[PrimeVue](https://primevue.org/) 套件、[daisyUI](https://daisyui.com/docs/install/) 套件
---
### 🪜 安裝 UI 框架
#### NuxtUI
```bash
npm i @nuxt/ui
```
##### 設定 NuxtUI
{%preview https://ui.nuxt.com/getting-started/installation/vue %}
#### PrimeVue
```bash
npm i primevue@latest primeicons primeflex
```
##### 設定 PrimeVue
{%preview https://primevue.org/vite %}
#### DaisyUI
```bash
npm install tailwindcss@latest @tailwindcss/vite@latest daisyui@latest
```
##### 設定 DaisyUI
{%preview https://daisyui.com/docs/install/vite/ %}
…
---
### 🕶️ TailwindCSS 相關
#### 只想安裝 TailwindCSS ,不安裝其他 UI 框架
```bash
npm install tailwindcss @tailwindcss/vite
```
#### 在 vite.config 匯入
```js
import tailwindcss from '@tailwindcss/vite'
```
#### Tailwind 的設定
文件
{%preview https://hackmd.io/@63Ywhax5TLKtGhFSWnacvQ/SJMNh1Oqxe %}
{%preview https://tailwindcss.com/docs/installation/using-vite %}
##### 在 vite.config 裡面的 plugins 中加入
```js
tailwindcss(),
```
##### 在 src\style.css 匯入 Tailwind
```css
@import "tailwindcss";
```
##### 檢查 main.js 中是否有匯入這個 css 檔案
```js
import './style.css'
```
---
## 2️⃣ 常駐工具型功能(必裝輔助開發用,不是主流程但超常出現)
📦 定義:專案未必一開始就用到,但絕大多數專案後期一定會補,甚至常常預設就先裝。
### 狀態管理、狀態儲存、 HTTP 請求、表單驗證
```bash
npm i pinia pinia-plugin-persistedstate axios vee-validate yup
```
### 開發用套件
自動引入 import 的工具、不用手動 import 與註冊 Vue 元件、自動根據 /src/pages 資料夾產生 vue-router 路由表、多版型(多 Layout)」功能、page對應layout、自動打包字體
```bash
npm i -D unplugin-auto-import unplugin-vue-components unplugin-vue-router vite-plugin-vue-layouts-next unplugin-fonts
```
### 在 /src 需手動建立的檔案建議(結構)
##### 新增 `src/頁面` 資料夾
> 放「主要頁面元件」(通常會被 router 導向)
> 📌 通常一個頁面對應一個 .vue 元件(例如:首頁、會員頁、商品頁)
資料夾名稱
> 安裝 unplugin-vue-router 的話選這個
```
pages
```
或
```
views
```
```
index.vue
```
```vue
<template>
<!-- index.vue -->
</template>
<script setup>
// ...
</script>
```
##### 新增 `src/版型` 資料夾
> 定義整體版型(如:有無側欄、有無導覽列的框架)
> 📌 常用於包住多個頁面,搭配 <router-view /> 使用
資料夾名稱
```
layouts
```
```
<template>
<div class="min-h-screen">
<div>
<!-- menu -->
</div>
<main>
<!-- content page -->
<router-view />
</main>
</div>
<div>
<!-- footer -->
</div>
</template>
<script setup>
// ...
</script>
```
##### 新增 `src/plugins` 資料夾
> 放 plugin 設定檔(UI 套件、驗證套件等)
> 📌 例如 PrimeVue、VeeValidate 的初始化設定、全域註冊等
資料夾名稱
```
plugins
```
##### 新增 `src/CSS樣式` 資料夾
> 放全域樣式檔、SCSS、變數設定
> 📌 若有用 SCSS、變數或 reset.css 都放這裡
資料夾名稱
```
styles
```
##### 新增 `src/放 useXXX()` 資料夾
> 自定義 Vue 邏輯的工具(使用 Composition API)
> 📌 用來寫 useXXX() 形式的函式工具箱
資料夾名稱
```
composables
```
##### 新增 `src/工具箱` 資料夾
> 純 JavaScript 邏輯工具函式(無 Vue 依賴)
> 📌 字串處理、格式化、日期運算等不牽涉狀態的通用工具
資料夾名稱
```
utils
```
或
```
helpers
```
#### 有安裝套件類
##### 新增 `src/路由` 資料夾
> 安裝 vue-router
> 🚦 處理頁面之間的跳轉(SPA 路由系統)
資料夾名稱
```
router
```
基礎檔案
```
index.js
```
```js
// src/router/index.js
import { setupLayouts } from 'virtual:generated-layouts'
import { createRouter, createWebHashHistory, START_LOCATION } from 'vue-router/auto'
import { routes } from 'vue-router/auto-routes'
import userService from '@/services/user'
import { useUserStore } from '@/stores/user'
// 🛠️ 第 2 步:建立 router 實例並套用 layout
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
// 🧩 第 1 步:套用 Layout 與自動路由
routes: setupLayouts(routes),
})
// 🛡️ 第 3 步:設定全域路由守衛 beforeEach(判斷登入狀態與頁面權限)
router.beforeEach(async (to, from, next) => {
const user = useUserStore()
if (from === START_LOCATION && user.isLoggedIn) {
try {
const { data } = await userService.profile()
user.login(data.user)
} catch (error) {
console.error(error)
user.token = ''
}
}
if (to.meta.login === 'no-login-only' && user.isLoggedIn) {
next('/')
} else if (to.meta.login === 'login-only' && !user.isLoggedIn) {
next('/login')
} else if (to.meta.admin && !user.isAdmin) {
next('/')
} else {
next()
}
})
// 🏷️ 第 4 步:導航完成後自動設定 document.title
router.afterEach(to => {
document.title = `${to.meta.title} | 網站標題`
})
// 🧯 第 5 步:onError 錯誤處理,避免 dynamic import 崩潰
router.onError((err, to) => {
if (err?.message?.includes?.('Failed to fetch dynamically imported module')) {
if (localStorage.getItem('router:dynamic-reload')) {
console.error('Dynamic import error, reloading page did not fix it', err)
} else {
console.log('Reloading page to fix dynamic import error')
localStorage.setItem('router:dynamic-reload', 'true')
location.assign(to.fullPath)
}
} else {
console.error(err)
}
})
// 🧹 第 6 步:router 初始化完成後清除錯誤 reload 記號
router.isReady().then(() => {
localStorage.removeItem('router:dynamic-reload')
})
export default router
```
##### 新增 `src/連接後端或外部API` 資料夾
> 安裝 expess 或是 axios
> 🔁 所有「跟後端互動」的動作都寫這裡(負責 axios 請求的封裝)
資料夾名稱
```
services
```
```js
// src/services/api.js
import axios from 'axios'
import { useUserStore } from '@/stores/user'
// 無須登入即可使用(接後端)
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:4000',
})
// 須登入才能使用(接後端)
const apiAuth = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:4000',
})
// 每次發送請求前自動加上 token
apiAuth.interceptors.request.use((config) => {
const user = useUserStore()
config.headers.Authorization = `Bearer ${user.token}`
return config
})
// token 相關 成功處理與失敗處理
apiAuth.interceptors.response.use(
(res) => res,
async (error) => {
if (
error.response &&
error.response.status === 400 &&
error.response.data.message === 'token 已過期' &&
error.config.url !== '/user/refresh'
) {
const user = useUserStore()
try {
// 直接使用 apiAuth instance 發送請求,避免循環相依
const { data } = await apiAuth.patch('/user/refresh')
user.token = data.token
error.config.headers.Authorization = `Bearer ${data.token}`
return axios(error.config)
} catch {
user.logout()
}
}
throw error
},
)
export default { api, apiAuth }
```
##### 新增 `src/鳳梨` 資料夾
> 安裝 pinia
> 🧠 管理全域狀態(登入資訊、購物車、token 等),類似 Vuex 的進化版
資料夾名稱
```
stores
```
```
pinia
```
檔案
```
index.js
```
```
// src/stores/index.js
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
export default pinia
```
---
### 日期處理
```bash
npm i dayjs
```
### icon 額外擴充
{%preview https://hackmd.io/@63Ywhax5TLKtGhFSWnacvQ/SkLmkfOlWe %}
## 3️⃣ 明確功能型功能(安裝你需要用的功能套件,依需求增減)
📦 定義:為了「特定功能」才會加的套件,專案不同會差很多。
作業要用到 gsap、swiper、animejs
```bash
npm install gsap swiper animejs
```
| 套件名 | 分類 | 用途 | 特點 | 適合情境 |
| ------------ | ----- | ---------- | ------------------------------------ | ------------------ |
| **GSAP** | 明確功能型 | 強大動畫函式庫 | 功能完整、控制精細、效能佳 | 頁面轉場、滾動動畫、複雜動畫流程 |
| **Swiper** | 明確功能型 | 幻燈片輪播工具 | 手機觸控友善、支援 loop / autoplay / lazyload | Banner、圖片輪播、步驟流程切換 |
| **Anime.js** | 明確功能型 | 動畫函式庫(較輕巧) | 語法簡潔、適合小動畫 | 元素浮動、icon 動畫、數字增減 |
> **Swiper**有vue版,所以:
> 📌 使用 Swiper 時需搭配 `swiper/vue` 元件匯入,並引入樣式 `swiper/css`
---
## 需增加的檔案內容
安裝完之後要思考:
1. vite.config 是否需掛載
2. main.js(或 .ts)是否需要匯入
### vite-project\vite.config.js
```
vite.config.js
```
```js
import { fileURLToPath, URL } from 'node:url'
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
// --- Plugins ---
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { VueRouterAutoImports } from 'unplugin-vue-router'
import VueRouter from 'unplugin-vue-router/vite'
import Layouts from 'vite-plugin-vue-layouts-next'
import tailwindcss from '@tailwindcss/vite'
// https://vite.dev/config/
export default defineConfig({
plugins: [
tailwindcss(),
VueRouter({
dts: './types/typed-router.d.ts',
}),
Vue(),
Layouts({
defaultLayout: 'default',
}),
AutoImport({
imports: [
'vue',
VueRouterAutoImports,
{
pinia: ['defineStore', 'storeToRefs'],
},
],
dts: 'src/auto-imports.d.ts',
dirs: ['src/stores'],
eslintrc: {
enabled: true,
},
vueTemplate: true,
}),
Components({
extensions: ['.vue'],
include: [/\.vue$/, /\.vue\?vue/],
dts: 'src/components.d.ts',
}),
],
optimizeDeps: {
exclude: [
'vue-router',
'unplugin-vue-router/runtime',
'unplugin-vue-router/data-loaders',
'unplugin-vue-router/data-loaders/basic',
],
},
define: { 'process.env': {} },
resolve: {
alias: {
'@': fileURLToPath(new URL('src', import.meta.url)),
},
extensions: ['.js', '.json', '.jsx', '.mjs', '.ts', '.tsx', '.vue'],
},
server: {
port: 3000,
},
})
```
### vite-project\src\App.vue
```
App.vue
```
```html
<template>
<div id="app">
<router-view />
</div>
</template>
<script setup>
// ...
</script>
```
### vite-project\src\main.js
```
main.js
```
```js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import App from './App.vue'
import router from './router'
// 引入 Tailwind CSS 主樣式
import './style.css'
const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
app.use(router)
app.mount('#app')
```
```js
import { createApp } from 'vue'
import router from './router'
import pinia from './stores'
import './style.css'
import App from './App.vue'
// 創建應用程式
const app = createApp(App)
// 安裝插件
app.use(pinia)
app.use(router)
// 掛載應用程式
app.mount('#app')
```
### vite-project\.browserslistrc
定義要支援的瀏覽器版本(例如 last 2 versions, > 1%)。
Vite / Babel / PostCSS / Autoprefixer 會依這裡決定要轉譯的語法和加的 CSS 前綴。
```
.browserslistrc
```
```
> 1%
last 2 versions
not dead
not ie 11
```
### vite-project\.editorconfig
統一編輯器的基本格式設定(縮排、換行符號、字元編碼等),確保團隊開發風格一致。
```
.editorconfig
```
```
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
```
### vite-project\.eslintrc-auto-import.json
unplugin-auto-import 生成的檔案,列出自動匯入的變數/函式,讓 ESLint 知道它們是合法的全域變數,不會報「未定義」
```
.eslintrc-auto-import.json
```
### vite-project\auto-imports.d.ts
unplugin-auto-import 自動生成,聲明自動匯入的函式/變數型別,讓 TypeScript 能正確提示與檢查。
```
auto-imports.d.ts
```
### vite-project\components.d.ts
unplugin-vue-components 生成,聲明自動註冊的 Vue 元件型別,讓模板內使用時有 IntelliSense 提示。
```
components.d.ts
```
### vite-project\index.html
Vite 的專案入口 HTML,會載入 JS 入口檔(如 main.js 或 main.ts)
```
index.html
```
### vite-project\jsconfig.json
設定專案的路徑別名(例如 @ 指向 src),提供給 VSCode 與 TypeScript 的 IntelliSense 使用。
在純 JS 專案中等同 tsconfig.json 的路徑設定功能。
```
jsconfig.json
```
```json
{
"compilerOptions": {
"allowJs": true, // 允許 JavaScript 檔案
"target": "ES2020", // 使用較新 JS 標準(支援 async/await)
"module": "ESNext", // 使用原生模組
"baseUrl": ".", // 設定相對路徑基礎
"paths": {
"@/*": ["src/*"] // 設定 @ 為 src 的別名
},
"moduleResolution": "bundler",// 配合 Vite bundler 行為
"jsx": "preserve", // 為 Vue JSX 保留
"types": ["vite/client"], // 支援 Vite 環境變數
"lib": ["ESNext", "DOM"] // 使用最新 JS + DOM 型別
},
"include": ["src/**/*", "types/**/*.d.ts"]
}
```
### vite-project\typed-router.d.ts
與 unplugin-vue-router 相關,提供型別安全的路由參數與路徑提示。
```
typed-router.d.ts
```
---
# 各資料夾「建立時機」與啟用條件
| 資料夾 / 功能區 | 建立時機 or 什麼情況需要? | 備註 |
| -------------- | ------------------------------------------- | --------------------------- |
| `router/` | 安裝 `vue-router` 後(無論是手動還是自動路由) | 建立 `index.js` 並定義 routes |
| `views/` | 一開始就需要,對應每個路由畫面 | 每個畫面一個 .vue |
| `components/` | 實作畫面時會自然需要(按鈕、表單、卡片等) | 建議分類 + 對應 props/slots |
| `plugins/` | 安裝任何 Plugin 後(如 PrimeVue, VeeValidate) | 把初始化邏輯集中收納 |
| `store/` | 有跨元件 / 跨頁共用資料時(登入狀態、購物車等) | Pinia + plugin 註冊 |
| `services/` | 只要開始呼叫 API,就應建立 | 每個功能模組一個 .js |
| `composables/` | 出現多次共用邏輯時(如 useForm、useAuth、useQueryString) | 自定義 useXXX 函式區 |
| `constants/` | 有固定選項、對照資料、狀態碼等時(如 select 選單) | 與邏輯分離,方便維護 |
| `.env` | 有 baseURL、PORT、API key 等變數需求時 | `VITE_` 為前端變數前綴 |
| `.gitignore` | 開專案第一天就該建立 | 避免上傳 node\_modules / .env 等 |
# 🧩 前端套件分類表
| 套件名稱 | 安裝位置 | 類型 | 用途說明 | 代表常見用途 |
| ---------------------- | ---- | ------- | ------------------------- | ----------- |
| `vue` | ✅ 前端 | 主框架 | 建立 Vue App | 必裝主角 |
| `vite` | ✅ 前端 | 開發工具 | 開發伺服器、熱更新 | 必裝主角 |
| `@vitejs/plugin-vue` | ✅ 前端 | 插件 | 支援 `.vue` 組件語法 | Vite 必備 |
| `vue-router` | ✅ 前端 | 路由工具 | 頁面切換、SPA | 路由系統 |
| `pinia` | ✅ 前端 | 狀態管理 | Vue 3 官方推薦 state 工具 | 全域資料 |
| `axios` | ✅ 前端 | HTTP 工具 | 前端請求 API | 抓資料 |
| `vee-validate` / `yup` | ✅ 前端 | 表單驗證 | 表單輸入檢查 | 登入、註冊 |
| `@iconify/vue` | ✅ 前端 | Icon | 通用 icon 套件 | 自定義圖示 |
| `dayjs` | ✅ 前端 | 日期處理 | 處理時間與格式 | 預約、顯示日期 |
| `gsap` / `animejs` | ✅ 前端 | 動畫 | 控制動畫流程 | 頁面轉場 |
| `swiper` | ✅ 前端 | 輪播工具 | 輪播圖、滑動效果 | banner、步驟切換 |
| `@vueuse/core` | ✅ 前端 | 工具函式庫 | 一堆超實用的 Vue composition 工具 | 類似小助手 |
| `vite-plugin-inspect` | ✅ 前端 | Vite 插件 | 檢查套件掛載情況 | debug 開發流程 |
---