1.前端耗時少,首屏加載速度快。由於後端拼接完了html,瀏覽器只須要直接渲染出來。html
2.有利於SEO。由於在後端有完整的html頁面,因此爬蟲更容易爬取得到信息,更有利於seo。前端
3.無需佔用客戶端資源。即解析模板的工做徹底交由後端來作,客戶端只要解析標準的html頁面便可,這樣對於客戶端的資源佔用更少,尤爲是移動端,也能夠更省電。vue
4.後端生成靜態化文件。即生成緩存片斷,這樣就能夠減小數據庫查詢浪費的時間了,且對於數據變化不大的頁面很是高效 。node
1.不利於先後端分離,開發效率低。(無框架前)webpack
2.佔用服務器端資源。ios
即服務器端完成html模板的解析,若是請求較多,會對服務器形成必定的訪問壓力。而若是使用前端渲染,就是把這些解析的壓力分攤了前端,而這裏確實徹底交給了一個服務器。git
2016 年 10 月 25 日, zeit.co 背後的團隊對外發布了 Next.js ,一個 React 的服務端渲染應用框架。幾小時後,與 Next.js 殊途同歸,一個基於 Vue.js 的服務端渲染應用框架應運而生,咱們稱之爲:Nuxt.js。github
Nuxt 是服務器呈現的簡約應用程序的框架,經過對客戶端和服務端基礎架構的抽象,Nuxt.js 可讓開發者更專一於頁面的UI渲染。做用就是在 node.js 上進一步封裝,而後省去咱們搭建服務端環境的步驟,只須要遵循這個庫的一些規則就能輕鬆實現 SSR。web
Nuxt.js 集成了如下組件/框架,用於開發完整而強大的 Web 應用:vue-router
壓縮並 gzip 後,總代碼大小爲:57kb (若是使用了 Vuex 特性的話爲 60kb)。
另外,Nuxt.js 使用 Webpack 和 vue-loader 、 babel-loader 來處理代碼的自動化構建工做(如打包、代碼分層、壓縮等等)。
work flow:
├── assets //用於組織未編譯的靜態資源如 LESS、SASS 或 JavaScript
│ └── README.md
├── components //用於組織應用的 Vue.js 組件。Nuxt.js 不會擴展加強該目錄下 Vue.js 組件,即這些組件不會像頁面組件那樣有 asyncData 方法的特性
├── layouts //佈局目錄 layouts 用於組織應用的佈局組件。若無額外配置,該目錄不能被重命名。
│ ├── README.md
│ └── default.vue
├── middleware //目錄用於存放應用的中間件
│ └── README.md
├── nuxt.config.js //nuxt 配置文件
├── pages //放page頁面,自動生產路由
│ ├── README.md
│ ├── index.vue
│
├── plugins //用於組織那些須要在 根vue.js應用 實例化以前須要運行的 插件
│ ├── README.md
│ └── axios.js
├── server
│ └── index.js //服務配置
├── static
│ ├── README.md //存放靜態文件,不被編譯
│ ├── favicon.ico
│ ├── icon.png
│ └── sw.js
├── store //vuex狀態
│ ├── README.md
│ ├── index.js
│ └── webLogin.js
複製代碼
Nuxt擴展了Vue的生命週期
export default {
middleware (ctx) {}, //服務端
validate (ctx) {}, // 服務端
asyncData (ctx) {}, //服務端
fetch (ctx) {}, // store數據加載
beforeCreate () { // 服務端和客戶端都會執行},
created () { // 服務端和客戶端都會執行 },
beforeMount () {},
mounted () {} // 客戶端
}
複製代碼
context 的可用屬性一覽:
屬性字段 | 類型 | 可用 | 描述 |
---|---|---|---|
app | Vue 根實例 | 客戶端 & 服務端 | 包含全部插件的 Vue 根實例。例如:在使用 axios 的時候,你想獲取 ![]() |
isClient | Boolean | 客戶端 & 服務端 | 是否來自客戶端渲染(廢棄。請使用 process.client ) |
isServer | Boolean | 客戶端 & 服務端 | 是否來自服務端渲染(廢棄。請使用 process.server ) |
isStatic | Boolean | 客戶端 & 服務端 | 是否來自 nuxt generate 靜態化(預渲染)(廢棄。請使用 process.static ) |
isDev | Boolean | 客戶端 & 服務端 | 是不是開發 dev 模式,在生產環境的數據緩存中用到 |
isHMR | Boolean | 客戶端 & 服務端 | 是不是經過模塊熱替換 webpack hot module replacement (僅在客戶端以 dev 模式) |
route | Vue Router 路由 | 客戶端 & 服務端 | Vue Router 路由實例 |
store | Vuex 數據 | 客戶端 & 服務端 | Vuex.Store 實例。只有vuex 數據流存在相關配置時可用 |
env | Object | 客戶端 & 服務端 | nuxt.config.js 中配置的環境變量,見 環境變量 api |
params | Object | 客戶端 & 服務端 | route.params 的別名 |
query | Object | 客戶端 & 服務端 | route.query 的別名 |
req | http.Request | 服務端 | Node.js API 的 Request 對象。若是 Nuxt 以中間件形式使用的話,這個對象就根據你所使用的框架而定。nuxt generate 不可用 |
res | http.Response | 服務端 | Node.js API 的 Response 對象。若是 Nuxt 以中間件形式使用的話,這個對象就根據你所使用的框架而定。nuxt generate 不可用 |
redirect | Function | 客戶端 & 服務端 | 用這個方法重定向用戶請求到另外一個路由。狀態碼在服務端被使用,默認 302 redirect([status,] path [, query]) |
error | Function | 客戶端 & 服務端 | 用這個方法展現錯誤頁:error(params) 。params 參數應該包含 statusCode 和 message 字段 |
nuxtState | Object | 客戶端 | Nuxt 狀態,在使用 beforeNuxtRender 以前,用於客戶端獲取 Nuxt 狀態,僅在 universal 模式下可用 |
beforeNuxtRender(fn) | Function | 服務端 | 使用此方法更新 NUXT 在客戶端呈現的變量,fn 調用 (能夠是異步) { Components, nuxtState } ,參考 示例 |
asyncData 方法會在組件(限於頁面組件)每次加載以前被調用。它能夠在服務端或路由更新以前被調用。在這個方法被調用的時候,第一個參數被設定爲當前頁面的上下文對象,你能夠利用 asyncData 方法來獲取數據並返回給當前組件。
export default {
data () {
return { project: 'default' }
},
asyncData (context) {
return { project: 'nuxt' }
}
}
複製代碼
注意:因爲 asyncData 方法是在組件 初始化 前被調用的,因此在方法內是沒有辦法經過 this 來引用組件的實例對象。
fetch 方法用於在渲染頁面前填充應用的狀態樹(store)數據, 與 asyncData 方法相似,不一樣的是它不會設置組件的數據。
若是頁面組件設置了 fetch 方法,它會在組件每次加載前被調用(在服務端或切換至目標路由以前)。
fetch 方法的第一個參數是頁面組件的 上下文對象 context,咱們能夠用 fetch 方法來獲取數據填充應用的vuex狀態樹。爲了讓獲取過程能夠異步,你須要返回一個 Promise,Nuxt.js 會等這個 promise 完成後再渲染組件。
警告: 您沒法在內部使用 this 獲取組件實例,fetch 是在組件初始化以前被調用
例如 pages/index.vue:
<template>
<h1>Stars: {{ $store.state.stars }}</h1>
</template>
<script>
export default {
fetch ({ store, params }) {
return axios.get('http://my-api/stars')
.then((res) => {
store.commit('setStars', res.data)
})
}
}
</script>
你也可使用 async 或 await 的模式簡化代碼以下:
<template>
<h1>Stars: {{ $store.state.stars }}</h1>
</template>
<script>
export default {
async fetch ({ store, params }) {
let { data } = await axios.get('http://my-api/stars')
store.commit('setStars', data)
}
}
</script>
複製代碼
若是要在 fetch 中調用並操做 store,請使用 store.dispatch,可是要確保在內部使用 async / await 等待操做結束:
<script>
export default {
async fetch ({ store, params }) {
await store.dispatch('GET_STARS');
}
}
</script>
store/index.js
// ...
export const actions = {
async GET_STARS ({ commit }) {
const { data } = await axios.get('http://my-api/stars')
commit('SET_STARS', data)
}
}
複製代碼
監聽 query 字符串的改變 默認狀況下,不會在查詢字符串更改時調用 fetch 方法。若是想更改此行爲,例如,在編寫分頁組件時,您能夠設置經過頁面組件的 watchQuery 屬性來監聽參數的變化。瞭解更多有關 API watchQuery page 的信息。
增長用戶體驗的兩個插件
toast能夠說是很經常使用的功能,通常的UI框架都會有這個功能。但若是你的站點沒有使用UI框架,而alert又太醜,不妨引入該模塊:
npm install @nuxtjs/toast
複製代碼
而後在nuxt.config.js中引入
module.exports = {
modules: [
'@nuxtjs/toast',
['@nuxtjs/dotenv', { filename: '.env.prod' }] // 指定打包時使用的dotenv
],
toast: {// toast模塊的配置
position: 'top-center',
duration: 2000
}
}
複製代碼
這樣,nuxt就會在全局註冊$toast方法供你使用,很是方便:
this.$toast.error('服務器開小差啦~~')
this.$toast.error('請求成功~~')
複製代碼
nuxt內置了頁面頂部loading進度條的樣式 推薦使用,提供頁面跳轉體驗。
//打開
this.$nuxt.$loading.start()
//完成
this.$nuxt.$loading.finish()
複製代碼
更多 API 詳見官網 zh.nuxtjs.org/api
源碼目錄:
這個是咱們項目生成的臨時文件,咱們項目運行時候配置的文件都是在這裏,你們能夠看到這裏的路由文件,沒錯,這個就是系統自動給咱們配置的路由文件,根據咱們的 pages 文件夾路徑生成的,你們還能夠看到,由app.js ,client.js 和 server.js 這兩個就是相似咱們的 SSR 中配置的那個 server.js 入口文件,而後還有 middleware.js 中間件文件,其實這個時候咱們大概能懂了,上邊咱們說的工做流程,走的就是這個 臨時文件.nuxt 文件夾中的內容,可是這個文件夾是如何生成的呢,你們請往下看。
本文主要研究nuxt的運行原理,分析它從接收一條nuxt指令,到完成指令背後所發生的一系列事情,在開始本文以前,請讀者務必親自體驗過nuxt.js的使用,而且具有必定的vue.js相關開發經驗。
經過查看nuxt.js工程目錄下的package.json文件,咱們能夠看到下列幾條指令:
"scripts": { "dev": "nuxt", // 開啓一個監聽3000端口的服務器,同時提供hot-reloading功能
"build": "nuxt build", //構建整個應用,壓縮合並JS和CSS文件(用於生產環境)
"start": "nuxt start", // 開啓一個生產模式的服務器(必須先運行nuxt build命令)
"generate": "nuxt generate" //構建整個應用,併爲每個路由生成一個靜態頁面(用於靜態服務器)
}
複製代碼
我們還歷來沒有看過咱們的依賴包哈,今天就來看看,打開咱們的 node_modules 文件夾下的 nuxt工程文件夾 進入到到bin目錄,咱們能夠看到幾個文件:
我們就說一下 dev 是如何工做的,我們先找到一個片斷,發現基本是執行了如下幾個步驟:
async run (cmd) {
const { argv } = cmd
await this.startDev(cmd, argv, argv.open)
},
async startDev (cmd, argv) {
let nuxt
try {
nuxt = await this._listenDev(cmd, argv)
} catch (error) {
consola.fatal(error)
return
}
try {
await this._buildDev(cmd, argv, nuxt)
} catch (error) {
await nuxt.callHook('cli:buildError', error)
consola.error(error)
}
return nuxt
},
複製代碼
那什麼是 nuxt() 類,它又是執行了什麼樣的方法呢?
上圖中每一步均可以在具體的代碼中自行瀏覽。在用戶輸入指令並實例化了Nuxt()類之後,實例化
同時,Nuxt()類也提供了一個close()公有方法,用於關閉其所開啓的服務器。
簡單來講,build()方法在判斷完運行條件後,會先初始化產出目錄.nuxt,而後經過不一樣目錄下的文件結構來生成一系列的配置,寫入模板文件後輸出到.nuxt目錄。接下來,則會根據不一樣的開發環境來調用不一樣的webpack配置,運行不一樣的webpack構建方案。
在nuxt/lib目錄下找到render.js文件,它包含着咱們即將要分析的三個方法:render(), renderRoute(), renderAndGetWindow()。
經過這張圖片,咱們能夠知道nuxt對於處理「客戶端渲染」與「服務端渲染」的邏輯實際上是很是清晰的。
上傳所有代碼到本身到服務器上執行 編譯打包:
npm run build
npm run start
複製代碼
建議部署方式Docker+K8S
------------------------------------我的項目-----------------------------------
若是你發現本項目有內容上的錯誤,歡迎提交 issues 進行指正。
建了一個「全棧大前端」的微信交流羣,歡迎純粹技術交流愛好者加入!