serverless搭建html,基于ServerLess的极简网页计数器:源码分析与实践
这几天基于支持HTML5无感认证的ServerLess平台开发了一款博客、门户网站等web平台常用的PV统计工具:page-counter 。主要用到的技术是js+webpack。
回首看来,解决了以下几个比较有意思的问题:
如何设计代码,用统一的方式支持多个ServerLess平台?
如何架构项目,使得其支持CDN和npm两种方式引入?
如何精简源码,源码大小控制在4kb?
如何借助webpack分离生产和测试环境?
如果有兴趣的同学,欢迎在阅读完本文后一起接入其他平台的开发; 觉得不错的同学,欢迎给个Star哦 。
项目目录
如上图所示,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 。
更多文章
serverless搭建html,基于ServerLess的极简网页计数器:源码分析与实践相关推荐
- 基于TCP网络通信的自动升级程序源码分析-客户端接收文件
升级程序客户端接收文件 /// <summary>/// 文件数据缓存 索引是 ConnectionInfo对象 数据包的顺序号 值是数据/// </summary>Dicti ...
- 基于‘纯洁的微笑’开源项目 — Favorites 源码分析
引言: 对于某语言不算熟悉的话自创项目是很痛苦的过程,即便笔者是一位掌握java的Android码农,对于java入门也是深感无力,毕竟语言是基础,但框架设计模式却与Android有出入,且学习成本较 ...
- 好看的极简网站导航源码自适应静态页
简介: 极简的网站导航源码自适应静态页,直接修改源码里的 index.js 即可! 网盘下载地址: http://kekewl.net/mwjkiWK49a00 图片:
- 干货|Pytorch弹性训练极简实现( 附源码)
点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 作者丨颜挺帅@知乎(已授权) 来源丨https://zhuanlan ...
- 基于后端开发Redisson实现分布式锁源码分析解读
一.分布式锁的概念和使用场景 分布式锁是控制分布式系统之间同步访问共享资源的一种方式. 在分布式系统中,常常需要协调他们的动作.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问 ...
- 国外php开源网站源码,国外收藏的一款免费PHP极简云网盘源码
可以快速搭建一个简单的私有网盘,无需数据库,登录后台请切换直链下载,不然下载链接打不开! 更新升级说明 此方法对任何版本的更新都有效 1.首先,备份整个/vfm管理/文件夹 2.不要替换用红色标记的文 ...
- Dubbo篇:基于Netty实现Dubbo协议编解码源码分析
Dubbo协议解析 Dubbo协议设计参考了TCP/IP协议,包括协议头和协议体两部分.16字节报文头主要携带了魔法数(0xdabb,用于分割两个不同请求),以及当前请求报文是否是Request.Re ...
- 【我的渲染技术进阶之旅】Google开源的基于物理的实时渲染引擎Filament源码分析:Android版本的Filament第一个示例:sample-hello-triangle
文章目录 一.效果展示 二.之前的博客 三.示例工程sample-hello-triangle源码分析 3.1 项目源码路径 3.2 分析源码 3.2.1 分析AndroidManifest.xml ...
- 【我的渲染技术进阶之旅】Google开源的基于物理的实时渲染引擎Filament源码分析:在android中如何使用filamesh命令将.obj或者.fbx文件转换为.filamesh文件?
文章目录 一.需求描述 1.1 为啥要学习`filamesh`命令 1.2 从android项目的build.gradle看起 1.3 查看FilamentToolsPlugin插件源代码 1.3.1 ...
最新文章
- 传承乡邦文化,展示国学之美,联墨香飘远,文明花放红;
- shiro源码分析(四)具体的Realm
- 基于CSS3飘带状3D菜单 菜单带小图标
- me21n增强BADI:ME_PROCESS_PO_CUST之process_account
- Android studio编译好的apk文件在哪里?
- 《大数据原理:复杂信息的准备、共享和分析》一一2.5 在标识符中嵌入信息:不推荐...
- am335x PDK3.0 设置为单网口配置记录
- 区间数多属性决策matlab,区间数多属性决策的改进理想解法
- 【51单片机快速入门指南】4.4.2:Mahony AHRS 九轴姿态融合获取四元数、欧拉角
- Java集合——HashMap、HashTable以及ConCurrentHashMap异同比较
- 报应!GitHub上线围剿Python计划,已有4万人跟进,你呢?
- 总结 10 年前端经验,谈谈前端人如何更快地成长
- (转)UIPageControl使亮点直接跳到点击dot上
- viiv个人计算机,欢娱尽情 欢跃平台PC导购
- Ext JS学习第八天 Ext基础之 认识Ext.js 和Ext-more.js
- linux读用户密码,linux用户/用户密码和用户组管理
- MySQL数据库安装教程
- Linux开发环境——SCL软件集
- 如何将宿舍门变成指纹开锁?
- 方腔驱动流的simple算法(附matlab与c++程序)
热门文章
- Angular 依赖注入学习笔记之工厂函数的用法
- SAP Spartacus 用户登录成功后,Access Token 持久化到浏览器 local storage 的执行原理
- SAP Spartacus B2B List里的listData$设计原理
- 对Angular使用了HttpClient的服务进行单元测试
- com.fasterxml.jackson将对象序列化成json时,出现在json里的属性名称是怎么来的
- WordPress Kyma插件里Connect和disconnect按钮的动态显示逻辑
- Y_CLIENT_QHD_504 role in GM6 ZSAP_CRM_BCR_SALESREP_DAIDE
- Marketing Cloud tile的semantic信息
- workflow and email in QD3 - IS_INBOX_USER method
- 关于SAP Fiori用户管理资料的一个问题