前端工程本質上是軟體工程的一種。軟體工程化關註的是性能、穩定性、可用性、可維護性等方面,註重基本的開發效率、運行效率的同時,思考維護效率。一切以這些為目標的工作都是"前端工程化"。工程化是一種思想而不是某種技術。 本篇文章你可以學到: 如何使小程式支持scss; 怎樣通過gulp編譯你的項目; 項目 ...
前端工程本質上是軟體工程的一種。軟體工程化關註的是性能、穩定性、可用性、可維護性等方面,註重基本的開發效率、運行效率的同時,思考維護效率。一切以這些為目標的工作都是"前端工程化"。工程化是一種思想而不是某種技術。
本篇文章你可以學到:
- 如何使小程式支持scss;
- 怎樣通過gulp編譯你的項目;
- 項目常用的模塊封裝;
- 小程式同webview之間如何優雅的進行交互;
- 集中式管理你的項目提高可維護性;
- 提升開發效率的小工具編寫;
全文全部基於原生的小程式開發所闡述,各種第三方框架開發不在此列。並不會將整個項目的搭建流程細緻的寫出來,而是挑其中我認為在開發過程中存在的一些很重要的點進行詳細陳述。
普通小程式開發流程有可能會遇到的坑
列舉部分常見的
- 小程式本身不支持常用的css預編譯器,導致樣式規範隨意散落在各個文件,無法統一進行管理,而現代前端開發中不論是less,sass,stylus 都可以提升css效率;
- 缺少統一的request攔截請求;
- 缺少統一的路由管理;
- 缺少集中式的API地址和ENV環境變數管理;
- 缺少統一的本地緩存讀取管理;
- 重覆的webview頁面;
- 不支持ES7以上的高級語法,如async await等特性;
- 不管是體驗版還是開發版只能存在一種環境,一旦發佈預覽測試環境切換繁瑣;
- 上線前需要手動修改線上環境,容易出錯......
如何解決?
要解決工程化的問題,需要從兩個角度入手:開發 && 部署。
開發
Question
- 如何提高開發生產效率?
- 如何降代碼維護難度?
Program
- 制定開發規範,提高團隊協作能力;
- 使用自動化編譯工具使項目支持各種插件和提高效率的工具;
- 模塊/組件化開發;
- 所有需要集中管理的地方進行統一封裝;
部署
- 環境切換;
- 壓縮打包;
項目搭建
完整目錄結構
開發流程
工程化方案選型
對於目前常用的工程化方案,webpack,rollup,parcel等來看,都常用與單頁應用的打包和處理,而小程式天生是 “多頁應用” 並且存在一些特定的配置。根據要解決的問題來看,無非是文件的編譯,修改,拷貝這些處理,對於這些需求,我們想到基於流的 gulp非常的適合處理,並且相對於webpack配置多頁應用更加簡單。所以小程式工程化方案推薦使用 gulp。
Start
初始化一個項目,結構如下
src
為開發目錄dist
(開啟編譯後可見)為預覽/上傳目錄.gitignore
git上傳忽略文件gulpfile.js
編譯配置文件CHANGELOG.md
版本更新日誌README.md
項目說明文件package.json
項目配置文件
編譯用到的插件 使用npm或yarn自行安裝,安裝過程不過多贅述,不會請自行搜索。
"gulp": "^3.9.1"
"gulp-sass": "^4.0.2"
scss編譯插件
"gulp-postcss": "^6.4.0"
強大的css處理插件
"gulp-rename": "^1.2.2"
更改文件名
"gulp-replace": "^1.0.0"
替換內容
"gulp-changed": "^3.2.0"
檢測改動
"autoprefixer": "^6.5.1"
自動添加首碼
如何使用scss?
gulp配置打包sass非常簡單,唯一需要註意的是@import的使用,wxss是支持樣式導入的,但上面說到過小程式是天生的多頁面應用,每一個頁面都對應一個wxss,因此sass打包會把import的文件打包到當前文件,從而導致當前文件的體積變大。由於微信限制單包代碼不能超過2M,因此當css越寫越多的時候,這種打包方式勢必會使樣式文件越來越大。
解決import導入問題
那如何解決import的導入問題呢,其實也比較簡單,說白了就是sass處理的時候,讓其不處理import部分的語句就可以了。有兩種方式可以做到,第一種是改寫sass處理的源碼,當遇到import語句時跳過。第二種是,在把文件交給sass處理前,我們先把import語句部分註釋掉,這樣sass處理的時候就會忽略了,當sass處理完成後,再把註釋掉的語句打開即可。顯然第一種成本比較高,也不好維護,所以我們採用第二種。
在處理import的時候,還有個地方是需要註意的。在sass中,import除了能引入css外,也可以引入變數,函數。因此,我們在處理的時候也需要註意區分,變數和函數最好有一個獨立的文件目錄存放,並且在import的時候,對於變數和函數,是必須交給sass處理的,也就是不能註釋掉。因此我們單獨配置了sass變數和函數存放的位置,這樣我們在打包的時候,遇到這樣的import語句,我們就跳過,交給sass處理,否則就代表其是引入了共用的樣式文件,這樣我們交給sass處理前,就先將其註釋掉,sass處理完成後再把註釋打開。
完整實現支持scss思路如下:
- 指定文件處理目錄
- gulp-replace通過正則匹配@import語句將其註釋
- 判斷當前@import語句是否存在於變數和函數文件的配置路徑中
- 不存在就註釋,存在就跳過
- 啟用gulp-sass編譯scss文件,
- 通過postcss對低版本ios和安卓進行相容樣式處理
- gulp-rename更改文件尾碼為.wxss
- gulp-replace通過正則匹配@import語句打開註釋
- 最後輸入到dist目錄
代碼如下
拷貝其餘頁面,註意要排除scss文件,或者使用gulp-clean清理無用文件
建立監聽任務
創建預設執行任務
將生成的dist目錄作為根目錄丟進小程式開發工具即可實時刷新預覽小程式,至此你的項目已經完全支持scss了,盡情的去浪吧。
提高你的代碼維護性——封裝
request請求攔截器
wx.request是小程式中最常用的api,在實際項目中會涉及到很多需要統一攔截/發送/處理,所以我們需要對wx.request進行二次封裝用來支持各類需求,以實現代碼的可維護性。小程式本身已經支持promise語法,
在此用promise
將其封裝成常用的.then
的形式
要做什麼?
- 可以通過header和data統一發送公共參數,如請求驗證的token,用戶id等信息...
- 可以統一進行錯誤攔截處理,如全局登錄狀態判斷,特殊code碼的處理...
- 可以根據配置自適應請求環境,如Mock,Dev,Test, Slave,Prod...
需要支持的功能
- 請求方式
- 參數傳遞
- 成功回調
- 失敗回調
- 是否開啟mock數據
- 請求時是否展示loading
- 請求錯誤時是否展示toast
代碼實現
調用方式
在app.js
入口文件內引入,並將其掛載到App對象上,需要調用時可通過getApp()
的方式調用
index.js
為例,關於API的引入會在後文介紹:
Router路由
路由的封裝主要是為了防止路由地址各個文件散落,無法集中管理的問題。
需要支持的功能
- 無參路由和有參路由
- 路由地址縮寫
- 參數傳遞
- 跳轉延時
- 跳轉類型
代碼實現
定義出存路由地址的對象,使用時直接通過key值匹配
實現一個parse方法解析參數為query拼接方式 定義一個push對象接收普通無參數path地址和有參數的option對象,option對象包含path(路由地址)、query(參數),duration(跳轉延時),openType(跳轉方式)
;
通過openType結合原生api實現路由的幾種跳轉方法
調用方式 還是老規矩,直接掛載App對象通過getApp()獲取直接調用
Stroage存儲
合理的Stroage方法封裝可以使你更優雅的管理你的本地緩存。此功能需要支持三種常用的setItem(設置緩存)、getItem(讀取緩存)、clear(清除緩存)
方法,並且在你的團隊內部最好整理一套寫入緩存的規範,不要一股腦丟在全局,應該按一些模塊進行劃分存取,這樣才能更好的維護你的本地緩存信息。
代碼實現
寫入和讀取均支持key ---> value
的普通方式也相容key--->value--->module
的模塊方式,預設使用同步的方式設置,之所以加catch是為了防止在特殊情況下小程式會報警設置緩存錯誤,如同步報錯則採用非同步容錯。
setItem寫入緩存
getItem讀取緩存 clear清除緩存 調用方式 同上掛載App,使用方法如下:寫入 讀取 清除
API地址和ENV環境變數管理
API地址和ENV環境變數可以做為兩個單獨配置的文件進行配置,API文件只存介面路徑,ENV存儲多個環境變數,環境對象內配置當前環境各種功能變數名稱,然後在app.js
配置當前環境變數,作為key值匹配ENV內的環境,將匹配的環境掛載App對象,配合前面封裝的fetchApi以env+url
的方式實現自動環境適配。
API
ENV app.js
統一的webview
微信小程式提供了在小程式中內嵌HTML頁面的能力,從微信小程式基礎庫1.6.4開始,可以在小程式內放置一個組件來鏈接HTML頁面。有了就可以方便的將幾端共用的h5頁面集成到小程式內部,為我們減少了可觀的工作量。
如果你有多個需要集成的webview頁面實際上無需為每個頁面都單獨建一個文件,只需對一個公共的webview頁面進行簡單封裝配合路由即可集中管理你的webview頁面。
代碼實現
wxml引入webview組件和載入中動畫,webview組件接收地址,和載入成功回調。
js中在data內定義webview頁面的地址列表,key用type代表指定路徑,value用page代表頁面鏈接,通過onload接收一個formpage參數對應type,動態載入組件上的src即可。需要註意的一點是,如果需要在webvie鏈接拼接獲取的參數,在某些安卓機型會因為提前渲染webview而src地址沒有初始化而產生白屏,所以最好的方式是通過一個變數控制組件的展示隱藏,確保需要渲染組件時數據已經初始化完成以保證頁面正常展示。如何解決多環境切換問題
小程式不像h5網頁只要部署到對應環境,就可以隨意輸入指定的環境功能變數名稱進行測試,而小程式像app一樣沒有網址這一說,它本身只會存在一個預覽版本,普通的流程是每次當測試同學需要在不同環境中測試時就需要找到開發同學手動更改環境並重新發佈體驗版。這樣的流程是很不靈活的,所以我們需要想一個辦法,讓一個小程式版本自由的切換多個環境,而無需手動改代碼配置發佈。
如何實現?
實現的思路有很多種,主要需要解決的就是環境如何進行切換的問題,在這裡我是通過利用小程式的重力感應api模擬搖一搖,將切換環境搓成一個一個隱藏的小彩蛋,測試人員只需要搖一搖彈出環境選項列表點擊對應選項更改App對象的config內的env環境屬性即可成功切換環境。
代碼實現
app.js也要進行處理,因為不能將該功能帶到線上所以需要進行邏輯判斷。
如何自動打包部署環境,防止手動配置易出錯的問題
在這裡其實還是要用到gulp這個神器,來實現不同環境的代碼打包,配置起來很容易,無非就是通過gulp-replace在打包的時候對app.js的環境變數進行配置,但要配合微信開發工具的自定義處理命令每次在發版本審核的時候只需要開啟該功能即可。
gulpfile.js
project.config.json 開發者工具
以上列舉了開發流程中常用的工程化解決方案,再此希望對大家有一個參考作用,如有問題歡迎指正。