最近在組內推廣進行項目(Vue
+ Express
)歷史邏輯下線專項,實踐完成後產出了一份 SOP,特此記錄
SOP(Standard Operating Procedure): 一種詳細的、書面的指導方案,用於指導如何完成特定任務或活動。
刪除無用路由與接口#
前置邏輯:
- 開啟埋點 SDK PV 插件自動上報或 Vue 插件路由自動上報,注意項目初始訪問是否正常上報
- 開啟埋點 SDK 接口請求上報功能(在通用請求響應攔截器裡設置)
無訪問路由#
通過 Druid SQL
從埋點上報數據中查詢近三個月頁面訪問記錄,對比項目中路由配置產出未訪問歷史路由,過濾掉明確需要使用的頁面並逐個在項目中搜索確認是否有項目內跳轉情況,之後與產品及後端確認剩餘頁面後才可刪除。
附未訪問路由匹配產出邏輯:
const fs = require('fs')
const path = require('path')
const list = [] as string[]
// 項目已訪問路由數據
const { data } = require('./data.json')
// 遍歷目錄生成路由列表(針對 nuxt 等約定式路由類項目)
const listFile = (dir: string) => {
const arr = fs.readdirSync(dir)
arr.forEach((item: string) => {
const fullpath = path.join(dir, item)
const stats = fs.statSync(fullpath)
if (stats.isDirectory()) {
listFile(fullpath)
} else {
list.push(fullpath)
}
})
return list
}
// 項目已訪問過路由列表,移除固定路由前綴
const projectVisitedPathList = data.map(item => item.uri.slice('/project_prefix'.length))
// 項目全量路由列表
const projectPath = '/your-project-path/src/pages'
const projectPathList = listFile(projectPath)
const startLen = projectPath.length
const indexEndString = '/index.vue'
const allPathList = projectPathList.map(item => {
if (item.endsWith('.vue')) {
if (item.endsWith(indexEndString)) {
// 移除前綴目錄與 /index.vue 後綴
return item.slice(startLen, -indexEndString.length)
}
// 移除前綴目錄與 .vue 後綴
return item.slice(startLen, -4)
}
}).filter(item => !!item)
// 將全量目錄路由列表與已訪問路由列表進行過濾,產出未訪問路由
const unVisitedList = allPathList.filter(item => !projectVisitedPathList.includes(item))
// 未訪問路由補充固定域名前綴並寫入新文件內
fs.writeFileSync('unVisitedList.json', JSON.stringify(unVisitedList.map(item => 'https://xxx.com/project_prefix' + item)))
附查詢 SQL
:
SELECT
uri,
SUM("count") as "total"
FROM
xxx
WHERE
"__time" >= @start
and "__time" <= @end
and type = '4' // 4 表示 pv 類型
and appId = @appId
GROUP BY
uri
ORDER BY
"total" DESC
無訪問接口#
同樣通過 Druid SQL
查詢近三個月前端接口訪問記錄,對比項目中接口路由配置產出未訪問歷史接口,並結合後端服務接口日誌確認後刪除,查詢 SQL
基本同上。
刪除無用 Store
#
結合路由刪除結果在項目內搜索排查對應 Store
是否還在使用:state
、getters
、mutations
、actions
,均未使用時可刪除。
刪除無用線上配置#
結合路由與 Store
刪除結果排查相關線上配置是否還在使用,未使用時可刪除。
刪除無使用模塊及變量#
未使用文件 / 變量檢測工具對比:
工具 | 原理 | 主要作用 | 備註 |
---|---|---|---|
webpack-deadcode-plugin | 使用 webpack 生成的 stats 文件,通過 webpack 編譯源文件時,生成的包含有關於模塊的統計數據的 JSON 文件 這些統計數據不僅可以幫助開發者來分析應用的依賴圖表,還可以優化編譯的速度 | 基於 webpack 構建簡單分析,掃描結果包括未使用文件與未使用變量 | 結果較準確,覆蓋面廣,推薦使用 產出分析文件後作為參考,再手動確認刪除(當前文件內有使用但導出未使用時會誤報) |
useless-files-webpack-plugin | 同上 | 基於 webpack 構建簡單分析,主要是文件是否未使用,可以配置自動刪除 | 檢測邏輯相似,功能不如前者 |
find-unused-exports | 基於 babel 和 postcss 查找項目中的無用模塊 | 單純 js 實現的基於文件依賴進行分析的包 | 與第一項可結合分析 |
ts-prune | TypeScript 服務提供了一個實用的 API:findAllReferences ts-morph 這個庫封裝了包括 findAllReferences 在內的一些底層 API,提供更加簡潔易用的調用方式 ts-prune 就是基於 ts-morph 封裝而成 | 可以分析文件中導出的變量是否有被使用 | 功能不如前者,測試後在全量導出、vue 文件引入等情況下干擾度大 不建議使用(後續代碼編寫也應盡量避免全量導出寫法) |
- 刪除無用頁面後,使用 webpack-deadcode-plugin 工具檢測掃描 + 手動確認後刪除(注:新增一條
npm script
命令用於後續持續性分析優化) - 開啟未使用變量檢測提示,配合 VS Code 插件提示輔助刪除
- 開啟
eslint
規則檢測js/ts/vue
文件,針對未使用變量提交時強報錯提示
注:官方針對{ "rules": { "@typescript-eslint/no-unused-vars": [ "error", { "argsIgnorePattern": "^_" } ], } }
no-unused-vars
規則不支持自動修復,需要手動修改- 開啟
tsc
編譯配置校驗未使用變量與未使用函數參數
{ "noUnusedLocals": true, "noUnusedParameters": true }
- 手動修改建議優先參考 VS Code 提示,注意以下情況:
- 未使用函數參數不在末尾時不能直接刪除,使用 _ 前綴約定
- 存在擴展參數解構時,不能直接刪除未使用變量導致副作用產生,需要針對特定行禁用語法(同 VS Code 提示)
- 調用函數返回值聲明未使用時 VS Code 提示會刪除整段聲明 + 調用,這裡只刪除聲明即可
- service 方法中參數未使用時如 controller 未傳入可直接刪除,否則使用 _ 前綴約定
- 開啟
監控報警配置#
通用類錯誤使用埋點 SDK 錯誤插件已上報,上線前需要調整觀察至一個穩定幅度,避免後續干擾
空路由 / 接口訪問需要新增採集邏輯:
- 空路由:404 訪問頁面展示,上報錯誤埋點,同時可與產品溝通導流邏輯。
- 空接口:服務端新增
Express
Router 兜底匹配上報錯誤日誌。- 上報邏輯
controller.on('mounted', () => { resolve(void 0) // 確保所有路由掛載完成後再處理 setImmediate(() => { app.all('/api/*', function (req: any, res: any) { routeLog.error('route_empty_error', { pathname: req.path, http_method: req.method, referer: req.headers.referer }) res.status(404).json() }) }) })
- 上報邏輯
報警配置
模塊 | 功能 | 報警策略(結合項目實際情況) |
---|---|---|
Vue Error | Vue 全局錯誤捕獲 | xx mins 突增 xxx |
ReferenceError | 引用錯誤 | xx mins 突增 xxx |
TypeError | 類型錯誤 | xx mins 突增 xxx |
空路由訪問 | 訪問空路由埋點上報 | xx mins 出現 xx 次 |
空接口訪問 | 訪問空接口日誌採集上報 | xx mins 出現 xx 次 |
驗證上線#
在預發驗證相應監控報警配置無誤後,先上線一台機器觀察 3 - 5 天正常後完成上線。