前端工程化

編譯
工程化是一個(gè)編譯和打包的過程。
首先,什么是編譯?
舉個(gè)例子,當(dāng)我們需要執(zhí)行一個(gè)java文件。
在前端工程化以前,作為一門解釋型語言,JavaScript是不需要像Java這樣經(jīng)過編譯這個(gè)過程,它可以在瀏覽器中直接運(yùn)行。
那么,為什么現(xiàn)在不這么做了?
瀏覽器兼容性問題
開發(fā)人員編寫的不再是純粹的JavaScript
解釋第一點(diǎn):
事實(shí)上,JS的版本每年都在升級(jí),tc39每年都會(huì)收集意見稿對(duì)JS標(biāo)準(zhǔn)做出一些改動(dòng),增加一些特性,刪除一些特性,其中最著名的版本就是ES2015(ES6)。
但JS的迭代跟Java的迭代不同,這個(gè)過程并不由開發(fā)者決定。
在Java中,只要開發(fā)者不主動(dòng)升級(jí)JDK,那么Java新版本的改動(dòng)就不會(huì)影響到開發(fā)者的代碼,代碼的運(yùn)行結(jié)果也始終不會(huì)脫離期望。
但在JS中,這個(gè)過程由瀏覽器廠商和用戶決定,開發(fā)者并不能知道自己的代碼會(huì)被作為什么版本的JS來執(zhí)行。
假如,開發(fā)者為了方便開發(fā),在自己的代碼中使用了ES2022的新特性,但用戶使用的是廠商在2020年發(fā)布的瀏覽器,那么,你費(fèi)盡心血編寫的代碼,將不能得到所期望的結(jié)果。
而且,瀏覽器廠家并不是只有Google,瀏覽器內(nèi)核也并不是只有blink,不同內(nèi)核,甚至相同內(nèi)核不同版本的瀏覽器對(duì)JavaScript的執(zhí)行能力也不一致。
我們需要一個(gè)工具,來將兼容性不那么良好的高版本JS,編譯成兼容性相對(duì)更加優(yōu)秀的低版本JS。
這樣的話,即可以在開發(fā)中使用新特性來簡(jiǎn)化開發(fā),也能確保在低版本瀏覽器中能夠被正確地執(zhí)行。
它就是babel。
解釋第二點(diǎn):
所有的網(wǎng)頁歸根結(jié)底由HTML(結(jié)構(gòu))、CSS(樣式)、JS(交互)組成。
但直接編寫上述三種文件來滿足現(xiàn)代網(wǎng)頁的開發(fā)需求是難以實(shí)現(xiàn)的,主要問題在于:
現(xiàn)代網(wǎng)頁結(jié)構(gòu)異常復(fù)雜,動(dòng)則成千上萬個(gè)dom,難以拆分
樣式表命名空間復(fù)雜,權(quán)限比重不清
操作dom的api并不是那么易于使用,且弱類型的JS難以維護(hù)
為了解決上述問題才有了React、Vue、Angluar、Svelet、Solid等前端框架。而這些框架為了解決上述問題提出了自己的代碼格式:react的jsx、vue的sfc,它們是JS又不是JS。
為了解決JS弱類型難以維護(hù)的問題,Microsoft提出了TypeScript,同樣的,.ts是JS又不是JS。
目錄結(jié)構(gòu)
為了在不同框架下保持統(tǒng)一,前端項(xiàng)目在目錄結(jié)構(gòu)上有一些不成文的約定
根目錄下:
public目錄,這個(gè)目錄中的文件會(huì)保持原樣輸出到打包好的代碼中
dist目錄,打包好的代碼默認(rèn)輸出到這個(gè)目錄出,若不存在則構(gòu)建工具會(huì)自動(dòng)生成它
src目錄,所有源代碼(除index.html外),都應(yīng)該存放在此目錄中
src目錄下:
assets目錄,存放圖片、字體、樣式表等網(wǎng)頁需要引用的靜態(tài)資源。注意,資源雖然是靜態(tài)的,但仍會(huì)在打包過程中被編譯,構(gòu)建工具會(huì)使用一段hash重命名這些資源,資源的路徑也會(huì)被改變。
api目錄,存放發(fā)送網(wǎng)絡(luò)請(qǐng)求相關(guān)代碼,比如封裝axios,react-query部分的代碼。
components目錄:存放公共組件,多次被引用才算公共組件,只被一個(gè)位置引用的組件不應(yīng)該出現(xiàn)在這里
hooks目錄:存放公共hook。注意,hook對(duì)項(xiàng)目框架是有依賴的,并不能跨平臺(tái)使用。
pages目錄:存放網(wǎng)頁代碼,每個(gè)網(wǎng)頁都應(yīng)該是一個(gè)目錄。
routes目錄:存放路由表,及路由配置代碼。
stores目錄:存放全局狀態(tài)機(jī),比如pinia、redux相關(guān)代碼。
types目錄:存放.d.ts聲明文件。
utils目錄:存放公共函數(shù),不同于公共hook。公共函數(shù)不對(duì)框架有依賴,這部分代碼應(yīng)當(dāng)是跨平臺(tái)的。
入口文件:整個(gè)應(yīng)用程序的入口文件
根組件:框架的根節(jié)點(diǎn)
路徑別名
在引入一個(gè)自定義模塊,或是使用靜態(tài)資源文件的時(shí)候,都會(huì)需要使用到路徑。
引用資源時(shí),相對(duì)路徑不應(yīng)當(dāng)被濫用。如下:
使用路徑別名,改變上面這種丑陋的引用方式。
有些構(gòu)建工具默認(rèn)配置了上述約定,而有些則需要手動(dòng)配置。
配置路徑別名(vite舉例)
打包
正如前面提到的,所有的網(wǎng)頁最終給到用戶的一定是HTML、CSS、JS。
構(gòu)建工具會(huì)將我們編寫好的.ts、.tsx、.jsx、.vue、.scss、.less等文件編譯成.js和.css。
需要注意:
有些打包工具會(huì)將有引用關(guān)系的模塊直接編譯為單個(gè).js。這往往會(huì)造成編譯出的.js過大,從而影響用戶打開網(wǎng)頁的速度。
對(duì)于體積較大的npm包,最好在打包時(shí)進(jìn)行分包。
必要時(shí)可以打包生成gzip,用以提高網(wǎng)頁的加載速度。(需要nginx開啟支持)