筆者最近業餘時間想着學點新東西,因而開始接觸服務器端渲染(SSR),花了一週的時間學習和實戰,而後在週末高仿掘金擼了一個 SSR 的 Demo 項目。javascript
技術棧選的是平滑開箱的 Nuxt,整個項目整合了 vue + nuxt + axios + vuex + vue-router (nuxt 自帶 vuex 和 vue-router)。css
項目目前實現瞭如下幾大功能html
服務器端渲染前端
靜態頁面部署vue
掘金首頁java
掘金推薦列表node
滾動分頁加載webpack
不一樣端的佈局適配ios
項目完整地址:nuxt-ssr-demonginx
前端交流羣:731175396
看完最終完成的效果圖,接下來,開始咱們的實戰之旅吧 ~
一個項目開始以前,我喜歡先搭好一個空架子。因此這裏仍是老規矩,先帶着你們把項目空殼搭好吧。
這裏關於項目初始化,我是直接使用的 Nuxt
官網提供的 starter 模板
# 安裝 vue-cli npm install -g vue-cli # 初始化項目 vue init nuxt-community/starter-template nuxt-ssr-demo # 安裝依賴 cd nuxt-ssr-demo npm install # Or yarn install # 啓動本地服務 npm run dev 複製代碼
訪問 http://localhost:3000 ,如今咱們來看下初始化好的項目目錄
├── assets css,圖片等資源都在這
├── components 組件相關
├── layouts 路由佈局
├── middleware 中間件
├── pages 路由頁面
├── static 靜態資源
├── pages 路由頁面
├── store vuex 相關
├── nuxt.config.js nuxt 相關配置
├── package.json 依賴相關
├── README.md 項目介紹
複製代碼
接觸過 vue
的小夥伴,看着這個目前可能會有點小疑問,爲何沒有 router 路由相關的文件?莫慌,Nuxt
會幫你將 pages 下面的文件自動解析成路由。因此在接下來的開發中,記得別瞎在 pages 下面新增文件,pages 下面的每個 vue 文件就是一個路由。
npm i axios -S
複製代碼
爲了項目以後更加方便的開發,咱們有必要對 axios 進行一層封裝,咱們要時刻養成這樣一種好習慣。
首先在根目錄下面新建 service
目錄,在其下面創建 config.js
和 index.js
兩個文件,下面的代碼僅供參考,若是你的項目還須要作額外的一些配置,可自行進行拓展
在 config.js
中寫入:
import http from 'http' import https from 'https' export default { // 自定義的請求頭 headers: { post: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, 'X-Requested-With': 'XMLHttpRequest' }, // 超時設置 timeout: 10000, // 跨域是否帶Token withCredentials: true, // 響應的數據格式 json / blob /document /arraybuffer / text / stream responseType: 'json', // 用於node.js httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }) } 複製代碼
在 index.js
中寫入:
import axios from 'axios' import qs from 'qs' import config from './config' const service = axios.create(config) // POST 傳參序列化 service.interceptors.request.use( config => { if (config.method === 'post') config.data = qs.stringify(config.data) return config }, error => { return Promise.reject(error) } ) // 返回結果處理 service.interceptors.response.use( res => { return res.data }, error => { return Promise.reject(error) } ) export default { // post 方法 post (url, data) { console.log('post request url', url) return service({ method: 'post', url, params: data }) }, // get 方法 get (url, data) { console.log('get request url', url) return service({ method: 'get', url, params: data }) }, // delete 方法 delete (url, data) { console.log('delete request url', url) return service({ methods: 'delete', url, params: data }) } } 複製代碼
使用過 vue
的同窗,確定知道對於項目中的跨域,vue-cli
對 webpack
中的 proxy
選項進行了一層封裝。它暴露出來的是一個叫 proxyTable
的選項,是對 webpack
中的 proxy
和其三方插件 http-proxy-middleware
的一個整合。
不幸的 Nuxt
中沒有 proxyTable
這麼一個配置項來進行跨域的配置。固然幸運的是,在 Nuxt
中你能夠直接經過配置 http-proxy-middleware
來處理跨域。更幸運的是 Nuxt
官方提供了兩個包來處理 axios
跨域問題。
首先,進行安裝
npm i @nuxtjs/axios @nuxtjs/proxy -D
複製代碼
而後在 nuxt.config.js
文件裏進行配置
modules: [ '@nuxtjs/axios' ], axios: { proxy: true }, proxy: { '/api': { target: 'xxx.target.com', pathRewrite: { '^/api': '' } } } 複製代碼
這裏須要注意,由於是服務器端渲染,咱們得時刻明確當前地址是屬於路由跳轉仍是屬於 axios 請求。因此咱們須要在 service/index.js
寫入如下判斷
// 判斷是路由跳轉仍是 axios 請求 if (process.server) { config.baseURL = `http://${process.env.HOST || 'localhost'}:${process.env.PORT || 3000}` } 複製代碼
而後你就能夠安心使用你的 axios 進行跨域請求了
先看下咱們 store 目錄下須要的一些文件
├── actions.js axios 請求相關
├── index.js 主入口文件
├── mutations.js 同步狀態操做相關
├── state.js 初始狀態相關
複製代碼
接下來咱們以此看看每一個文件的內容
import request from '~/service' const api = '/api' export const banner = async (store, params) => { return await request.get(`${api}/v1/get_banner`, params) } 複製代碼
export default { counter: 1, isPhone: false } 複製代碼
export function INCREMENT (state) { state.counter++ } export function PCORPHONE (state, bool) { state.isPhone = bool } 複製代碼
import Vue from 'vue' import Vuex from 'vuex' import state from './state' import * as mutations from './mutations' import * as actions from './actions' Vue.use(Vuex) const store = () => new Vuex.Store({ state, mutations, actions }) export default store 複製代碼
而後你就能夠在頁面中進行使用了
<template> <div class="page"> <button @click="handleClick">{{ counter }}</button> <p>{{ banner.name }}</p> </div> </template> <script> import { mapState } from 'vuex' export default { async asyncData ({ store, error }) { // 對 axios 進行批量處理 let [ res ] = await Promise.all([ store.dispatch('banner') ]).catch((e) => { error({ statusCode: 404, message: 'Post not found' }) }) return { banner: res.banner } }, computed: { ...mapState({ counter: state => state.counter }) }, methods: { handleClick () { this.$store.commit('INCREMENT') } } } </script> 複製代碼
Nuxt
的項目不比 vue
的項目,提供了主入口文件供咱們對全局組件進行配置。但要作到這個點也比較簡單,咱們只須要按照 Nuxt
官網給出的規範來,將組件引入的相關配置寫入到 plugins 目錄下便可
好比,我須要引入三方組件庫 element-ui ,咱們只需在 plugins 目錄下新建一個 element-ui.js
文件,並寫入
import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) 複製代碼
而後在 nuxt.config.js
文件中引入
plugins: [ '~/plugins/element-ui' ] 複製代碼
最後你就能夠在你的項目中使用 element-ui
組件庫裏面的組件了。
固然,你想配置本身本地的全局組件,也是同樣的作法。先在 plugins 目錄下新建一個 js 文件,而後引入你的文件,最後再在 nuxt.config.js
文件中引入便可。
和組件管理同理,不一樣的就是,css 須要存放在 assets 目錄下。好比,如今我須要有一個 main.css
文件對路由跳轉進行動態切換。
首選,你得在 assets/main.css
中寫入重置樣式吧
.page-enter-active, .page-leave-active { transition: opacity .2s; } .page-enter, .page-leave-active { opacity: 0; } 複製代碼
而後,你只要在 nuxt.config.js
進入引入便可
css: [ '~/assets/stylus/main.styl' ] 複製代碼
關於 Nuxt
更多的用法,我就不一一介紹了,詳細請參考:Nuxt.js 文檔官網
而後關於項目的具體開發,也是屢見不鮮了,這裏我也不展開描述了。若是想了解的,能夠去 github 自行查閱。有問題的話能夠加老司機羣 731175396 ,而後在羣裏問我便可。
接下來的篇幅,我將講一下項目部署的一些點
到這一步的同窗,你得先確保你擁有一個本身的服務器。若是沒有的話,感受去買一個,如今阿里雲和騰訊雲都在搞活動,巨便宜哦 ~
OK,文章繼續。在進行部署講解前,咱們先看一下 Nuxt
提供的幾個命令
命令 | 描述 |
---|---|
nuxt | 啓動一個熱加載的 Web 服務器(開發模式) localhost:3000 |
nuxt build | 利用 webpack 編譯應用,壓縮 JS 和 CSS 資源(發佈用) |
nuxt start | 以生成模式啓動一個 Web 服務器 (nuxt build 會先被執行) |
nuxt generate | 編譯應用,並依據路由配置生成對應的 HTML 文件 (用於靜態站點的部署) |
咱們從官網給出的文檔能夠看出,部署靜態化頁面須要用到的命令是 nuxt generate
,執行的時候會在根目錄下面生成 dist 目錄,裏面的文件都是靜態化頁面須要的打包好的文件。
這裏須要特別注意的一點是,若是你的項目中存在 axios 請求的話,記得在你本地開啓一個本地服務哦 ~ 否則打包的時候執行到 axios 請求的時候會報錯。由於前面咱們經過使用 node 的 process 對運行環境進行了是跳轉仍是請求的斷定,而打包進行請求的時候是不依賴 node 環境的
這裏,我先假設小夥伴們均可以正常執行 nuxt generate
並生成對應的 dist 目錄。
爲了項目的並行開發,咱們通常會在 .gitignore
文件裏面將打包文件給忽略掉,但咱們靜態化頁面的部署有須要用到 dist 目錄下的全部打包文件。因此這裏咱們將使用 gh-pages 將打包文件發佈到咱們的 git 倉庫
# 安裝 gh-pages npm i gh-pages -D 複製代碼
而後在 package.json
寫入配置(固然你也能夠新建文件執行發佈)
"scripts": {
"deploy": "gh-pages -d dist"
}
複製代碼
執行 npm run deploy
,而後你的 dist 目錄就會發到大家倉庫的 gh-pages 分支了
打包文件上傳好以後,你須要作的第一件事就是鏈接好你的服務器。而後在 cd 到服務器根目錄下面,在 data/www
目錄下面將你的項目 git clone
下來。而後切換到 gh-pages
分支
接下來,開始配置你的 nginx (還沒下載 nginx 的同窗請自行解決)
server { # 端口,默認是 80 listen 81; # 服務名(寫域名或者 ip 地址均可以) server_name 123.12.123.12; # server 根目錄 root /data/www/nuxt-ssr-demo; # 主入口文件 index index.html; # 反向代理 location /api/ { proxy_pass https://xxx.target.com/; } } 複製代碼
而後重啓 nginx
sudo service nginx restart
複製代碼
而後你就能在 http://123.12.123.12:81 訪問到你部署好的靜態化頁面了
看到上面靜態化頁面部署,詳細有同窗會問。進行靜態化頁面部署,豈不是沒有了服務器端渲染的優點了。
對的,若是你的項目只是靜態頁面的話,作靜態化部署是徹底 OJBK 的。但若是牽扯到請求,仍是乖乖的進行服務器端的部署吧 ~
開始前,請確保你的服務器上已經搭建好了 node 環境。沒有的同窗,我建議使用 nvm 安裝 node 。接下來,開始部署
第一步,將以前 clone 下面的 git 項目切換到主開發分支,而後爲了以後的方便修改一下你的 package.json
"scripts": {
"build": "npm run lint && nuxt build && npm start",
"start": "nuxt start"
}
複製代碼
第二步,啓動服務
npm run build
複製代碼
第三步,配置你的 nginx 文件
# 經過 upstream nodejs 能夠配置多臺 nodejs 節點,作負載均衡 # keepalive 設置存活時間。若是不設置可能會產生大量的 timewait # proxy_pass 反向代理轉發 http://nodejs upstream nodenuxt { server 127.0.0.1:3000; # nuxt 項目監聽端口 keepalive 64; } server { listen 82; server_name 118.25.109.133; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Nginx-Proxy true; proxy_cache_bypass $http_upgrade; proxy_pass http://nodenuxt; # 反向代理 } } 複製代碼
最後,從新啓動 nginx 服務
sudo service nginx restart
複製代碼
若是咱們按照上面的步驟進行部署的話,服務器會常常斷掉鏈接,那咱們的服務也就斷了。因此爲了守護好咱們的 nodejs 進程,這裏我將使用 pm2 對進程進行守護
首先全局安裝 pm2
npm i pm2 -g
複製代碼
而後進入到項目目錄,執行
pm2 start npm --name "nuxt-ssr-demo" -- run build
複製代碼
而後,媽媽不再用擔憂個人 nodejs 進程說斷就斷啦 ~
對於 pm2 用法,請小夥伴們輸入 pm2 --help
而後自行查閱
文章到這就要結束了,這裏我作一個小總結。在一週的學習和實戰中,產出一個高仿掘金的 SSR Demo 的同時,也踩了一些坑。
對於 Nuxt
,在使用層面,是比較簡單、好上手的。相對 vue-ssr 來講,它大大的簡化了開發的配置,讓開發人員能夠只需思考業務的開發,而不用太去擔憂文件的配置。其中 Nuxt
經過監聽 pages 目錄文件變動並自動生成路由更是直接省去了咱們日常對於路由的配置。
可是,目前 Nuxt
總體仍是有待提升的,目前社區相關的三方插件比較有限,市面上相關的參考資料也相對比較少。
無論如何,但願 Nuxt
社區能夠愈來愈好吧 ~
最後,想看項目源碼的小夥伴,這裏我再最後放一次連接
項目完整地址:nuxt-ssr-demo
前端交流羣:731175396
我的準備從新撿回本身的公衆號了,以後每週保證一篇高質量好文,感興趣的小夥伴能夠關注一波。