使用Nuxt.js创建服务器端渲染的Vue.js应用

本文概述

当你浏览网站时, 诸如Vue之类的JavaScript框架/库可以提供出色的用户体验。大多数提供了一种动态更改页面内容的方式, 而不必每次都向服务器发送请求。

但是, 这种方法存在问题。最初加载你的网站时, 你的浏览器未显示完整的页面。取而代之的是, 它被发送了很多代码来构建页面(HTML, CSS, 其他文件)以及如何将它们全部组合在一起的说明(JavaScript框架/库)将所有这些信息组合在一起需要大量的时间在你的浏览器实际显示之前。这就像一堆书和一个平装书柜一样。你必须先构建书架, 然后再将书装满。

解决此问题的方法很聪明:在服务器上拥有一个框架/库版本, 可以构建一个随时显示的页面。然后将完整的页面连同进行进一步更改的能力一起发送到浏览器, 并且仍然具有动态页面内容(框架/库), 就像将现成的书架和一些书一起发送一样。当然, 你仍然必须将书放在书架中, 但是马上有了一些可用的东西。

客户端和服务器端渲染的视觉比较

除了愚蠢的类比之外, 还有很多其他优点。例如, 一个很少更改的页面(例如”关于我们”页面)不需要每次用户每次都重新创建。因此, 服务器可以创建一次, 然后将其缓存或存储在某个地方以备将来使用。这些类型的速度改善似乎很小, 但是在一个环境中, 直到以毫秒(或更短)为单位来衡量响应时间, 每一点都很重要。

如果你想了解有关Vue环境中SSR优势的更多信息, 请查看Vue自己关于SSR的文章。有多种选择可实现这些结果, 但Vue团队也推荐的最受欢迎的选择是Nuxt。

为什么选择Nuxt.js

Nuxt.js基于流行的React库Next的SSR实现。在了解了这种设计的优点之后, 为Vue设计了一个类似的实现, 称为Nuxt。那些熟悉React + Next组合的人会发现应用程序的设计和布局中有很多相似之处。但是, Nuxt提供了Vue特定的功能来为Vue创建强大而灵活的SSR解决方案。

Nuxt已于2018年1月更新为可用于生产的1.0版本, 并且是一个活跃且得到良好支持的社区的一部分。很棒的事情之一是, 使用Nuxt构建项目与构建任何其他Vue项目没有什么不同。实际上, 它提供了许多功能, 使你可以在减少的时间内创建结构良好的代码库。

值得注意的另一件事是, Nuxt不必用于SSR。它被推广为用于创建通用Vue.js应用程序的框架, 并包含用于使用同一代码库创建静态生成的Vue应用程序的命令(nuxt生成)。因此, 如果你担心要深入研究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将为该目录创建根路由。生成项目后, 页面目录中已经存在一个index.vue组件, 该组件与你网站的首页或登录页面相关。 (在开发示例中, 它就是localhost:3000。)

Nuxt扫描pages目录中的Vue文件并输出适当的页面。

那更深的路线呢? Pages目录中的子目录有助于构建路由。因此, 如果我们需要查看产品页面, 则可以构建如下的Pages目录:

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

现在, 如果导航到/ products / view, 我们将在products目录中看到view.vue组件。如果我们改为导航到/ products, 我们将在products目录中看到index.vue组件。

你可能会问, 为什么我们不像在/ about页面中那样在pages目录中创建product.vue组件。你可能会认为结果相同, 但是两种结构之间存在差异。让我们通过添加另一个新页面来演示这一点。

假设我们希望为每个员工提供单独的”关于”页面。例如, 让我们为我创建一个关于页面。它应该位于/ 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中, 这是相同的概念, 只是我们只使用<nuxt />而不是<router-view />。因此, 让我们更新about.vue组件以允许使用嵌套路由:

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

现在, 当我们导航到/ about时, 我们获得了以前拥有的about.vue组件, 仅有一个标题。但是, 当我们导航到/ about / ben-jones时, 我们将在<nuxt />占位符所在的位置显示标题和ben-jones.vue组件。

这不是我们最初想要的, 但是创建一个”关于”页面的列表的想法是一个有趣的概念, 当单击该页面时, 将他们的信息填入页面的某个部分是一个有趣的概念, 所以让我们暂时将其保留。如果你确实想要其他选项, 那么我们要做的就是重组目录。我们只需要将/ about目录中的about.vue组件移至其名称, 并将其重命名为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的Context中的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将显示什么。我们将使用带有嵌套_product_id.vue组件的product.vue组件, 该组件具有两个路由参数:category_id和product_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目录(类似于Pages目录)的结构来构建Vuex Store。如果你不需要商店, 只需删除目录即可。存储有两种模式, 经典模式和模块模式。

经典版要求你在商店目录中具有index.js文件。在那里, 你需要导出一个返回Vuex实例的函数:

import Vuex from 'vuex'

const createStore = () => {
 return new Vuex.Store({
   state: ..., mutations: ..., actions: ...
 })
}

export default createStore

这使你可以根据需要创建商店, 就像在普通Vue项目中使用Vuex一样。

模块模式还要求你在商店目录中创建index.js文件。但是, 此文件仅需要导出Vuex存储的根状态/更改/操作。下面的示例指定了空白的根状态:

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

然后, 商店目录中的每个文件都将以其自己的名称空间或模块添加到商店中。例如, 让我们在某个地方创建一个存储当前产品的位置。如果我们在商店目录中创建一个名为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)
 }
}

加载操作中的setTimeout模拟某种API调用, 它将使用响应更新商店;在这种情况下, 需要一秒钟。现在, 让我们在产品/视图页面中使用它:

<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提供的解决方案来解决此问题(称为获取)。

再次强调一下, 我们不再需要npm安装vuex, 因为它已经包含在Nuxt软件包中。将index.js文件添加到store目录时, 所有这些方法都会自动向你开放。

这是解释的主要两个目录;其余的要简单得多。

组件

其中的Components目录包含可重用的组件, 例如导航栏, 图像库, 分页, 数据表等。由于Pages目录中的组件已转换为路线, 因此你需要在其他地方存储这些类型的组件。通过导入它们, 可以在页面或其他组件中访问这些组件:

import ComponentName from ~/components/ComponentName.vue

资产

这包含未编译的资产, 并且与Webpack加载和处理文件的方式有关, 而不是与Nuxt的工作方式有关。如果你有兴趣, 建议阅读自述文件中的指南。

static

它包含静态文件, 这些文件已映射到站点的根目录。例如, 在此目录中放置一个名为logo.png的图像, 将使其在/logo.png中可用。这对于元文件(例如robots.txt, favicon.ico)以及你需要的其他文件很有用。

版面

通常, 在Vue项目中, 你具有某种根组件, 通常称为App.vue。在这里, 你可以设置(通常是静态的)应用布局, 其中可能包括导航栏, 页脚, 然后是vue-router的内容区域。默认布局正是这样做的, 并在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>

这里的所有都是它的。除非指定, 否则页面组件将使用默认布局, 但是当你导航到/ admin时, 它现在将使用admin-layout.vue布局。当然, 如果你愿意, 可以在多个管理屏幕之间共享此布局。要记住的一件事是, 布局必须包含<nuxt />元素。

关于布局, 还有最后一点要注意。你可能在进行实验时注意到, 如果键入无效的URL, 则会看到错误页面。实际上, 此错误页面是另一种布局。 Nuxt有其自己的错误布局(此处为源代码), 但是如果你要对其进行编辑, 则只需创建一个error.vue布局即可使用。需要注意的是, 错误布局必须没有<nuxt />元素。你还可以访问组件上的错误对象, 并显示一些基本信息。 (如果要检查它, 则在运行Nuxt的终端中将其打印出来。)

中间件

中间件是可以在呈现页面或布局之前执行的功能。你可能有多种原因要这样做。路由保护是一种流行的用法, 你可以在Vuex存储中检查有效的登录名或验证某些参数(而不是在组件本身上使用validate方法)。我最近从事的一个项目是使用中间件根据路线和参数生成动态面包屑。

这些功能可以是异步的。请小心, 因为在解决中间件之前, 不会向用户显示任何内容。他们还可以访问Nuxt的上下文, 我将在后面解释。

外挂程式

该目录允许你在创建应用程序之前注册Vue插件。这使该插件可以在Vue实例上的整个应用程序中共享, 并且可以在任何组件中访问。

大多数主要插件都具有Nuxt版本, 可以通过遵循其文档轻松地将其注册到Vue实例。但是, 在某些情况下, 你将要开发插件或需要为此目的改编现有的插件。我从文档中借用的示例显示了如何针对vue通知执行此操作。首先, 我们需要安装该软件包:

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通知。一个示例在示例项目的/ plugin中。

这样就完成了目录结构的精简。似乎有很多东西要学习, 但是如果你正在开发Vue应用, 那么你已经在建立相同的逻辑。 Nuxt帮助你简化设置并帮助你专注于构建。

Nuxt所做的不只是协助开发。它通过提供额外的功能来为你的组件增压。

Nuxt的增压组件

刚开始研究Nuxt时, 我一直在阅读有关Page组件如何增压的信息。听起来不错, 但它的确切含义和带来的好处并不清楚。

这意味着所有Page组件都具有附加的附加方法, Nuxt可以使用这些方法提供附加功能。实际上, 当我们使用validate方法检查参数并在用户无效时重定向用户时, 我们已经看到了其中一种。

Nuxt项目中使用的两个主要方法是asyncData和fetch方法。两者在概念上非常相似, 它们在生成组件之前异步运行, 并且可用于填充组件和存储的数据。它们还使页面能够在发送给客户端之前完全在服务器上呈现, 即使我们必须等待一些数据库或API调用也是如此。

asyncData和fetch有什么区别?

  • asyncData用于填充Page组件的数据。当你返回一个对象时, 然后在渲染之前将其与数据输出合并。
  • fetch用于填充Vuex商店。如果你返回诺言, 则Nuxt将等到它解决后再进行渲染。

因此, 让我们充分利用它们。还记得早先在/ products / view页面上遇到的一个问题, 即在进行虚假API调用时短暂显示了商店的初始状态?解决此问题的一种方法是在组件或商店中存储一个布尔值, 例如loading = true, 然后在API调用完成时显示一个正在加载的组件。之后, 我们将设置loading = false并显示数据。

取而代之的是, 让我们使用fetch在渲染之前填充商店。在名为/ products / view-async的新页面中, 让我们将创建的方法更改为访存;那应该起作用, 对吗?

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

这里有个要注意的地方:这些”增压”方法在创建组件之前运行, 因此它并不指向组件, 因此无法访问组件上的任何内容。那么我们如何在这里访问商店?

上下文API

当然, 有解决方案。在Nuxt的所有方法中, 都为你提供了一个参数(通常是第一个参数), 其中包含一个非常有用的对象, 称为”上下文”。在这里, 你将需要在整个应用程序中引用所有内容, 这意味着我们无需等待Vue首先在组件上创建这些引用。

我强烈建议你查看Context文档, 以了解可用的内容。一些方便的应用程序是应用程序, 你可以在其中访问所有插件, 重定向(可用于更改路线, 显示错误页面显示错误)以及一些不言自明的功能(例如路线, 查询和存储)。

因此, 要访问商店, 我们可以解构上下文并从中提取商店。我们还需要确保返回承诺, 以便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应用程序中也可能有用。上下文也可用于所有中间件以及其他Nuxt方法, 例如NuxtServerInit, 这是在初始化存储之前运行的特殊存储操作(下一节将对此进行示例)

使用SSR时的注意事项

我敢肯定, 很多人(包括我自己)开始使用Nuxt之类的技术, 同时又像对待其他任何Vue项目一样最终将其碰壁, 在Nuxt中我们通常无法正常工作的东西似乎是不可能的。随着更多这些警告记录在案, 将更容易克服, 但是开始调试时要考虑的主要事情是客户端和服务器是两个单独的实体。

最初访问页面时, 请求将发送到Nuxt, 服务器将尽可能多地构建该页面和应用程序的其余部分, 然后服务器将其发送给你。然后, 由客户负责继续导航并根据需要加载块。

我们希望服务器先执行尽可能多的操作, 但有时它无法访问所需的信息, 从而导致工作在客户端进行。或更糟糕的是, 当客户端呈现的最终内容与服务器预期的内容不同时, 客户端将被告知从头开始重建内容。这表明应用程序逻辑有问题。值得庆幸的是, 如果这种情况开始发生, 则会在浏览器的控制台(处于开发模式)中生成错误。

让我们以如何解决常见问题(会话管理)为例。假设你有一个可以登录帐户的Vue应用程序, 并且你使用决定保留在localStorage中的令牌(例如JWT)存储了会话。最初访问站点时, 你想根据API对令牌进行身份验证, 该API将返回一些基本的用户信息(如果有效), 然后将该信息放入商店中。

阅读完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。考虑到这发生在哪里, 这是有道理的。该方法在服务器上运行, 它不知道客户端上的localStorage中存储了什么。实际上, 它甚至都不知道” localStorage”是什么!所以这不是一个选择。

服务器尝试执行localStorage.getItem('token'),但抛出错误,然后在下面的标题中说明了问题。

那有什么解决方案?实际上有一些。你可以让客户端初始化商店, 但最终会失去SSR的好处, 因为客户端最终会完成所有工作。你可以在服务器上设置会话, 然后使用该会话对用户进行身份验证, 但这是要设置的另一层。与localStorage方法最相似的是使用Cookie。

Nuxt可以访问cookie, 因为它们是随请求一起从客户端发送到服务器的。与其他Nuxt方法一样, nuxtServerInit可以访问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时的目标。此处部署的基本概念是在你选择的任何平台上运行构建过程, 并设置一些配置。我将使用文档中的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应用程序已准备就绪, 可供世界各地观看。其他平台具有不同的设置, 但是过程类似。当前列出的官方部署方法是:

  • 现在
  • 独孤(数字海洋)
  • Nginx的

单页应用程序(SPA)

如果你想利用Nuxt提供的一些额外功能, 但又避免服务器尝试渲染页面, 则可以将其部署为SPA。

首先, 最好在没有SSR的情况下测试你的应用程序, 因为默认情况下, npm run dev在SSR启用的情况下运行。要更改此设置, 请编辑nuxt.config.js文件并添加以下选项:

mode: 'spa', 

现在, 当你运行npm run dev时, SSR将被关闭, 并且该应用程序将作为SPA运行, 供你测试。此设置还可以确保以后的版本都不会包含SSR。

如果一切正常, 则部署与SSR应用程序完全相同。只要记住你需要设置模式即可:首先使用” spa”, 以使构建过程知道你需要SPA。

静态页面

如果你根本不想使用服务器, 而是想生成供静态主机服务(例如Surge或Netlify)使用的页面, 则可以选择此选项。请记住, 没有服务器, 你将无法访问Context中的req和res, 因此, 如果你的代码依赖于此, 请确保将其容纳。例如, 在生成示例项目时, 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游戏?尝试阅读srcminier研究员MarkoMišura撰写的JavaScript设计模式综合指南。

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?