用 vuetify-loader 提升 Vue 开发体验

好久没写文章,心血来潮发一篇

重点先放三遍

不用 Vuetify 也可以用 vuetify-loader 哦不用 Vuetify 也可以用 vuetify-loader 哦不用 Vuetify 也可以用 vuetify-loader 哦
const vuetify = 'vue' + 'buetify'

现在已经有许多基于 Vue 的 UI 框架、元件库都提供方便易用且客製化的方案,
从 Vuetify 的命名可以看到是为了美化 Vue 而存在,美化範围不只限于 UI,也包含程式码和开发体验。

今天主要和大家分享 vuetify-loader 如何提升 SFC 开发体验。

如果你也思考过以下问题,你可以考虑使用 vuetify-loader 来少写一些程式码。

你写了很多共用的元件,且在专案中被频繁地使用该如何确保被弃用的元件,在建置时不会被打包如何用命名规範来管理元件

重複且频繁的在专案各处引入相同的元件

举例来说,专案中有一个 BaseButton 这个基本的按钮元件,当我在不同的元件中使用时会是这样:

PageA.vue
<template>    <base-button>Click me!</base-button></template>
import BaseButton from '@/components/BaseButton'export default {    components: {        BaseButton    }}

这个作法很普通,但是当有十个页面时就需要引入 10 次 BaseButton,并且加入到 components 物件中

随着这样的 UI 元件慢慢变多,一个页面就需要引入一堆基础元件,牺牲的就是前端工程师的开发体验,下面举个例:

PageB.vue
<template>    <base-button>Click me!</base-button>    <base-tooltip></base-tooltip>    <base-input></base-input>    <base-alert></base-alert>    <base-container>        <base-layout>            <base-flex>                ...            </base-flex>        </base-layout>    </base-container></template>
import BaseButton from '@/components/BaseButton'import BaseTooltip from '@/components/BaseTooltip'import BaseInput from '@/components/BaseInput'import BaseAlert from '@/components/BaseAlert'import BaseContainer from '@/components/BaseContainer'import BaseLayout from '@/components/BaseLayout'import BaseFlex from '@/components/BaseFlex'export default {    components: {        BaseButton,        BaseTooltip,        BaseInput,        BaseAlert,        BaseContainer,        BaseLayout,        BaseFlex    }}

同样的道理,有十个以上的页面,每个页面都要引入这么多基础元件时,牺牲的就是前端工程师的开发体验。

这也衍生一个问题,当我要移除 BaseButton 这个元件时,不只要移除在 template 中的

<base-button>Click me!</base-button>

同时也要移除 script 中的

import BaseButton from '@/components/BaseButton'components: { BaseButton }

如果我忘了移除 js 中的引用,

此时专案若有使用 Eslint,他可能会好心的提醒你:

The "BaseButton" component has been registered but not used.eslint(vue/no-unused-components)

万一不幸的事情发生了,我没有使用 Eslint,又忘了移除 script 中的引用,就「可能」会在无形中增加了专案的 bundle size。

看到这里有些人可能想到不错的解决办法

将共用元件注册为全域元件,避免不断重複引入元件

时常看到的解决範例:

main.js
import Vue from 'vue'import BaseButton from '@/components/BaseButton'import BaseTooltip from '@/components/BaseTooltip'import BaseInput from '@/components/BaseInput'import BaseAlert from '@/components/BaseAlert'import BaseContainer from '@/components/BaseContainer'import BaseLayout from '@/components/BaseLayout'import BaseFlex from '@/components/BaseFlex'Vue.component('BaseButton', BaseButton)Vue.component('BaseTooltip', BaseTooltip)Vue.component('BaseInput', BaseInput)Vue.component('BaseAlert', BaseAlert)Vue.component('BaseContainer', BaseContainer)Vue.component('BaseLayout', BaseLayout)Vue.component('BaseFlex', BaseFlex)

这方法相比在各处不断地引用基础元件有更好的开发体验,也让开发专案时可以更多的专注在商业逻辑上

但是这并没有办法主动避免弃用的元件在建置时不小心被打包的问题

如果 BaseButton 是一个被弃用的元件,我需要在专案中透过全域搜寻 BaseButtonbase-button,确认没有任何地方用到这个元件后,回到 main.js 移除以下两行代码:

import BaseButton from '@/components/BaseButton'Vue.component('BaseButton', BaseButton)

同样的问题是如果我忘了移除,那 BaseButton 元件就「肯定」会增加专案的 bundle size,并且不会有 Eslint 的提示。

那有没有方法或工具能同时兼顾开发体验、专注开发商业逻辑,又能避免弃用元件建置时被打包呢?

本文的重点 vuetify-loader

vuetify-loader 是一个 webpack 的套件,用于自动引用 Vuetify 的元件

可以参考 vuetify-loader 文件的 Automatic Imports。

很少有 UI 框架自带 tree shaking 功能的,这也是我喜欢 Vuetify 的原因之一

你可以在设置 webpack plugins new VuetifyLoaderPlugin 时,带入 match 函式,
所有的元件中的每一个 tag 会执行一次 match 函式,参数有:

originalTag: tag 如何被使用的,例如 <base-button>Click me!</base-button> 就会是 base-buttonkebabTag : 将 originalTag 转为 kebab-casecamelTag : 将 originalTag 转为 PascalCasepath : SFC 的相对路径component : 该 tag 所在的那个元件被解析后的物件,主要包含 SFC 的三个区块 (template, script, style)

可以根据这些参数组合出适合专案的自动引入元件功能

match 需要回传一个长度为 2 的阵列:

第一个元素会被插入在该元件的 components 属性中

第二个元素为自动引用该元件的路径

以下用 Vue CLI 3 建立的专案做为範例:

vue.config.js

const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin')module.exports = {  configureWebpack: {    plugins: [      new VuetifyLoaderPlugin({        match (originalTag, { kebabTag, camelTag, path, component }) {          if (kebabTag.startsWith('base-')) {            return [camelTag, `import ${camelTag} from '@/components/${camelTag}.vue'`]          }        }      })    ]  }}

这边解释一下上面这段程式码的效果
我用 BaseButton 做举例:
如果在 PageA.vue 中使用

<template>    <BaseButton>Click me!</BaseButton>    或    <base-button>Click me!</base-button></template>

在 script 中不必再写:

import BaseButton from '@/components/BaseButton'export default {    components: {        BaseButton    }}

在每一个元件中,若有 tag 的使用为 BaseButtonbase-button 皆符合 kebabTag.startsWith('base-') 的这个条件。
此时回传长度为 2 的阵列

return ['BaseButton', `import BaseButton from '@/components/BaseButton.vue'`]

vuetify-loader 接着自动在 PageA.vue 元件中,引用 BaseButton

当有天 BaseButton 被弃用时,我只需要直接移除 PageA 中的

<BaseButton>Click me!</BaseButton>

<base-button>Click me!</base-button>

我甚至不需要意识到 BaseButton 已经被弃用,也不会造成多余的引入

因为删掉 template 中的 tag,同时 vuetify-loader 也移除了对 BaseButton 元件的引入

注意:这个範例的 import 条件判断只有以 PascalCase 方式命名,且放在 @/components/ 底下的元件才会被正确引入,当然你也可以写适合自己专案的客製化条件

总结:

vuetify-loadermatch 函式提供自动引入元件的功能,伴随两项优点:

避免频繁引入相同的基础元件,使专案开发能专注在商业逻辑,并提升开发体验避免弃用元件在建置时被打包

最后,很重要说三次

不用 Vuetify 也可以用 vuetify-loader 哦不用 Vuetify 也可以用 vuetify-loader 哦不用 Vuetify 也可以用 vuetify-loader 哦

你心动了吗? 快去使用看看 vuetify-loader

欢迎留言提问、补充或一起讨论,
如果我的分享对你有帮助,可以顺手按个讚,我会更有动力。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章