编写 Nuxt 模块代码片段
在本主题中,我们将把已创建的自定义模块拆解为小型代码片段。
您可以在我们的 |
使用顶层选项
还记得我们在 "编写基础模块" 章节提到的可传入模块的配置选项吗?模块选项是在 Nuxt
配置文件中注册模块时的顶级选项。我们甚至可以组合不同模块的多个选项,并实现选项共享。让我们通过以下步骤尝试结合使用 @nuxtjs/axios
和 @nuxtjs/proxy
模块的示例:
-
使用
npm
同时安装这两个模块:$ npm i @nuxtjs/axios $ npm i @nuxtjs/proxy
bash这两个模块深度整合可避免
CORS
问题(我们将在后续开发跨域应用时详细讨论)。虽然无需手动注册@nuxtjs/proxy
模块,但必须确保其存在于package.json
的依赖项中。 -
在
Nuxt
配置文件中注册@nuxtjs/axios
模块并设置两个模块的顶级选项:// nuxt.config.js export default { modules: [ '@nuxtjs/axios' ], axios: { proxy: true }, proxy: { '/api/': { target: 'https://jsonplaceholder.typicode.com/', pathRewrite: {'^/api/': ''} }, } }
javascriptaxios
自定义选项中的proxy: true
会启用@nuxtjs/proxy
模块。proxy
选项中的/api/: {...}
配置指示@nuxtjs/axios
模块将 https://jsonplaceholder.typicode.com/ 作为API
服务器目标地址,而pathRewrite
选项会在HTTP
请求时移除地址中的/api/
前缀(因为目标API
不存在该路由)。 -
在任意组件中无缝使用:
// pages/index.vue <template> <ul> <li v-for="user in users"> {{ user.name }} </li> </ul> </template> <script> export default { async asyncData({ $axios }) { const users = await $axios.$get('/api/users') return { users } } } </script>
vue
通过这种组合使用方式,我们只需书写简化的 API
地址(如 /api/users
替代完整的 https://jsonplaceholder.typicode.com/users )。这使得代码更加整洁,无需每次调用都书写完整 URL
。注意配置的 /api/
前缀会在所有 API
请求中自动添加,因此需要通过 pathRewrite
在发送请求时移除(如前文所述)。
更多关于这两个模块的顶级选项信息可参考:
本示例代码片段存放于 |
使用 addPlugin 辅助函数
还记得在 "编写基础模块" 章节中提到的 ModuleContainer
实例和可通过 this
关键字访问的 this.addPlugin
辅助方法吗?在以下示例中,我们将创建一个通过该辅助方法提供 bootstrap-vue
插件的模块,该插件将被注册到 Vue
实例。让我们通过以下步骤创建这个模块片段:
-
安装
Bootstrap
和BootstrapVue
:$ npm i bootstrap-vue $ npm i bootstrap
bash -
创建插件文件来导入
vue
和bootstrap-vue
,并使用use
方法注册bootstrap-vue
:// modules/bootstrap/plugin.js import Vue from 'vue' import BootstrapVue from 'bootstrap-vue/dist/bootstrap-vue.esm' Vue.use(BootstrapVue)
javascript -
创建模块文件,使用
addPlugin
方法添加刚创建的插件文件:// modules/bootstrap/module.js import path from 'path' export default function (moduleOptions) { this.addPlugin(path.resolve(__dirname, 'plugin.js')) }
javascript -
在
Nuxt
配置文件中添加该bootstrap
模块的路径:// nuxt.config.js export default { modules: [ ['~/modules/bootstrap/module'] ] }
javascript -
在任意组件中使用
bootstrap-vue
,例如创建一个切换警告文本的Bootstrap
按钮:// pages/index.vue <b-button @click="toggle"> {{ show ? '隐藏' : '显示' }} 警告 </b-button> <b-alert v-model="show"> 你好 {{ name }}! </b-alert> import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' export default { data () { return { name: 'BootstrapVue', show: true } } }
vue
通过这个模块片段,我们无需在每次需要使用 bootstrap-vue
时都进行导入,因为它已通过上述模块全局添加。我们只需要导入其 CSS
文件。在使用示例中,我们使用 Bootstrap
的自定义 <b-button>
组件来切换 Bootstrap
的自定义 <b-alert>
组件。<b-button>
组件将切换按钮上的 "隐藏" 或 "显示" 文本。
有关 |
使用 Lodash 模板
这再次呼应了我们在 "编写基础模块" 章节创建自定义模块时的做法——利用 Lodash
模板通过条件判断块来改变注册插件的输出行为。Lodash
模板正是通过 <%= %>
插值分隔符实现数据属性动态注入的代码块。让我们通过以下步骤尝试另一个简单示例:
-
创建插件文件导入
axios
,并添加条件判断块确保为axios
提供请求URL
,同时在开发模式 (npm run dev
) 下将请求结果打印到终端用于调试:// modules/users/plugin.js import axios from 'axios' let users = [] <% if (options.url) { %> users = axios.get('<%= options.url %>') <% } %> <% if (options.debug) { %> // 仅开发环境代码 users.then((response) => { console.log(response); }) .catch((error) => { console.log(error); }) <% } %> export default ({ app }, inject) => { inject('getUsers', async () => { return users }) }
javascript -
创建模块文件,使用
addPlugin
方法添加刚创建的插件文件,并通过options
参数传递请求URL
和this.options.dev
布尔值:// modules/users/module.js import path from 'path' export default function (moduleOptions) { this.addPlugin({ src: path.resolve(__dirname, 'plugin.js'), options: { url: 'https://jsonplaceholder.typicode.com/users', debug: this.options.dev } }) }
javascript -
在
Nuxt
配置文件中添加该模块路径:// nuxt.config.js export default { modules: [ ['~/modules/users/module'] ] }
javascript -
在任意组件中使用
$getUsers
方法,例如:// pages/index.vue <li v-for="user in users"> {{ user.name }} </li> export default { async asyncData({ app }) { const { data: users } = await app.$getUsers() return { users } } }
vue
在此示例中,Nuxt
在复制插件到项目时会用 https://jsonplaceholder.typicode.com/users 替换 options.url
。而 options.debug
的条件判断块在生产构建时会被移除,因此在生产模式(npm run build
和 npm run start
)下不会在终端看到 console.log
输出。
该示例模块片段存放于 |
添加 CSS 库
在《使用 addPlugin
辅助方法》章节的模块片段示例中,我们创建了一个全局集成 bootstrap-vue
插件的模块,使得组件中无需重复导入该插件,如下所示:
// pages/index.vue <b-button size="sm" @click="toggle"> {{ show ? '隐藏' : '显示' }} 警告 </b-button> import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' export default { //... }
vue
看起来相当简洁,因为我们不必每次都导入 bootstrap-vue
,而只需要导入 CSS
样式。然而,我们仍然可以通过模块将样式添加到应用程序的全局 CSS 堆栈中来节省几行代码。让我们创建一个新的示例,看看如何通过以下步骤来实现:
-
创建一个模块文件,其中包含一个名为
options
的常量变量,用于将模块和顶级选项传递给插件文件,以及一个if
条件块,用于确定是否使用普通的JavaScript push
方法将CSS
文件推送到Nuxt
配置文件的css
选项中:// modules/bootstrap/module.js import path from 'path' export default function (moduleOptions) { const options = Object.assign({}, this.options.bootstrap, moduleOptions) if (options.styles !== false) { this.options.css.push('bootstrap/dist/css/bootstrap.css') this.options.css.push('bootstrap-vue/dist/bootstrap-vue.css') } this.addPlugin({ src: path.resolve(__dirname, 'plugin.js'), options }) }
javascript -
创建插件文件注册
bootstrap-vue
,并添加Lodash
模板条件块打印模块处理的选项:// modules/bootstrap/plugin.js import Vue from 'vue' import BootstrapVue from 'bootstrap-vue/dist/bootstrap-vue.esm' Vue.use(BootstrapVue) <% if (options.debug) { %> <% console.log (options) %> <% } %>
javascript -
在
Nuxt
配置中添加模块路径,通过moduleOptions
控制CSS
注入,并通过顶级选项传递debug
模式状态:// nuxt.config.js export default { modules: [ ['~/modules/bootstrap/module', { styles: true }] ], bootstrap: { debug: process.env.NODE_ENV === 'development' ? true : false } }
javascript -
移除组件中的
CSS
导入语句:// pages/index.vue <script> - import 'bootstrap/dist/css/bootstrap.css' - import 'bootstrap-vue/dist/bootstrap-vue.css' export default { //... } </script>
vue
所以,最终,我们可以在我们的组件中使用 bootstrap-vue
插件及其 CSS
文件,而无需导入所有这些文件。这里是另一个通过模块代码片段将 Font Awesome CSS
选项推送到 Nuxt
配置文件中的快速示例:
// modules/bootstrap/module.js
export default function (moduleOptions) {
if (moduleOptions.fontAwesome !== false) {
this.options.css.push('font-awesome/css/font-awesome.css')
}
}
javascript
更多关于 完整示例代码存放于 |
注册自定义 webpack 加载器
当我们需要扩展 Nuxt
的 webpack
配置时,通常会在 nuxt.config.js
中使用 build.extend
实现。但通过模块中的 this.extendBuild
方法同样可以达成目标,以下是基础模板:
export default function (moduleOptions) {
this.extendBuild((config, { isClient, isServer }) => {
//...
})
}
javascript
例如,假设我们需要通过 svg-transform-loader
扩展 webpack
配置(该 loader
用于修改 SVG
图像的标签和属性),主要功能包括填充颜色(fill
)、描边(stroke
)等操作。该 loader
支持在 CSS/Sass/Less/Stylus/PostCSS
中使用,例如:
/* 填充白色 */
.img {
background-image: url('./img.svg?fill=fff');
}
/* Sass变量描边,如果你想在 Sass 中使用变量来描边 SVG 图像,你可以这样做: */
$stroke-color: fff;
.img {
background-image: url('./img.svg?stroke={$stroke-color}');
}
css
让我们创建一个示例模块,将此加载器注册到 Nuxt webpack
的默认配置中,以便我们可以通过以下步骤在我们的 Nuxt
应用程序中操作 SVG
图像:
-
安装
loader
:$ npm i svg-transform-loader
bash -
创建模块文件:
// modules/svg-transform-loader/module.js export default function (moduleOptions) { this.extendBuild((config, { isClient, isServer }) => { //... }) }
bash -
在
this.extendBuild
回调中移除默认svg
规则:const rule = config.module.rules.find( r => r.test.toString() === '/\\.(png|jpe?g|gif|svg|webp)$/i' ) rule.test = /\.(png|jpe?g|gif|webp)$/i
javascript -
在前面的代码块之后添加以下代码块,将
svg-transform-loader
加载器推送到默认webpack
配置的模块规则中:config.module.rules.push({ test: /\.svg(\?.*)?$/, // 匹配img.svg和img.svg?param=value use: [ 'url-loader', 'svg-transform-loader' ] })
javascript -
在
Nuxt
配置中注册模块:// nuxt.config.js export default { modules: [ ['~/modules/svg-transform-loader/module'] ] }
javascript -
在组件中使用 SVG 转换功能:
<!-- pages/index.vue --> <template> <div> <div class="background"></div> <img src="~/assets/bug.svg?stroke=red&strokewidth=4&fill=blue"> </div> </template> <style lang="less"> .background { height: 100px; width: 100px; border: 4px solid red; background-image: url('~assets/bug.svg?stroke=red&strokewidth=2'); } </style>
vue
你可以在 https://www.npmjs.com/package/svg-transform-loader 找到更多关于 svg-transform-loader 的信息。如果你想了解更多关于规则测试的信息,并查看 Nuxt 默认 webpack 配置的完整内容,请访问以下链接:
你可以在我们的 GitHub 仓库的 /chapter-6/nuxt-universal/module-snippets/webpack-loader/ 找到我们刚刚创建的示例模块代码片段。 |
注册自定义 webpack 插件
Nuxt
模块不仅能注册 webpack
加载器,还能通过 this.options.build.plugins.push
注册 webpack
插件,其基础架构如下:
export default function (moduleOptions) {
this.options.build.plugins.push({
apply(compiler) {
compiler.hooks.<hookType>.<tap>('<PluginName>', (param) => {
//...
})
}
})
}
javascript
其中 <tap>
依赖钩子类型,钩子类型可以是 tapAsync
、tapPromise
或 tap
。下面通过 Nuxt
模块创建一个简单的 "Hello World" webpack
插件:
-
使用我们提供的模块/插件架构创建一个模块文件,用于打印 "Hello World!",如下所示:
// modules/hello-world/module.js export default function (moduleOptions) { this.options.build.plugins.push({ apply(compiler) { compiler.hooks.done.tap('HelloWordPlugin', (stats) => { console.log('Hello World!') }) } }) }
javascript注:当
done
钩子触发时,会传入stats
(统计信息)作为参数。 -
在
Nuxt
配置中添加模块路径:// nuxt.config.js export default { modules: [ ['~/modules/hello-world/module'] ] }
javascript -
运行
npm run dev
后,终端将显示 "Hello World!"。
请注意,apply
方法、编译器(compiler
)、钩子(hooks
)和 taps
都是构建 webpack
插件的关键部分。
如果您是 webpack 插件的新手,并想了解更多关于如何开发 webpack 插件的信息,请访问 https://webpack.js.org/contribute/writing-a-plugin/。 您可以在我们的 |
在特定钩子上创建任务
如果你需要在 Nuxt
启动时,在特定的生命周期事件(例如,当所有模块加载完毕后)执行某些任务,你可以创建一个模块并使用 hook
方法来监听该事件,然后执行相应的任务。请看以下示例:
-
如果你想在所有模块加载完成后执行某些操作,请尝试以下方法:
export default function (moduleOptions) { this.nuxt.hook('modules:done', moduleContainer => { //... }) }
javascript -
如果你想在渲染器创建完成后执行某些操作,请尝试以下方法:
export default function (moduleOptions) { this.nuxt.hook('render:before', renderer => { //... }) }
javascript -
在编译器(默认使用
webpack
)启动前执行操作:export default function (moduleOptions) { this.nuxt.hook('build:compile', async ({ name, compiler }) => { //... }) }
javascript -
在
Nuxt
生成页面之前执行操作:export default function (moduleOptions) { this.nuxt.hook('generate:before', async generator => { //... }) }
javascript -
当
Nuxt
准备就绪时执行操作:export default function (moduleOptions) { this.nuxt.hook('ready', async nuxt => { //... }) }
javascript
以下步骤演示如何创建一个监听 modules:done
钩子的简单模块:
-
创建模块文件,在所有模块加载完成后打印 'All modules are loaded':
// modules/tasks/module.js export default function (moduleOptions) { this.nuxt.hook('modules:done', moduleContainer => { console.log('All modules are loaded') }) }
javascript -
创建其他模块,分别打印 'Module 1'、'Module 2' 等:
// modules/module1.js export default function (moduleOptions) { console.log('Module 1') }
javascript -
在
Nuxt
配置文件中添加钩子模块及其他模块路径:// nuxt.config.js export default { modules: [ ['~/modules/tasks/module'], ['~/modules/module3'], ['~/modules/module1'], ['~/modules/module2'] ] }
javascript -
运行
Nuxt
应用($npm run dev
),终端将输出:Module 3 Module 1 Module 2 All modules are loaded
bash
可见钩子模块始终最后执行,其余模块按模块配置顺序执行。
钩子模块支持异步操作(可使用 async/await
或返回 Promise
)。
更多关于
示例模块代码存放于 |