Nuxt,离线优先PWA教程

作者 : IT 大叔 本文共9023个字,预计阅读时间需要23分钟 发布时间: 2020-09-14

我喜欢Vue.js。这是一个很棒的JavaScript框架-在我看来很容易超越其他产品-之所以说些什么,是因为我认为它们也很酷。是的,他们在某些方面做得比Vue好。他们中有些人 Vue和Vue后来采用它之前做过一些事情。但是即使如此,还是有充分的理由选择Vue。

只是为了快速浏览它们:

  1. Vue的学习曲线很好。
  2. 它鼓励逐步采用旧项目。
  3. 发展是由社区需求驱动的。
  4. Vue维护者与其他框架维护者有着友好的关系,从而可以自由交流思想和概念。

也许有些事情可能会更好

这里还有很多要点,但让我继续批评Vue.js-根据您打算构建的应用程序类型或应用程序的大小,即使使用CLI,也要搭建Vue.js应用程序可能会很麻烦。

另外,关于创建Vue应用程序的详细信息也必须遵守-这并不困难,但是,如果您打算使用Vuex或Vue路由器,则需要少量配置,然后您才能启动商店或期望路由正常工作。

文件的保存位置,组件文件夹或布局如何也可能有很大的不同。当然,当Vue CLI搭建新项目时,它会提供帮助,但是对于Vue路由器,例如,您需要继续修改路由器index.js才能准确记录路由。

这是很小的变化,但是随着应用程序的不断发展和变化,很容易将其遗忘。的确,任何应用程序,无论使用何种语言或框架,最终都将保留需要检查的项目清单,但我们应尽力将清单保持较小,并在有意义时使其自动化

输入Nuxt.js。

如果我要创建一个新的Vue项目,除非它很小,否则很少使用Vue CLI而不是Nuxt。Nuxt使一切变得简单。路由已经预先配置好,并根据目录结构动态确定。它很容易理解用于确定布局,中间件和组件的选项。

实际上,您可以以该博客的结构为例。这是GitHub

Nuxt可以担任许多职务。就此博客而言,它是基于git的CMS和静态网站生成器。但是我也使用它来创建一个单页应用程序,从而为浏览器提供了丰富的体验。它可以是通用应用程序,可以非常轻松地提供预渲染甚至服务器端的渲染页面。实际上,要创建服务器端呈现的应用程序而不是单页应用程序,这里是nuxt.config.js的配置行:

ssr: true, // will be a spa if set to false

在不提供示例的情况下很难描述如何使用Nuxt-因此让我们一起创建一个Nuxt应用程序。

示例应用程序要求

首先,让我们获得一些要求。

让我们将其作为调查应用程序。适用于需要定期检查消火栓的消火栓检查员(确信这是虚假的工作)。因此它具有以下要求:

  1. 需要用户登录。
  2. 以表格形式收集有关消火栓的数据。(消防栓序列号和条件)
  3. 必须脱机工作(消防栓并不总是靠近手机信号塔或WIFI)。
  4. 连接(或重新连接)时必须传输消防栓数据。
  5. 专为在手机或平板电脑上工作而设计。

好,太棒了。让我们对应用程序的体系结构做出一些决定。

它需要登录,因此我们将使用Auth0。Auth0将允许我们与其他身份验证系统集成,因此我们可以为各种消防栓检查员公司提供支持。

它需要一个表格,因此我们将使用引导程序来满足该要求。有可用的更新更好的CSS框架,但是引导程序只需很少的工作就可以为我们提供我们需要的一切(很多我们不需要)。

嗯,需求3、4和5确实指向PWA(渐进式Web应用程序)。因此,我们也将该应用程序设为PWA。

好。怎么办?那么所有这些都可以通过Nuxt完成。

在Nuxt中做

对于身份验证,我们可以使用@ nuxtjs / auth。这是完美的,因为它具有与Auth0的内置集成。但是,如果我不想使用Auth0,则它对少数其他身份验证提供程序具有内置支持,或者我们可以扩展它以使用所需的任何身份验证提供程序。

Nuxtjs / auth具有@ajax库的@ nuxtjs / axios依赖性-这是完美的,因为无论如何我们都需要使用它来传输表单数据。

我们还需要创建此表单。我们选择了bootstrap,因此我们将使用bootstrap-vue,它具有一个方便的Nuxt.js模块,可简化所有操作。另外,bootstrap-vue可以指定我们正在使用的引导程序功能,因此我们可以使用webpack(内置于Nuxt中)对其余的信息进行树状处理。大!对于引导程序的缺点来说,这不是一个完美的解决方法,但这是有的。

最后,我们有此PWA要求。也有一个模块。@ nuxtjs / pwa似乎拥有我们需要的一切。它将处理所有图标和清单内容,并允许我们轻松注册服务工作者并确定用户离线时应使用的路由和行为。

现在,注意我不需要指定的所有内容。我不需要调用Vue路由器,因为它已经混在一起了。Vuex也在其中,它是nuxt / auth的依赖项,但我们自己可能不需要它。

我们通过运行以下命令来创建项目:

npx create-nuxt-app <project-name>

在运行时,它将允许我们一些选择来获取一些依赖。PWA是一个选项,但是仍然需要额外的npm安装。我们还将使用Axios,因此现在更有意义。我们还可以选择引导程序或其他一系列CSS框架。

让我们继续并引入auth模块:

npm install @nuxtjs/auth

并且,如果尚未安装,请确保安装Axios:

npm intall @nuxtjs/axios

然后我们修改nuxt.config.js以添加到modules属性:

modules: [
  '@nuxtjs/axios',
  '@nuxtjs/auth'
],

auth: {
  // Options
}

脚手架工具还帮助我们选择了测试工具。我选择了杰斯特。

感谢提醒Nuxt!测试很重要。但是,抱歉,我不会谈论测试本教程。

最后,@ nuxtjs / auth提醒我们,我们需要通过在商店目录中添加index.js文件来初始化Vuex商店。添加index.js文件时,Nuxt将自动导入Vuex并对其进行配置以供使用。(这可以防止将Vuex添加到不需要它的项目中。)

接下来让我们拉入PWA模块:

npm install @nuxtjs/pwa

并且不要忘记设置清单!

manifest: {
    name: 'Fire hydrant surveyor',
    short_name: 'Hydrant Surveyor',
    lang: 'en',
    display: 'standalone',
},

Nuxt PWA实际上是5个不同的模块,其中只有一个模块需要我们提供一些自定义代码。

  • 图标模块-将配置PWA图标并使之可用。
  • 元模块-将为移动应用程序设置一些通用选项。
  • 清单模块-使用配置的值创建清单文件。
  • Workbox模块-允许设置服务工作者和可缓存资源-这是我们将进行大量工作以处理脱机行为的地方。
  • 一个信号模块-注入一个API,该API允许在移动设备上创建推送通知。

让我们看一下所有这些是什么样的:

这里是!

就像这样,我们有一个具有PWA功能,内置CSS框架和身份验证的功能正常的应用程序。

在这一点上,我们应该考虑剩下的任务:

  1. 创建一个Auth0帐户,然后将适当的信息添加到nuxt配置中。
  2. 使用auth0登录名和消火栓调查表构建适当的页面。
  3. 将可缓存资产添加到工作箱(包含在PWA模块中)。
  4. 配置和定制服务工作者以处理脱机工作流。

让我们去吧。从#1开始。

创建Auth0帐户非常简单。您可以使用GitHub登录。Auth0将自动为您设置一个应用程序。然后,您可以获取nuxtjs / auth模块所需的所有信息。您将需要在Auth0应用程序设置中进行一些设置,例如允许的来源,允许的回调URI等。您可以参考Auth0文档,了解如何执行此操作。

在nuxt.config.js中,您需要定义重定向和策略对象。请注意,回调和登录名不能相同。该模块需要路由到其他页面,以完成对从登录事件返回的用户数据的处理。

在nuxt.config.js中:

auth: {
    redirect: {
      login: '/',
      callback: options.redirectUri
    },
    strategies: {
      local: false,
      auth0: {
        domain: options.domain,
        client_id: options.client_id,
      }
    }
  },

options对象在单独的文件auth_config.js中定义。为了方便起见,我为项目做了此操作,但对于实际项目,我将使用.env文件,以便可以通过CI / CD管道为每个环境注入正确的值。

export const options = {
        domain: '...',
        client_id: '...',
        redirectUri: '/signed-in' //or whatever you configure in Auth0 Application Settings
} 

尽管其中包含的值不是秘密的,但是建议不要将文件检入源代码管理。以后您可以修改此文件以使其具有Audience属性,并根据构建环境更改值。

接下来,我们将修改主路径以包含一个登录按钮。

<div class="links">
  <button
    class="button--green"
    @click="login"
  >
    Login
  </button>
</div>

我们将在Vue实例中定义一个登录方法。

export default {
  methods: {
    login() {
      this.$auth.loginWith('auth0')
    }
  }
}

注意:撰写本文时,存在一个问题,需要安装其他npm软件包。

npm install nanoid@2.1.11

现在,当您对此进行测试时,应该将您重定向到Auth0登录页面。成功注册或登录后,您将被重定向回redirect_uri,在本示例项目中,我将其设置为http:// localhost:3000

现在,让我们进一步修改组件模板,以便在登录后显示不同的内容。

<div class="links">
  <b-button
    v-if="!$auth.loggedIn"
    variant="primary"
    size="lg"
    @click="login"
  >
    Login
  </b-button>
  <b-button
    v-else
    variant="warning"
    @click="logout"
    size="lg"
  >
    Logout
  </b-button>
</div>

请注意,我们开始切换为对按钮使用bootstrap-vue组件。b按钮组件可以接受一个变体和一个大小道具。

现在,请确保我们正确获取了页面的脚本部分:

import { mapGetters } from 'vuex'
export default {
  methods: {
    login() {
      this.$auth.loginWith('auth0')
    },
    logout() {
      this.$auth.logout();
    }
  },
  computed: mapGetters(['isAuthenticated']),
}

大!现在,通过这些简单的更改,我们有了一个带有身份验证的应用程序。因此,我们现在已经完成了#1和#2的一部分。

这是GitHub中的结果。

#2的其余部分是构建调查表。让我们真正快速地将其作为一个组件。

Bootstrap-vue使一切变得非常容易。它包含引导程序类作为组件

<template>
  <b-container fluid>
    <b-form-row>
      <b-col sm="3">
        <label for="serial-serialNumber">Hydrant Serial serialNumber</label>
      </b-col>
      <b-col sm="9">
        <b-form-input
          type="text"
          v-model="serialNumber"
          id="serial-serialNumber"
          placeholder="Enter the hydrant serial serialNumber"
        ></b-form-input>
      </b-col>
    </b-form-row>
    <b-form-row>
      <b-col sm="3">
        <label for="condition">Hydrant Condition</label>
      </b-col>
      <b-col sm="9">
        <b-form-select v-model="condition" :options="options" id="condition"></b-form-select>
      </b-col>
    </b-form-row>
    <b-form-row align-h="end">
        <b-col cols="*">
            <b-button @click="submit">Submit</b-button>
        </b-col>
    </b-form-row>
  </b-container>
</template>

Bootstrap-vue采取了将网格系统变成组件的方法。我有时会对这个决定表示怀疑,但是它很容易使用。在此模板中,容器(b容器)具有行(b行或b形式行)的集合。每行最多可以有12列。其他列将换行到下一行。b-col组件可以表示1到12之间的任意数量的列。然后,您可以确定每个视口大小应占用多少列。

例如,您可能希望引导b-col在移动设备上占用12列(全宽),因此您可以将cols =“ 12”指定为b-col组件的属性。但随后您可能决定在平板电脑上它应占用6列(半角宽度),因此您可以指定sm =“ 6”,这也是一个属性。这使您可以在html中声明如何在宽度上在每个视口上显示元素。很方便!

除了为我们提供Bootstrap-Vue抽象的相当不错的网格系统之外,我们还可以使用许多实用程序组件。在这种形式下,我只需要一个输入,一个选择和一个按钮-因此我使用了这些的引导版本。Bootstrap具有开箱即用的支持,可以很好地访问表单,并且组件上的选项可以使您想起事情-例如设置占位符。

这是一种非常简单的形式-我们只需要几件事。我们将通过发出结果将完成的结果发送回父级。这是组件的脚本部分:

export default {
  data() {
    return {
      serialNumber: "",
      condition: null,
      options: [
        { value: null, text: "Please choose a hydrant condition." },
        { value: "poor", text: "Poor" },
        { value: "fair", text: "Fair" },
        { value: "good", text: "Good" },
        { value: "excellent", text: "Excellent" },
      ],
    };
  },
  methods: {
    submit() {
      this.$emit("submit-form", { serialNumber, condition });
    },
  },
};

现在,父组件可以根据需要处理结果。让我们来看看父母。你知道吗?让我们继续进行重构,以便也使用bootstrap-vue。

<template>
  <b-container class="pt-5">
    <b-row align-h="center" class="mt-5">
      <b-col cols="*">
        <h1 class="title">Fire Hydrant Surveyor</h1>
      </b-col>
    </b-row>
    <b-row align-h="center" v-if="$auth.loggedIn">
      <b-col sm="9" class="my-4">
        <survey-form @submitForm="handleFormResult"></survey-form>
      </b-col>
    </b-row>
    <b-row align-h="center" class="mt-3">
      <b-col cols="*">
        <b-button v-if="!$auth.loggedIn" variant="primary" size="lg" @click="login">Login</b-button>
        <b-button v-else variant="warning" @click="logout" size="lg">Logout</b-button>
      </b-col>
    </b-row>
  </b-container>
</template>

在父级中,我们还需要导入组件并定义处理程序:

import surveyForm from '../components/survey-form'

export default {
  components: [
    surveyForm
  ],
...
  methods: {
    ...
    async handleFormResult(formObj) {
      //do stuff
    }
  }

这是我们冒险之旅的GitHub

现在,我们需要弄清楚如何处理此表单数据。我们将数据发送到我们的服务器,但是我们要怎么做呢?同样,我们需要创建服务工作者来处理离线行为。

我发现有人创建了一个不错的测试API,因此我可以发送表单数据而不必部署整个其他项目,我只需要对数据进行一些处理即可。

async handleFormResult(formObj) {
      //https://jsonplaceholder.typicode.com/posts is a test API I'm borrowing 
      //I'm making the data fit because I'm too lazy to make my own test API
      const post = {
        title: formObj.serialNumber,
        body: formObj.condition,
        userId: 1
      }
      try {
        const result = await this.$axios.$post('https://jsonplaceholder.typicode.com/posts', post);
        console.log(result);
      } catch(e) {
        console.log(e);
      }
    }

好的,现在发送请求时,我会将结果发布到控制台。只要我在线,一切都看起来不错。

但是当我离线时呢?

事实证明,我们需要的只是nuxt / pwa模块,Workbox将在其中为我们处理一切。

为了启用我们想要的行为-重新发送应用离线时发生的失败请求-我们需要为工作箱创建一个特殊的插件。

在plugins文件夹中,我创建了一个名为的文件,workbox-sync.js并添加了以下代码:

const bgSyncPlugin = new workbox.backgroundSync.BackgroundSyncPlugin('formQueue', {
    maxRetentionTime: 24 * 60 // Retry for max of 24 Hours (specified in minutes)
});

workbox.routing.registerRoute(
    /https:\/\/jsonplaceholder\.typicode\.com\/posts/,
    new workbox.strategies.NetworkOnly({
      plugins: [bgSyncPlugin]
    }),
    'POST'
  );

我们正在创建一个新的后台同步插件,然后在路由上注册该插件。工作箱寄存器路由方法采用3个参数,路由的正则表达式(因此,您可以使用正则表达式为一系列相似的路由定义相同的行为),策略和http谓词。

接下来,您需要通过以下配置行将此插件添加到工作箱nuxt.config.js

  pwa: {
    ...
    workbox: {
      cachingExtensions: '@/plugins/workbox-sync.js',
      enabled: true //should be off actually per workbox docs due to complications when used in prod
    }
  }

请注意,您不能在workbox-sync.js文件中导入。原因是该插件被注入到工作箱模块为我们创建的sw.js脚本的中间。导入不能在脚本中间执行。

另外,您会注意到我有,enabled: true但是根据@ nuxtjs / pwa工作箱文档,您通常不应该这样做,因为在开发环境和生产环境之间切换时,这可能会引起问题。我在这里这样做是因为它非常方便。否则,在dev中运行时不会启用服务工作者。

现在,当我运行工作npm run dev箱时,将创建服务工作者。如果我通过浏览器devtools将应用程序切换为脱机状态,则发布到服务器的操作将失败,但是一旦我切换回联机状态,服务工作人员就会重新发送请求。

让我们来看看这一点。

在这里,我们正在发送成功的请求。

Chrome开发工具显示成功发送到我们的api

但是,让我们将状态从开发工具更改为脱机状态,然后观察请求失败。

Chrome开发工具显示无法发送到我们的api

现在,服务人员负责重新发送请求。它将使用与最初发送的信息相同的信息,因此请注意,如果您使用的是任何种类的过期认证数据。但是,如果我们有把握地确保身份验证令牌在用户重新联机之前将一直有效,那么该解决方案将非常有用。

如果您不能依靠它,那么您可能需要使用另一种解决方案,根据失败的请求,使用localforage将数据保留在indexdb中。然后,您将需要创建一个自定义服务工作程序,该工作程序将需要确定您是否重新联机并使用最新的可用身份验证凭据重新发送数据。

Chrome开发人员工具显示成功重试后发送到我们的API

对于我们的代码的最终结果,让我们在这里看看

我们只需很少的自定义代码即可满足所有要求。

现在进行部署,需要将Auth0配置为接受我的生产域名。

另外,我们需要继续进行重构,以重构auth.config.js并将其替换为.env。

我继续这样做,首先安装了跨环境

npm install cross-env

然后,我创建了.env文件并将其填充为:

DOMAIN='...auth0.com'
CLIENTID='aHashFromAuth0'
REDIRECTURI='/signed-in'

然后,我从nuxt.config中删除了auth.config的导入,并将选项替换为以下内容:

auth: {
    redirect: {
      login: '/',
      callback: process.env.REDIRECTURI
    },
    strategies: {
      local: false,
      auth0: {
        domain: process.env.DOMAIN,
        client_id: process.env.CLIENTID,
      }
    }
  },

现在,我可以通过CI / CD管道注入变量。

这是最终结果。

Nuxt有各种各样的库和插件,可以帮助您实现想要的工作。迅速取得成功很重要,这样您就可以磨合业务需求。

我希望这对进行离线优先应用程序的任何人都有用!

免责声明:
1. 本站资源转自互联网,源码资源分享仅供交流学习,下载后切勿用于商业用途,否则开发者追究责任与本站无关!
2. 本站使用「署名 4.0 国际」创作协议,可自由转载、引用,但需署名原版权作者且注明文章出处
3. 未登录无法下载,登录使用金币下载所有资源。
IT小站 » Nuxt,离线优先PWA教程

常见问题FAQ

没有金币/金币不足 怎么办?
本站已开通每日签到送金币,每日签到赠送五枚金币,金币可累积。
所有资源普通会员都能下载吗?
本站所有资源普通会员都可以下载,需要消耗金币下载的白金会员资源,通过每日签到,即可获取免费金币,金币可累积使用。

发表评论