簡介
一個適合小頁面的模板開發工具,基於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
* 有問題歡迎留言交流