简介
一个适合小页面的模板开发工具,基于webpack,支持热重载,将css、js打包到一个html模板文件中。
这个小工具的适用场景不广,但设计思路能带来不小的启发。
具体可移步:github.com/SP-Lyu/TDS
* 单纯当作工作小总结写了,其实可以拆出很多细小但有用的文章
广告模板工具
TDS其实是为了一些小型的广告模板服务的,当年接手这一块只能手动生产这些模板,开发维护起来特别麻烦 (没错,本人就是靠发小广告为生)。
<!-- 常见的广告模板 -->
<!-- Head -->
<style>
/* Style Sheet */
</style>
<div id="{{ADID}}" class="wrapper">
<img src="{{IMG}}" />
<img src="{{IMG}}" />
<img src="{{IMG}}" />
<div><a href="{{CLICK_URL}}">{{DESC}}</a></div>
<div class="logo">
<!-- LOGO logic -->
</div>
<script>
// monitor
// animate logic
var id = {{ADID}};
var conf = {
showtime: {{TIME}}
// ...
}
// ...
</script>
</div>
<!-- Tail -->
复制代码
在一些搜索场景或者网盟场景下面的广告前端逻辑,往往具备以下几个特点:
- 对展现及加载速度要求高
- 页面简单、交互逻辑较少,但公共组件多
- 迭代速度快,新模板往往能刺激点击率的提升
- 后端会维护一套模板填入物料,联调时前后端相互耦合阻塞
所以对于商业广告展现的前端开发,有这几点需要关注:
- 优化展现速度,去除不必要的请求
- 组件化开发,批量打包更新
- 前端需要维护一套模拟数据便于开发、测试
着手优化
根据上述的诉求点,最终产出了一个模板开发工具,以命令行的形式完成模板的开发环境初始化、开发、打包、测试等。
命令大全:
tpl -s 切换至不同的业务线
tpl -l 查看当前业务线中的模板
tpl -i <tpl_name> 初始化新模板
tpl -d <tpl_name> -p <port> [-q] 开发
tpl -b <tpl_name> [-q] [-u] [-c charset] 打包模板(-u:是否不压缩HTML文件 -c:转换至目标编码)
tpl -B [-q] [-u] [-c charset] 打包当前业务线中所有模板
tpl --delete 删除模板
复制代码
下面介绍一下这个工具结合实际应用解决的几个痛点:
展现及加载速度优化
通常的页面开发,都是前端只保留一个简单的html,通过CDN、静态文件、缓存等方式引入CSS与JS文件,但该方式并不完全适用于广告展现的应用场景。 广告页面 交互少,逻辑简单 ,即使将css、js代码完全算上,亦不过15K左右大小,按照1MB/s的下载速度,传输仅需要15ms即可完成,而一般花在请求上的TTFB时间已大大超过这个值了。所以最耗时的不是资源下载,而是请求本身。
所以此处的优化思路应该是:css与js以行内引入的方式打包进模板,减少资源请求数,达到展现速度最快的目的。
TDS中采用了以ejs为模板,将打包好的css与js以字符串的形式通过webpack
引入模板,达到行内引入的目的。 webpack配置:
{
// ...
plagins:[
new MiniCssExtractPlugin({
filename: "main.css",
}),
new HtmlWebpackPlugin({
files:{
"css":[`./main.css`],
"js":[`./main.js`]
},
filename: `test.tpl`,
inject: false,
template: `test.ejs`,
title: tpl
}),
new OptimizeCSSAssetsPlugin({})
]
// ...
}
复制代码
ejs模板引入:
CSS:
<style type="text/css"><%= compilation.assets[htmlWebpackPlugin.files.css[0]].source() %></style>
JS:
<script></script>
复制代码
组件化开发
组件化的过程中,要考虑到 模块可复用 以及 业务间的模块独立
模块可复用
因为一些动画逻辑(抽奖、弹窗、轮播等)在多套模板中是公用的,且随着时间推移,这些逻辑的批量更改的需求若处理不好,会徒增很多开发量。就需要webpack
配合上一定的脚本,进行批量打包。
在TDS中,通过Node
引入webpack
进行打包,并通过commander.js
,将Node
程序命令化,从而达到批量打包的目的。
可以移步packer.js中看到详细的配置引入。
在开发的过程中,由于想要把热重载也加入TDS工具中,调研了一下现有的几种方法,但最终发现,可以直接在Node环境下引入webpack-dev-server
启动热重载。以下是示例:
const webpack = require("webpack");
const WebpackDevServer = require("webpack-dev-server");
const compiler = webpack({
//webpack conf
});
const s = new WebpackDevServer(,{
quiet: false,
contentBase: './'
});
s.listen(8808, '0.0.0.0', function(){});
复制代码
这种方式的引入,比用webpack-dev-middleware
+ webpack-hot-middleware
简单多了(但不知道为啥官方把它藏得那么深,可能是因为应用场景少吧)
官方例子
业务间独立
不同业务需求会存在多个模板,这里还得考虑一下业务独立的问题,能更好地将TDS应用于多业务线开发。由于运用了commander.js
将TDS命令化,可以进行很多定制,例如将开发区块以业务线进行区分,加入了workspace
的概念,可以执行tpl -s
切换工作区间,且之后的一切操作(新增、删除、打包模板等),都是基于当前工作区间完成的。
每个业务会有自己的初始化模板,存放至templage_xxx文件夹中,新增之后的模板文件放在src/xxx/
下,打包生成的模板则放在out/xxx/
下,这样能保证每个业务相互独立不干扰。 这个实现起来也十分简单,创建一个.user_config
文件记录下当前用户所处的业务线,以此作为工作区间进行模板配置的读取、操作即可。
// .user_config
{
current_workspace: 'buns'
}
复制代码
Mock数据构造
一开始开发维护过程中遇到的最蛋疼的问题就是,前端对于这种模板文件需要自己再去将值回填才能进行调试,对于前期的兼容性、交互、样式等的测试十分不友好。TDS维护了一套简单的测试方法:使用HtmlWebpackPlugin
打包ejs模板的时候,配置当前的打包选项,可以区分出当前的开发环境以及需要用到的mock数据:
// webpack配置
new HtmlWebpackPlugin({
files:{
"css":['out/.tmp/main.css'],
"js":['out/.tmp/main.js'],
},
// ↓当前环境置为开发环境
dev: true,
// ↓将文件以字符串数组的方式,写入mock中
mocks: get_files(`${tpl_path}/mocks/`),
// ↓将文件以字符串数组的方式,写入mock中
gmocks: get_files(`${tpl_path}/../Gmocks/`),
filename: tpl + '.html',
inject: false,
template: tpl_path + '/' + tpl + '.ejs',
name: tpl,
workspace
})
复制代码
数据源直接可以通过ejs文件中的htmlWebpackPlugin.options.dev
选项区分。
<% const ejs_env = htmlWebpackPlugin.options; %>
<% /*公共头部*/ %>
<%= ejs_env.dev?ejs_env.gmocks['head.html'] : '' %>
<div id="current_show"></div>
<script></script>
<script>// handle window.__g_ad_data</script>
<% /*公共尾部*/ %>
<%= ejs_env.dev ? ejs_env.gmocks['tail.html'] : '' %>
复制代码
这样就能在自己开发过程中维护一套有效的mock数据,打包项目代码时,直接通过环境的判断就能达到将后端模板字段打包的目的。
最终打包生成的模板:
<div id="current_show"></div>
<script></script>
<script>// handle window.__g_ad_data</script>
复制代码
产出
最后的整体产出,由于加上了js、css、html的打包逻辑,对比之前的模板体积大约下降了30%左右,且去除了css、js的加载逻辑,页面的整体加载时间(不算图片)接近于一次http请求的时间。
且对于开发人员来说,前后端的开发可以彻底分离,不再需要繁琐的沟通成本。
资料
commander.js
webpack NodeApi
webpack-dev-server NodeApi
* 有问题欢迎留言交流