# 壹、nuxt.js 課程
## 一、linux server 建立 - 使用 google gcp

## 為什麼要用 nuxt
## 二、linux 指令

## 三、使用 pm2 架設 nuxt 站台
### 1. 專案的開發環境
1、開發環境 - Development (DEV)
2、生產環境 - Production (PROD、PRO)
3、測試環境 - System Integrate Test (SIT)
4、了解 nuxt 如何建構各種環境 - package.json
### 2. 學習架設nuxt網站,其實就是架設 node.js 網站
使用pm2架設生產環境所需的 server
- 我們通常會使用 pm2 來架設(管理) node.js 網站
- 使用 pm2 的好處:重開機會自動重啟 node 程式、cpu 負載平衡的設定 (需設定)
- 架設 nuxt 應用程式,請使用 nuxt-start 套件與 pm2 做搭配。
- 安裝 pm2 配合 nuxt-start 使用
| npm install pm2 -g
| npm install nuxt-start
- 執行 pm2
| pm2 init
| npm run build (因為 nuxt-start Package 也吃生產環境,所以安裝完nuxt-package 要在 build 一次)
| pm2 start
- 查看 pm2 狀態
| pm2 list
- 關閉 pm2
| pm2 delete all
## 四、伺服器環境安裝 node.js、pm2、nginx、git
到 google gcp linux 下安裝環境
### 1. 安裝 NVM
[NVM](https://github.com/nvm-sh/nvm) 使用
```
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
```
安裝完後重開 google linux
- pm2
安裝環境在 node 特定版本下,如果切換版本會失效
```
npm install -g pm2
```
- git
| sudo apt update
| sudo apt install git
- nginx
| sudo apt update
| sudo apt install nginx
## 五、linux 使用 git 部署 nuxt 網站
- gitlab 設定 master 分支 - 本機
1、git status // 查看 develop 版控檔案的情形
2、commit 未提交的檔案
3、git checkout master //切到 master 分支
3、git merge develop //本機將 develop 分支合併至 master 分支
4、git push -u origin master
5、在 gitlab 上設定 Default Branch 為 master (Settings → Repository)
- 從 gitLab clone 程式碼到 linux
1、gitlab clone 專案 / git pull→ 4 → 5 → pm2 reload id
2、練習刪除專案資料夾 (rm -r 專案 / sudo rm -r 專案)
3、cd 到專案
4、npm install
5、npm run build
6、pm2 start

git pull -> pm2 relaod {id} 才會重抓程式碼
## 六、網域註冊與設定 DNS
- 到網域服務網站購買網域, ex: goDaddy
- 將A紀錄指向 VM 的 ip

- 外部 ip 位置為浮動的,因此要把它設定為固定 ip 才不會跑掉
- 左邊選單 → 虛擬私有雲網路 → 外部 ip 位址
- 保存 → 臨時 改成 靜態
## 七、nginx 架站
1、node 透過 pm2 來架設站台 (port 通常都設定在1024 以上)
2、架設 nginx 伺服器 (nginx 偵聽 80 port)
3、nginx 透過 反向代理機制,將 來源網址 代理到 node 站台
### 一、nginx 指令
1、sudo nginx //啟動 nginx 伺服器 (預設裝好己啟動)
2、sudo nginx -s reload //重整nginx 伺服器
3、sudo nginx -s stop //快速停止伺服器
4、nginx 位置:/etc/nginx
5、nginx log 檔位置: /var/log/nginx
### 二、nginx config 設定
1、sudo nano /etc/nginx/conf.d/yourdomain.com.conf
2、
server {
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://localhost:3001;
}
}
3、[進階參考](https://zh.nuxtjs.org/faq/nginx-proxy/):主要是處理緩存和最佳化配置
## 八、開發->手動部署->上線
### 1. SSL 憑證
1、參考[這篇文章](https://www.newscan.com.tw/all-seo/what-ssl-certificate.htm)
2、使用 SSL For Free 線上工具,取得免費 SSL 憑證 (憑證機構為 Let’s Encrypt)
3、但是 Let’s Encrypt 憑證每三個月就過期了
4、Linux 可透過 certbot 來自動更新憑證
### 2. certbot 安裝流程
1、
sudo apt-get update
sudo apt-get install software-properties-common // 載入 certbot 的 ppa
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx # 安裝 python 的 certbot for nginx
2、sudo certbot --nginx // 產生憑證
3、sudo nginx -s reload // 重新整理 nginx
4、sudo certbot renew --dry-run // 檢查憑證續約情況 (非必要流程)
5、sudo certbot renew //執行憑證續約動作
### 3. 開發 -> 手動部署 -> 上線
開發 (develop) →
commit →
git checkout master →
git merge develop →
git push -u origin master →
登入 linux 主機 →
cd 專案 →
git pull →
npm install →
npm run build →
pm2 reload id →
上線
# 貳、nuxt.js 開發準備工作
## 一、nuxt 開箱 - vue 重點整理
### 1. nuxt 注意事項
- node 使用 CommonJS 作為模組化編程的標準
- CommonJS 使用 require 引入模組,module.exports 導出模組。(es6 使用 import、export)
- 禁止在 created() 寫 alert, window 屬性,因為 node 的環境下沒有 window
- nuxt 引用 vue 組件、vue 套件、npm 套件要注意是否有 node.js 不支援的語法
- 自定義 port 號
package.json → "dev": "nuxt --port 3013"
- export import
1、export function → import { function 名稱 } from '~/assets/js/tool.js';
2、export default function → import 自定義名稱 from '~/components/Logo.vue';
## 二、scss 的安裝與引用
### 1. 引用
- ~ @ 代表根目錄
**nuxt.config.js 和非 nuxt 結構的檔案除外**
必須使用 ./ 相對路徑去找檔案
- 放在 static 資料夾裡的引用方式
```
<img src="/demo.png" alt="">
```
- 通常為靜態資源,不會被變動的資源
### 2. 安裝 scss
| npm install node-sass sass-loader
node-sass、sass-loader版本不要用最新的
```
"node-sass": "^6.0.0",
"sass-loader": "^10"
```
## 三、nuxt.config.js 設置
### 配置、視圖、數據資料

配置包含全域設定、plugin、模塊
- head
- css 設定
- 引入 favicon link
linkL [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon' }
]
- 引入 static 資料夾要用 /
- 加入全域 css
css: ['~/assets/scss/main.scss'];
- 引用 cdn
script: [
{ src: "/jquery.min.js" },
{ src: "http://...." }
]
## 四、nuxt 圖片處理 - webpack 相關設定
### 1. css 背景圖片
css 背景引入圖片不能加斜線
background: url(~assets/images/...)
### 2. nuxt 圖檔轉 base64
- nuxt 圖檔小於 1kb 會自動轉為 base64 編碼
- 將預設 1kb 的限制調高
```javascript=
// nuxt.config.js
build: {
loaders: {
imgUrl: { limit:100000 } // 將圖檔大小調整為 100k 以下就轉為 base64
}
}
```
- 修改 webpack 設定檔案
```javascript=
// nuxt.config.js
build: {
extend(config, ctx) {
// 將原設定檔做覆蓋
}
}
```
### 3. postCSS 相關設定
- 透過 postCSS 為 css 加上前綴
```javascript=
// nuxt.config.js
build: {
postcss: {
preset: {
autoprefix: {
browsers: ["last 1 version"]
}
}
}
}
```
#### 4. 將 css 輸出成單一檔案
```webpack=
build: {
extractCSS: true
}
```
- 相關資訊
[官方文件](https://github.com/browserslist/browserslist)、[中文翻譯](https://juejin.im/post/5b8cff326fb9a019fd1474d6)
[nuxt文件](https://zh.nuxtjs.org/faq/postcss-plugins/)
[autoprefixer demo](https://autoprefixer.github.io/)
## 五、nuxt 頁面架構 - layout 與 page 的關係
### 1. nuxt page 指定不同 layout
```javascript=
// page 資料夾內的 .vue 檔案
export default {
layout: 'default2'
// 預設為 layouts/default,現在指向為 layouts/default2
// layout 有加 s
}
```
### 2. 自定義錯誤頁面
當找不到頁面時,nuxt 會自動去抓 layouts/error.vue 內的頁面。
[參考文件](https://zh.nuxtjs.org/docs/2.x/concepts/views/#error-page)
### 3. 不同的 page 可以定義不同的 head
注意和 nuxt.cofig.js 不同的是,這邊要用 funciton 的形式
```javascript=
<template>
<h1 class="red">Hello World</h1>
</template>
<script>
export default {
head () {
return {
title: this.title,
meta: [
{ hid: 'description', name: 'description', content: 'My custom description' }
],
script:
[
{ src: "https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.4/gsap.min.js" }
]
}
}
</script>
```
[參考文件](https://zh.nuxtjs.org/docs/2.x/concepts/views/)
### 4. 自定義 nuxt 模板
相當於最外層的 document

- 根目錄新增一個 app.html
```javascript=
// app.html
<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
<head {{ HEAD_ATTRS }}>
{{ HEAD }}
</head>
<body {{ BODY_ATTRS }}>
{{ APP }}
</body>
</html>
```
[參考文件](https://zh.nuxtjs.org/docs/2.x/concepts/views/#document-apphtml)
## 六、nuxt-link 與 頁面切換
- 頁面切換
<nuxt-link to="/">回首頁</nuxt-link>
如果使用
<a to="/">回首頁</a>
就會頁面重整。
- nuxt-link
nuxt-link 有一個重要的特性,他會幫你預加載要連結的頁面資源。他會將要連結的網址的 css 先加載到當前頁面。
如果你不要加載
<nuxt-link to="/" no-prefetch>回首頁</nuxt-link>
- css scope
為了讓頁面不互相影響,可以在 style 裡面加上 scope
## 七、nuxt component
- component 命名都是以大寫開頭
- 廣義的定義: .vue 檔都是 component
- 狹義的定義: 只有在 component 資料夾裡面才算
- nuxt component 資料夾裡面的 vue 檔不等於 pages 裡面的 vue 檔 (head, asyncData)
- component 裡面也可以引用 component
- 綁定在元件上的 click 需要加上 .native 來觸發
```vue=
<Logo @click.native="trigger" />
```
## 八、nuxt router
### 1. router 現身
```javascript=
this.$router.push('/demo');
this.$router.push({
path: '/demo'
})
this.$router.push({
name: 'demo'
})
```
### 2. 動態路由
- 在資料夾或檔案前加上_,該路由就會變成動態的
- 查看路由,console.log(this.$route)
- 指定到達的動態路由
```javascript=
<nuxt-link :to="{
name: 'demi',
params: {
test: n
}
}">
```

### 3. 嵌套路由
將資料夾裡的 page 包一層 component 出來。
在page資料夾下定義相同名稱的資料夾名稱與.vue檔案
Demo資料夾的頁面最外面就會包一層 demo.vue的資料
```vue
// pages/demo.vue
<template>
<h1>outside component</h1>
<nuxt-child />
</template>
```

### 4. 自定義路由
1、建立 router.js 檔案
```vue=
import path from "path"
//nuxt router 改在這裡定義
export default [
{
name: 'testRouter',
path: '/demo/testRouter',
component: path.resolve(__dirname, 'pages/demo/tpl.vue'),
},
{
name: 'index',
path: '/',
component: path.resolve(__dirname, 'pages/index.vue'),
}
];
```
2. 在 nuxt.config.js 設定覆蓋掉原本檔案
```vue=
import router from "./router.js"
router: {
mode: 'history', //這段可以不用寫
extendRoutes (routes, resolve) {
return router
}
}
```
## 九、nuxt plugin
### 1. CDN 套件 -> 最簡單
### 2. 使用 nuxt plugin 自包 js 套件或 vue 套件
- 包裝一般的 vue 套件
- npm install vuejs-datepicker
- plugins 新增一個檔案:datepicker.js → 撰寫套件
- nuxt.config.js 安裝 plugin → 可以設定該套件只在 客戶端 運作

- 安裝一般的 js 套件
- npm install gsap
- plugins 新增一個檔案:gsap.js → 撰寫套件

### 3. 使用 nuxt modules 來引入套件
- nuxt 安裝 axios module
- npm install @nuxtjs/axios

## 十、SSR 的運作原理

nuxt 只有第一次進入網頁時,才會用 SSR。
之後的跳頁就會回歸到 spa 模式。
# 貳、資料處理
## 一、asyncData
- 只能實作在 page 頁面,不能放在 component
- 第一次載入會在 server 端運行,之後就會在 client端執行
- asyncData return 出來的 data,會取代 vue 中的 data
- 打 ajax 時,要返回一個 promise,或採用 async await 執行,才能取代 data
- 方法一:透過 async await
```javascript=
async asyncData(context) {
let data = await context.$axios("/api/test");
return data.data;
}
```
```javascript=
async asyncData({$axios}) { // 透過解構
let data = await $axios("/api/test");
return data.data;
}
```
- 方法二:返回一個 promise
```javascript=
asyncData(context){
return context.$axios("/api/test").then(data => {
return data.data
})
}
```
- acyncData 的 this 是 undefined,不是 vue 中的 this,須透過 context 上下文提供的 app vue 實例來操作前端的行為
## 二、nuxt 的生命週期

## 三、nuxt 的 proceess
- process 是 node.js 的一個全域物件,提供 node 執行時的相關資訊
- nuxt 前端的 process 不等於後端的 process
- nuxt 最常使用 process.client 和 process.server 來判斷目前程式碼在前端還是後端運作
- 判斷生產環境or開發環境 process.env.NODE_ENV
## 四、nuxt vuex
### 1. 輕量級的寫法

```javascript=
export const state = () => ({
test_data:{
aaa: 1,
bbb: "string"
}
})
export const getters = {
get_aaa: state => {
return state.test_data.aaa;
},
get_aaabbb: state => {
return state.test_data.aaa + state.test_data.bbb;
},
}
export const mutations = {
add_test_data: (state, payload) => {
state.test_data.title = payload.title
state.test_data.aaa ++;
},
}
export const actions = {
}
```
### 2. 大型專案的寫法
在根目錄創造一個 constants.js 檔案,作為 vuex 的全域變數名稱。
使用 types 中的變數名稱來命名函數
```javascript=
import * as types from '@/constants.js'
export const state = () => ({
test_data:{
aaa: 1,
bbb: "string"
}
})
export const getters = {
[types.SET_CONFIG_URL]: state => {
return state.test_data.aaa;
},
get_aaabbb: state => {
return state.test_data.aaa + state.test_data.bbb;
},
}
export const mutations = {
add_test_data: (state, payload) => {
state.test_data.title = payload.title
state.test_data.aaa ++;
},
}
export const actions = {
}
```
- 模組變多後,那每個檔案都要寫import * as types from '@/constants.js',會很麻煩,這時可以透過 nuxt.config.js 去設定全域變數
- nuxt.config.js 設定
import webpack from 'webpack'
build: {
plugins: [
new webpack.ProvidePlugin({
_M: "~/constants.js"
})
]
}
- 使用 _M 代替之前的 types
[_M.SET_CONFIG_URL]:(state, payload) =>{
},
## 四、nuxt vuex action
- action 內可以做非同步的行為
- action 內可以透過 context 內的方法去變動 vuex 其他的資料
```javascript=
export const actions = {
async ajaxTest(context, payload) {
let data = await this.$axios("/api/test");
console.log(data)
// 使用 mutation 去將 ajax 回來的資料填進去 data
context.commit("add_test_data", {
title: data.data
})
}
}
```
## 五、 vuex fetch
asnycData 是更動 page 中 data 的資料
fetch 則是更動 vuex 中 state 的資料