使用 Nuxt.js 創建服務器端渲染的 Vue.js 應用程序

已發表: 2022-03-11

Vue 等 JavaScript 框架/庫可以在瀏覽您的網站時提供出色的用戶體驗。 大多數都提供了一種動態更改頁面內容的方法,而無需每次都向服務器發送請求。

但是,這種方法存在一個問題。 最初加載您的網站時,您的瀏覽器沒有收到要顯示的完整頁面。 相反,它會發送一堆片段來構建頁面(HTML、CSS、其他文件)以及如何將它們放在一起的說明(JavaScript 框架/庫) 將所有這些信息放在一起需要大量時間在您的瀏覽器實際顯示某些內容之前。 就像收到一堆書和一個平裝書櫃一樣。 你必須先建造書櫃,然後把書裝滿。

對此的解決方案很聰明:在服務器上擁有一個框架/庫版本,可以構建一個可以顯示的頁面。 然後將這個完整的頁面連同進行進一步更改的能力一起發送到瀏覽器,並且仍然具有動態頁面內容(框架/庫),就像發送一個現成的書櫃和一些書籍一樣。 當然,你仍然需要把書放在書櫃裡,但你有一些可以立即使用的東西。

客戶端和服務器端渲染的視覺比較

除了愚蠢的類比之外,還有許多其他優點。 例如,一個很少更改的頁面,例如關於我們的頁面,不需要在用戶每次請求時都重新創建。 因此,服務器可以創建一次,然後將其緩存或存儲在某處以供將來使用。 這些速度改進可能看起來很小,但在響應時間以毫秒(或更短)為單位的環境中,每一點都很重要。

如果您想了解更多關於 SSR 在 Vue 環境中的優勢的信息,您應該查看 Vue 自己關於 SSR 的文章。 實現這些結果有多種選擇,但最流行的一種,也是 Vue 團隊推薦的,是 Nuxt。

為什麼選擇 Nuxt.js

Nuxt.js 基於名為 Next 的流行 React 庫的 SSR 實現。 看到這種設計的優點後,又為 Vue 設計了一個類似的實現,叫做 Nuxt。 熟悉 React+Next 組合的人會發現應用程序的設計和佈局有很多相似之處。 然而,Nuxt 提供了 Vue 特定的功能,為 Vue 創建了一個強大而靈活的 SSR 解決方案。

Nuxt 於 2018 年 1 月更新為生產就緒的 1.0 版本,是一個活躍且得到良好支持的社區的一部分。 偉大的事情之一是使用 Nuxt 構建項目與構建任何其他 Vue 項目沒有什麼不同。 事實上,它提供了一系列功能,讓您可以在更短的時間內創建結構良好的代碼庫。

另一個需要注意的重要事情是Nuxt 不必用於 SSR 。 它被推廣為用於創建通用 Vue.js 應用程序的框架,並包含一個命令 ( nuxt generate ) 用於使用相同的代碼庫創建靜態生成的 Vue 應用程序。 因此,如果您擔心深入 SSR,請不要驚慌。 您始終可以創建一個靜態站點,同時仍然利用 Nuxt 的功能。

為了把握 Nuxt 的潛力,讓我們創建一個簡單的項目。 如果您想查看此項目的最終源代碼,則託管在 GitHub 上,或者您可以查看使用nuxt generate創建並託管在 Netlify 上的實時版本。

創建 Nuxt 項目

首先,讓我們使用一個名為vue-cli的 Vue 項目生成器來快速創建一個示例項目:

 # install vue-cli globally npm install -g vue-cli # create a project using a nuxt template vue init nuxt-community/starter-template my-nuxt-project

經過幾個選項後,這將在my-nuxt-project文件夾或您指定的任何內容中創建一個項目。 然後我們只需要安裝依賴並運行服務器:

 cd my-nuxt-project npm install # Or yarn npm run dev

我們去吧。 打開瀏覽器到localhost:3000並且您的項目應該正在運行。 與創建 Vue Webpack 項目沒有太大區別。 但是,當我們查看應用程序的實際結構時,並沒有太多東西,尤其是與 Vue Webpack 模板之類的東西相比。

項目目錄及其與 Nuxt 配置文件的關係圖

查看package.json還顯示我們只有一個依賴項,即 Nuxt 本身。 這是因為 Nuxt 的每個版本都針對特定版本的 Vue、Vue-router 和 Vuex 進行了定制,並為您將它們捆綁在一起。

項目根目錄下還有一個nuxt.config.js文件。 這允許您自定義 Nuxt 提供的一系列功能。 默認情況下,它會為您設置標題標籤、加載欄顏色和 ESLint 規則。 如果您渴望查看可以配置的內容,請參閱文檔; 我們將在本文中介紹一些選項。

那麼這些目錄有什麼特別之處呢?

項目佈局

如果您瀏覽創建的目錄,所有這些目錄都有隨附的自述文件,其中簡要說明了該目錄中的內容,並且通常是指向文檔的鏈接。

這是使用 Nuxt 的一個好處:應用程序的默認結構。 任何優秀的前端開發者都會構建一個類似這樣的應用程序,但是對於結構有很多不同的想法,在團隊合作時,一些時間不可避免地會進入討論或選擇這種結構。 Nuxt 為您提供了一個。

Nuxt 將查找某些目錄並根據找到的內容為您構建應用程序。 讓我們一一檢查這些目錄。

頁面

這是唯一需要的目錄。 此目錄中的任何 Vue 組件都會根據其文件名和目錄結構自動添加到vue-router 。 這非常方便。 通常,無論如何我都會有一個單獨的 Pages 目錄,並且必須在另一個路由器文件中手動註冊每個組件。 對於較大的項目,此路由器文件可能會變得複雜,並且可能需要拆分以保持可讀性。 相反,Nuxt 將為您處理所有這些邏輯。

為了演示,我們可以在 Pages 目錄中創建一個名為about.vue的 Vue 組件。 讓我們添加一個簡單的模板,例如:

 <template> <h1>About Page</h1> </template>

當您保存時,Nuxt 會為您重新生成路線。 看到我們將組件稱為about.vue ,如果您導航到/about ,您應該會看到該組件。 簡單的。

有一個文件名是特殊的。 命名文件index.vue將為該目錄創建根路由。 生成項目時,pages 目錄中已經有一個index.vue組件,它與您網站的主頁或登錄頁面相關聯。 (在開發示例中,這只是localhost:3000 。)

Nuxt 掃描 pages 目錄下的 Vue 文件並輸出相應的頁面。

更深的路線呢? Pages 目錄中的子目錄有助於構建您的路線。 因此,如果我們想要一個查看產品頁面,我們可以像這樣構建我們的 Pages 目錄:

 /pages --| /products ----| index.vue ----| view.vue

現在,如果我們導航到/products/view ,我們將在 products 目錄中看到view.vue組件。 如果我們導航到/products ,我們將在 products 目錄中看到index.vue組件。

你可能會問為什麼我們不只是在 pages 目錄中創建products.vue組件,而是像我們為/about頁面所做的那樣。 你可能認為結果是一樣的,但是這兩種結構是有區別的。 讓我們通過添加另一個新頁面來演示這一點。

假設我們想要為每個員工提供一個單獨的 About 頁面。 例如,讓我們為我創建一個關於頁面。 它應該位於/about/ben-jones 。 最初,我們可以嘗試像這樣構建 Pages 目錄:

 /pages --| about.vue --| /about ----| ben-jones.vue

當我們嘗試訪問/about/ben-jones時,我們得到的是about.vue組件,與/about相同。 這裡發生了什麼?

有趣的是,Nuxt 在這裡所做的是生成一個嵌套路由。 這種結構表明您需要一個永久的/about路線,並且該路線內的任何內容都應嵌套在其自己的視圖區域中。 在 vue-router 中,這將通過在about.vue組件中指定一個<router-view />組件來表示。 在 Nuxt 中,這是相同的概念,除了<router-view /> ,我們簡單地使用<nuxt /> 。 因此,讓我們更新about.vue組件以允許嵌套路由:

 <template> <div> <h1>About Page</h1> <nuxt /> </div> </template>

現在,當我們導航到/about時,我們得到了之前的about.vue組件,只有一個標題。 但是,當我們導航到/about/ben-jones時,我們會在<nuxt/>佔位符所在的位置呈現標題ben-jones.vue組件。

這不是我們最初想要的,但是擁有一個包含人員列表的 About 頁面的想法,當點擊時,在頁面上的一個部分填充他們的信息是一個有趣的概念,所以讓我們現在保持原樣. 如果您確實想要其他選項,那麼我們要做的就是重組我們的目錄。 我們只需將about.vue組件移動到/about目錄中並將其重命名為index.vue ,因此生成的結構將是:

 /pages --| /about ----| index.vue ----| ben-jones.vue

最後,假設我們想使用路由參數來檢索特定產品。 例如,我們希望能夠通過導航到/products/edit/64來編輯產品,其中 64 是product_id 。 我們可以通過以下方式做到這一點:

 /pages --| /products ----| /edit ------| _product_id.vue

注意_product_id.vue組件開頭的下劃線——這表示一個路由參數,然後可以在$route.params對像或 Nuxt 上下文中的params對像上訪問(稍後會詳細介紹)。 請注意,參數的鍵將是不帶初始下劃線的組件名稱(在本例中為product_id ),因此請盡量保持它們在項目中的唯一性。 因此,在_product_id.vue中,我們可能會有類似的內容:

 <template> <h1>Editing Product {{ $route.params.product_id }}</h1> </template>

您可以開始想像更複雜的佈局,使用 vue-router 進行設置會很痛苦。 例如,我們可以將以上所有內容組合成一條路線,例如:

 /pages --| /categories ----| /_category_id ------| products.vue ------| /products --------| _product_id.vue

推斷/categories/2/products/3會顯示什麼並不難。 我們會有products.vue組件和一個嵌套_product_id.vue組件,有兩個路由參數: category_idproduct_id 。 這比等效的路由器配置更容易推理。

當我們討論這個話題時,我傾向於在路由器配置中做的一件事是設置路由器防護。 由於 Nuxt 正在為我們構建路由器,因此可以使用beforeRouteEnter在組件本身上完成。 如果要驗證路由參數,Nuxt 提供了一個名為validate的組件方法。 因此,如果您想在嘗試渲染組件之前檢查product_id是否為數字,您可以將以下內容添加到_product_id.vue的腳本標記中:

 export default { validate ({ params }) { // Must be a number return /^\d+$/.test(params.product_id) } }

現在,導航到/categories/2/products/someproduct會導致 404,因為someproduct不是有效數字。

這就是 Pages 目錄。 學習如何在這個目錄中正確地構建你的路由是必不可少的,所以最初花一點時間對於充分利用 Nuxt 很重要。 如果您正在尋找一個簡短的概述,參考文檔進行路由總是有幫助的。

如果您擔心無法控制路由器,請不要擔心。 此默認設置適用於各種項目,只要它們結構良好。 但是,在某些情況下,您可能需要向路由器添加比 Nuxt 自動為您生成或重組的路由更多的路由。 Nuxt 提供了一種在配置中自定義路由器實例的方法,允許您添加新路由和自定義生成的路由。 您還可以編輯路由器實例的核心功能,包括 Nuxt 添加的額外選項。 因此,如果您確實遇到了極端情況,您仍然可以靈活地找到合適的解決方案。

店鋪

Nuxt 可以基於 store 目錄的結構構建你的 Vuex store,類似於 Pages 目錄。 如果您不需要商店,只需刪除目錄即可。 商店有兩種模式,經典和模塊。

Classic要求您在 store 目錄中有一個index.js文件。 在那裡,您需要導出一個返回 Vuex 實例的函數:

 import Vuex from 'vuex' const createStore = () => { return new Vuex.Store({ state: ..., mutations: ..., actions: ... }) } export default createStore

這使您可以隨心所欲地創建商店,就像在普通的 Vue 項目中使用 Vuex 一樣。

模塊模式還需要您在 store 目錄中創建一個index.js文件。 然而,這個文件只需要為你的 Vuex 存儲導出根狀態/突變/動作。 下面的示例指定了一個空白根狀態:

 export const state = () => ({})

然後,store 目錄中的每個文件將被添加到 store 中自己的命名空間或模塊中。 例如,讓我們創建一個地方來存儲當前產品。 如果我們在 store 目錄中創建一個名為product.js的文件,那麼商店的命名空間部分將在$store.product中可用。 這是該文件可能看起來的簡單示例:

 export const state = () => ({ _id: 0, title: 'Unknown', price: 0 }) export const actions = { load ({ commit }) { setTimeout( commit, 1000, 'update', { _id: 1, title: 'Product', price: 99.99 } ) } } export const mutations = { update (state, product) { Object.assign(state, product) } }

load 動作中的setTimeout模擬某種 API 調用,它將使用響應更新存儲; 在這種情況下,需要一秒鐘。 現在,讓我們在products/view頁面中使用它:

 <template> <div> <h1>View Product {{ product._id }}</h1> <p>{{ product.title }}</p> <p>Price: {{ product.price }}</p> </div> </template> <script> import { mapState } from 'vuex' export default { created () { this.$store.dispatch('product/load') }, computed: { ...mapState(['product']) } } </script>

需要注意的幾點:在這裡,我們在創建組件時調用了我們的假 API。 您可以看到我們正在調度的product/load操作在 Product 下命名。 這清楚地表明我們正在處理商店的哪個部分。 然後,通過將狀態映射到本地計算屬性,我們可以輕鬆地在模板中使用它。

有一個問題:當 API 運行時,我們會看到一秒鐘的原始狀態。 稍後,我們將使用 Nuxt 提供的解決方案來解決此問題(稱為fetch )。

再次強調這一點,我們npm install vuex ,因為它已經包含在 Nuxt 包中。 當您將index.js文件添加到 store 目錄時,所有這些方法都會自動向您打開。

這是解釋的主要兩個目錄; 其餘的要簡單得多。

成分

Components 目錄包含您的可重用組件,例如導航欄、圖片庫、分頁、數據表等。由於 Pages 目錄中的組件被轉換為路由,您需要在其他地方存儲這些類型的組件。 這些組件可以通過導入在頁面或其他組件中訪問:

 import ComponentName from ~/components/ComponentName.vue

資產

這包含未編譯的資產,更多地與 Webpack 如何加載和處理文件有關,而不是與 Nuxt 的工作方式有關。 如果您有興趣,我建議您閱讀自述文件中的指南。

靜止的

這包含映射到站點根目錄的靜態文件。 例如,將名為 logo.png 的圖像放在此目錄中將使其在/logo.png可用。 這適用於 robots.txt、favicon.ico 等元文件以及您需要的其他可用文件。

佈局

通常,在 Vue 項目中,您有某種根組件,通常稱為App.vue 。 您可以在此處設置(通常是靜態的)應用程序佈局,其中可能包括導航欄、頁腳,然後是 vue-router 的內容區域。 default佈局正是這樣做的,並在 layouts 文件夾中為您提供。 最初,它只有一個帶有<nuxt />組件的 div(相當於<router-view /> ),但可以根據需要設置樣式。 例如,我在示例項目中添加了一個簡單的導航欄,用於在各種演示頁面中導航。

一個佈局可以應用於多個頁面。

您可能希望為應用的某個部分設置不同的佈局。 也許您有某種看起來不同的 CMS 或管理面板。 要解決此問題,請在 Layouts 目錄中創建一個新佈局。 舉個例子,讓我們創建一個admin-layout.vue佈局,它只有一個額外的標題標籤,沒有導航欄:

 <template> <div> <h1>Admin Layout</h1> <nuxt /> </div> </template>

然後,我們可以在 Pages 目錄中創建一個admin.vue頁面,並使用 Nuxt 提供的一個名為layout的屬性來指定我們要用於該組件的佈局的名稱(作為字符串):

 <template> <h1>Admin Page</h1> </template> <script> export default { layout: 'admin-layout' } </script>

這裡的所有都是它的。 除非指定,否則頁面組件將使用default佈局,但是當您導航到/admin時,它現在使用admin-layout.vue佈局。 當然,如果您願意,可以在多個管理屏幕上共享此佈局。 要記住的一件重要的事情是佈局必須包含一個<nuxt />元素

關於佈局還有最後一件事需要注意。 您在試驗時可能已經註意到,如果您鍵入一個無效的 URL,您會看到一個錯誤頁面。 這個錯誤頁面實際上是另一種佈局。 Nuxt 有自己的錯誤佈局(源代碼在這裡),但如果你想編輯它,只需創建一個error.vue佈局,然後使用它。 這裡需要注意的是錯誤佈局不能有<nuxt />元素。 您還可以訪問組件上的error對象,其中包含一些要顯示的基本信息。 (如果您想檢查它,它會在運行 Nuxt 的終端中打印出來。)

中間件

中間件是可以在渲染頁面或佈局之前執行的函數。 您可能出於多種原因想要這樣做。 路由保護是一種流行的用途,您可以在其中檢查 Vuex 存儲以獲取有效登錄或驗證某些參數(而不是在組件本身上使用validate方法)。 我最近參與的一個項目使用中間件根據路由和參數生成動態麵包屑。

這些函數可以是異步的; 請小心,因為在解決中間件之前不會向用戶顯示任何內容。 他們還可以訪問 Nuxt 的 Context,我稍後會解釋。

插件

該目錄允許您在創建應用程序之前註冊 Vue 插件。 這允許插件在 Vue 實例上的整個應用程序中共享,並且可以在任何組件中訪問。

大多數主要插件都有一個 Nuxt 版本,可以按照他們的文檔輕鬆註冊到 Vue 實例。 但是,在某些情況下,您將為此目的開發插件或需要調整現有插件。 我從文檔中藉用的一個示例顯示瞭如何為vue-notifications執行此操作。 首先,我們需要安裝包:

 npm install vue-notifications --save

然後在插件目錄中創建一個名為vue-notifications.js的文件,並包含以下內容:

 import Vue from 'vue' import VueNotifications from 'vue-notifications' Vue.use(VueNotifications)

非常類似於在普通 Vue 環境中註冊插件的方式。 然後編輯項目根目錄下的nuxt.config.js文件,並將以下條目添加到 module.exports 對象:

 plugins: ['~/plugins/vue-notifications']

而已。 現在您可以在整個應用程序中使用vue-notifications 。 示例項目中的/plugin就是一個例子。

這樣就完成了目錄結構的概要。 這似乎需要學習很多東西,但如果你正在開發一個 Vue 應用程序,那麼你已經在設置相同的邏輯。 Nuxt 有助於抽象設置並幫助您專注於構建。

不過,Nuxt 不僅僅是協助開發。 它通過提供額外的功能來增強您的組件。

Nuxt 的增壓組件

當我第一次開始研究 Nuxt 時,我一直在閱讀有關 Page 組件是如何增壓的。 這聽起來很棒,但目前還不清楚這到底意味著什麼以及它帶來了什麼好處。

這意味著所有 Page 組件都附加了額外的方法,Nuxt 可以使用這些方法來提供額外的功能。 事實上,當我們使用validate方法檢查參數並在參數無效時重定向用戶時,我們已經看到過其中之一。

Nuxt 項目中使用的兩個主要方法是asyncDatafetch方法。 兩者在概念上非常相似,它們在組件生成之前異步運行,並且可以用於填充組件和存儲的數據。 即使我們必須等待某些數據庫或 API 調用,它們也使頁面能夠在將其發送到客戶端之前在服務器上完全呈現。

asyncDatafetch有什麼區別?

  • asyncData用於填充 Page 組件的數據。 當您返回一個對象時,它會在渲染之前與data輸出合併。
  • fetch用於填充 Vuex Store。 如果你返回一個 Promise,Nuxt 會等到它被解析後再渲染。

所以讓我們好好利用這些。 還記得之前在/products/view頁面上,我們遇到了一個問題,即在進行虛假 API 調用時,商店的初始狀態被短暫顯示? 解決此問題的一種方法是將布爾值存儲在組件或 Store 中,例如loading = true ,然後在 API 調用完成時顯示加載組件。 之後,我們將設置loading = false並顯示數據。

相反,讓我們在渲染之前使用fetch填充 Store。 在一個名為/products/view-async的新頁面中,讓我們將created的方法更改為fetch ; 那應該工作,對吧?

 export default { fetch () { // Unfortunately the below line throws an error // because 'this.$store' is undefined... this.$store.dispatch('product/load') }, computed: {...} }

這裡有一個問題:這些“增壓”方法在組件創建之前運行,所以this並不指向組件,並且它上面的任何內容都不能被訪問。 那麼我們如何訪問這裡的商店呢?

上下文 API

當然,有一個解決方案。 在 Nuxt 的所有方法中,都為您提供了一個參數(通常是第一個),其中包含一個非常有用的對象,稱為 Context。 這就是你需要在整個應用程序中引用的所有內容,這意味著我們不需要等待 Vue 首先在組件上創建這些引用。

我強烈建議您查看 Context 文檔以了解可用的內容。 一些方便的是app ,您可以在其中訪問所有插件, redirect可用於更改路由, error用於顯示錯誤頁面,以及一些不言自明的插件,例如routequerystore

因此,要訪問 Store,我們可以解構 Context 並從中提取 Store。 我們還需要確保我們返回了一個 Promise,以便 Nuxt 在渲染組件之前可以等待它解決,因此我們也需要對我們的 Store 操作進行小幅調整。

 // Component export default { fetch ({ store }) { return store.dispatch('product/load') }, computed: {...} } // Store Action load ({ commit }) { return new Promise(resolve => { setTimeout(() => { commit('update', { _id: 1, title: 'Product', price: 99.99 }) resolve() }, 1000) }) }

您可以根據您的編碼風格使用 async/await 或其他方法,但概念是相同的——我們告訴 Nuxt 在嘗試渲染組件之前確保 API 調用完成並使用結果更新 Store。 如果您嘗試導航到/products/view-async ,您將看不到產品處於初始狀態的內容閃爍。

您可以想像,即使沒有 SSR,這在任何 Vue 應用程序中都有多大用處。 Context 也可用於所有中間件以及其他 Nuxt 方法,例如NuxtServerInit ,它是在 Store 初始化之前運行的特殊存儲操作(下一節中將有一個示例)

使用 SSR 時的注意事項

我敢肯定,許多(包括我自己)開始使用 Nuxt 之類的技術,同時像對待任何其他 Vue 項目一樣對待它,最終碰壁了,我們知道在 Nuxt 中通常可以正常工作的東西似乎是不可能的。 隨著越來越多的這些警告被記錄下來,它會更容易克服,但是在開始調試時要考慮的主要事情是客戶端和服務器是兩個獨立的實體。

當您最初訪問一個頁面時,會向 Nuxt 發送一個請求,服務器會盡可能多地構建該頁面和應用程序的其餘部分,然後服務器將其發送給您。 然後,客戶端有責任繼續導航並根據需要加載塊。

我們希望服務器先做盡可能多的事情,但有時它無法訪問所需的信息,這導致工作改為在客戶端完成。 或者更糟糕的是,當客戶端呈現的最終內容與服務器預期的不同時,客戶端被告知從頭開始重建它。 這是一個很大的跡象,表明應用程序邏輯有問題。 值得慶幸的是,如果這種情況開始發生,您的瀏覽器控制台(處於開發模式)中會生成一個錯誤。

讓我們舉一個例子來說明如何解決一個常見問題,會話管理。 想像一下,您有一個 Vue 應用程序,您可以在其中登錄帳戶,並且您的會話使用您決定保留在localStorage中的令牌(例如 JWT)存儲。 當您最初訪問該站點時,您希望根據 API 對該令牌進行身份驗證,如果有效,該 API 會返回一些基本用戶信息並將該信息放入 Store 中。

閱讀完 Nuxt 的文檔後,您會看到有一個名為NuxtServerInit的方便方法,它允許您在初始加載時異步填充 Store。 聽起來很完美! 因此,您在 Store 中創建用戶模塊並在 Store 目錄的index.js文件中添加適當的操作:

 export const actions = { nuxtServerInit ({ dispatch }) { // localStorage should work, right? const token = localStorage.getItem('token') if (token) return dispatch('user/load', token) } }

刷新頁面時,會出現錯誤, localStorage is not defined 。 想想這發生在哪裡,這是有道理的。 該方法是在服務端運行的,它不知道客戶端的localStorage中存儲了什麼; 事實上,它甚至都不知道“localStorage”是什麼! 所以這不是一個選擇。

服務器嘗試執行 localStorage.getItem('token') 但拋出一個錯誤,然後下面的標題解釋了問題。

那麼解決方案是什麼? 實際上有幾個。 您可以讓客戶端來初始化存儲,但最終會失去 SSR 的好處,因為客戶端最終會完成所有工作。 您可以在服務器上設置會話,然後使用它來驗證用戶,但這是另一個需要設置的層。 與localStorage方法最相似的是使用 cookie。

Nuxt 可以訪問 cookie,因為它們是與客戶端的請求一起發送到服務器的。 與其他 Nuxt 方法一樣, nuxtServerInit可以訪問 Context,這一次作為第二個參數,因為第一個是為存儲保留的。 在 Context 上,我們可以訪問req對象,該對象存儲來自客戶端請求的所有標頭和其他信息。 (如果您使用過 Node.js,這將特別熟悉。)

因此,在將令牌存儲在 cookie 中(在本例中稱為“令牌”)之後,讓我們在服務器上訪問它。

 import Cookie from 'cookie' export const actions = { nuxtServerInit ({ dispatch }, { req }) { const cookies = Cookie.parse(req.headers.cookie || '') const token = cookies['token'] || '' if (token) return dispatch('user/load', token) } }

一個簡單的解決方案,但可能不會立即顯而易見。 學會思考某些操作發生在哪裡(客戶端、服務器或兩者)以及他們可以訪問的內容需要一些時間,但這樣做的好處是值得的。

部署

使用 Nuxt 進行部署非常簡單。 使用相同的代碼庫,您可以創建 SSR 應用程序、單頁應用程序或靜態頁面。

服務端渲染應用(SSR App)

這可能是您在使用 Nuxt 時的目標。 這裡部署的基本概念是在您選擇的任何平台上運行build過程並設置一些配置。 我將使用文檔中的 Heroku 示例:

首先,在package.json中為 Heroku 設置腳本:

 "scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", "heroku-postbuild": "npm run build" }

然後使用heroku-cli設置 Heroku 環境(此處的設置說明:

 # set Heroku variables heroku config:set NPM_CONFIG_PRODUCTION=false heroku config:set HOST=0.0.0.0 heroku config:set NODE_ENV=production # deploy git push heroku master

而已。 現在,您的 SSR Vue 應用程序已經準備好讓全世界看到。 其他平台有不同的設置,但過程是相似的。 目前列出的官方部署方式有:

  • 現在
  • Dokku(數字海洋)
  • Nginx

單頁應用程序 (SPA)

如果您想利用 Nuxt 提供的一些額外功能但避免服務器嘗試呈現頁面,那麼您可以部署為 SPA。

首先,最好在不使用 SSR 的情況下測試您的應用程序,因為默認情況下npm run dev在啟用 SSR 的情況下運行。 要更改它,請編輯nuxt.config.js文件並添加以下選項:

 mode: 'spa',

現在,當您運行npm run dev時,SSR 將被關閉,應用程序將作為 SPA 運行以供您測試。 此設置還確保未來的構建不會包含 SSR。

如果一切正常,那麼部署與 SSR 應用程序完全相同。 請記住,您需要先設置mode: 'spa'以讓構建過程知道您想要一個 SPA。

靜態頁面

如果您根本不想與服務器打交道,而是想生成用於靜態託管服務(例如 Surge 或 Netlify)的頁面,那麼可以選擇此選項。 請記住,如果沒有服務器,您將無法訪問 Context 中的reqres ,因此如果您的代碼依賴於它,請務必適應它。 例如,在生成示例項目時, nuxtServerInit函數會引發錯誤,因為它試圖從請求標頭中的 cookie 中獲取令牌。 在這個項目中,這並不重要,因為該數據並未在任何地方使用,但在實際應用程序中,需要有一種替代方法來訪問該數據。

排序完成後,部署就很容易了。 您可能首先需要更改的一件事是添加一個選項,以便nuxt generate命令也將創建一個備用文件。 這個文件會提示託管服務讓 Nuxt 處理路由而不是託管服務,拋出 404 錯誤。 為此,將以下行添加到nuxt.config.js

 generate: { fallback: true },

這是一個使用 Netlify 的示例,目前不在 Nuxt 文檔中。 請記住,如果這是您第一次使用netlify-cli ,系統將提示您進行身份驗證:

 # install netlify-cli globally npm install netlify-cli -g # generate the application (outputs to dist/ folder) npm run generate # deploy netlify deploy dist

就這麼簡單! 正如文章開頭提到的,這裡有這個項目的一個版本。 以下服務還有官方部署文檔:

  • GitHub 頁面

了解更多

Nuxt 正在迅速更新,這只是它提供的一小部分功能。 我希望這篇文章能鼓勵您嘗試一下,看看它是否有助於提高您的 Vue 應用程序的功能,讓您更快地開發並利用其強大的功能。

如果您正在尋找更多信息,請查看 Nuxt 的官方鏈接:

  • 文檔
  • 操場
  • GitHub
  • 常問問題

想要升級您的 JavaScript 遊戲? Try reading The Comprehensive Guide to JavaScript Design Patterns by fellow Toptaler Marko Mišura.