前端工程化是建立高效前端開發體系的關鍵。
它涵蓋工具鏈設計、模組化方案、效能最佳化,以及架構模式等多個面向。
效能最佳化體系#
一切沒有效能剖析(Profiling)的效能最佳化都是耍流氓
凡是真正有價值的效能最佳化,必定是從端到端的業務場景出發,建立完整體系後才能考量得當。
效能體系四步驟#
1. 現狀評估和建立指標
↓
2. 技術方案設計
↓
3. 執行實施
↓
4. 結果評估和監控建立指標#
效能問題的三個主要方面:
| 方面 | 與業務的關係 |
|---|---|
| 頁面載入效能 | 與使用者流失率強相關 |
| 動畫與操作效能 | 影響使用者體驗 |
| 記憶體、電量消耗 | 影響行動裝置體驗 |
秒開率指標#
秒開率 = 一秒內打開的使用者數 / 使用者總數
相較於「平均載入時間」,秒開率更能反映大多數使用者的體驗,並且不會受少數極端值影響。
技術方案#
頁面載入時間受影響的因素:
- DNS 查詢
- TCP 連線建立
- HTTPS 憑證交換
- 資源下載(體積和請求數)
最佳化方向#
| 方向 | 具體措施 |
|---|---|
| 減少請求數 | 合併資源、CSS Sprites、內嵌小資源 |
| 減少體積 | 壓縮、Tree Shaking、程式碼分割 |
| 利用快取 | HTTP 快取、Service Worker |
| 預先載入 | DNS 預解析、資源預先載入 |
| 延遲載入 | 圖片延遲載入、路由延遲載入 |
執行實施#
工程實施的三個層次:
| 層次 | 特點 |
|---|---|
| 純管理 | 依賴行政手段,執行不穩定 |
| 制度化 | 培訓、checklist、定期 review |
| 自動化 | 發布平台整合、自動檢測 |
推薦制度化和自動化結合的方案,在發布流程中自動檢測效能指標。
結果監控#
資料採集#
使用 Performance API:
// 頁面載入時間
const timing = performance.timing;
const pageLoadTime = timing.loadEventEnd - timing.navigationStart;
// 首次繪製時間
const paintEntries = performance.getEntriesByType("paint");
const firstPaint = paintEntries.find((e) => e.name === "first-paint");
const firstContentfulPaint = paintEntries.find(
(e) => e.name === "first-contentful-paint"
);
// 上報資料
navigator.sendBeacon(
"/analytics",
JSON.stringify({
pageLoadTime,
firstPaint: firstPaint?.startTime,
fcp: firstContentfulPaint?.startTime,
})
);工具鏈設計#
工具體系的目標#
工具體系的「元問題」:
- 版本一致:團隊成員使用相同版本的工具
- 避免衝突:工具之間能夠良好配合
工具鏈組成#
前端開發的核心流程:
初始化專案 → 開發除錯 → 測試 → 建置 → 發布對應的工具:
| 流程 | 工具範例 |
|---|---|
| 初始化 | create-react-app, vue-cli, Vite |
| 開發除錯 | Webpack Dev Server, Vite |
| 測試 | Jest, Vitest, Cypress |
| 建置 | Webpack, Vite, esbuild |
| 發布 | CI/CD 工具 |
統一命令列入口#
# 統一的命令格式
def init # 初始化專案
def dev # 開發除錯
def test # 執行測試
def build # 建置
def publish # 發布好處:
- 團隊成員不需要學習各種工具的具體命令
- 可以接手別人的專案立即開發
- 便於切換底層工具實作
版本控制策略#
// package.json
{
"devDependencies": {
"webpack": "5.88.0", // 鎖定版本
"vite": "^4.4.0" // 允許小版本更新
}
}使用 package-lock.json 或 yarn.lock 確保依賴版本一致。
模組化方案#
模組化演進#
| 時期 | 方案 | 特點 |
|---|---|---|
| 早期 | 全域變數 | 命名衝突 |
| AMD/CMD | RequireJS, SeaJS | 瀏覽器端模組化 |
| CommonJS | Node.js | 同步載入,伺服器端 |
| ES Module | ES6+ | 官方標準,靜態分析 |
ES Module#
// 匯出
export const name = "module";
export function greet() {}
export default class MyClass {}
// 匯入
import MyClass, { name, greet } from "./module.js";
import * as module from "./module.js";
// 動態匯入
const module = await import("./module.js");ES Module 支援靜態分析,使 Tree Shaking 成為可能。
CommonJS vs ES Module#
| 特性 | CommonJS | ES Module |
|---|---|---|
| 載入時機 | 執行時 | 編譯時 |
| 匯出 | module.exports | export |
| 匯入 | require() | import |
| 動態匯入 | 支援 | import() |
| Tree Shaking | 困難 | 支援 |
前端架構#
元件化#
元件化是把使用者介面(UI, User Interface)上的各種元素拆解為元件。
接著規定元件的標準,並建立元件得以執行的環境。
主流方案比較#
| 方案 | 特點 |
|---|---|
| React | JSX、彈性高、生態豐富 |
| Vue | 樣板語法、上手簡單、MVVM |
| Angular | TypeScript、完整框架 |
| Web Components | W3C 標準、無需執行時依賴 |
選型考慮因素:
- 團隊技能分布
- 行動裝置或桌面
- 是否需要與 Native 整合
- 社群生態與長期維護
適配方案#
適配的三個要素:
| 要素 | 說明 | 解決方案 |
|---|---|---|
| PPI | 每英吋像素數 | media 規則 |
| DPR | 裝置像素比 | viewport 規則 |
| 解析度 | 螢幕寬高 | vw/vh 單位 |
/* 響應式斷點 */
@media (max-width: 768px) {
.container {
padding: 10px;
}
}
/* 使用 vw 實現自適應 */
.text {
font-size: clamp(14px, 4vw, 18px);
}單頁應用(SPA)#
單頁應用程式(SPA, Single Page Application)將多個頁面的內容實作在同一個實際頁面內。
因此失去了頁面之間天然的解耦關係,必須透過架構設計來實現「邏輯頁面」。
SPA 的挑戰#
邏輯頁面解耦
- 每個邏輯頁面獨立開發
- 支援獨立發布
路由管理
- 保持前進後退歷史
- 使用 History API 或 Hash
// History API
history.pushState({ page: 1 }, "Page 1", "/page1");
window.addEventListener("popstate", (e) => {
// 處理後退
});
// Hash 路由
window.addEventListener("hashchange", () => {
const hash = location.hash;
// 根據 hash 渲染對應頁面
});- 程式碼分割
// 動態匯入實現按需載入
const Home = () => import("./pages/Home.vue");
const About = () => import("./pages/About.vue");建置工具#
Webpack 核心概念#
// webpack.config.js
module.exports = {
entry: "./src/index.js", // 入口
output: {
// 輸出
path: path.resolve(__dirname, "dist"),
filename: "[name].[contenthash].js",
},
module: {
// 模組處理
rules: [
{ test: /\.js$/, use: "babel-loader" },
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
],
},
plugins: [
// 外掛
new HtmlWebpackPlugin(),
],
optimization: {
// 最佳化
splitChunks: { chunks: "all" },
},
};Vite 優勢#
// vite.config.js
export default {
plugins: [vue()],
build: {
rollupOptions: {},
},
};| 特性 | Webpack | Vite |
|---|---|---|
| 開發模式 | 打包後服務 | 原生 ESM |
| 熱更新 | HMR | 更快的 HMR |
| 建置 | 自身 | Rollup |
| 設定 | 複雜 | 簡潔 |
監控指標#
工具體系監控#
| 指標 | 意義 |
|---|---|
| 除錯/建置次數 | 開發活躍度 |
| 建置平均時長 | 開發體驗 |
| 使用的工具版本 | 版本碎片化程度 |
| 發布次數 | 迭代頻率 |
效能監控指標#
| 指標 | 說明 |
|---|---|
| FP | First Paint,首次繪製 |
| FCP | First Contentful Paint,首次內容繪製 |
| LCP | Largest Contentful Paint,最大內容繪製 |
| FID | First Input Delay,首次輸入延遲 |
| CLS | Cumulative Layout Shift,累計版面位移 |
| TTI | Time to Interactive,可互動時間 |
總結#
| 領域 | 核心要點 |
|---|---|
| 效能最佳化 | 建立指標 ➡️ 技術方案 ➡️ 執行 ➡️ 監控 |
| 工具鏈 | 版本一致、避免衝突、統一入口 |
| 模組化 | ES Module 為主,支援 Tree Shaking |
| 架構 | 元件化、適配、SPA 路由管理 |
| 建置工具 | Vite(開發體驗)/ Webpack(生態豐富) |
持續改進
效能和工程化不是一次性的工作,需要:
- 不斷最佳化指標
- 跟進技術發展迭代方案
- 改進制度和自動化工具
- 持續監控和分析資料