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

我的博客地址

正式地址
測試地址
前端源碼
后端源碼

文章目錄

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

前言

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

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

打包路徑和命令添加

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

    image.png

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

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

    image.png

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

    image.png

filename和chunkFilename

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

image.png

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

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

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

    image.png

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

    image.png

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

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

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

publicPath

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

image.png

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

image.png

那么這個配置有什么用處呢?

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

    image.png

單獨打包CSS

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


image.png

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

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

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

    image.png

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

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

    image.png

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

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


    image.png

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

在上面的打包配置中,因為之前做了路由組件的代碼分割,所以組件PageAPageB會被單獨打包成js文件,再來看看打包的情況表,會發(fā)現(xiàn)page-a的公用模塊(引入的庫)體積高達800多k,這對于網(wǎng)頁加載資源而言是非常大的:

image.png

我們可以通過配置WebPack的optimization來對代碼進一步分割,使得打出來的包更小。

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

    image.png

    然后配置runtimeChunk:
    image.png

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

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

    image.png

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

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

    image.png

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

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

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

    1. 使用terser-webpack-plugin優(yōu)化js壓縮過程:
      terser-webpack-plugin是一個js代碼優(yōu)化插件,他可以使用多線程和緩存更快的壓縮js代碼,優(yōu)化打包體驗,并且使用非常簡單。
      為什么使用這個插件呢?因為webpack默認使用的webpack.optimize.UglifyJsPlugin插件是不支持es6語法的,當(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

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

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


image.png

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

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

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

image.png

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

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

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

image.png

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

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

image.png

這樣就消除了上面所說的webpack的警告了。

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


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

    image.png

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

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

image.png

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

image.png

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

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

image.png

最后

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容