本篇文章同步更新於個人部落格,歡迎交流指教~謝謝您的閱讀
Nuxt3 定義了完整的目錄規則,讓我們可以輕鬆配置功能,專注在開發上
透過 npx nuxi@latest init <project-name>
安裝專案後,可以看到如下的預設目錄
看起來分類似乎有點不齊全,接下來跟著官方文件一起建立完整的專案目錄
my-app/
|—— .nuxt/
|—— .output/
|—— assets/
|—— components/
|—— composables/
|—— content/
|—— layouts/
|—— middleware/
|—— node_modules/
|—— pages/
|—— plugins/
|—— public/
|—— server/
|—— api/
|—— routes/
|—— middleware/
|—— utils/
|—— .env
|—— .gitignore
|—— .nuxtignore
|—— app.config.ts
|—— app.vue
|—— nuxt.config.ts
|—— package.json
|—— tsconfig.json
Nuxt 在編譯過程中生成的暫存資料夾。是 Nuxt 執行編譯和 server 端渲染時使用的重要資源,無法手動調整裡面的內容(每次執行編譯時會覆寫)
執行生產環境編譯 nuxt build
(npm run build
)時自動生成的資料夾,跟 .nuxt
資料夾一樣,每次執行編譯時會更新覆寫
用來存放像是 CSS、Sass、字體、圖片等需要被 webpack 或是 Vite 編譯的靜態資源(壓縮、最佳化),如不需經過編譯,則存放於 public/
用來定義 Vue 共用元件,Nuxt 會自動引入,名稱規則為:路徑前綴 + 元件名稱,例如巢狀目錄結構如下
components/
|—— base/
|—— about/
|—— Button.vue
Button.vue
的元件名稱為
<BaseAboutButton />
組合式函式,利用 Composition API 來封裝和複用 **有狀態邏輯(Stateful Logic)**的函式,取代 Options API mixins
的功能。定義在 composables/
內的檔案 Nuxt 會自動引入
我們可以將不同的邏輯抽象成單獨的 composable
,並組合在 setup
函式中。比起 mixins
,composable
協助我們更好理解組件的結構和功能,並提高程式碼的可讀性
以 composables/useCounter.js
為例
// composables/useCounter.js
export default function() {
const count = ref(0);
const increment = () => {
count.value++;
};
return {
count,
increment
};
}
在元件內使用共用方法
// pages/count.vue
<template>
<div>
<span>{{ count }}</span>
<button type="button" @click="increment">add</button>
</div>
</template>
<script setup>
const { count, increment } = useCounter();
</script>
composables 和 utils 比較可以參考 這篇文章
搭配 Nuxt Content 套件,可以讀取 content/
目錄,並解析存放於此資料夾內的 .md
、.yml
、.csv
以及 .json
檔案,建立一套內容管理系統(CMS),主要功能:
簡單來說,Nuxt Content 能夠解析 Markdown 語法文章,做到像 Hexo 一樣的功能,協助我們打造技術部落格
Nuxt Content 相關應用推薦參考 這篇文章
用來存放共用模板,官方文件提到,如果整個專案只有一個模板,建議直接在 app.vue
定義即可
首先新增預設模板 layouts/default.vue
,必須加上 <slot />
,引用的頁面才能插入內容
// layouts/default.vue
<template>
<div>
default layout
<slot />
</div>
</template>
在頁面上使用 layout
// app.vue
<template>
<div>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</div>
</template>
layouts/
|—— default.vue
|—— custom.vue
如果我們想在單一元件使用 custom.vue
layout,可以用 definePageMeta
覆蓋預設模板
// pages/about.vue
<script>
definePageMeta({
layout: 'custom'
});
</script>
Nuxt 內的 路由守衛(Navigation Guards),相當於 Vue Router 內的 beforeEach callback,協助我們在進到頁面前執行一些事件,像是權限檢查
middleware 定義方式:
middleware/
定義,並在需要的頁面引入.global
後綴,在所有頁面切換時自動執行middleware/
|—— auth.ts
|—— setup.global.ts
建立一個 middleware
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const auth = useState('auth');
if (!auth.value.isAuth) {
return navigateTo('/login');
}
});
在頁面內使用
// pages/about.vue
<script setup>
definePageMeta({
middleware: [
function (to, from) { // 匿名方式
// 客製 middleware
},
'auth'
]
});
</script>
用來配置主要頁面的資料夾,定義後 Nuxt 會自動整合 Vue Router,依照資料夾以及檔案結構配置路由,例如:pages/work.vue
會被映射到 /work
如果要使用
pages/
,app.vue
需加上<NuxtPage />
用於顯示定義的頁面
動態路由使用方括號 []
包覆(Nuxt2 使用下底線 _
)
範例:
pages/
|—— index.vue
|—— products-[category]/
|—— [id].vue
透過 $route
可以取得 category
跟 id
值:
<template>
<p>{{ $route.params.category }} - {{ $route.params.id }}</p>
</template>
當我們切到頁面 /products-bag/112345
,畫面渲染如下:
bag - 112345
使用 [...slug].vue
匹配該路徑下的所有層級路由,可以用來處理找不到路由的預設頁面
範例:
pages/
|—— index.vue
|—— [...slug].vue
當使用者輸入不存在的頁面,例如:/hello
或是 /hello/claire
,會自動轉到 [...slug].vue
用來定義插件,plugins/
內的檔案 Nuxt 會自動引入,如果要限制在 server 或是 client 端使用,檔名需加上 .server
或 .client
後綴
範例: 引入 vue3-notification 第三方套件
npm i @kyvg/vue3-notification
plugin
plugins/
|—— notification.client.ts
import Notifications from '@kyvg/vue3-notification';
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(Notifications);
});
<script>
import { useNotification } from '@kyvg/vue3-notification';
export default {
setup() {
const { notify } = useNotification();
onMounted(() => {
notify({
title: "Authorization",
text: "You have been logged in!",
});
});
}
};
</script>
靜態資源資料夾(同 Nuxt2 的 static/
),用來存放不需要被編譯的檔案,像 CSS、 文字或圖片,透過根目錄 /
即可使用 public/
檔案,檔案如需被編譯,則存放於 assets/
Nuxt3 搭配新的伺服器引擎 Nitro,讓我們可以在 server 端定義內容,像是建立 API 以及透過 Server Middleware 處理事件
簡單說明 server/
內的資料夾功能:
/api
前綴的 API 路徑/api
前綴的 API 路徑定義在 utils/
內的檔案 Nuxt3 會自動引入,官方文件提到 utils/
資料夾的拆分主要是為了跟 composables/
做區隔,前面有提到 composables/
利用 Composition API 來封裝和複用 有狀態邏輯(Stateful Logic),而 utils/
則用來定義 無狀態邏輯(Stateless Logic)
以 utils/toThousands.js
為例(將數字帶入千分號)
// utils/toThousands.js
export default num => {
if (!num) {
return num;
}
const parts = num.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
};
在頁面使用
// pages/count.vue
<template>
<div>
$ {{ toThousands(19999) }}
</div>
</template>
編譯結果: $ 19,999
設定 Nuxt 編譯時忽略根目錄 layouts
、pages
、components
、composables
、middleware
內的檔案
# 忽略 layout custom.vue
layouts/custom.vue
# 忽略 layout -ignore.vue 結尾的檔案
layouts/*-ignore.vue
# 忽略 page about.vue
pages/about.vue
# 忽略 ignore 資料夾內的 page 檔案
pages/ignore/*.vue
# 忽略 route middleware custom 資料夾內檔案,排除 custom/bar.js
middleware/custom/*.js
!middleware/custom/bar.js
設定全域共用的資料,只能在 client 端取得
官方文件提到,不建議將任何機密資料存放於此
// app.config.ts
export default defineAppConfig({
theme: {
color: '#0d6efd'
}
})
在頁面使用
// pages/about.vue
<script>
export default {
setup() {
const appConfig = useAppConfig();
onMounted(() => {
console.log(appConfig.theme.color); // output: #0d6efd
});
}
};
</script>
專案進入點,Nuxt3 將 app.vue
移到目錄頁,讓開發者可以只使用 app.vue
來建置網站(例如單頁 Landing Page),而不定義 pages/
資料夾。
如果要使用 pages/
,app.vue
需加上 <NuxtPage />
用於顯示定義的頁面(功能同 Vue Router <router-view />
)
// app.vue
<template>
<div>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</div>
</template>
Nuxt 設定檔,相關設定 參考文件
// nuxt.config.ts
export default defineNuxtConfig({
// My Nuxt config
})
配置 extends 或是覆蓋預設的 TypeScript 設定
如要設定路徑別名,若直接在
tsconfig.json
設定,將會覆寫預設的alias
,建議在nuxt.config
檔設定,Nuxt 會加到自動生成的tsconfig
// tsconfig.json
{
"extends": "./.nuxt/tsconfig.json" // 自動生成的 tsconfig
}
參考資源:
https://nuxt.com/docs/guide/directory-structure/nuxt
https://ithelp.ithome.com.tw/articles/10295432