從零搭建項(xiàng)目(7) --- 前端: 打包與環(huán)境變量設(shè)置

我的博客地址

正式地址
測(cè)試地址
前端源碼
后端源碼

文章目錄

  1. 項(xiàng)目及其技術(shù)棧介紹
  2. 前端: 項(xiàng)目初始化
  3. 前端: 使用Sass和Antd
  4. 前端: 開發(fā)體驗(yàn)優(yōu)化
  5. 前端: 搭建路由和狀態(tài)管理
  6. 前端: 支持Axios
  7. 前端: 打包與環(huán)境變量設(shè)置
  8. 前端: 團(tuán)隊(duì)代碼規(guī)范
  9. 后端: 項(xiàng)目初始化和使用Koa相關(guān)
  10. 后端: 使用TypeORM和MySQL
  11. 部署: 使用nginx部署前端項(xiàng)目
  12. 部署: 后端部署
  13. 部署: 使用jenkins自動(dòng)化部署

前言

在前端開發(fā)完成后,都需要將編寫的代碼編譯打包成靜態(tài)文件,之后才會(huì)部署到服務(wù)器上,而WebPack就是這樣一個(gè)打包工具,它所有的loader、plugin都是圍繞這一個(gè)功能進(jìn)行的擴(kuò)展,這篇文章就在之前搭建的基礎(chǔ)上來(lái)介紹一下WebPack的打包配置吧,所用到的知識(shí)點(diǎn)如下:

  1. 打包路徑和命令添加
  2. filenamechunkFilename: hashchunkhashcontenthash
  3. publicPath
  4. 單獨(dú)打包CSS
  5. optimization優(yōu)化打包
  6. 環(huán)境變量設(shè)置區(qū)分生產(chǎn)開發(fā)環(huán)境

打包路徑和命令添加

  • 添加打包路徑
    其實(shí)在開始介紹前端搭建的第一篇文章中我們就已經(jīng)將打包的入口和出口都在webpack.config.js中制定好了:

    image.png

    這段配置意思是讓W(xué)ebPack通過src/index.tsx作為入口,遞歸地建立模塊依賴關(guān)系,然后打包輸出模塊,模塊輸出后存放在根目錄的dist文件夾中

  • 添加打包命令
    去到package.json加上如下命令:

    image.png

  • 測(cè)試打包
    我們運(yùn)行npm run build之后可以看到包已經(jīng)打好了:

    image.png

filename和chunkFilename

webpackoutput配置中,filename是打包文件名,也就是說(shuō)我們列在entry中的文件打包出來(lái)的名字,在本例中就是app:

image.png

chunkFilename則是未列在entry中的模塊文件,下面劃紅線的都屬于chunk file:
image.png

filenamechunkFilename則是對(duì)這兩種文件命名的設(shè)定,這個(gè)命名很重要嗎?
是的,因?yàn)闉g覽器存在緩存問題,如果按照目前配置,每一次代碼變化的情況下打包出來(lái)的文件名不變,瀏覽器優(yōu)先加載緩存中的文件,然后導(dǎo)致頁(yè)面沒有展示最新的頁(yè)面情況。

  • 要解決這個(gè)問題我們先把chunkFilename設(shè)置好:

    image.png

  • 然后可以通過給文件名設(shè)置hash值的方式保證每次打包的文件名都是不同的,filenamechunkFilename都支持該設(shè)置:

    image.png

  • 另外這個(gè)hash值的設(shè)置有三種: 分別是hashchunkhashcontenthash

    1. hash: hash和整個(gè)項(xiàng)目的配置有關(guān),只要項(xiàng)目中有代碼改變,那么所有打包出來(lái)的hash值都會(huì)變,并且所有文件共用一個(gè)hash值
    2. chunkhash: chunkhashhash不同點(diǎn)在于,它根據(jù)入口文件進(jìn)行依賴文件解析,然后構(gòu)建對(duì)應(yīng)的hash值,也就是每個(gè)打包出來(lái)的文件hash值都是不一樣的,每次修改代碼時(shí)候,他會(huì)根據(jù)依賴關(guān)系自動(dòng)修改相關(guān)模塊的hash值,但是打包出來(lái)對(duì)應(yīng)的js和css文件的hash會(huì)相同。
    3. contenthash: 在打包代碼的時(shí)候,一般會(huì)將CSS文件分離出來(lái),然后我們通常會(huì)在組件中引入CSS文件,這時(shí)候如果使用的是chunkhash,在只修改組件js代碼的情況下因?yàn)閷?duì)應(yīng)的css文件的hash值相同,打包出來(lái)的css文件的hash值也會(huì)跟著變,這時(shí)候就可以使用contenthash了,他會(huì)針對(duì)每個(gè)文件的內(nèi)容來(lái)計(jì)算hash值。

在本例中,我們就使用chunkhash即可,CSS的contenthash可以在后面對(duì)css文件進(jìn)行分離的時(shí)候再配置。

publicPath

publicPath也是ouput中的一個(gè)屬性,用于處理打包后的引入資源路徑,比如上面我沒有添加publicPath的時(shí)候,打包出來(lái)的index.html引入資源的路徑:

image.png

現(xiàn)在我把publicPath設(shè)置為/,再來(lái)看看打包出來(lái)的index.html的引入資源路徑就成了絕對(duì)路徑了:
image.png

image.png

那么這個(gè)配置有什么用處呢?

  • 用處
    在我們對(duì)前端項(xiàng)目打包完畢之后,js和css等較大的靜態(tài)資源都會(huì)被上傳到cdn上面,而index.html則會(huì)留在我們自己的服務(wù)器上,用戶訪問index.html的時(shí)候,index.html加載的css和js路徑就應(yīng)該是cdn域名上的資源,也就是說(shuō)假設(shè)我的cdn域名為https://cdn.xxx.com/,那么這串東西就應(yīng)在放到publicPath中讓他自己在資源引入的前面加上,比如下面的例子:
    image.png

    image.png

單獨(dú)打包CSS

在前面的打包配置中,我們雖然可以打包成功,但是這時(shí)候的css是被嵌入到j(luò)s文件中的:


image.png

這對(duì)于模塊化來(lái)說(shuō)不大好,而且還會(huì)導(dǎo)致js文件變得更大從而降低網(wǎng)頁(yè)加載速度,所以需要將css額外抽離出來(lái)。

  • 使用mini-css-extract-plugin抽離css
    在webpack4.0后,推薦使用mini-css-extract-plugin來(lái)對(duì)css文件進(jìn)行分離,首先我們需要安裝mini-css-extract-plugin包,這個(gè)包里面包含一個(gè)loader和一個(gè)plugin,后續(xù)需要分別進(jìn)行配置
    npm i -D mini-css-extract-plugin

  • 配置loader
    接下來(lái)我們?nèi)サ?code>build/rules/styleRules.js文件中引入他:

    image.png

    在這里需要注意一點(diǎn):
    sass-loader是將sass文件編譯為css,而css-loader是將css轉(zhuǎn)為CommonJS模塊,style-loader是將對(duì)應(yīng)的JS生成為style 節(jié)點(diǎn),那么如果我們要分離css文件的話,應(yīng)該是在css-loader之后進(jìn)行,所以下面我們把之前style-loader的地方全都替換成MiniCssExtractPlugin:
    image.png

  • 配置plugin
    然后去到build/plugins.js文件中,引入并使用mini-css-extract-plugin并使用,配置主要是filenamechunkFilename:

    image.png

    注意這里需要用contenthash而不是chunkhash,否則打包出來(lái)的和引用該css的js文件的hash值是一樣的,而且改css還會(huì)導(dǎo)致打包后的js文件的hash值產(chǎn)生變化。

  • 打包結(jié)果
    可以看到css文件已經(jīng)被抽離了出來(lái),并且js和css文件的hash值是不一樣的:


    image.png

使用optimization優(yōu)化打包

在上面的打包配置中,因?yàn)橹白隽寺酚山M件的代碼分割,所以組件PageAPageB會(huì)被單獨(dú)打包成js文件,再來(lái)看看打包的情況表,會(huì)發(fā)現(xiàn)page-a的公用模塊(引入的庫(kù))體積高達(dá)800多k,這對(duì)于網(wǎng)頁(yè)加載資源而言是非常大的:

image.png

我們可以通過配置WebPack的optimization來(lái)對(duì)代碼進(jìn)一步分割,使得打出來(lái)的包更小。

  • 首先我們?nèi)サ?code>build文件夾下新建文件optimization.js,新建并導(dǎo)出一個(gè)對(duì)象:

    image.png

    然后配置runtimeChunk:
    image.png

    runtime是指webpack運(yùn)行環(huán)境(模塊解析和加載)和模塊信息清單,而runtimeChunk就是詢問該清部分清單代碼是否單獨(dú)打包出來(lái),我們這里將其單獨(dú)打包出來(lái)并命名為manifest

  • 然后我們通過配置splitChunkcacheGroups將一些公共模塊分離出來(lái)打包:

    image.png

    這里面的priority是優(yōu)先級(jí)的意思,數(shù)字越大優(yōu)先級(jí)越高,antd依賴moment,所以moment優(yōu)先級(jí)比antd高,然后commons是剩余模塊統(tǒng)一打包不做分割了。

  • 接下來(lái)我們把optimization導(dǎo)入到webpack中去使用:

    image.png

    然后查看一下打包結(jié)果:
    image.png

    可以清楚的看到之前vendor~page-a文件從發(fā)800多k變成了500多k,另外還多出來(lái)一個(gè)vendor文件有270多k,說(shuō)明是可以顯著減少打包出來(lái)的文件的大小的。
    如果還需要繼續(xù)細(xì)分,可以繼續(xù)在splitChunks.cacheGroups配置中將公用模塊繼續(xù)細(xì)分并添加進(jìn)去,使得打包的代碼越來(lái)越小

  • 壓縮js優(yōu)化和壓縮css代碼并優(yōu)化

    1. 使用terser-webpack-plugin優(yōu)化js壓縮過程:
      terser-webpack-plugin是一個(gè)js代碼優(yōu)化插件,他可以使用多線程和緩存更快的壓縮js代碼,優(yōu)化打包體驗(yàn),并且使用非常簡(jiǎn)單。
      為什么使用這個(gè)插件呢?因?yàn)閣ebpack默認(rèn)使用的webpack.optimize.UglifyJsPlugin插件是不支持es6語(yǔ)法的,當(dāng)然你可以先用babel轉(zhuǎn)一下再用UglifyJsPlugin也沒所謂。
      首先我們安裝npm i -D terser-webpack-plugin
      然后在build/optimization.js文件中配置minimizer,導(dǎo)入terser-webpack-plugin并使用即可:

      image.png

    2. 壓縮css代碼并優(yōu)化壓縮過程
      在之前的打包中,我們的js代碼雖然已經(jīng)經(jīng)過了壓縮,但是css代碼還沒有壓縮:

      image.png

      這時(shí)候我們需要使用optimize-css-assets-webpack-plugin來(lái)做這件事。
      首先安裝它npm i -D optimize-css-assets-webpack-plugin
      然后繼續(xù)在minimizer中進(jìn)行配置:
      image.png

最后我們重新打包來(lái)看看結(jié)果:


image.png

可以看到css文件也被壓縮了。

環(huán)境變量設(shè)置區(qū)分生產(chǎn)開發(fā)環(huán)境

在webpack4.0之后,打包的時(shí)候會(huì)出現(xiàn)這個(gè)警告:

image.png

這是因?yàn)樵?.0后webpack受到parcel的競(jìng)爭(zhēng),而parcel就是號(hào)稱0配置的打包器,所以webpack也內(nèi)置了一套默認(rèn)的打包配置,但是開發(fā)環(huán)境和生產(chǎn)環(huán)境的配置是不一樣的,所以需要通過配置webpack.mode屬性來(lái)告訴webpack處于什么環(huán)境,另外開發(fā)環(huán)境和生產(chǎn)環(huán)境有些不一樣,例如生產(chǎn)環(huán)境一般不需要sourcemap功能,之前打包出來(lái)很多.map文件就是因?yàn)殚_啟了sourcemap所致,所以我們也需要通過環(huán)境變量來(lái)對(duì)此進(jìn)行區(qū)分。

  • 使用cross-env設(shè)置環(huán)境變量
    cross-env是一個(gè)專門用于設(shè)置webpack運(yùn)行或者打包時(shí)候的進(jìn)程環(huán)境變量的工具,注意是進(jìn)程環(huán)境變量而不是全局變量,這中變量在webpack打包結(jié)束后就沒有了,所以不能寫入到業(yè)務(wù)代碼中(當(dāng)然也是可以寫入的,不過需要另外配置)。

我們首先安裝它npm i -D cross-env
然后去到package.json文件中,在script定義的命令中插入環(huán)境變量, 使用windows的同學(xué)需要注意,寫法可能有點(diǎn)不一樣,具體谷歌即可:

image.png

這一步的目的就是將NODE_ENV這個(gè)變量插入到進(jìn)程中,開發(fā)和生產(chǎn)分別是developmentproduction

然后我們?nèi)サ?code>webpack.config.js中,添加mode屬性的設(shè)置,通過process.env.NODE_ENV即可獲取之前設(shè)置的環(huán)境變量:

image.png

這樣就消除了上面所說(shuō)的webpack的警告了。

  • 通過環(huán)境變量分別配置開發(fā)生產(chǎn)webpack配置
    既然已經(jīng)可以區(qū)分生產(chǎn)和開發(fā)環(huán)境,那么webpack中的有些配置也可以進(jìn)行區(qū)分了:


    image.png
  • 注入環(huán)境變量到代碼中
    按照前面的說(shuō)法,通過cross-env注入的變量只能存在于webpack打包或者編譯的進(jìn)程中,那么有時(shí)候我們需要在代碼運(yùn)行的過程中獲取到這個(gè)環(huán)境變量怎么辦呢?
    例如上一章我們配置Axios的時(shí)候的baseURL就需要區(qū)分生產(chǎn)和開發(fā)環(huán)境:

    image.png

    當(dāng)然也是有解決方案的,我們可以使用WebPack自帶的插件DefinePlugin做到這點(diǎn)。

首先我們?nèi)サ?code>build/plugins.js文件中,在里面引入這個(gè)插件,然后進(jìn)行變量配置即可:

image.png

之后我們到PageA組件中,使用process.env.NODE_ENV變量查看一下效果:

image.png

可以看到變量已經(jīng)被注入到了代碼中,而不是只存在于webpack打包和編譯的進(jìn)程中了:
image.png

另外還需要記得把baseURL換成生產(chǎn)環(huán)境的url,在本例中,生產(chǎn)環(huán)境的請(qǐng)求url是https://test.oxcblog.club/api:

image.png

最后

經(jīng)過上面的這么多步驟,我們的webpack配置也基本算是告一段落了,下一篇文章將會(huì)介紹使用團(tuán)隊(duì)代碼規(guī)范相關(guān)的插件: commitlint、eslint、stylelint等。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,185評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,446評(píng)論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,951評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,189評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,718評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,800評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,420評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,755評(píng)論 2 371

推薦閱讀更多精彩內(nèi)容