:::warning
參考[Nuxt 3 學習筆記](https://ithelp.ithome.com.tw/users/20152617/ironman/5934)
:::
## 目錄
[TOC]
## ▊ CSR、SSR、SSG
### ▎客戶端渲染 (Client-Side Rendering, CSR)
所有的頁面渲染 (render) 都透過瀏覽器端的 Javascript 來完成,也就是所有的邏輯、取資料、路由、template 都在客戶端處理,因為此特性也可以做到只渲染部分 HTML 達到更好的效能,體驗上也會比較順暢。
像 **Vue** 這類 **SPA (Single-Page Application)** 框架,會將前後端進行分離的框架,僅專注在畫面上,所以通常是 CSR。


當HTML下載完後,FCP 會發生,此時畫面會是空白的,若是等待 Javascript 檔案下載的過程比較久,畫面也會持續是空白的,直到完成下載後執行渲染觸發畫面更新才達到 TTI 。
:::info
:information_source: **FCP (First Contentful Paint,首次內容繪製)**
* 瀏覽器在頁面上呈現第一個 DOM 元素的時間,此元素可能不是從伺服器呈現或載入的第一個元素,但它是用戶可以看到的第一個元素。
:information_source: **TTI (Time-to-interactive,可交互時間)**
* 頁面載入後,使用者可與瀏覽器互動並能給予回應的時間。
:::
#### ▏優點
##### ▢ 使用者體驗較佳
跳轉頁面時,不再需要由伺服器重新渲染整個頁面,前端框架會幫我們實現部分元素更新,所以使用者體驗較佳。
##### ▢ 實現前後端分離
讓前端能更專注 UI 開發,後端專注 API。
##### ▢ 伺服器負擔較小
因為渲染工作皆在客戶端完成,所以伺服器負擔也較小。
#### ▏缺點
##### ▢ 載入速度慢
因為要等待 Javascript 下載和執行渲染,所以使用者必須等待一段時間才能看到頁面的內容,在低階的的裝置上體驗會比較差。
##### ▢ 不利於搜尋引擎最佳化 (Search Engine Optimization, SEO)
因為CSR的特性,搜尋引擎蒐集與索引到的HTML並不包含客戶端所需要即時請求的資料,所以無法解析這些資料可能含有的關鍵字等索引。
:::success
:writing_hand: **解決方法**
* 採用**預渲染 (pre-rendering)** 讓網頁請求送達伺服器端後,返回包含資料的HTML:像是**Server-Side Rendering** 和 **Static Site Generationa** 等技術。
:::
---
### ▎伺服器端渲染 (Server-Side Rendering, SSR)
又稱為 **後端渲染**,伺服器收到使用者的請求之後,會在伺服器端生成完整的 HTML,因為生成 HTML 的時候會在伺服器端先取得內部或外部 API 資料,所以相較於 CSR 從瀏覽器端取資料的模式,SSR 可以省去多次的來回往返。


伺服器渲染完後 HTML 傳給使用者,此時已有完整的 HTML,接著下載並執行瀏覽器端互動所需要的 Javascript。
#### ▏優點
##### ▢ TTI 較快
因為需要的 Javascript比較少,所以有較快的TTI。也有更多的 JS 預算可以留給第三方 JS 使用。
##### ▢ 有利於 SEO
因為首次進入網站時,HTML已經在伺服器端渲染完畢,搜尋引擎便能準確抓取資料。
#### ▏缺點
##### ▢ TTFB 較慢
因為在伺服器產生完整的 HTML 很花時間。如果同時有許多人造訪 server 造成負擔很重,或是有一些非常慢的 API,都有可能讓 server 的回應速度非常慢。
##### ▢ 互動性體驗差
因為 SSR 的頁面在每次互動之間都要重新讀取頁面,這在使用體驗上就不如 CSR 的頁面順暢。
:::info
:information_source: **TTFB (Time to First Byte,第一個字節時間)**
* Web 瀏覽器在造訪網站後,接收到伺服器回應數據的時間,也就是當使用者的滑鼠點擊網站的那一刻開始,到接收到一個數據資料之間所等待的時間。
:::
---
### ▎靜態頁面生成 (Static Site Generation, SSG)
是產生靜態頁面的技術,使用 SSG 技術的網站通常在編譯打包時期就會連帶編譯產出靜態網頁,因此 SSG 非常適合做內容不大會變動的靜態網站,這些編譯出來的頁面也能上 CDN 被快取。
不過也會因為網站大小而導致因為打包的時間可能過長,且在頁面內容需要改變,就必須要重新編譯打包,所以沒辦法像 CSR 或 SSR 具有動態內容的彈性。
雖然 SSG 有一些缺點與劣勢,但也有 ISR (Incremental Static Regeneration) 等技術來解決。
#### ▏優點
##### ▢ 減輕伺服器負擔
打包編譯時產生出網頁原始碼 HTML 檔案,即靜態資源檔案,因此能很好的搭 CDN 緩存來減輕伺服器負擔。
##### ▢ 有利於SEO
因為打包編譯時產生出網頁原始碼 HTML 檔案,正是可以讓搜尋引擎爬蟲解析的完整網頁資料。
#### ▏缺點
##### ▢ 彈性差
如果頁面經常變動,就得再一次打包編譯,重新產生出新的一份網頁原始碼 HTML 檔案。
### ▎SSR (後端渲染) + SPA (單頁式應用程式)
若是採用SSR渲染首次進入的HTML,再用CSR做後續動態的取資料更新畫面,不就能解決SPA常見的白畫面或SEO優化問題嗎?
=> **Nuxt 框架** 或 Next.js
## ▊ Nuxt 3 介紹
### ▎Isomorphic JavaScript 與 Universal JavaScript
Nuxt 3 是一個 **Isomorphic JavaScript** 框架
#### ▏Isomorphic (同構) JavaScript
同樣的 JavaScript 程式碼可以在客戶端及伺服器端運行,也就是說同一份 Code 除了能在前端瀏覽器也能在後端執行。
#### ▏Universal JavaScript
同樣的 JavaScript 程式碼可以在不同的環境執行,也就是不僅可以在前後端執行,還可以在本機設備和嵌入式架構上運行。
### ▎Nitro
Nuxt 3 由一個全新的伺服器引擎 Nitro 提供支持,它具有以下幾個特點:
* 跨平台支持,支持 Node.js 與瀏覽器等
* Serverless 支持
* API 路由,使用 `unjs/h3`
* 自動程式碼拆分 (code-splitting) 與異步加載 chunk (async-loaded chunks)
* 混合渲染模式,供靜態 (static)與無伺服器 (serverless) 網站
* 開發伺服器上的 HMR (hot module reloading)
### ▎Nuxt 3 渲染模式
#### ▏Client-side Only Rendering
也就是客戶端渲染 CSR
#### ▏Universal Rendering
**是 Nuxt 3 預設的渲染模式**,等於 SSR + SPA。
#### ▏Hybrid Rendering
可以為每個路由設置不同的渲染與緩存規則,讓部分頁面是 CSR,另一部份是 SSR。
#### ▏Edge-Side Rendering
Nitro 為 Nuxt 3 提供支持的全新伺服器端渲染引擎,能為 Node.js、Deno、Worker 等提供跨平台的支持,讓 Nuxt 可以在 CDN Edge Workers 進行渲染。
能有效分擔在伺服器端渲染時的資源負荷,將其提升到另一個層次,從而減少網路延遲及成本。
### ▎Nuxt 3 的建構工具
* Vite (預設) / webpack
* Rollup
* PostCSS
* esbuild
Nuxt 3 已經配置好一堆設定,要調整配置,可以在 `nuxt.config` 中進行調整。
## ▊ 使用 nuxi 建立第一個專案
### ▎ 開始建立
#### ▏使用 nuxi 建立 Nuxt 3 專案
1. 在終端機輸入:`npx nuxi init nuxt-app`
完成後可以發現目前目錄下多了一個名為 `nuxt-app` 的資料夾,這個資料夾也就是 Nuxt 3 專案的根目錄。

2. 進入專案目錄`nuxt-app`:`cd nuxt-app`
3. 安裝相關套件:`npm install`
4. 啟動 Nuxt:`npm run dev -- -o`
在`app.vue`我們可以看到 `<NuxtWelcome />` ,但沒有看到設定 import 的地方, 因為 Nuxt 可以自動導入元件。

## ▊ Nuxt CLI 常用指令
在專案目錄下記得使用 `npx` 來執行 `nuxi`
### ▎`nuxi init`
```
npx nuxi init|create [dir]
```
用來初始化一個 Nuxt 專案,等價 `nuxi create` 指令。
* `dir` 可以填字串作為專案與資料夾名稱,也可以填寫完整路徑來建立專案目錄。
### ▎`nuxi dev`
```
npx nuxi dev [--open, -o] [--port, -p]
```
當我們輸入 `npm run dev -- -o` 時,其實是依據 `package.json` 中的 `scripts` 執行 `nuxt dev -o`。
* `-o`:服務啟動後開啟瀏覽器
* `-p`:將預設的 Port:3000 調整為其他數值
### ▎`nuxi cleanup`
```
npx nuxi clean|cleanup
```
等價 `nuxi create` 指令,用來刪除 Nuxt 自動產生的檔案和緩存,包括:
* `.nuxt`
* `.output`
* `node_modules/.vite`
* `node_modules/.cache`
### ▎`nuxi upgrade`
```
npx nuxi upgrade [--force|-f]
```
用來將目前專案的 Nuxt 3 升級至最新的版本
* `-f`:強制更新
## ▊ 環境建置
### ▎TypeScript
1. 安裝插件
* Vue Language Features (Volar)
* TypeScript Vue Plugin (Volar)
3. 安裝 Vue 類型檢查套件:`npm install -D vue-tsc`
5. 調整 `nuxt.config.ts` 設定:`typescript.typeCheck: true`
### ▎ESLint
1. 安裝套件:`npm install -D eslint @nuxtjs/eslint-config-typescript eslint-plugin-vue`
2. 配置 ESLint 設定黨
在根目錄建立 `.eslintrc.js`:
```javascript
module.exports = {
env: {
browser: true,
es2021: true
},
extends: ['@nuxtjs/eslint-config-typescript', 'plugin:vue/vue3-recommended'],
parserOptions: {
ecmaVersion: 13,
sourceType: 'module'
},
plugins: [],
rules: {},
overrides: [
{
files: [
'**/pages/**/*.{js,ts,vue}',
'**/layouts/**/*.{js,ts,vue}',
'**/app.{js,ts,vue}',
'**/error.{js,ts,vue}'
],
rules: {
'vue/multi-word-component-names': 'off'
}
}
]
}
```
### ▎Prettier
1. 安裝Prettier 套件:`npm install -D prettier eslint-config-prettier eslint-plugin-prettier`
2. 配置 Prettier 設定檔案
在根目錄建立 `.prettierrc.js`:
```javascript
module.exports = {
printWidth: 100, // 每行文字數量達 100 字元就換到新的一行
semi: false, // 每個語句的結尾不需要分號
singleQuote: true, // 字串使用單引號,而不是雙引號
trailingComma: 'none' // 如 Object、Array 內的元素不需要尾隨逗號
}
```
4. 配置 ESLint 設定檔案
```
module.exports = {
env: {
browser: true,
es2021: true
},
extends: ['@nuxtjs/eslint-config-typescript', 'plugin:vue/vue3-recommended', 'prettier'],
parserOptions: {
ecmaVersion: 13,
sourceType: 'module'
},
plugins: ['prettier'],
rules: {
'prettier/prettier': 'error'
},
overrides: [
{
files: [
'**/pages/**/*.{js,ts,vue}',
'**/layouts/**/*.{js,ts,vue}',
'**/app.{js,ts,vue}',
'**/error.{js,ts,vue}'
],
rules: {
'vue/multi-word-component-names': 'off'
}
}
]
}
```
## ▊ Tailwind CSS
走兩種配置的方法:**使用 Nuxt Tailwind 模組** 和 **Tailwind CSS 官方指引步驟**。
### ▎使用 Nuxt Tailwind 模組
1. 安裝套件:`npm install -D @nuxtjs/tailwindcss`
2. 添加模組至 `nuxt.config.ts`
```javascript
modules: ['@nuxtjs/tailwindcss'],
typescript: {
typeCheck: true
}
```
#### ▏擴充或覆寫`@nuxtjs/tailwindcss`配置
想要修改可以透過建立設定檔來新增或覆寫預設定
##### ▢ `tailwind.css`
若存在路徑檔名一致的 `./assets/css/tailwind.css` 檔案,即可取代預設的 `tailwind.css` 檔案。
```css
/* 預設內容 */
@tailwind base;
@tailwind components;
@tailwind utilities;
```
##### ▢ `tailwind.config.js`
專案目錄下若存在 `tailwind.config.js` 檔案就會以新的配置拓展或覆寫 預設的 `tailwind.config`。
```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./components/**/*.{vue,js,ts}',
'./layouts/**/*.vue',
'./pages/**/*.vue',
'./composables/**/*.{js,ts}',
'./plugins/**/*.{js,ts}',
'./app.{js,ts,vue}'
],
theme: {
extend: {}
},
plugins: []
}
```
### ▎Tailwind CSS 官方指引步驟
若使用 `@nuxtjs/tailwindcss` 進行配置可以跳過這段。
1. 安裝相關套件:`npm install -D tailwindcss postcss@latest postcss-custom-properties@latest autoprefixer@latest`
2. 建立 `tailwind.config.js`:`npx tailwindcss init`
4. 調整 `tailwind.config.js`,在 `content` 添加一些路徑:
```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./components/**/*.{vue,js,ts}',
'./layouts/**/*.vue',
'./pages/**/*.vue',
'./composables/**/*.{js,ts}',
'./plugins/**/*.{js,ts}',
'./app.{js,ts,vue}'
],
theme: {
extend: {}
},
plugins: []
}
```
1. 建立 `tailwind.css`:建立目錄 `assets` 與子目錄 `css` 用來放置 Tailwind CSS 的自定義指令, `tailwind.css` 的路徑應會是 `./assets/css/tailwind.css` 檔案內容如下。
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
1. 配置全域共用 CSS:修改專案根目錄的 `nuxt.config.ts` 檔案,在 `css` 參數陣列內新增 `tailwind.css` 路徑,讓 Nuxt 可以配置全域共用的 CSS,並添加 `postcss` 選項及我們剛才安裝的套件作為插件,最後 `nuxt.config.ts` 檔案看起來如下。
```javascript
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
postcss: {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {}
}
},
css: ['@/assets/css/tailwind.css'],
typescript: {
typeCheck: true
}
})
```
<br>
建完後專案目錄會是:
```
nuxt-app
├── .nuxt/
├── assets/
│ └── css/
│ └── tailwind.css // 手動新增的檔案,用於設置 Tailwind CSS 指令並讓全部頁面引用
├── node_modules/
├── .eslintrc.js
├── .gitignore
├── .prettierrc.js
├── app.vue
├── nuxt.config.ts
├── package-lock.json
├── package.json
├── README.md
├── tailwind.config.js // Tailwind 初始化指令產生的設定檔
└── tsconfig.json
```
### ▎自動排序 Tailwind CSS 的 Class
1. 安裝插件 `npm install -D prettier-plugin-tailwindcss`
2. 配置設定檔
開啟 `.prettierrc.js` 檔案,添加 `'prettier-plugin-tailwindcss'` 至 `plugins` 陣列中:
```javascript
module.exports = {
plugins: [
'prettier-plugin-tailwindcss'
],
printWidth: 100, // 每行文字數量達 100 字元就換到新的一行
semi: false, // 每個語句的結尾不需要分號
singleQuote: true, // 字串使用單引號,而不是雙引號
trailingComma: 'none' // 如 Object、Array 內的元素不需要尾隨逗號
}
```
1. 自動修正效果
設置 `editor.codeActionsOnSave` 中 `source.fixAll.eslint`: `true` 來達到保存後自動修正 prettier 引發的 ESLint 錯誤。
```javascript
"editor.codeActionsOnSave": {
"source.fixAll": true
}
```
## ▊ Nuxt 3 目錄結構
### ▎Nuxt 3 預設的目錄結構
完整的 Nuxt 3 專案目錄結構:
```
nuxt-app/
├── .nuxt/
├── .output/
├── assets/
├── components/
├── composables/
├── content/
├── layouts/
├── middleware/
├── node_modules/
├── pages/
├── plugins/
├── public/
└── server/
├── api/
├── routes/
└── middleware/
├── .gitignore
├── .nuxtignore
├── app.config.ts
├── app.vue
├── nuxt.config.ts
├── package.json
└── tsconfig.json
```
#### ▏`.nuxt` 目錄
開發環境下由 Nuxt 產生出 Vue 的網站,`.nuxt` 目錄是自動產生的,不應該任意的調整裡面檔案。
#### ▏`.output` 目錄
當網站準備部署至正式環境時,每次編譯建構專案時,皆會自動重新產生,不應該任意的調整裡面檔案。
#### ▏`assets` 目錄
靜態資源檔案所放置的位置,目錄內通常包含以下類型的檔案:
- CSS 樣式檔案 (CSS、SASS 等...)
- 字型
- 圖片
這些靜態資源,最終在專案編譯建構時,由 Vite 或 webpack 進行編譯打包。
#### ▏`components` 目錄
放置 Vue 元件的地方,Nuxt 會**自動載入**這個目錄中的任何元件。
#### ▏`composables` 目錄
組合式函數放置的目錄,簡單來說可以把常用或通用的功能寫成一個共用的函數或 JS 檔案,放置在這個目錄視為組合式函數,Nuxt 也會**自動載入**這些組合式函數,讓需要使用的頁面或元件可以直接做使用。
#### ▏`content` 目錄
透過使用 [Nuxt Content](https://content.nuxtjs.org/),我們可以在這個目錄下建立 `.md`、`.yml`、`.csv` 和 `.json` 檔案,Nuxt Content 會讀取並解析這些文件並進行渲染,用來建立基於文件的 CMS。
#### ▏`layouts` 目錄
用於放置通用或可能重複使用到的佈局模板,提供程式碼的可重複使用性。
#### ▏`middleware` 目錄
Nuxt 3 提供了路由中間件的概念,用以在導航到下一個頁面之前執行一些程式碼如權限驗證。
#### ▏`node_modules` 目錄
通常有使用 Node.js 的套件管理,例如 NPM,對此目錄應該有一些印象,使用 Nuxt 3 及專案所需要的相依套件都會存放在這個目錄。
#### ▏`pages` 目錄
這個目錄主要是用來配置我們的頁面,你也可以只使用 `app.vue` 來完成你的網站,但如果建立了 `pages` 這個目錄,Nuxt 3 會自動整合 `vue-router`,並會依據目錄及檔案結構規則來`自動產生出對應路由`,也是 Nuxt3 產生路由的方式。
#### ▏`plugins` 目錄
Nuxt 會自動載入這個目錄檔案,作為插件使用,在檔案名稱可以使用後綴 `.server` 或 `.client`,例如, `plugin.server.ts` 或 `plugin.client.ts` 來決定只讓伺服器端或客戶端載入這個插件。
#### ▏`public` 目錄
這個目錄主要用於伺服器根目錄提供的文件,包含必須固定的檔案名稱如 `robots.txt` 或不太會變動的 `favicon.ico`。
#### ▏`server` 目錄
用於建立任何後端的邏輯如後端 API,這個目錄下還包含了 `api`、`server` 和 `middleware` 來區分功能,不具有自動載入,但支援 HMR。
#### ▏`.gitignore` 檔案
在使用 Git 版本控制時,可以設置一些不需要或忽略關注變動的檔案及目錄。
#### ▏`.nuxtignore` 檔案
可以設置讓 Nuxt 編譯建構時,一些不需要或忽略檔案。
#### ▏`app.config.ts` 檔案
提供服務運行時暴露給客戶端使用的設定,因此,請不要在 `app.config.ts` 檔案中添加任何機密資訊。
#### ▏`app.vue` 檔案
Nuxt 3 網站的入口點元件。
#### ▏`nuxt.config.ts` 檔案
用於配置 Nuxt 專案的設定檔。
#### ▏`package.json` 檔案
這個檔案裡面定義了專案資訊、腳本、相依套件及版本號,通常有使用 Node.js 套件管理工具建置的專案都會包含此檔案。
#### ▏`tsconfig.json` 檔案
Nuxt 3 會在 `.nuxt` 目錄下`自動產生`一個 `tsconfig.json` 檔案,其中已經包含了一些解析別名等預設配置;你可以透過專案目錄下的 `tsconfig.json` 來配置擴展或覆蓋 Nuxt 3 預設的 TypeScript 設定檔。