想要學習Webpack前端工程化構建,你必需要掌握這些核心知識點

引言

在好久以前,模塊化管理尚未出現,若是咱們開發一個頁面想要引入一些依賴的話,最多見的作法就是將依賴文件引入到.html文件中。好比,咱們要使用JS的一些依賴庫,就要在.html文件中使用<script>標籤引用;要引用CSS的依賴就要使用<link>標籤。若是頁面中引入的依賴文件太多,那麼向服務發送的請求也隨之增多,勢必會拖慢網頁的加載速度,影響用戶體驗。另外,網頁的內容也會變得很臃腫,增長維護的難度。javascript

在移動互聯網時代的網站,正在逐漸演化成Web應用(Web Application,簡稱WebAPP),瀏覽器也在此之際不斷的發展壯大,各類基於JavaScript語言的框架橫空出世,Web前端發展速度着實之快,讓咱們也不得不加快學習的腳步。如今的Web前端更傾向於單頁面應用(single-page application,簡稱SPA),減小頁面的刷新次數,這就形成了龐大的頁面代碼管理問題,若是管理很差會致使不少問題,好比各個模塊耦合度變高、難以維護等等。這就催生了模塊管理器。css

簡單來講,Webpack就是一個「模塊打包機」,它的主要工做就是分析項目中的結構找到JavaScript模塊,根據各個模塊之間的依賴關係進行靜態分析,而後打包成一個獨立的靜態模塊供瀏覽器調用,這樣就能夠大大減小請求次數,提供網頁的性能,提升用戶的體驗。Webpack還有一個做用就是把瀏覽器目前還解釋不了的擴展語言(例如ScssTypeScript等)進行編譯,轉換成瀏覽器能夠識別的內容。React中使用的是ES6的語法,在一些主流的瀏覽器上還不支持ES6,全部須要對Webpack進行配置後,React才能正常運行。html

Webpack不只是學習前端框架的前提,也是同窗們未來面試必問、筆試必考、工做必用的內容,隨着前端工程化的發展,Webpack正在變得愈來愈重要,尤爲對於大型的一線互聯網公司,會不會Webpack甚至能直接決定你是否能被錄用。我從一個技術小白到全棧工程師,也經歷了前端開發從刀耕火種到百家爭鳴的各個階段,在這個過程當中沉澱了不少知識,也積累了大量的實踐經驗,也但願經過個人知識分享,讓更多同窗受益,避免你們踩坑。前端

一、Webpack簡介與環境搭建

如今的網頁開發愈來愈複雜,咱們能夠把網頁看作是一個功能豐富的應用,爲了實現複雜的功能,就須要導入不少的JavaScript庫和一大堆依賴包。爲了簡化開發的複雜度,前端社區也涌現出了不少的方法,以便於提升開發效率。可是利用一些方法開發的文件每每須要進行額外的處理才能讓瀏覽器識別,並且手動處理又很是的繁瑣,這就爲Webpack這樣的工具誕生提供了需求。java

1.一、模塊化與工程化

隨着Web前端的不斷髮展,前端開發也正在逐漸往Web應用的方式轉變,應用場景也變的愈來愈複雜,須要更新的技術來解決開發中遇到的問題。前端模塊化和工程化也呼之欲出,前些年比較流行的構建工具備GruntGulpFIS等,可是通過近幾年ReactVue框架的發展,不在使用傳統的方式來操做DOM。在這個過程當中,前端逐漸發展成了模塊化和單頁應用爲主的形式。node

Webpack也就是在這樣的發展潮流中,被更多的人視爲主流的前端構建工具。這也就引出了咱們如今要講的模塊化和工程化。react

百度百科是這樣解釋模塊化的:webpack

模塊化是指解決一個複雜問題時,自頂向下逐層把系統劃分紅若干模塊的過程,有多種屬性、分別反映其內部特性。git

在咱們的生活中也常常會見到模塊化的應用場景,好比如今的家用電器(電視機、電腦主機等)都是模塊化的,若是這些家電壞了,維修的時候通常都是直接拿個新的模塊更換一下就能夠了,由此能夠看出,模塊化不只僅是編程語言的概念。模塊化應用到生活中,一樣是能夠提升辦事效率的。github

那咱們主要說的前端模塊化具體指什麼呢?

前端模塊化通常指的是JavaScript的模塊,最多見的是Node.js中的NPM包管理,有了模塊化,咱們在寫代碼的時候就避免了不少的重複工做,也不在只是作copy的事情了。有了模塊化以後,開發者能夠把更多的時間精力放到業務邏輯和代碼的維護上。目前,有不少主流的模塊化規範,好比CommonJSAMDES6 Module等規範,甚至在CSS中也採用了@import的方式實現模塊化。LessSass做爲CSS的預處理語言,使用了@import來導入一些變量、函數和mixin的定義。

接下來,咱們在聊聊什麼是工程化。當開發Web應用的場景愈來愈複雜時,咱們所面臨的問題也會隨之增長:

  1. 在大型項目中,多模塊下如何管理依賴?

  2. 頁面複雜度提高以後,多頁面、多系統、多狀態怎麼辦?

  3. 團隊協做開發中如何統一規範?

    ……

以上這些問題都是在軟件工程中必需要解決的問題,工程化問題須要運用工程化工具來解決。在早期,前端工程化主要是以GruntGulp等構建工具爲主,在這個時期解決的是重複任務的問題,他們將某些功能拆解成固定步驟的任務,而後編寫工具來解決,好比:圖片壓縮、地址添加hash等,都是固定套路的重複工做。

在近幾年,前端工程化的發展得益與Node.js的發展,Webpack的插件機制解決了前端資源依賴管理的問題,從而進化成了一整套前端工程化解決方案。

1.二、什麼是Webpack

官方解釋:

本質上,webpack 是一個現代JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle

通常像GruntGulp這類的構建工具,打包思路是:先遍歷源文件,而後匹配規則,最後再打包,這個過程很耗費資源。而Webpack能夠作到按需加載,與其餘構建工具不一樣之處在於:Webpack是從入口文件開始,通過模塊依賴加載、分析和打包三個流程完成項目的構建。在加載、分析和打包的三個過程當中,能夠針對性的作一些解決方案,達到按需加載的目的,好比拆分公共代碼(code split)等。

Webpack在打包時遵循「一切皆模塊」的思想,即JS是模塊,CSS等文件也是模塊,還能夠將ES6轉爲ES5,而且能夠對LessSass這些CSS預處理器進行編譯。在打包過程當中經過強大的Loader和插件機制來完成解決方案的封裝,最後對項目進行壓縮和優化等操做。Webpack解決了傳統構建工具實現不了的問題,被更多的前端開發者使用。

1.三、Webpack環境搭建

1.3.一、安裝Node.js

Webpack實際是用Node.js寫的,因此要先安裝Node.js環境。

首先進入Node.js的官網,選擇對應系統下載安裝包:

對於 windows 用戶,直接下載安裝包安裝便可,若是是 Macos 用戶,推薦使用 brew 進行安裝。

Node.js有不少版本,包括穩定版和開發版,不一樣的項目須要的Node.js版本不一樣,推薦你們安裝 8.x 以上的版本。

1.3.二、NPM簡介與經常使用命令

(1)NPM包管理工具

簡單來講,NPM(Node Package Manager)是包含在Node.js裏面的一個包管理工具,NPM會隨着Node.js一塊兒安裝,咱們能夠在命令提示符(如下演示的命令均爲windows系統環境)中查看NPM的版本:

NPM爲開發者提供了一個代碼模塊共享的大平臺,當咱們項目中須要使用某個模塊(JavaScript包)時,能夠直接使用NPM包管理工具來下載對應的包並安裝,咱們也能夠把本身用Node.js寫的代碼發佈到平臺上供他人使用。

在搭建一個前端項目以前,一般會在項目的根目錄下生成一個名爲package.json的文件做爲NPM包的描述文件,使用該文件來定義項目信息、配置包依賴關係。package.json文件能夠本身手動建立,也可使用命令來建立:

npm init
複製代碼

在命令提示符中輸入上面命令(先 cd 到項目根目錄下,再執行命令)後,會向用戶提問一系列問題,根據對應的提示回答問題,若是不回答直接輸入回車,程序會按照默認選項進行配置。期間使用 -f(表示force)、-y(表示yes)會跳過提問階段,直接生成一個新的package.json文件。

文件中包含了NPM包的基本信息(項目名稱、版本號、項目描述、做者)和依賴管理,例如:

{
    "name": "demo",
    "version": "1.0.0",
    "dependencies": {
        "webpack": "^4.29.6"
    }
}
複製代碼

name:表示咱們當前的項目名稱,若是未來發布到npmjs.com平臺上,會以這個名字來命名,還有一種命名方式是@scope/name,表示做用域包。

version:是當前項目的版本,NPM是圍繞 語義版本控制(semver)思想而設計的,這種規範是以 主版本號.次版本號.修訂號MAJOR.MINOR.PATCH)的描述形式,其分別表示的意思是:

  • 主版本號:當你作了不兼容的API修改;
  • 次版本號:當你作了向下兼容的功能性新增;
  • 修訂號:當你作了向下兼容的問題修正(例如,修改了一個bug);

dependencies:是demo這個項目中的依賴,還有devdependencies也是描述當前項目的依賴,這兩者的區別咱們會在下面進行詳細的說明。上面package.json示例中dependencies裏存放了有關於webpack的版本號,版本號前面有個^,意思是主版本是4的最新版本,每次執行安裝命令的時候,會更新符合這個規則的最新包。

(2)NPM的經常使用命令

咱們經常使用的NPM命令主要是作四種操做:安裝、刪除、初始化、配置。

安裝某個NPM

npm install packageName
## 簡寫
npm i packageName
複製代碼

安裝package.json中的全部依賴

npm install
複製代碼

安裝指定版本的包

npm i packageName@x.x.x
複製代碼

全局安裝依賴包

npm i packageName --global
## 簡寫
npm ipackageName -g
複製代碼

安裝依賴包,而且將依賴寫入package.json文件的dependencies部分

npm i packageName --save
## 簡寫,簡寫中-S是大寫字母
npm i packageName -S
複製代碼

安裝依賴包,而且把依賴寫入package.json文件的devdependencies部分

npm i packageName --save-dev
## 簡寫
npm i packageName -D
複製代碼

刪除某個NPM

npm uninstall packageName

複製代碼

初始化一個NPM項目,自動生成package.json文件

npm init

複製代碼

單次設置鏡像,使用淘寶NPM鏡像替換官方NPM鏡像

因爲NPM網站屬於境外服務器,因此咱們爲了保證下載NPM包時的網絡穩定性,會將下載鏡像換成國內的鏡像,其中淘寶NPM鏡像是國內最大的一家NPM鏡像網站,在下載NPM包時,使用 cnpm 命令代替原來的 npm 命令。

npm [命令] --registry=https://registry.npm.taobao.org

複製代碼

設置默認npm使用淘寶鏡像

npm config set registry https://registry.npm.taobao.org

複製代碼

安裝cnpm包,安裝成功後npm命令更換爲cnpm命令

npm install -g cnpm --registry=https://registry.npm.taobao.org
## 安裝成功以後,直接像使用npm同樣使用cnpm便可,例如:安裝某個包就變成了
cnpm i packageName

複製代碼

設置環境變量

npm set xxx
## 例如:
npm set init-author-name 'Your name'

複製代碼

查看某個包的信息

npm info
## 例如:
npm info lodash

複製代碼

查找npm倉庫

npm search
## 後面能夠跟字符串或者正則表達式,例如:
npm search webpack

複製代碼

樹形的展現當前項目安裝的全部模塊,以及對應的依賴

npm list
## 例如,查看全局安裝的模塊:
npm list --global

複製代碼

(3)dependencies 和 devDependencies 區別

在上面關於NPM經常使用命令中,咱們有講到 dependenciesdevDependencies 的命令分別是:

# 自動把模塊和版本號添加到dependencies部分,將依賴安裝到生產環境
npm install module-name --save
# 自動把模塊和版本號添加到devdependencies部分,將依賴安裝到開發環境
npm install module-name --save-dev

複製代碼

不少同窗不太理解什麼是開發環境和生產環境,簡單來講,就是在項目的開發階段就是開發環境;項目上線了,開始正式提供對外服務,在生產環境下,通常會關掉錯誤報告,打開錯誤日誌等操做。

devdependencies配置的是開發環境,安裝項目開發時所依賴的模塊。好比像webpack工具,只是用來構建項目和打包,這些都是在開發階段才使用的,等項目上線後就用不到webpack工具了,那麼咱們就能夠把webpack安裝到開發環境中(使用 --save-dev命令安裝到devdependencies下);

dependencies是生產環境,安裝項目運行時所依賴的模塊。好比jQuery庫,,等項目上線之後依然是要繼續使用的,咱們就要安裝在生產環境中(使用 --save 命令安裝到dependencies下),若是沒有把須要的依賴安裝到生產環境中,項目上線運行時就有可能會報錯。

(4)本地模式和全局模式

咱們在安裝NPM包時,有兩種模式可選:一是本地模式,二是全局模式。

默認是本地模式安裝,本地模式是指在執行npm install命令後,會在執行命令的目錄下建立node_modules目錄,而後再把下載的依賴和安裝包保存到node_modules目錄下。

全局模式是指將下載的依賴和安裝包保存到全局路徑下的方式,在Node.js中使用require依賴時,會優先查找本身當前文件中的node_modules目錄,若是沒有,在循環遍歷上層的node_modules,若是還找不到依賴,就會去全局模式下的安裝目錄尋找。

package.json中增長bin字段,而且指向包內對應的文件映射路徑,就能夠把該文件放到PATH中,使用npm命令執行了,例如:

"bin": {
  "testCmd": "bin/cmd.js"
}

複製代碼

配置好bin字段後,在項目根目錄輸入 npm link xxx 就能夠執行testCmd命令了, 使用 npm link 命令,將 npm 模塊連接到對應的運行項目中去,方便地對模塊進行調試和測試 。

(5)修改NPM全局模式的默認安裝路徑

通常狀況下,咱們安裝Node.js環境,程序會自動把NPM全局模塊的路徑設置在系統盤(一般是C盤下),咱們在項目開發階段不建議全局路徑設置在系統盤,不但會影響電腦的性能,並且還很不安全。能夠經過如下命令來設置默認下載的全局路徑目錄:

輸入命令,查看當前配置

npm config ls

複製代碼

運行結果:

若是是第一次使用NPM安裝包的話,在配置中只會看到prefix的選項,就是NPM默認的全局安裝目錄。可是若是有屢次使用NPM安裝包的話,就會看到cacheprefix兩個路徑,以下圖:

第一步:

在欲更改的目錄下新建兩個文件夾,分別是:node_global_modulesnode_cache,效果如圖:

第二步:

打開命令提示符,執行下面兩條命令:

npm  config set prefix "D:\dev\nodejs\node_modules\npm\node_global_modules"
npm  config set cache "D:\dev\nodejs\node_modules\npm\node_cache"

複製代碼

執行成功後,能夠用 npm config ls 命令查看配置的結果,效果如圖:

第三步:

驗證配置成功後,須要配置環境變量。在環境變量中,新建一個系統變量,變量名:NODE_HOME,變量值:D:\dev\nodejs,效果如圖:

Path變量名中,新建變量值:

%NODE_HOME% %NOED_HOME%\node_modules %NODE_HOME%\node_modules\npm\node_global_modules\

效果如圖:

保存以後,能夠從新執行全局安裝命令,查看NPM依賴包在全局的默認安裝目錄是否爲咱們配置好的目錄,若是成功下載到了設置後的目錄下,就成功修改了默認全局安裝路徑。

(6)NPM Scripts

NPM不只能夠用於模塊管理,還能夠用於執行腳本。能夠在package.json文件中添加scripts字段,用於指定腳本命令,以供NPM直接調用,示例以下:

// package.json
{
    "scripts": {
        "build": "webpack",
        "start": "node src/scripts/dev.js"
    }
}

複製代碼

scripts裏面放的是npm要執行的命令,格式是key-value形式,爲了簡化操做,具體命令爲value,自定義的簡化命令爲key,當npm運行key命令時,等同於執行後面的value命令。例如,在package.json添加上面字段以後,能夠直接使用npm run buildnpm run start命令了 ,並且npm run start命令還能夠簡寫成npm start

注意:上面提到的簡寫,只有npm run start才能夠簡寫,並非全部script命令都支持這種簡寫的方式。

除了 npm 外,還有一些包管理工具,主要是針對 npm 的下載速度慢、node_modules 混亂等缺點設計的,例如yarnpnpm

在後面會講到使用create-react-app腳手架工具搭建React開發環境,在自動生成的package.json文件中配置的scripts字段內容是:

"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject"
}

複製代碼

咱們在命令窗口中直接執行npm start就至關於執行了npm react-scripts start命令,經過這個命令能夠啓動React服務,而且在瀏覽器輸入IP地址就能夠訪問React項目了。

1.3.三、安裝Webpack

(1)安裝Webpack

webpack的安裝須要使用NPM來完成,安裝命令以下:

## 全局安裝
npm install -g webpack
## 安裝到項目目錄中
npm install --save-dev webpack

複製代碼

安裝好以後,就可使用webpack的命令了。

(2)安裝Webpack-cli

Webpack-cliWebpackCLI (Command-line interface)工具,若是在項目中,咱們可使用下面的方式安裝:

# 本地安裝
npm install webpack-cli --save-dev
# 全局安裝
npm install webpack-cli -g

複製代碼

因爲webpack是用於項目構建和打包的工具,因此咱們在安裝時使用--save-dev命令把webpack-cli放到開發環境的字段下。

二、Webpack中常規配置項介紹

2.一、webpack.config.js 配置文件

當咱們安裝好webpack以後,就可使用webpack命令了,好比要將一個main.js文件打包成一個bundle.js文件,可使用以下命令:

webpack main.js bundle.js

複製代碼

通常在實際的項目開發中,要把這些命令寫到一個webpack.config.js的文件中。上面打包操做能夠作以下配置:

module.exports = {
	entry: './main.js',
	output: {
		filename: 'bundle.js'
	}
};

複製代碼

在上面的配置文件中,咱們配置了項目的入口(entry)和出口(output),在該項目的關係圖中,entry字段指定了入口文件,即把main.js做爲起點。output字段是指定了輸出位置,即指定webpack把整理後的資源放在哪裏。

2.二、webpack核心概念

webpack主要有4個核心概念:

入口(entry):項目入口,也是webpack全部依賴關係圖的起點。

出口(output):指定webpack打包應用程序的目錄。

加載器(loader):加載須要處理的模塊,對模塊進行轉換處理。

插件(plugins):定義項目要用到的插件。

2.2.一、webpack入口(entry)和出口(output)

在前面的內容中,咱們已經瞭解到了,webpack是一個模塊打包工具,須要處理具備依賴關係的各個模塊,這些模塊會構成一個依賴關係圖(dependency graph)。webpack的入口就是這張關係圖的起點,指的是入口文件。webpack出口指的是須要把這張關係圖導出到哪一個文件中,即導出文件。

(1)入口(entry)

entry字段指定了入口文件,也能夠理解爲當前項目啓動時運行的第一個文件,語法爲:

entry: string | object | Arrary<string>

複製代碼

entry字段支持多種類型,值能夠是字符串、對象、數組。簡單來理解,就是entry能夠指定一個文件入口,也能夠指定多文件入口。咱們舉例來講明entry的用法:

單文件入口示例

// 使用key-value方式
module.exports = {
    entry: 'path/to/my/entry/main.js'
};

// 或者使用對象方式
module.exports = {
    entry: {
        main: 'path/to/my/entry/main.js'
    }
};

// entry也可使用數組指定多個入口文件路徑,輸出時會合並輸出
module.exports = {
    mode: 'development',
    entry: ['./src/app.js', './src/home.js'],
    output: {
        filename: 'array.js'
    }
};

複製代碼

多文件入口

// entry配置3個獨立的入口文件,會打包成3個對應的bundle
module.exports = {
    entry: {
        home: 'path/to/my/entry/home.js',
        search: 'path/to/my/entry/search.js',
        list: 'path/to/my/entry/list.js'
    }
};

複製代碼

(2)出口(output)

output字段是指定entry對應文件編譯打包後的輸出位置,也能夠理解爲指定webpack把整理好的資源放到哪裏。output字段經常使用的屬性有:

  • path:指定打包完成的文件存放的路徑;
  • filename:指定打包完成的文件的文件名稱;
  • publicPath:指定一個在瀏覽器中被引用的URL地址;

若是不指定path參數,將默認將打包文件輸出到webpack.config.js同級目錄下;若是不指定output,打包文件會默認輸出到dis/main.js,即output字段的path屬性默認是disfilename屬性默認是main

一個webpack的配置能夠包含多個entry,可是隻能有一個output。對於不一樣的entry能夠經過output.filename佔位符語法來區分,例如:

module.exports = {
    entry: {
        home: 'path/to/my/entry/home.js',
        search: 'path/to/my/entry/search.js',
        list: 'path/to/my/entry/list.js'
    },
    output: {
        filename: '[name].js',
        path: __dirname + '/dist'
    }
};

複製代碼

在上面的配置中,output.filename指定的[name]就是一個佔位符,對應的是entry中的keyhomesearchlist),最終輸出的結果是:

path/to/my/entry/home.js → dist/home.js
path/to/my/entry/search.js → dist/search.js
path/to/my/entry/list.js → dist/list.js

複製代碼

目前webpack支持的佔位符有:

佔位符 含義
[hash] 模塊標識符的hash
[chunkhash] chunk內容的hash
[name] 模塊的名稱
[id] 模塊標識符
[query] 模塊的query,例如,文件名 ? 後面的字符串
[function] 一個 return 出一個 string 做爲 filename 的函數

2.2.二、webpack 加載器(loader)

loader是解析處理器,你們都知道,webpack的任務就是把具備依賴關係的各個文件進行整合並打包,這些文件的類型有不少,好比.html.css.js.scss.jpg等等。可是webpack只認識JavaScript文件,那如何識別其餘文件呢?loader就解決了這個問題。好比,不少瀏覽器不支持ES6語法,webpack能夠經過loader配置,將ES6語法轉化爲ES5的語法,還能夠將圖片轉化爲base64dataURL ,還能夠經過loader直接在JavaScript文件中使用import 引入csshtml

loaderwebpack構建文件的過程當中起着相當重要的做用,實現能夠經過loader識別出要對哪些文件進行預處理,而後loader轉換這些須要預處理的文件,並添加到bundle(構建後的模塊)中。在React框架開發時,常常會用到JSX這種擴展語言來編寫DOM,目前幾乎全部的瀏覽器都不支持JSX格式,那麼loader就能夠在使用JSX以前作一些預處理操做,將其轉化成JavaScript語言,示例以下:

module.exports = {
	entry: {
		app: './app.js'
	}
	output: {
		filename: 'bundle.js',
    	path: './dist'
	}
	module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                use: 'babel-loader'
            },
            {
                test: /\.css$/,
                use: 'css-loader'
            }
        ]
    }
}

複製代碼

在上面的例子中,test字段表示要對哪些類型的文件進行構建,use字段表示要用哪些模塊對該類型的文件進行構建。在test項中使用/\.css$/這種正則表達式來匹配須要處理的模塊文件,即匹配以.css爲後綴的文件。

在配置loader以前,use中的模塊是須要安裝的,命令以下:

npm install --save-dev babel-loader
npm install --save-dev css-loader

複製代碼

提示:

webpack的早期版本中,loader的寫法是:

module.exports = {
......
module: {
	loaders: [
		{
		  test: /\.(js|jsx)/,
		  loader: 'babel-loader'
		},
		......
	]
}
}

複製代碼

webpack最新版本中已經廢棄了loadersloader的寫法,改爲了 rulesuse

2.2.三、webpack 插件(plugin)

pluginwebpack起着重要的做用,經過plugin能夠解決loader解決不了的問題,以此來豐富webpack的功能。webpack自己就是有不少插件組成的,因此內置了不少插件。除了內置插件,咱們也能夠經過NPM包的方式來使用插件,好比如今須要安裝一個html-webpack-plugin的插件,先執行安裝命令:

npm install --save-dev html-webpack-plugin

複製代碼

而後在webpack.config.js文件中配置plugins

var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: {
        app: './app.js'
    },
    output: {
        filename: 'bundle.js',
        path: './dist'
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)/,
                use: 'babel-loader'
            },
            {
                test: /\.css$/,
                use: 'css-loader'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin()
    ]
}

複製代碼

上面的示例中,plugins參數爲一個數組,能夠傳入多個plugin,另外須要注意plugin是能夠帶參數的,因此plugins屬性傳入的必修爲new實例。

三、使用Babel轉換JavaScript代碼

3.一、什麼是Babel

Babel是一個JavaScript的編譯器,咱們在webpack中可使用ES6以上版本的語法寫代碼,可是目前主流的瀏覽器僅支持ES5語法,經過Babel能夠將ES6+語法自動轉換成ES5語法,來適配瀏覽器的JavaScript解釋器。

好比說,咱們使用ES6語法中的箭頭函數實現代碼:

(val) => (val + 1) ;

複製代碼

使用Babel轉化成ES5語法後:

function(val){
	return val+1 ;
}

複製代碼

3.二、babel-cli命令行工具的使用

在項目中安裝babel-cli,命令以下:

npm install --save-dev @babel/core @babel/cli
## 簡寫
npm i -D @babel/core @babel/cli

複製代碼

而後再安裝轉換規則:

# 安裝 preset-env
npm i -D @babel/preset-env
# 執行 CLI 添加--presets
npx babel babel.js --presets=@babel/preset-env

複製代碼

測試babel-cli命令行工具,先建立一個app.js文件,輸入下面的代碼:

[1, 2, 3].map(n => n ** 2);

複製代碼

而後在命令行中輸入下面命令:

npx babel app.js
## 或者 指定輸出結果到固定文件
npx babel app.js --out-file appout.js
## 簡寫
npx babel app.js -o appout.js

複製代碼

轉化命令執行成功後,app.js的語法就變成了ES5語法:

[1, 2, 3].map(function(n) {
    return Math.pow(n, 2);
});

複製代碼

3.三、Babel配置文件

Babel還支持配置文件的方式進行轉化操做,配置文件支持兩種形式:

(1)使用package.jsonbabel屬性

示例:

{
    "name": "demo",
    "version": "1.0.0",
    "babel": {
        "presets": ["@babel/preset-env"]
    }
}

複製代碼

(2)使用.babelrc文件

在項目的根目錄建立.babelrc.babelrc.js文件,Babel會在正在被轉義的文件當前目錄中查找一個.babelrc文件, 若是不存在,它會向外層目錄遍歷目錄樹,直到找到一個 .babelrc 文件,或一個 package.json 文件中有 "babel": {} 。 在文件中配置以下:

{
    "presets": ["@babel/preset-env"]
}

複製代碼

3.四、在webpack中使用babel

第一步:安裝依賴包

# 安裝開發依賴
npm i webpack babel-loader webpack-cli @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
# 將 runtime 做爲依賴
npm i @babel/runtime -S

複製代碼

第二步:建立webpack.config.js文件,配置以下:

module.exports = {
    //......
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                [
                                    '@babel/preset-env',
                                    {
                                        useBuiltIns: 'usage'
                                    }
                                ]
                            ]
                        }
                    }
                ]
            }
        ]
    }
};

複製代碼

Babel配置到webpack.config.js文件的options中,或者是配置到.babelrc文件, 或者使用package.jsonbabel 字段。

四、配置webpack-dev-server本地服務器

webpack-dev-server 就是一個Express的小型服務器,經過Express的中間件 webpack-dev-middlewareWebpack進行交互的。

4.一、安裝webpack-dev-server服務

在項目中安裝:

npm i webpack-dev-server

複製代碼

啓動服務:

npx webpack-dev-server

複製代碼

服務啓動成功後,在瀏覽器中訪問webpack-dev-server的默認地址 localhost:8080,就能夠默認的index.html頁面,若是沒有該頁面,就會顯示文件目錄。

4.二、整合Webpack

webpack-dev-server服務整合到webpack的配置文件中,webpack.config.js配置文件內容以下:

const path = require('path');
module.exports = {
    //...
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        port: 9000  //服務器端口
    }
};

複製代碼

還能夠將webpack-dev-server放到package.jsonscripts裏面,來簡化服務啓動命令:

{
    "scripts": {
        "dev": "webpack-dev-server --mode development --config webpack.config.dev.js --hot --inline --port 3000"
    }
}

複製代碼

配置完成後,可使用下面命令啓動服務:

npm run dev

複製代碼

執行npm run dev實際就是執行的對應webpack-dev-server命令。

4.三、配置熱加載

熱加載也叫模塊熱替換( Hot Module Replacement ,簡稱HMR),配置熱加載後,在應用運行期間修改代碼,不須要從新刷新頁面就能夠在瀏覽器中加載更新後的內容。 經過配置 webpack.HotModuleReplacementPlugin 插件來開啓全局的 HMR 功能。

修改webpack.config.js文件,開啓熱加載:

const path = require('path');
module.exports = {
    entry: './src/index.js',
    devServer: {
        open: true, //自動打開瀏覽器
        contentBase: path.join(__dirname, 'dist'),//指定服務器將從哪一個目錄去查找內容文件
        port: 9000, //服務器端口
        hot: true // 開啓 hmr 支持
    },
    plugins: [
        // 添加 hmr plugin
        new webpack.HotModuleReplacementPlugin()
    ]
};

複製代碼

完成上面的配置後,重啓服務,在瀏覽器訪問默認地址 http://localhost:9000 ,而後再修改JavaScript代碼,就能夠實時看到效果了。

若是使用webpack-dev-servercli功能只須要經過執行下面命令,就能夠開啓自動刷新功能:

webpack-dev-server --hot --inline

複製代碼

執行上面命令會自動將webpack.HotModuleReplacementPlugin這個插件添加到 Webpack 的配置中去。這種是最簡單的配置方式了。

4.四、本地服務器的常見配置項

常見配置以下:

# 修改端口號和 host
webpack-dev-server --port 3000 --host 127.0.0.1

# 啓動inline 模式的自動刷新
webpack-dev-server --hot --inline

# 手動指定 webpack config 文件
webpack-dev-server --config webpack.xxx.js

# 指定 webpack 的 mode
webpack-dev-server --mode development

# watch 功能,文件發生變化則觸發從新編譯
webpack-dev-server --watch

# dev-server默認會將工做目錄(當前目錄)最爲基本目錄,能夠手動修改它
webpack-dev-server --content-base ./build

# 查看幫助
webpack-dev-server -h

# 開啓inline模式,自動刷新頁面
webpack-dev-server --hot --inline

複製代碼

五、配置React開發環境

5.一、使用webpack配置React環境

5.1.一、搭建React項目

建立React項目的文件夾,在項目根目錄下打開命令提示符,執行初始化命令,生成package.json文件:

npm init -y

複製代碼

依次執行下列命令,若是已經安裝了cnpm的話,可使用cnpm替代npm命令,執行命令完成基礎建立:

# 安裝 react react-dom依賴
npm i react react-dom

# 安裝 webpack 和 webpack-cli 開發依賴
npm i webpack webpack-cli -D

# 安裝 babel
npm i babel-loader @babel/core @babel/preset-env -D

# 安裝 babel preset-react
npm i @babel/preset-react -D

複製代碼

建立webpack.config.js配置文件,並在配置文件中添加對JSX語法的Babel編譯支持:

module.exports = {
    resolve: {
        extensions: ['.wasm', '.mjs', '.js', '.json', '.jsx']
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/, // jsx/js文件的正則
                exclude: /node_modules/, // 排除 node_modules 文件夾
                use: {
                    // loader 是 babel
                    loader: 'babel-loader',
                    options: {
                        // babel 轉義的配置選項
                        babelrc: false,
                        presets: [
                            // 添加 preset-react
                            require.resolve('@babel/preset-react'),
                            [require.resolve('@babel/preset-env'), {modules: false}]
                        ],
                        cacheDirectory: true
                    }
                }
            }
        ]
    }
};

複製代碼

在項目根目錄建立 src/App.jsx 文件,src是源文件目錄,App.jsx文件內容以下:

import React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
    return (
        <div> <h1>Hello React and Webpack</h1> </div>
    );
};
export default App;
ReactDOM.render(<App />, document.getElementById('app')); 複製代碼

src目錄下建立index.jsx文件,內容以下:

import App from './App'; // 這裏能夠省略.jsx

複製代碼

將文件添加到webpack.config.js中的entry

module.exports = {
    entry: './src/index.jsx',
    // ...
};

複製代碼

接下來在src目錄下建立index.html文件,做爲項目的模板,內容以下:

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="UTF-8" />
        <title>Hello React Webpack</title>
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

複製代碼

須要使用 html-webpack-plugin 插件來複制 index.htmldist 文件夾下。

首先是安裝 html-webpack-plugin

npm i html-webpack-plugin -D

複製代碼

而後修改webpack.config.js配置:

const HtmlWebPackPlugin = require('html-webpack-plugin');
module.exports = {
    // ...
    plugins: [
        new HtmlWebPackPlugin({
            template: 'src/index.html',
            filename: 'index.html',
            inject: true
        })
    ]
};

複製代碼

上面的操做都完成以後,能夠執行打包命令:

npx webpack --mode development

複製代碼

運行結果:

打包成功後,會在項目的根目錄下自動生成dist文件夾,存放的是webpack編譯打包後的文件。這時,咱們就能夠把打包的命令放到package.json文件的scripts中,配置以下:

//package.json文件
{
    "scripts": {
        "build": "webpack --mode production"
    }
}

複製代碼

配置好了之後,咱們就可使用簡化的命令來操做打包了:

npm run build

複製代碼

5.1.二、配置React項目的本地服務

(1)配置服務

第一步:安裝webpack-dev-server依賴:

npm i webpack-dev-server -D

複製代碼

第二步:在webpack.config.js配置文件中添加服務相關配置,完整配置以下:

//webpackage.config.js

const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');
module.exports = {
    mode: 'development',
    devtool: 'cheap-module-source-map',
    devServer: {
        contentBase: path.join(__dirname, './src/'),
        publicPath: '/',
        host: '127.0.0.1',
        port: 3000,
        stats: {
            colors: true
        }
    },
    entry: './src/index.jsx',
    // 將 jsx 添加到默認擴展名中,省略 jsx
    resolve: {
        extensions: ['.wasm', '.mjs', '.js', '.json', '.jsx']
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/, // jsx文件的正則
                exclude: /node_modules/, // 排除 node_modules 文件夾
                use: {
                    // loader 是 babel
                    loader: 'babel-loader',
                    options: {
                        // babel 轉義的配置選項
                        babelrc: false,
                        presets: [
                            // 添加 preset-react
                            require.resolve('@babel/preset-react'),
                            [require.resolve('@babel/preset-env'), {modules: false}]
                        ],
                        cacheDirectory: true
                    }
                }
            }
        ]
    },
    plugins: [
        new HtmlWebPackPlugin({
            template: 'src/index.html',
            filename: 'index.html',
            inject: true
        })
    ]
};

複製代碼

第三步:修改package.json文件的scripts配置,添加start字段:

{
    "scripts": {
        "build": "webpack --mode production",
        "start": "webpack-dev-server --mode development --open"
    }
}

複製代碼

第四步:執行啓動服務命令:

npm start

複製代碼

服務啓動成功後,會自動打開瀏覽器,並訪問 http://127.0.0.1:3000/ ,效果如圖:

(2)配置熱加載

第一步:在src目錄中新建dev.js文件,添加如下代碼:

if (module.hot) {
    module.hot.accept(err => {
        if (err) {
            console.error('Cannot apply HMR update.', err);
        }
    });
}

複製代碼

上面代碼用於觸發HMR,這部分代碼不屬於業務代碼。

第二步:在webpack.config.js配置文件中添加熱加載配置:

// webpack.config.dev.js

const webpack = require('webpack'); //增長導入webpack

module.exports = {
    devServer: {
    	...
		hot: true, //在devServer中增長hot字段
    	...
    },
    ...
    entry: ['./src/index.jsx', './src/dev.js'], //在entry字段中添加觸發文件配置
    ...
    plugins: [
		// plugins中增長下面內容,實例化熱加載插件
		new webpack.HotModuleReplacementPlugin(),
    ...
    ]
    ...
}

複製代碼

第三步:啓動服務,測試熱加載

執行啓動服務命令:

npm start

複製代碼

服務啓動後,會自動打開瀏覽器,咱們在App.js中修改內容,保存後會看到瀏覽器內自動更新,效果以下圖:

5.二、使用create-react-app快速搭建環境

Create React AppFaceBookReact團隊官方出的一個構建React單頁面應用的腳手架工具。它自己集成了Webpack,並配置了一系列內置的loader和默認的npm的腳本,能夠很輕鬆的實現零配置就能夠快速開發React的應用。

create-react-appReact中最簡單的建立單頁面程序的方式,安裝命令以下:

npm install -g create-react-app

複製代碼

在須要建立項目的文件夾下啓動命令提示符,使用create-react-app建立項目,命令以下:

create-react-app my-app

複製代碼

上面命令中,my-app是建立的項目名稱。執行 cd my-app 進入到項目根目錄下,執行啓動服務命令:

npm start

複製代碼

服務啓動成功後,會自動打開瀏覽器,效果如圖:

到此,React項目就搭建成功了。

六、總結

咱們這個章節先經過前端的發展歷程引出了爲何要使用Webpack構建項目,而後經過對Webpack的常規配置、Babel轉換、搭建本地服務進行了詳細的講解,最後使用Webpack搭建React開發環境。

做爲一套React框架教程,對Webpack的使用有了解就能夠了,因爲Webpack主要是用於項目的構建和打包,甚至有的同窗在工做中根本就接觸不到Webpack,或者是項目中只配置一次Webpack,後面就再也不用了。對於這些同窗來講,但願這篇教程可以給你帶來一些新的知識儲備,在之後用到的時候,可以有操做的思路和方法。

關於Webpack的知識遠遠比這篇教程中的內容要多,不過對於項目開發來講,掌握這些基礎知識就夠用了。你們必定要培養獨立思考和解決問題的能力,在項目構建過程當中,若是遇到了問題,根據所學的知識尋找解決問題的方法,經過實踐來提高本身的編程能力,你們加油!

相關文章
相關標籤/搜索