問題現狀
- 后端采用 多服務 + nginx 的技術架構 根據業務拆分成不同的項目,具體服務通過location由nginx轉發代理到不同的機器(端口)上。
- 前端采用的是 dva + roadhog 的 SPA 頁面。在前期路由少,頁面小的情況下,開發順暢無壓力。
- 隨着開發的不斷進行,前端開發的瓶頸漸顯,前端代碼量不斷增加,引入的第三方包不斷擴大,每次動態編譯花費時間不斷加大,最終打包文件不斷變大。
- 每次發布版本必須全量發布,即使是改動一點點的功能,無法按模塊發布前端代碼。
- 開發人員在開發階段必須通過
--max_old_space_size命令強制分配內存來避免node進程out of memory
項目前端相關指標:
| \ | 業務代碼大小 | 打包后代碼總量 | 路由數量 | 編譯總時長 | 熱加載時長 |
|---|---|---|---|---|---|
| 總量 | 5.26 MB | 35.5MB | 近100個 | 20分 | 45 s |
可以看到前端編譯的時間已經極大的影響了開發人員的開發時間和開發效率
改進目標
- 以
功能模塊為第一維度分割大項目。 - 盡量不影響用戶體驗。
- 切換到新頁面同步左側菜單欄的狀態。
- 子項目可以分開獨立發布上線。
解決思路
- 將舊項目的部分功能拉出來,獨立成多個單獨可正常運行的子項目。
- 借鑒后端 nginx 的分發思想,通過
location分發到不同靜態目錄。 - 將子項目前端代碼部署到多個路徑(甚至是機器),每個子項目獨立發布,互不影響。
實現步驟
1. 前端項目拆分
- 更新前端路由模式,從
hash模式改為history模式
/src/index.js:
import browserHistory from 'history/createBrowserHistory';
const app = dva({
history: browserHistory(),
});
- 修改路由配置,刪除非本項目的路由
- 從model、service、route刪除非本項目的文件
- 刪除非本項目的依賴,並更新
package.json - 刪除
/src/index.ejs首頁文件中非本項目的文件引入
2. nginx分發
- 增加子路徑的分發,有多個增加多個
nginx.conf:
location /sub-path/ {
alias /xxx/dist/; #靜態文件路徑
try_files $uri $uri/ /xxx/dist/index.html; #404時重新定向到靜態文件目錄下的index.html下
}
- 修改根目錄的處理方式,由root更新為alias(防止root權重問題導致nginx不執行try_files)
nginx.conf:
location / {
alias /xxxx/dist/; #靜態文件路徑
try_files $uri $uri/ /xxxx/dist/index.html; #404時重新定向到靜態文件目錄下的index.html下
}
3. 404路徑優化
- 前端404路由由渲染頁面優化為重定向資源,把路由控制權轉交給
nginx - 為防止
前端404路由和nginx404路由同時存在導致無限刷新需緩存一個更新狀態在本地,防止死刷新
tryRefresh() {
if (window.sessionStorage.getItem('refresh') === 'true') {
window.sessionStorage.removeItem('refresh');
this.show404 = true;
} else {
window.sessionStorage.refresh = 'true';
this.show404 = false;
window.location.href = window.location.href;
}
}
4. 菜單狀態同步
- 根據url路徑,同步更新左側菜單欄的狀態
setDefaultOpenKeys() {
try {
const { location: { pathname } } = this.props;
let keys = [];
const pathItems = pathname.replace('/', '', 1).split('/');
const pathItemsWithoutLast = pathItems.slice(0, pathItems.length-1);
this.setState({
openKeys: pathItemsWithoutLast,
});
} catch (err) {
// what you do
}
}
5. 配置項目自動發布
- 配置發布相關,自測,上線代碼
最終結果
將前端代碼拆分成為一個基礎模板和3個子項目。
- 前后數據對比:
| \ | 業務代碼大小 | 打包后代碼總量 | 路由數量 | 編譯總時長 | 熱加載時長 |
|---|---|---|---|---|---|
| 項目 - 舊 | 5.26 MB | 35.5MB | 近100個 | 20分 | 45 s |
| 項目模板 | 0.45 MB | 2MB | 2個 | 15s | 1 s |
| 子項目一 | 3.5 MB | 28MB | 近70個 | 12分 | 7 s |
| 子項目二 | 4.2 MB | 12MB | 10個 | 4分 | 5 s |
| 子項目三 | 2 MB | 9.16MB | 16個 | 1.5分 | 2 s |
待優化點
- 有些公共的文件沒有抽離出來,導致子項目總和是大於原項目的。抽離出公共文件和依賴,防止資源浪費。
- 常量的公共接口可以做sesionStorage緩存(例如菜單欄),防止項目切換重復調用接口造成浪費。
