【Webpack 插件之自动注册 Vue 指令】

129 阅读4分钟

背景

创建一个 Webpack 插件来自动注册 Vue 指令,并使用第三方实例自动进行埋点跟踪。这个插件会自动注册一个 Vue 指令,获取指令绑定的字符串,并使用从第三方获取的埋点实例的方法和字符串进行调用。

实现步骤

1.创建 Webpack 插件:在插件中注册 Vue 指令。 2.从第三方获取埋点实例:假设我们已经有一个方法可以获得埋点实例。 3.在 Vue 指令中调用埋点方法:根据指令绑定的字符串调用埋点方法。

示例代码

    Class AutoTrackingPlugin {
        constructor(options) {
            this.options = options || {};
        }

        apply(compiler){
            // Webpack 的 compile 阶段进行处理
            compiler.hooks.emit.tapsAsync('AutoTrackingPlugin', (compilation,callback)=>{
                // 构建一个指令注册的 Vue 代码
                const directiveCode = `
                    import Vue from Vue;
                    import trackingInstance from '${this.options.trackingInstance}';

                    // 自定义指令
                    Vue.directive('auto-track', {
                        bind(el, binding) {
                            const eventName = binding.value; // 获取指令绑定的字符串

                            // 保存事件处理函数的引用
                            const trackEvent = ()=>{
                                // 实例,调用埋点实例的方法,一般看各自业务代码的各自实现
                                if(trackingInstance && typeof trackingInstance.track==='function') {
                                    trackingInstance.track(eventName);
                                }else {
                                    console.warn('Tracking instance is not avaliable or track method is not a function.')
                                }
                            }

                            // 注册事件监听
                            el.addEventListener('click', trackEvent)
                            
                            // 将事件处理函数保存在元素上,以便在unbind中使用
                            el._trackEvent = trackEvent;
                        },
                        unbind(el){
                            // 移除事件监听
                            el.removeEventListener('click', el._trackEvent)

                            // 清除引用
                            delete el._trackEvent; 
                        }
                    })
                `;

                // 将指令代码添加到一个新的文件中
                compilation.assets['auto-tracking-directive.js']= {
                    source:()=>directiveCode,
                    size:()=>directiveCode.length
                };

                callback();
            })
        }
    }

    module.exports = AutoTrackingPlugin;
使用实例

使用插件

    // webpack.config.js
    // path 是引入插件的路径,可能是本体,可能是线上包
    const AutoTrackingPlugin = require('path')

    module.exports = {
        // ...其他配置项
        plugins: [
            new AutoTrackingPlugin({
                trackingInstance:'path/to/your/tracking/instance', // 埋点实例路径
            })
        ]
    }

使用vue指令

    <template>
        <button v-auto-track="'button_click_id'">Click me</button>
    </template>
    <script>
        export default {
            // ...
        }
    </script>
插件代码解析

1.构造函数:接受一个 options 参数,其中可以传递第三方埋点实例的路径。

    constructor(options) {
        this.options = options || {};
    }

2.apply方法:在 emit 钩子中添加代码,将 Vue 指令注册到生成的 JavaScript 文件中。

    apply(compiler) {
        compiler.hooks.emit.tapAsync('AutoTrackingPlugin', (complilation,callback)=>{
            // ...
            callback();
        })
    }

3.注册 Vue 指令:

  • 创建一个名为 auto-track 的自定义指令。
  • 在 bind 方法中,获取指令绑定的字符串 binding.value ,并将其作为事件名称。
  • 为元素添加一个 click 事件监听器,在事件触发时调用埋点实例的方法。
    Vue.directive('auto-track',{
        bind(el,binding) {
            const eventName = binding.value; // 获取字符串作为参数
            // ...
        },
        unbind(el){
            // ...
        }
    })

4.添加到输出文件:将生成的 Vue 指令代码添加到 auto-tracking-directive.js 文件中,供 Vue 组件使用。

拓展

可以使用 schema-utils 来校验插件输入项

schema-utils 是一个 JSON Schema 校验库,内部使用了 ajv(Another JSON Schema Validator) 库,这个库被大多数校验工具所使用,是一个快速、灵活的 JSON Schema 验证器,支持最新的 JSON Schema 规范和许多额外的功能,像 element-ui 的表单校验就能看出来和下面要写的很类似。

使用 ajv 的好处。性能:性能高效,能快速处理验证;灵活性:支持复杂的 schema 功能,如 allOf、anyOf、oneOf等;扩展性:可以通过插件扩展 ajv。

1.安装 schema-utils : 确保安装了 schema-utils,一般可以考虑使用 npm 或者 yarn 安装到开发环境

    npm install schema-utils --save-dev

或者

    yarn add schema-utils --dev

2.定义 schema: 可以定义一个 JSON Schema 来描述插件的配置选项。

3.在插件中校验选项: 在插件的构造函数中使用 schema-utils 来验证选项。

部分示例代码
    // AutoTrackingPlugin.js
    const {validate} = require ('schema-utils');

    const schema = {
        type:'object',
        properties: {
            trackingInstance: {
                type: 'string',
                minLength:1,
            },
        },
        required: ['trackingInstance']
    }

    class AutoTrackingPlugin {
        constructor(options) {
            // 验证传入的选项
            validate(schema,options,{
                name:'AutoTrackingPlugin',
                baseDataPath:'options', 
            });

            this.options = options || {};
        }
    }
代码解释

validate 中的参数说明

  • name:用于指定验证的上下文名称。主要作用:1、上下文描述:name 主要作用于在验证过程中为特定的插件或模块提供一个上下文名称,帮助识别是哪个插件的选项正在被验证。这在错误信息中会非常有用,尤其是在大型项目中,有多个插件同时使用时。 2、错误信息的清晰度:当选项不符合 schema 时,name 会出现在错误信息中,帮助开发者快速定位问题。例如,如果你在调用 validate 时传入 name: 'AutoTrackingPlugin',当验证失败时,错误信息可能会显示为:
    AutoTrackingPlugin: options.trackingInstance must be a string
  • baseDataPath: 用于在验证选项时提供基准路径信息。主要作用:1、描述上下文:在验证过程中,如果出现错误,baseDataPath 将帮助用户理解错误信息中的数据结构层次。例如,当插件选项不符合定义的 schema 时,baseDataPath 将指示错误发生的位置。 2、清晰的错误信息:如果你设置 baseDataPath 为 'options',当选项不符合 schema 时,错误信息会更清晰地指向具体的选项问题,例如 'options.trackingInstance',而不只是显示 'trackingInstance'

总结

通过自定义一个 Webpack 的自定义插件去自动给 Vue 项目添加指令,方便快捷给项目代码添加埋点代码,减少重复及繁琐性。

参考资料

Webpack 官方文档-自定义插件