基於ServerLess的極簡網頁計數器:源碼分析與實踐

image.png

這幾天基於支持HTML5無感認證的ServerLess平臺開發了一款博客、門戶網站等web平臺經常使用的PV統計工具:page-counter 。主要用到的技術是js+webpack。javascript

回首看來,解決了如下幾個比較有意思的問題:css

  • 如何設計代碼,用統一的方式支持多個ServerLess平臺?
  • 如何架構項目,使得其支持CDN和npm兩種方式引入?
  • 如何精簡源碼,源碼大小控制在4kb?
  • 如何藉助webpack分離生產和測試環境?

源碼地址:github.com/dongyuanxin…html

npm地址:www.npmjs.com/package/pag…前端

若是有興趣的同窗,歡迎在閱讀完本文後一塊兒接入其餘平臺的開發; 以爲不錯的同窗,歡迎給個Star哦java

🔍查看所有文章目錄 / 閱讀原文🔍jquery

項目目錄

如上圖所示,bin/backend 目錄是暫時沒用的。幾個比較重要的目錄功能說明:webpack

  • 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不支持抽象接口,可是也能夠經過拋出錯誤來實現:css3

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 統一暴露出去:git

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 接口的指定方法的子類便可。es6

快速方便:支持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
複製代碼

打包後的源碼放入版本庫,這樣藉助 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

更多文章

⭐在GitHub上收藏/訂閱⭐

《前端知識體系》

《設計模式手冊》

《Webpack4漸進式教程》

⭐在GitHub上收藏/訂閱⭐

相關文章
相關標籤/搜索