基于ServerLess的极简网页计数器:源码分析与最佳实践

栏目: JavaScript · 发布时间: 4年前

内容简介:这几天基于支持HTML5无感认证的ServerLess平台开发了一款博客、门户网站等web平台常用的PV统计工具:回首看来,解决了以下几个比较有意思的问题:

基于ServerLess的极简网页计数器:源码分析与最佳实践

这几天基于支持HTML5无感认证的ServerLess平台开发了一款博客、门户网站等web平台常用的PV统计工具: page-counter 。主要用到的技术是js+webpack。

回首看来,解决了以下几个比较有意思的问题:

  • 如何设计代码,用统一的方式支持多个ServerLess平台?
  • 如何架构项目,使得其支持CDN和npm两种方式引入?
  • 如何精简源码,源码大小控制在4kb?
  • 如何借助webpack分离生产和测试环境?

源码地址: https://github.com/dongyuanxin/page-counter

npm地址: https://www.npmjs.com/package/page-counter

如果有兴趣的同学,欢迎在阅读完本文后一起接入其他平台的开发; 觉得不错的同学,欢迎给个Star哦

项目目录

基于ServerLess的极简网页计数器:源码分析与最佳实践

如上图所示,bin/backend 目录是暂时没用的。几个比较重要的目录功能说明:

  • build/ : webpack的配置文件,分别是公共配置、开发模式配置、生产模式配置
  • dist/
    • index.template.html: 开发模式下配合webpack的html模板文件
    • page-counter.min.js: 打包后的page-counter内容,供CDN引入
    • page-counter.bomb-1.6.7.min.js:我手动修改并且打包的Bomb平台源码
  • examples/ : gh-pages页面,请看此页面
  • deploy.sh : gh-pages部署脚本,支持ssh和https协议
  • index.js : npm的入口文件
  • index.build.js : CDN打包入口文件
  • src/ :
    serverless/
    config.js
    utils.js
    

抽象接口:支持多Serverless平台

src/serverless/interface.js 中定义了不同平台的类的公共父类。虽然js不支持抽象接口,但是也可以通过抛出错误来实现:

export default class ServerLessInterface {
  constructor () {}

  ACL () {
    throw new Error('Interface method "ACL" must be rewritten')
  }

  setData () {
    throw new Error('Interface method "setData" must be rewritten')
  }

  count () {
    throw new Error('Interface method "count" must be rewritten')
  }
}

而 leancloud.js 、bomb.js 等不同平台的类都要实现这个接口中的这3个方法。然后通过 src/serverless/index.js 统一暴露出去:

import LeanCloud from './leancloud'
import Bomb from './bomb'

class ServerLessFactory {
  constructor (name) {
    name = name.toLocaleLowerCase()

    switch (name) {
      case 'leancloud':
        return new LeanCloud()
      case 'bomb':
        return new Bomb()
      default:
        throw new Error('Serverless must be one of [ leancloud, bomb ]')
    }
  }
}

export default ServerLessFactory

这两种设计,既解耦了不同平台的代码,而且还约束了实现规则。如果想接入更多平台,只需要创建新文件,并且暴露一个继承 ServerLessInterface 接口的指定方法的子类即可。

快速方便:支持CDN和npm的使用

一个成熟的前端小 工具 需要考虑到多种引入方式,目前主流的就是cdn和npm。例如jquery,cdn引入,jq会被自动挂载在window对象上;npm引入,则作用域只在当前文件模块有用。

在考察了多种同类工具后,针对cdn和npm做了不同的处理。

npm

对外暴露 PageCounter 对象,其上有3个方法:

  • setData() :将当前页面信息发送到云数据库
  • countTotal() : 统计数据库总记录数(网站总PV),并且将返回结果 自动放入 id为page-counter-total-times的标签里
  • countSingle() : 统计数据库符合要求的记录数(当前页面PV),并且将返回结果 自动放入 id为page-counter-single-times的标签里
import PageCounter from './src'

export default PageCounter

CDN

不会在全局挂载上述对象方法,会自动执行上面的3种方法。考虑到并发以及pv数允许1以内的误差,没有保证串行。

import PageCounter from './src'

PageCounter.setData()
PageCounter.countTotal()
PageCounter.countSingle()

精简源码:巧用package.json和第三方SDK

经过精简,打包后cdn引入的源码只有4kb。npm引入的话,webpack会自动进行tree shaking。因为要对接不同的serverless平台,因此需要使用他们的sdk。

而这些sdk分成2种:

  • 类似leancloud:既可以npm引入,也可以cdn引入后自动挂载到window对象
  • 类似bomb:无cdn引入,只要npm引入

针对第二种情况,我采取的方案是手动打包编译。比如对于bomb的sdk,专门创建新的工程,然后配合webpack和以下代码,进行打包。

import Bomb from 'hydrogen-js-sdk'
window.Bomb = Bomb

打包后的源码放入版本库,这样借助 https://unpkg.com 等常见的CDN平台就可以引入了。这么做的很重要的一点是: 代码中都是通过window上的对象读取对应serverless平台的api,这样就不会被webpack识别,进而发生重复无用打包

关于读取配置的文件,都放在了 src/config.js 下。考虑到script标签引入造成的变量挂载时间点不确定,读取采用了动态读取。 为了操作起来更方便,而不是像调用函数那样,借助了 es6类语法中的 setter和getter。

// 举个例子:
class Config {
  constructor() {}

  get serverless() {
    if (!window.PAGE_COUNTER_CONFIG) {
      throw new Error('Please init variable window.PAGE_COUNTER_CONFIG')
    }

    return window.PAGE_COUNTER_CONFIG.serverless || 'leancloud'
  }
}

const config = new Config()
console.log(config.serverless) // 返回当前最新的window.PAGE_COUNTER_CONFIG.serverless

最后讲讲package.json的小技巧。虽然代码中没有使用import语法读取sdk的对象,但是我还是把leancloud、bomb平台的sdk放入了 dependencies 。这样做有什么好处呢?

用户只需要安装page-counter即可,其他sdk自动安装(不需要手动再敲命令)。然后用户就可以使用下面语法美滋滋引入:

import('hydrogen-js-sdk') 
  .then(res => {
    // 将 Bomb 对象挂载在 window 上
    window.Bomb = res.default
    // 设置应用信息
    window.PAGE_COUNTER_CONFIG = {
      // ...
    }
    return import('page-counter')
  })
  .then(res => {
    const PageCounter = res.default
    PageCounter.setData() // 发送当前页面数据
    PageCounter.countTotal() // 将总浏览量放入 ID 为 page-counter-total-times 的DOM元素中
    PageCounter.countSingle() // 将当前页面浏览量放入 ID 为 page-counter-single-times 的DOM元素中
  })

Webpack:分离生产和开发环境

不得不说,webpack真的好用呀。脏活累活以及常见工具,它都给你承包了。

webpack.base.conf.js 是两种模式的公共配置,指明入口文件以及代码环境(web)。并且能够识别模式,然后自行拼接配置。

webpack.prod.conf.js :生产模式,主要为了打包源码,方便CDN引入。

webpack.dev.conf.js : 开启热更新以及本地服务器方便调试,渲染的前端调试页面的模板文件就是 dist/index.template.html


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First Rails

Head First Rails

David Griffiths / O'Reilly Media / 2008-12-30 / USD 49.99

Figure its about time that you hop on the Ruby on Rails bandwagon? You've heard that it'll increase your productivity exponentially, and allow you to created full fledged web applications with minimal......一起来看看 《Head First Rails》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具