部署 Nuxt SPA

如果我们有 Node.js 运行时服务器,我们可以像部署通用 SSR Nuxt 应用程序一样部署 Nuxt SPA。如果我们没有,那么我们只能将 SPA 作为静态站点部署到静态托管服务器(如 GitHub Pages)。你可以按如下方式部署静态生成的 Nuxt SPA

  1. 确保在 Nuxt 配置文件的 mode 选项中已将值设置为 spa

    // nuxt.config.js
    export default {
      mode: 'spa'
    }
  2. 确保你的 package.json 文件中也包含以下运行脚本:

    {
      "scripts": {
        "generate": "nuxt generate"
      }
    }
  3. 运行 npm run generate,就像你对通用 SSR Nuxt 应用程序所做的那样。你将在终端中看到以下输出:

    ℹ Generating output directory: dist/
    ℹ Generating pages
    ✓ Generated /about
    ✓ Generated /login
    ✓ Generated /secret
    ✓ Generated /users
    ✓ Generated /

    在上面的输出中,如果你导航到项目中的 /dist/ 文件夹,你将在根目录中找到一个 index.html 文件,以及每个子文件夹中都包含一个 index.html 文件,子文件夹的名称与路由名称相同。但是,你不会在生成的动态路由(例如 /users/1)中找到任何这些页面。这是因为与通用模式不同,动态路由不会在 spa 模式下生成。

    此外,如果你打开 /dist/ 文件夹中的 index.html 文件,你会发现所有 index.html 文件都是完全相同的——只是一些 “空” 的 HTML 元素,类似于经典的 SPA。此外,每个 index.html 文件都不包含其单独的元信息,只包含来自 nuxt.config.js 的通用元信息。这些页面的元信息将在运行时进行水合(填充和更新)。因此,对于一个 “静态” SPA 来说,这似乎是违反直觉且 “半成品” 的。最重要的是,没有生成静态 payload。这意味着如果你在浏览器中导航到 localhost:3000/users,你会注意到此页面仍然从 https://jsonplaceholder.typicode.com/users 请求其数据,而不是像通用 SSR Nuxt 应用程序那样从 payload 中获取数据。这是因为即使你在 Nuxt 配置文件中为 target 属性设置了 staticNuxt 也不会在 spa 模式下生成静态内容。为了克服这些问题,我们可以从通用模式生成我们需要的静态内容。

  4. Nuxt 配置文件中 mode 选项的 spa 更改为 universal

    // nuxt.config.js
    export default {
      mode: 'universal'
    }
  5. 运行 npm run generate,以便 Nuxt 将对 API 进行 REST API 调用以检索用户,并将其内容导出到本地静态 payload。你将看到以下输出:

    ℹ Generating output directory: dist/
    ℹ Generating pages with full static mode
    ✓ Generated /about
    ✓ Generated /secret
    ✓ Generated /login
    ✓ Generated /users
    ✓ Generated /users/1
    ✓ Generated /users/2
    ...
    ...
    ✓ Generated /users/10
    ✓ Generated /

    请注意,在上面的输出中没有生成动态路由。如果你再次导航到 /dist/ 文件夹,你应该看到 /users/ 文件夹现在包含多个文件夹,每个文件夹都包含自己的用户 ID。这些文件夹中的每一个都包含一个 index.html 文件,其中包含该特定用户的内容。现在,每个 index.html 文件都包含其自己的元信息和在 /dist/_nuxt/static/ 中生成的 payload

    此外,如果你打开 /dist/ 文件夹中的 index.html 文件,你会发现所有 index.html 文件都是完全相同的——只是一些 “空” 的 HTML 元素,类似于经典的 SPA。此外,每个 index.html 文件都不包含其单独的元信息,只包含来自 nuxt.config.js 的通用元信息。这些页面的元信息将在运行时进行水合(填充和更新)。因此,对于一个 “静态” SPA 来说,这似乎是违反直觉且 “半成品” 的。最重要的是,没有生成静态 payload。这意味着如果你在浏览器中导航到 localhost:3000/users,你会注意到此页面仍然从 https://jsonplaceholder.typicode.com/users 请求其数据,而不是像通用 SSR Nuxt 应用程序那样从 payload 中获取数据。这是因为即使你在 Nuxt 配置文件中为 target 属性设置了 staticNuxt 也不会在 spa 模式下生成静态内容。为了克服这些问题,我们可以从通用模式生成我们需要的静态内容。

  6. 更改 Nuxt 配置文件中 mode 选项的 universalspa

    // nuxt.config.js
    export default {
      mode: 'spa'
    }
  7. 现在,在你的终端运行 npm run build。你应该看到以下输出:

    Hash: c36ee9714ee9427ac1ff
    Version: webpack 4.43.0
    Time: 5540ms
    Built at: 11/07/2020 07:58:09
    Asset      Size Chunks             Chunk Names
    ../server/client.manifest.json  9.31 KiB                [emitted]
    LICENSES                         617 bytes                [emitted]
    app.922dbd1.js                    57 KiB      0          [emitted] [immutable]  app
    commons/app.7236c86.js           182 KiB      1          [emitted] [immutable]  commons/app
    pages/about.75fcd06.js           667 bytes      2          [emitted] [immutable]  pages/about
    pages/index.76b5c20.js           784 bytes      3          [emitted] [immutable]  pages/index
    pages/login.09e509e.js          3.14 KiB      4          [emitted] [immutable]  pages/login
    pages/secured.f086299.js         1.36 KiB      5          [emitted] [immutable]  pages/secured
    pages/users/_id.e1c568c.js        1.69 KiB      6          [emitted] [immutable]  pages/users/_id
    pages/users/index.b3e7aa8.js       1.5 KiB      7          [emitted] [immutable]  pages/users/index
    runtime.266b4bf.js               2.47 KiB      8          [emitted] [immutable]  runtime
    + 1 hidden asset
    Entrypoint app = runtime.266b4bf.js commons/app.7236c86.js app.922dbd1.js
    ℹ Ready to run nuxt generate
  8. 忽略 "Ready to run nuxt generate" 的消息。相反,首先通过终端上的 nuxt start 命令从 /dist/ 目录测试你的生产静态 SPA

    $ npm run start

    你应该得到以下输出:

    Nuxt.js @ v2.14.0> Environment: production
    Nuxt.js @ v2.14.0> Rendering: client-side
    Nuxt.js @ v2.14.0> Target: static
    Listening: http://localhost:3000/
    ℹ Serving static application from dist/

    现在,像 localhost:3000/users 这样的路由将不再从 https://jsonplaceholder.typicode.com 请求其数据。相反,它们将从 /dist/ 文件夹中的 /static/ 文件夹中的 payload 中获取数据。

  9. 最后,只需将此 /dist/ 目录部署到你的静态托管服务器即可。

    如果你正在寻找免费的静态托管服务器,可以考虑使用 GitHub Pages。使用它,你的站点将拥有以下格式的域名:

    <username>.github.io/<app-name>

GitHub 还允许你使用自定义域名而不是他们的域名来提供你的站点。有关更多信息,请遵循 GitHub 帮助站点的指南:https://help.github.com/en/github/working-with-github-pages/configuring-a-custom-domain-foryour-github-pages-site。但是,在本书中,我们将向你展示如何在 GitHub 的 github.io 域名上提供你的站点。我们将在下一节中学习如何做到这一点。

你可以在本书 GitHub 仓库的 /chapter-15/frontend/ 中找到本节的代码。

部署到 GitHub Pages

GitHub Pages 是 GitHub 提供的一项静态站点托管服务,用于托管和发布你的 GitHub 存储库中的静态文件(仅限 HTML、CSS 和 JavaScript)。只要你在 GitHub 上拥有用户帐户并为你的站点创建了 GitHub 存储库,你就可以将你的静态站点托管在 GitHub Pages 上。

请访问 https://guides.github.com/features/pages/ 以了解如何开始使用 GitHub Pages。

你只需要转到你的 GitHub 存储库的 Settings 部分,然后向下滚动到 GitHub Pages 部分。然后,你需要单击 Choose a theme 按钮以开始创建你的静态站点的过程。

将你的 Nuxt SPA 的静态版本部署到 GitHub Pages 相当容易——你只需要对 Nuxt 配置文件进行一些小的配置更改,然后使用 git push 命令将其上传到你的 GitHub 存储库。当你创建 GitHub 存储库并创建 GitHub Pages 时,默认情况下,静态页面的 URL 将以以下格式提供:

<username>.github.io/<repository-name>

因此,你需要将此 <存储库名称> 添加到 Nuxt 配置文件的 router base 选项中,如下所示:

export default {
  router: {
    base: '/<repository-name>/'
  }
}

但是,更改 base 名称会在开发 Nuxt 应用程序时干扰 localhost:3000。让我们学习如何解决这个问题:

  1. Nuxt 配置文件中为开发环境和生产环境的 GitHub Pages 创建一个 if 条件,如下所示:

    // nuxt.config.js
    const routerBase = process.env.DEPLOY_ENV === 'GH_PAGES' ? {
      router: {
        base: '/<存储库名称>/'
      }
    } : {}

    如果进程环境中的 DEPLOY_ENV 选项包含 GH_PAGES,则此条件只会将 /<repository-name>/ 添加到 router 选项的 base 键中。

  2. 使用展开运算符将此 routerBase 常量添加到配置文件的 Nuxt 配置中:

    // nuxt.config.js
    export default {
      ...routerBase
    }
  3. package.json 文件中设置 DEPLOY_ENV='GH_PAGES' 脚本:

    // package.json
    "scripts": {
      "build:gh-pages": "DEPLOY_ENV=GH_PAGES nuxt build",
      "generate:gh-pages": "DEPLOY_ENV=GH_PAGES nuxt generate"
    }

    使用这两个 npm 脚本之一,/<repository-name>/ 的值将不会注入到你的 Nuxt 配置中,并且在运行 npm run dev 进行开发时不会干扰开发过程。

  4. 就像上一节的步骤 4 一样,将 Nuxt 配置文件的 mode 选项的 spa 更改为 universal,以便使用 nuxt generate 命令生成静态 payload 和页面:

    $ npm run generate:gh-pages
  5. 就像上一节的步骤 6 一样,将 Nuxt 配置文件的 mode 选项的 universal 更改回 spa,以便使用 nuxt build 命令构建 SPA

    $ npm run build:gh-pages
  6. Nuxt 生成的 /dist/ 文件夹中的文件推送到你的 GitHub 存储库,从而推送到 GitHub Pages

Nuxt SPA 部署到 GitHub Pages 就是这样了。但是,请确保在将你的静态站点推送到 GitHub Pages 时,/dist/ 文件夹中包含一个空的 .nojekyll 文件。

Jekyll 是一个简单的、支持博客的静态站点生成器。它将纯文本转换为静态网站和博客。GitHub Pages 在后台由 Jekyll 提供支持,默认情况下,它不会构建任何以点“.”、下划线“_”开头或以波浪号“~”结尾的文件或目录。当在 GitHub Pages 中提供静态站点时,这将成为一个问题,因为在构建 Nuxt SPA 时,一个名为 _nuxt 的子文件夹也会在 /dist/ 文件夹中生成;这个 /_nuxt/ 文件夹将被 Jekyll 忽略。要解决此问题,我们需要在 /dist/ 文件夹中包含一个空的 .nojekyll 文件来关闭 Jekyll。当我们为 Nuxt SPA 构建静态页面时,会生成此文件,因此请确保也将其推送到你的 GitHub 存储库。

做得好——你已经完成了本书的另一个简短章节!如果你想在 Nuxt 中构建 SPA 而不是使用 Vue 或其他框架(如 AngularReact),Nuxt SPA 是一个不错的选择。但是,如果你提供需要即时或实时发布的 Web 服务(如社交媒体网站),那么静态生成的 Nuxt SPA 可能不是一个好的选择。这一切都取决于你的业务性质以及你是否想要使用 Nuxt 的全部功能(通用 SSR)还是仅客户端版本的 NuxtNuxt SPA)。接下来,我们将总结我们在本章中学到的内容。