# 壹、nuxt.js 課程 ## 一、linux server 建立 - 使用 google gcp ![](https://i.imgur.com/9grEyF6.png) ## 為什麼要用 nuxt ## 二、linux 指令 ![](https://i.imgur.com/xBlWVlt.png) ## 三、使用 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 ![](https://i.imgur.com/Kbe55cI.png) git pull -> pm2 relaod {id} 才會重抓程式碼 ## 六、網域註冊與設定 DNS - 到網域服務網站購買網域, ex: goDaddy - 將A紀錄指向 VM 的 ip ![](https://i.imgur.com/k80lSO0.png) - 外部 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 設置 ### 配置、視圖、數據資料 ![](https://i.imgur.com/1EYB0oP.png) 配置包含全域設定、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 ![](https://i.imgur.com/2J4kVl2.png) - 根目錄新增一個 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 } }"> ``` ![](https://i.imgur.com/2YP2r15.png) ### 3. 嵌套路由 將資料夾裡的 page 包一層 component 出來。 在page資料夾下定義相同名稱的資料夾名稱與.vue檔案 Demo資料夾的頁面最外面就會包一層 demo.vue的資料 ```vue // pages/demo.vue <template> <h1>outside component</h1> <nuxt-child /> </template> ``` ![](https://i.imgur.com/hxdA76z.png) ### 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 → 可以設定該套件只在 客戶端 運作 ![](https://i.imgur.com/922eaZL.png) - 安裝一般的 js 套件 - npm install gsap - plugins 新增一個檔案:gsap.js → 撰寫套件 ![](https://i.imgur.com/4Hmoo6i.png) ### 3. 使用 nuxt modules 來引入套件 - nuxt 安裝 axios module - npm install @nuxtjs/axios ![](https://i.imgur.com/36Op7hM.png) ## 十、SSR 的運作原理 ![](https://i.imgur.com/f1g4hwf.png) 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 的生命週期 ![](https://i.imgur.com/zbpVbf1.png) ## 三、nuxt 的 proceess - process 是 node.js 的一個全域物件,提供 node 執行時的相關資訊 - nuxt 前端的 process 不等於後端的 process - nuxt 最常使用 process.client 和 process.server 來判斷目前程式碼在前端還是後端運作 - 判斷生產環境or開發環境 process.env.NODE_ENV ## 四、nuxt vuex ### 1. 輕量級的寫法 ![](https://i.imgur.com/QVEykRS.png) ```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 的資料