编写 Nuxt 模块

模块本质上是一个在 Nuxt 启动时执行的顶级 JavaScript 函数。 Nuxt 会按顺序调用每个模块,并等待所有模块执行完毕后再继续调用 Vue 实例、Vue 插件以及需要注入到 $rootNuxt 上下文中的全局函数。由于模块的调用时机早于它们(如 Vue 实例等),我们可以利用模块来覆盖模板、配置 webpack 加载器、添加 CSS 库或执行应用所需的其他任务。此外,模块还能打包为 npm 包并与 Nuxt 社区共享。可通过以下链接查看 Nuxt 社区提供的生产级模块: https://github.com/nuxt-community/awesome-nuxt#official

现在让我们尝试使用 Axios 模块——这是一个为 Nuxt 集成 Axioshttps://github.com/axios/axios )的模块。它自带诸如自动设置客户端和服务端基础 URL 等功能,后续章节将探索其部分特性。若需深入了解该模块,请访问 https://axios.nuxtjs.org/ 。以下是具体使用步骤:

  1. 通过 npm 安装:

    $ npm install @nuxtjs/axios
  2. Nuxt 配置文件中配置:

    // nuxt.config.js
    module.exports = {
      modules: [
        '@nuxtjs/axios'
      ]
    }
  3. 在任意位置使用,例如页面的 asyncData 方法中:

    // pages/index.vue
    async asyncData({ $axios }) {
      const ip = await $axios.$get('http://icanhazip.com')
      console.log(ip)
    }

    也可在 mounted 方法(或 createdupdated 等)中使用:

    // pages/index.vue
    async mounted() {
      const ip = await this.$axios.$get('http://icanhazip.com')
      console.log(ip)
    }

每当访问 /about 页面时,浏览器控制台会显示你的 IP 地址。现在你可以像使用原生 Axios 那样发起 HTTP 请求,而无需每次手动导入,因为该模块已将其全局注入。这非常便利,不是吗?接下来我们将从基础模块开始,指导你编写自己的模块。

编写基础模块

正如前文所述,模块本质上是函数,并可选择性地打包为 npm 模块。以下是创建模块所需的最基础结构:

// modules/basic.js
export default function (moduleOptions) {
  // ....
}

只需在项目根目录创建 /modules/ 文件夹即可开始编写模块代码。若需将模块发布为 npm 包,必须包含以下代码:

module.exports.meta = require('./package.json')

如需创建并发布模块为 npm 包,可参考 Nuxt 社区提供的模板: https://github.com/nuxt-community/module-template/tree/master/template

无论为 Nuxt 社区还是自有项目开发模块,每个模块均可访问以下内容:

  • 模块选项

    可通过配置文件以 JavaScript 对象形式传递选项:

    // nuxt.config.js
    export default {
      modules: [
        ['~/modules/basic/module', { language: 'ES' }],
      ]
    }

    在模块函数的首个参数 moduleOptions 中访问这些选项:

    // modules/basic/module.js
    export default function (moduleOptions) {
      console.log(moduleOptions)
    }

    控制台将输出:

    { language: 'ES' }
  • 配置选项

    还可创建自定义选项(如 tokenproxybasic)并传递特定配置(这些选项可用于模块间共享):

    // nuxt.config.js
    export default {
      modules: [
        ['~/modules/basic/module'],
      ],
      basic: { // 自定义选项
        option1: false,
        option2: true,
      }
    }

    通过 this.options 访问自定义选项:

    // modules/basic/module.js
    export default function (moduleOptions) {
      console.log(this.options['basic'])
    }

    控制台将输出:

    { option1: false, option2: true }

    亦可合并 moduleOptionsthis.options

    // modules/basic/module.js
    export default function (moduleOptions) {
      const options = {
        ...this.options['basic'],
        ...moduleOptions
      }
      console.log(options)
    }

    输出结果为:

    { option1: false, option2: true }
  • Nuxt 实例

    通过 this.nuxt 访问 Nuxt 实例,可用方法参见: https://nuxtjs.org/api/internals-nuxt (例如 hook 方法,用于在 Nuxt 启动时绑定特定事件的任务)

  • ModuleContainer 实例

    通过 this 访问 ModuleContainer 实例,可用方法参见: https://nuxtjs.org/api/internals-module-container (例如常用方法 addPlugin,用于在模块中注册插件)

  • module.exports.meta 代码行

如之前所述,若要将模块发布为 npm 包则必须包含这行代码。但在本书中,我们将指导你完成为项目创建模块的步骤。现在让我们通过以下步骤创建一个非常基础的模块:

  1. 创建包含以下代码的模块文件:

    // modules/basic/module.js
    const { resolve } = require('path')
    
    export default function (moduleOptions) {
      const options = {
        ...this.options['basic'],
        ...moduleOptions
      }
    
      // 添加插件
      this.addPlugin({
        src: resolve(__dirname, 'plugin.js'),
        fileName: 'basic.js',
        options
      })
    }
  2. 创建包含以下代码的 plugin 文件:

    // modules/basic/plugin.js
    var options = []
    
    <% if (options.option1 === true) { %>
      options.push('option 1')
    <% } %>
    
    <% if (options.option2 === true) { %>
      options.push('option 2')
    <% } %>
    
    <% if (options.language === 'ES') { %>
      options.push('language ES')
    <% } %>
    
    const basic = function () {
      return options
    }
    
    export default ({ app }, inject) => {
      inject('basic', basic)
    }

    请注意,<%= %> 符号是 Lodashtemplate 函数中用于插值数据属性的分隔符。我们将在本章后续再次讨论这些符号。如需了解更多关于 Lodash 模板函数的信息,请访问 https://lodash.com/docs/4.17.15#template。

  3. Nuxt 配置文件中仅包含模块文件路径(/modules/basic/module.js),并按如下方式提供 basic 自定义选项的配置:

    // nuxt.config.js
    export default {
      modules: [
        ['~/modules/basic/module', { language: 'ES' }],
      ],
      basic: {
        option1: false,
        option2: true,
      }
    }
  4. 可以在任意位置使用该模块,例如:

    // pages/index.vue
    mounted () {
        const basic = this.$basic()
        console.log(basic)
    }
  5. 每次访问首页时,浏览器控制台将显示以下输出:

    ["option 2", "language ES"]

注意 module.js 如何处理语言和选项等高级配置细节。它还负责注册实际执行工作的 plugin.js 文件。可以看出,模块本质上是插件的封装器。我们将在后续章节深入探讨这一点。

请注意,如果编写的模块仅用于构建时和开发环境,应在 Nuxt 配置文件中使用 buildModules 选项来注册模块,而不是使用 Node.js 运行时的 modules 选项。有关此选项的更多信息,请访问: https://nuxtjs.org/guide/modules#build-only-moduleshttps://nuxtjs.org/api/configuration-modules