编写并发布vue-analytics-track插件

542 阅读3分钟

前言

本文主要是记录并回顾我是在埋点事件上报的过程中对插件封装的具体过程,用于记录、回顾、终结

过程中主要做了三件事:

  1. 编写针对埋点的vue插件
  2. 进行性能上报
  3. 进行异常上报

本章只记录如何编写、发布插件

涉及技术点:

  1. Vue 插件的本质
  2. Vue.directive() 全局方法
  3. 如何手动挂载 Vue 实例
  4. Vue.use() 的原理
  5. 如何打包成 umd 格式
  6. 发布 npm 包

准备知识

什么是Vue插件,它和Vue组件有什么区别?来看一下官网的解释:

“插件通常用来为 Vue 添加全局功能。”
“组件是可复用的 Vue 实例,且带有一个名字。”
—— Vue.js 官网

简单来说:插件、和组件的共同目的就是复用,插件为全局提供功能的,组件是针对于单文件.vue或者Vue.component('componentA',{}) 注册的。

比如: 我们常用的 vuex,vue-router,这些都是通过插件进行注册

插件添加到全局的方式

一般有这几种方式:

  • 添加全局静态方法或者变量: Vue.myFunction
  • 添加全局资源:指令/过滤器/过渡:Vue.directive("mydirective", {....
  • 通过全局混入来添加一些组件选项: Vue.mixin({created: function () {....
  • 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现: Vue.prototype.$Myproto

插件的使用

插件需要通过 Vue.use() 方法注册到全局,并且需要在调用 new Vue() 启动应用之前完成。

import Vue from 'vue'
import iView from 'view-design'
Vue.use(iView) // 注册插件
...

准知识完成之后,下面以实现一个简易的事件上报插件 analytics-report 为例,给大家介绍怎么开发和发布一个 Vue 插件。

开发插件

希望达到的效果:

// src/main.js
import Vue from 'vue'
import analyticsReport from 'analytics-report'

Vue.use(analyticsReport)
...
// src/toolbar.vue
<li
   title="图表(Ctrl+B)"
   v-analytics-track:ViewChart
   @click="clickTool('图表',$event)" >
</li>
// 点击的时候自动进行 ViewChart 事件上报
// XXX.vue
直接通过 this.$Analytics 进行调用

编写 analytics-report

image.png 具体细节不讲了 看代码就能懂

import"./AnalysysAgent_SDK/AnalysysAgent_JS_SDK.min.js";
import"./AnalysysAgent_SDK/AnalysysAgent_Encrypt.min.js";
import"./AnalysysAgent_SDK/AnalysysAgent_GBK.min.js";
import"./AnalysysAgent_SDK/AnalysysAgent_PageViewStayTime.min.js";
import {installPrototype , installDirective} from './register'

/* 必须暴露 install 方法 */
const install = function (Vue, options) {
  if (install.installed) return;
  install.installed = true;

  initSDK(Vue, options); 
  // 通过全局 directive 方法添加一些全局指令,如:analysys-track
  installDirective(Vue, options); 
};

const vueEventReport = { install };

vueEventReport.options = {
  appkey: '/*设置为实际APPKEY*/', //APPKEY
  debugMode: process.env.NODE_ENV === "development" ? 2 : 0,  
  uploadURL:'/*设置为实际地址*/', //上传数据的地址
  /**如无自定义配置,则与uploadURL相同**/
  autoHeatmap: true, // 点击位置热图、点击元素热图
  autoWebstay: true,
  autoTrack: false, // 全埋点
  encryptType: 1, // 默认不加密0 加密1,2
  sendType: "post", // 接口上传日志
};

// 初始化埋点SDK
function initSDK(Vue, options) {
  vueEventReport.options  = {
    ...vueEventReport.options,
    ...options
  }
  window.AnalysysAgent.init(vueEventReport.options)
  installPrototype(Vue, vueEventReport.options)
}

// 支持 CommonJS
if (typeof exports == "object") {
  module.exports = vueEventReport;
  // 支持 AMD
// eslint-disable-next-line no-undef
} else if (typeof define == "function" && define.amd) {
  // eslint-disable-next-line no-undef
  define([], function () {
    return vueEventReport;
  });
  // Vue 是全局变量时,自动调用 Vue.use()
} else if (window.Vue) {
  window.vueEventReport = vueEventReport;
  // eslint-disable-next-line no-undef
  Vue.use(vueEventReport);
}

export default vueEventReport;


// plugin/register.js
// 注册全局指令
function installDirective(Vue) {
  Vue.directive("analytics-track", {
    bind(el, binding  ) {
      el.handler= (ev) => {
        ev.stopPropagation()
        let eventName = binding.arg
        let track = Vue.prototype.$Analytics && Vue.prototype.$Analytics.track
        let props
        if(!eventName) {
          console.log('事件名称不能为空,举例:v-analytics-track:myEvent');
          return
        }
        if(!track) {
          console.log('Vue.prototype.$Analytics 为空');
          return
        }
        if(binding.value === '') {
          track(eventName); return 
        }
        // 针对传递的是function 来获取动态获取data中的参数
        binding.value instanceof Function ? props = binding.value(el) : props = binding.value
        track(eventName, props)
      }

      el.addEventListener("click", el.handler) // 添加点击事件监听
    },
    unbind: function (el) {
      el.removeEventListener("click", el.handler) // 移出点击事件监听
    },
  });
}

function installPrototype(Vue, options) {
  // 挂载埋点
  Vue.prototype.$Analytics = window.AnalysysAgent;
  Vue.prototype.$AnalysysAgent = window.AnalysysAgent;
  Vue.prototype.$Analytics.options = options
}

// 注册全局组件
function installComponent(Vue, options) {
  console.log("options: ", options);
  //  Vue.component(testPanel.name, testPanel) // testPanel.name 组件的name属性
}

// 注册全局生命周期钩子
function installMixin(Vue, options) {
  console.log("options: ", options);
  // Vue.mixin({
  //  created: function () {
      // console.log("mixin --- 我自己的混入");
  //   },
  // });
}

export {installComponent, installMixin, installDirective, installPrototype}

配置参数可以随意配置自己需要的

Vue.use(analyticsReport, {
  debugMode: 0
});

发布插件

第一步要进行打包,最好有自己插件的打包环境,推荐使用。

测试完成,可以实现我们的想要的内容。下面我们就要把我们的内容打包发布到npm 上去。 为了不和开发的项目环境发生冲突,我们采用另外一个项目,专门做打包发布的。

我使用了现成的webpack模板: webpack-simple  这个简化版的webpack

具体webpack-simple可查看: # vue + webpack(webpack-simple)安装教程

1. 修改webpack.config.js

var path = require('path')
var webpack = require('webpack')

module.exports = {
  entry: './src/plugin/index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'vueAnalyticsReport.js',
    library: 'vueAnalyticsReport', // library指定的就是你使用require时的模块名,这里便是require("vueAjaxUpload")
    libraryTarget: 'umd', //libraryTarget会生成不同umd的代码,可以只是commonjs标准的,也可以是指amd标准的,也可以只是通过script标签引入的。
    umdNamedDefine: true // 会对 UMD 的构建过程中的 AMD 模块进行命名。否则就使用匿名的 define。
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader'
        ],
      },      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
          }
          // other vue-loader options go here
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    },
    extensions: ['*', '.js', '.vue', '.json']
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true,
    overlay: true
  },
  performance: {
    hints: false
  },
  devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
}

重点是entry和output整对就行,其他配置项不需要删除就行

2. 修改 package.json

image.png

{
  "name": "vue-analytics-report",
  "description": "A Vue Plugin",
  "version": "1.0.0",
  "author": "Hello-GBY <nameGBY@163.com>",
  "license": "MIT",
  "private": false,
  "main": "dist/vueAnalyticsReport.js",
  "scripts": {
    "dist": "webpack --config ./webpack.config.js",
    "pub": "npm run dist  && npm publish",
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/Hello-GBY/vue-analytics-report.git"
  },
  "bugs": {
    "url": "https://github.com/Hello-GBY/vue-analytics-report/issues"
  },
  "homepage": "https://github.com/Hello-GBY/vue-analytics-report#readme",
   .....
}

3. 打包

npm run dist 打包这里面容易有问题,一般是库模块没有,或者ESlint提示第三方库格式不对 此时可以 在项目根目录下 .eslintgnore 配合路径,忽略该文件如: src/plugin/AnalysysAgent_SDK/**

打包成功之后,下面进行真正的发包操作啦

4. npm 登录

npm注册 www.npmjs.com/signup

按照上边的要求输入的全名、用户名、邮箱、密码进行注册

已有账号可直接登录

通过 npm adduser 进行登录,输入用户名称、密码、邮箱之后,会让你验证

这里用终端会不显示密码,推荐在Git Bash上登录就能看到输入的密码

adduser 过程可能会有很多问题:

  • npm config get registry 地址不是https协议啊
  • npm 版本不对
  • npm 升级之后、node 版本不对啊

一定要看认真提示信息,然后自行百度啦~

登录成功之后就可以执行

发包

执行 npm publish 就可以发包啦

发布完之后,我们就可以转到我们的npm 官网上看看我们的项目。

www.npmjs.com/package/vue…

其他

下一章节将讲述如何进行前台性能收集,和异常收集 让插件承载更多好玩的功能