前端工程化詳解 & 包管理工具
- 前端工程化
- 什么是前端工程化
- 前端工程化發展
- 腳手架能力
- 體驗度量
- 規范流程
- 效能流程扭轉
- 穩定性建設
- 針對整體穩定性建設
- 可監控:
- 前端監控系統
- 包管理工具
- npm包詳解
- package.json
- name 模塊名
- description 模塊描述信息
- keywords:關鍵詞
- homepage:模塊首頁
- repository:git倉庫地址
- private 私有化
- version 包版本
- 依賴配置
- 目錄 & 文件項目
- script 腳本命令
- 依賴版本管理
- 版本約束文件 package-lock.json
- npm install 原理
- pnpm
- 怎么做到節省空間,提高安裝速度的?
- multirepo vs monorepo
- 工程化體系
- 腳手架能力
- 體驗度量
- 規范流程
- npm package.json 解析
- 包管理工具 pnpm等
不要僅僅只是局限于開發一個需求,而是要站在宏觀的角度上看整個技術體系,對技術領域有全方位的認識。
工程化體系的演進,以及演進過程中做的什么事情,現有鏈路是否在工作流中存在,如果沒有的話,自己嘗試將工程鏈路進行搭建。
前端工程化
什么是前端工程化
前端工程化 = 前端 + 軟件工程
軟件工程:系統和軟件工程層面上的方法、規范,技術手段提升開發的效率,軟件工程來自于實體行業類似建筑行業的方法論,將建筑行業的方法論運用到軟件領域上,軟件領域的相關方法論又延伸到前端上
前端工程化 = 將工程化的方法系統化應用到前端開發中
Clean Code 代碼整潔指導
基于業務訴求 => 產出架構設計 又快又好又穩 <= 系統 演進 可量化的方法
前端工程化發展
- 前后端不分離,服務端渲染前端頁面,jsp,php內嵌前端邏輯
- 前后端分離:B/S架構
- 模塊化:AMD,CMD,CommonJS,esmodule格式化規范工程+vite 開發
模塊化 vite
(1)規范化 AMD CMD
(2)組件化 => 組件庫 elementUI,ant design - 自動化:解決之前人工重復干預的事情,自動化構建使得體積非常的小,可以管理,簡化開發過程。 前端框架自動化,構建系統 應運而生
基于自動化做的最佳實踐:
開箱即用的框架,vite create-vite,不需要進行額外的配置,就可以在當前的工程中進行開發,無需從零到一進行整個項目的搭建。但是不能只停留在使用層面,需要了解其中的原理,消化吸收變成自己的。
達到的目標:好 快 穩
vite在開發環境設計思路巧妙,與傳統打包工具是不太一樣的,有了vite后,基于程序構建,按需引入就是秒級的開發體驗,無論當前工程多么龐大,都與當前是無關的,當前需要哪個文件,才會及時進行編譯處理,不會走構建的過程,是no-bundle的思想,內部的很多設計思路都是比較巧妙的
比如,預構建,怎么去進行預構建,需要進行模塊的轉換,像怎么把commonJS模塊轉為esModule模塊,
因為esModule模塊才能被瀏覽器所引入,解析執行import的邏輯,相關模塊進行預編譯處理,用到esbuild,
esbuild使用 go 語言來處理,能夠多線程的對當前的文件進行打包處理,
所以現在,不要僅僅局限于前端相關語言開發工程化,還要嘗試使用不同語言,rest,go語言,使用這些語言開發的工具,都可以被前端所使用。
構建工具使用其他語言來處理了
=>JS:高級語言,要處理成機器所能識別的語言,需要各種各樣的轉化
高級語言使用babel-loader進行轉化的化,需要經歷 ast 的轉換,經歷詞法分析,語法分析,代碼轉換為語法樹,將語法樹進行修改調整,修改調整轉換成代碼的過程,需要頻繁的經歷轉義,是比較耗時的,性能比較差的
如果再加上其他語言進行并行處理的話,效率是比較高的,就像 swc-loader 平替 babel-loader
其他語言加上提高效率 swc-loader => babel-loader
前端市場逐漸趨于飽和,從熱門到穩定的階段
并沒有大的變動
當下能做的,生成自己的開發工程的最佳實踐
腳手架能力
場景:非常多的系統,集成到同一個portal當中
技術體系:微前端 => 進行系統架構升級
主子應用
可以主子應用各自的技術體系
=> 形成自己的腳手架
=> 1. 封裝一個子應用模板,需要引入組件庫,來保證視覺的風格統一;引入編碼規范,保證代碼風格統一;子應用中需要適配微前端體系
=> 2. 通過自己的腳手架拉取這樣的模板,xxx create 拉取模板
業務項目生成周期的幾個階段:
-
準備階段
技術選型
代碼規范的制定
(1)分支管理規范 git workflow
(2)項目初始化規范
(3)lint規范
集成到腳手架當中做處理,無需去關注統一的,又比較繁瑣的這樣的內容 -
生態規范:UI庫 物料規范等
-
三方規范
(1) npm 發包
(2)github,需要遵循 ci cd 等規范 -
開發階段
(1)規范落地
(2)開發 打包流程
(3)本地 mock 服務
(4)代碼質量管控
(5)單元測試,E2E測試
這些都是在開發階段可以集成的點 -
發布流程
(1)git commitlint
(2)changlog 規范
(3)部署 驗收
業務項目生成周期:
MRD(市場層面調研最終產生的結果)=> PRD(產品方案的評審) =>進入上述所說的階段
體驗度量
=> 簡歷中 最好體現性能優化策略
用戶體驗:定義指標,衡量系統好不好
定性:問卷
定量
=> 舉例:度量 京東的首頁 性能
- 關注指標:FCP(首屏加載時間),LCP(最大內容加載時間) ,TTFB(首字節時間)
TTFB:在ssr渲染時,客戶端發起請求到服務端響應數據這樣一個過程的時間,用來衡量網絡消耗的
性能相關網站
LCP:對指標的衡量,性能優化的提升,怎么做才能有更好的體驗
-
收集數據:performance api 上報階段數據,不能以本機(手機,電腦)這種樣本量比較少的去分析數據
從瀏覽器中輸入url,到最終界面load,經歷如下幾個階段:
DNS解析,TCP的建聯,請求的時間,響應的時間,頁面加載渲染的時間,最終load完成
比如,針對計算DNS時間,domainLoopupEnd - domainLoopupStart,在每個階段打相關點,收集到對應的數據進行上報,記錄當前用戶這次訪問所消耗的,這樣的話,這些數據才是 可信賴 的。
策略優化,比如,針對webpack的優化措施,針對網絡請求的優化措施,針對圖片處理相關的優化措施等。
數據效果:
衡量指標 — 不能用平均數據來看
性能水位分為100位,看95%的那個人
P95 LCP 4.0s 提升到了 2.4s => 才有可信度
P99 -
體驗度量設計
要解決的問題:無行為埋點,埋點數據的上報,針對度量數據完善數據指標,各個階段進行上報,建立度量體系
規范流程
效能流程扭轉
針對這樣的一個平臺,就能關注到團隊規模層面下需求層面一個產品的健康度,團隊成員代碼健康度等。
穩定性建設
前端的幾把斧子:性能,穩定性,研發效率,質量
每個階段都不能忽視
關注的幾個點:
- 可預防
- 可監控
- 可回滾
針對整體穩定性建設
發布前防控
- 基礎建設
團隊機制:編碼規范 故障規范 日志規范,p0,p1,p2,p3
穩定性工具:CLI,Snippet,物料市場 - 研發態能力建設
迭代質量:依賴監測,測試用例,數據聚合
源碼架構:模塊化,容器化,狀態管控
攻防演練:故障演練,壓測演練,CR注入
全域容災:容災策略,容災演練,容災預警
發布后監控:
- 研發態能力建設
監控預警:腳本異常,接口異常,資源異常
監控大盤:數據大盤,監控排名,預警配置
行為監控:行為上報,sourcemap,行為可視化
線上工具:健康報告,定義指標看板,錯誤定位
可監控:
前端監控系統
要關注的幾個點:
- 異常捕獲 收集異常(腳本,資源,接口)相關內容,監聽 onError,promise事件來捕獲
- 數據上報,通過gif圖像方式避免跨域的問題
- 針對數據采集,每個階段需要打上標
- 數據清洗
- 數據持久化
- 數據可視化
包管理工具
npm包詳解
package.json
{"name": "demo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","dependencies":{"antd":"ant-design/ant-design#4.0.0-alpha.8","axios": "^1.2.0","test-js":"file:../test", // npm link"test2-js":"http://cdn*sSom/test2-js.tar.gz","core-js":"^1.1.5"},"devDependencies": {"eslint": "^5.16.0","eslint-config-airbnb-base": "^13.2.0","eslint-plugin-import": "^2.17.3"},"peerDependencies": {"react":">=16.8.0"},"optionalDependencies":{},"bundledDependencies": ["package1","package2"]
}
name 模塊名
name:模塊名,需要遵循官方的建議和規范
成為整個模塊的url,命令行參數和文件夾相關的名稱
在空間下要發模塊的話,需要使用@符,像 @abc/def 避免命名重復,類似,作用域命名@babel/cli
查看當前包名是否被占用
npm view xxx(包名)
輸出 404 說明沒有被占用
npm search xxx 查看包內容
通過正則的方式,返回最匹配的包,以及其他相似的包
npm search xxx --json
通過json的方式返回
description 模塊描述信息
description:模塊描述信息
keywords:關鍵詞
有利于模塊的檢索
homepage:模塊首頁
repository:git倉庫地址
private 私有化
"private": true
意味著當前包不能發到 npm 上,對應著version也沒有效果
version 包版本
查看最新版本數據 – 用的較多
npm view xxx version
返回所有版本數據
npm view xxx versions
遵循 semver
規范
-
發布版本:
x.y.z
x— major 主版本,做了不兼容api修改
y — minor 次版本號,向下兼容,功能性新增
z — patch 修訂號,向下兼容,問題修正 -
先行版本:
alpha 內部版
beta 內測版
rc 公測版
像 1.0.0-beta.0
升級修訂號
npm version patch
升級次版本號
npm version minor
升級主版本號
npm version major
比較版本號大小
npm install semver
做版本校驗的話,安裝 semver 版本包
npm install semver
比較版本號大小,使用semver來比較
依賴配置
-
dependencies 項目運行時所依賴的模板
- react:^16.8.6
- react-dom:^16.8.6
-
devDependencies 只在開發環境使用
eslint jest,線上是不需要的 -
peerDependencies 基礎庫(很少用),類庫,像 antd 限制 react 版本,用react-hook,需要使用16.8.0版本后的版本,那么就可以寫成:
業務項目依賴 demo 安裝react 16.8.0以后的版本"peerDependencies": {"react":">=16.8.0"},
-
optionalDependencies 可選擇的依賴,可有可無的(很少用)
需要注意的是:optionalDependencies中的配置會覆蓋 dependencies 中的配置
那么需要放在optionalDependencies的配置,就不用放在 dependencies 配置中了,只需要配置一個地方即可 -
bundledDependencies 數組,這些模塊將在這個包發布的時候,會一起打包
"bundledDependencies": ["package1","package2"]
目錄 & 文件項目
"main": "index.js",
- main:程序入口的主文件、
import {xxx} from ‘demo’ - bin 命令行工具入口
像 @babel/cli 中的bin目錄
"bin": {"babel": "./bin/babel.js","babel-external-helpers": "./bin/babel-external-helpers.js"},
執行 babel 命令時候,就執行的是 bin 目錄下的 babel.js 這個文件內容
- 發布配置
files數組中的內容,推送到服務器
"files":["/dist","/assets","/schema.json","Readme.md"],
npm publish
最終代碼目錄內容:
script 腳本命令
- test:測試腳本
- dev
- build
- publish: pnpm run dev && npm run build 命令組合
"scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev": "pnpm run dev","build": "pnpm run build:fast","publish": "pnpm run dev && npm run build"},
依賴版本管理
- “signale”: “1.4.0”: 固定版本號;
- “figlet”: “*”: 任意版本(>=0.0.0);
- “react”: “16.x”: 匹配主要版本(>=16.0.0 <17.0.0);
- “react”: “16.3.x”: 匹配主要版本和次要版本(>=16.3.0 <16.4.0);
-
~
~ x.y.z 安裝到patch(z)的最新版本
比如,~16.3.4,安裝了16.3.4,下次如果patch的最新是10的話,就安裝到 16.3.10 版本,不能安裝到 16.4.x 這個版本 -
^
^x.y.z:保證主版本不變的情況
下,保持次版本,修訂版本
是最新
版本。
比如:"react-dom":"^16.8.6"
要求,小于17.0.0,大于等于16.8.6等等
大于等于x.y.z版本,小于最新版本
版本約束文件 package-lock.json
生成lock文件進行版本約束,鎖定版本內容
不管什么時候去安裝,只要不去進行人為進行修改,那么所依賴的版本號都是固定的
npm install 原理
早期npm版本(npm 2.x),是通過遞歸
的方式進行包的安裝的
npm 3.x,將早期的嵌套結構改為扁平結構
扁平結構還可能碰到幽靈依賴的情況:
例如,顯示引入了 buffer,但是 buffer 又依賴了下面兩個模塊:base64-js 、 ieee754。
扁平結構使得 base64-js 、 ieee754 這兩個的目錄結構變成這樣:
這時候,文件中這樣寫:
import xx from ‘base64-js’;
但是沒有顯示的引入 base64-js依賴,但是可以去使用,這樣的情況就叫做 幽靈依賴
這樣是有問題的
以后 buffer 不依賴 base64-js這個了,那么my-app安裝時候就沒有base64-js了,那么就不能使用base64-js了
解決方案:使用 pnpm
pnpm
performance npm - 高性能的 npm
速度很快 節省磁盤空間的包管理工具
節省空間 提高安裝速度
npm的問題:隨著時間的堆積,整個工程的體積會非常非常大,因為內部會重復包的情況
像這樣:
怎么做到節省空間,提高安裝速度的?
resolved 處理了 1193 個包,
reused 復用了 1138個包,
downloaded 重新下載了 1個包,
added 0, done
這是由于:
pnpm不是安裝到當前目錄下的,是安裝對應系統的全局目錄下面,可以讓包進行復用
查看全局目錄下的內容
pnpm store path
全局環境 每個項目都是獨立的
利用 軟鏈接(符號鏈接)
硬鏈接
來處理
- 顯示的依賴,安裝到node_modules下面
- 間接依賴 安裝到 .pnpm 目錄下 => 解決幽靈依賴問題,無法跨越層級訪問其他包的依賴,只能找當前層級下的內容 無法跨越層級訪問其他包的依賴
- 符號鏈接(軟鏈接) 相當于快捷方式,更快的訪問路徑
這里通過軟鏈接
的方式,鏈接的是 .pnpm 目錄下的這個包,以 eslint-config-prettier 為例:
而這里 鏈接的是 pnpm store下的對應文件,通過硬鏈接
的方式
整個過程:
這也就是pnpm為什么快,并且體積小的原因,也解決了多版本的問題
multirepo vs monorepo
multirepo 傳統的方式,單獨的倉庫,彼此互不影響
monorepo 嚴格統一 多個項目放到一個倉庫里面處理,適用于 底層類庫,基礎庫,多個項目放到一個倉庫里去管理,方便統一管理
像babel,vite,react,vue,都是通過monorepo,將相似的包都放在一個倉庫當中,便于整體維護
每個包都是單獨的npm模塊,都可以單獨發包
在package.json入口層面上,可以統一管理相關的打包,發布,部署