使用 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 游戏? 尝试阅读 Toptaler Marko Mišura 的 JavaScript 设计模式综合指南。