Webpack in Node:前端模板開發工具TDS
一個適合小頁面的模板開發工具,基於webpack,支援熱過載,將css、js打包到一個html模板檔案中。
這個小工具的適用場景不廣,但設計思路能帶來不小的啟發。
具體可移步:ofollow,noindex">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><%= compilation.assets[htmlWebpackPlugin.files.js[0]].source() %></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> <% if(ejs_env.dev){ %> window.__g_ad_data = { title: '測試資料', img: './src/<%= ejs_env.workspace%>/<%= ejs_env.name%>/static/test.png', url: 'https://google.com' }; <% } else {%> <!-- 後端填寫資料模組,以Google Ctemplate為例 --> window.__g_ad_data = { title: '{{TITLE}}', img: '{{IMG}}', url: '{{URL}}' }; <%}%> </script> <script>// handle window.__g_ad_data</script> <% /*公共尾部*/ %> <%= ejs_env.dev ? ejs_env.gmocks['tail.html'] : '' %> 複製程式碼
這樣就能在自己開發過程中維護一套有效的mock資料,打包專案程式碼時,直接通過環境的判斷就能達到將後端模板欄位打包的目的。
最終打包生成的模板:
<div id="current_show"></div> <script> <!-- 後端填寫資料模組,以Google Ctemplate為例 --> window.__g_ad_data = { title: '{{TITLE}}', img: '{{IMG}}', url: '{{URL}}' }; </script> <script>// handle window.__g_ad_data</script> 複製程式碼
產出
最後的整體產出,由於加上了js、css、html的打包邏輯,對比之前的模板體積大約下降了30%左右,且去除了css、js的載入邏輯,頁面的整體載入時間(不算圖片)接近於一次http請求的時間。
且對於開發人員來說,前後端的開發可以徹底分離,不再需要繁瑣的溝通成本。