在好久以前,模塊化管理尚未出現,若是咱們開發一個頁面想要引入一些依賴的話,最多見的作法就是將依賴文件引入到.html
文件中。好比,咱們要使用JS
的一些依賴庫,就要在.html
文件中使用<script>
標籤引用;要引用CSS
的依賴就要使用<link>
標籤。若是頁面中引入的依賴文件太多,那麼向服務發送的請求也隨之增多,勢必會拖慢網頁的加載速度,影響用戶體驗。另外,網頁的內容也會變得很臃腫,增長維護的難度。javascript
在移動互聯網時代的網站,正在逐漸演化成Web應用(Web Application,簡稱WebAPP
),瀏覽器也在此之際不斷的發展壯大,各類基於JavaScript
語言的框架橫空出世,Web前端發展速度着實之快,讓咱們也不得不加快學習的腳步。如今的Web前端更傾向於單頁面應用(single-page application,簡稱SPA
),減小頁面的刷新次數,這就形成了龐大的頁面代碼管理問題,若是管理很差會致使不少問題,好比各個模塊耦合度變高、難以維護等等。這就催生了模塊管理器。css
簡單來講,Webpack
就是一個「模塊打包機」,它的主要工做就是分析項目中的結構找到JavaScript
模塊,根據各個模塊之間的依賴關係進行靜態分析,而後打包成一個獨立的靜態模塊供瀏覽器調用,這樣就能夠大大減小請求次數,提供網頁的性能,提升用戶的體驗。Webpack
還有一個做用就是把瀏覽器目前還解釋不了的擴展語言(例如Scss
、TypeScript
等)進行編譯,轉換成瀏覽器能夠識別的內容。React
中使用的是ES6
的語法,在一些主流的瀏覽器上還不支持ES6
,全部須要對Webpack
進行配置後,React才能正常運行。html
Webpack
不只是學習前端框架的前提,也是同窗們未來面試必問、筆試必考、工做必用的內容,隨着前端工程化的發展,Webpack
正在變得愈來愈重要,尤爲對於大型的一線互聯網公司,會不會Webpack
甚至能直接決定你是否能被錄用。我從一個技術小白到全棧工程師,也經歷了前端開發從刀耕火種到百家爭鳴的各個階段,在這個過程當中沉澱了不少知識,也積累了大量的實踐經驗,也但願經過個人知識分享,讓更多同窗受益,避免你們踩坑。前端
如今的網頁開發愈來愈複雜,咱們能夠把網頁看作是一個功能豐富的應用,爲了實現複雜的功能,就須要導入不少的JavaScript
庫和一大堆依賴包。爲了簡化開發的複雜度,前端社區也涌現出了不少的方法,以便於提升開發效率。可是利用一些方法開發的文件每每須要進行額外的處理才能讓瀏覽器識別,並且手動處理又很是的繁瑣,這就爲Webpack
這樣的工具誕生提供了需求。java
隨着Web前端的不斷髮展,前端開發也正在逐漸往Web應用的方式轉變,應用場景也變的愈來愈複雜,須要更新的技術來解決開發中遇到的問題。前端模塊化和工程化也呼之欲出,前些年比較流行的構建工具備Grunt
、Gulp
、FIS
等,可是通過近幾年React
、Vue
框架的發展,不在使用傳統的方式來操做DOM
。在這個過程當中,前端逐漸發展成了模塊化和單頁應用爲主的形式。node
Webpack
也就是在這樣的發展潮流中,被更多的人視爲主流的前端構建工具。這也就引出了咱們如今要講的模塊化和工程化。react
百度百科是這樣解釋模塊化的:webpack
模塊化是指解決一個複雜問題時,自頂向下逐層把系統劃分紅若干模塊的過程,有多種屬性、分別反映其內部特性。git
在咱們的生活中也常常會見到模塊化的應用場景,好比如今的家用電器(電視機、電腦主機等)都是模塊化的,若是這些家電壞了,維修的時候通常都是直接拿個新的模塊更換一下就能夠了,由此能夠看出,模塊化不只僅是編程語言的概念。模塊化應用到生活中,一樣是能夠提升辦事效率的。github
那咱們主要說的前端模塊化具體指什麼呢?
前端模塊化通常指的是JavaScript
的模塊,最多見的是Node.js
中的NPM
包管理,有了模塊化,咱們在寫代碼的時候就避免了不少的重複工做,也不在只是作copy的事情了。有了模塊化以後,開發者能夠把更多的時間精力放到業務邏輯和代碼的維護上。目前,有不少主流的模塊化規範,好比CommonJS
、AMD
、ES6 Module
等規範,甚至在CSS
中也採用了@import
的方式實現模塊化。Less
和Sass
做爲CSS
的預處理語言,使用了@import
來導入一些變量、函數和mixin
的定義。
接下來,咱們在聊聊什麼是工程化。當開發Web應用的場景愈來愈複雜時,咱們所面臨的問題也會隨之增長:
在大型項目中,多模塊下如何管理依賴?
頁面複雜度提高以後,多頁面、多系統、多狀態怎麼辦?
團隊協做開發中如何統一規範?
……
以上這些問題都是在軟件工程中必需要解決的問題,工程化問題須要運用工程化工具來解決。在早期,前端工程化主要是以Grunt
、Gulp
等構建工具爲主,在這個時期解決的是重複任務的問題,他們將某些功能拆解成固定步驟的任務,而後編寫工具來解決,好比:圖片壓縮、地址添加hash等,都是固定套路的重複工做。
在近幾年,前端工程化的發展得益與Node.js
的發展,Webpack
的插件機制解決了前端資源依賴管理的問題,從而進化成了一整套前端工程化解決方案。
官方解釋:
本質上,
webpack
是一個現代JavaScript
應用程序的靜態模塊打包器(module bundler)。當webpack
處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個bundle
。
通常像Grunt
、Gulp
這類的構建工具,打包思路是:先遍歷源文件,而後匹配規則,最後再打包,這個過程很耗費資源。而Webpack
能夠作到按需加載,與其餘構建工具不一樣之處在於:Webpack
是從入口文件開始,通過模塊依賴加載、分析和打包三個流程完成項目的構建。在加載、分析和打包的三個過程當中,能夠針對性的作一些解決方案,達到按需加載的目的,好比拆分公共代碼(code split)等。
Webpack
在打包時遵循「一切皆模塊」的思想,即JS
是模塊,CSS
等文件也是模塊,還能夠將ES6
轉爲ES5
,而且能夠對Less
、Sass
這些CSS
預處理器進行編譯。在打包過程當中經過強大的Loader
和插件機制來完成解決方案的封裝,最後對項目進行壓縮和優化等操做。Webpack
解決了傳統構建工具實現不了的問題,被更多的前端開發者使用。
Webpack
實際是用Node.js
寫的,因此要先安裝Node.js
環境。
首先進入Node.js的官網,選擇對應系統下載安裝包:
對於 windows
用戶,直接下載安裝包安裝便可,若是是 Macos
用戶,推薦使用 brew 進行安裝。
Node.js
有不少版本,包括穩定版和開發版,不一樣的項目須要的Node.js
版本不一樣,推薦你們安裝 8.x
以上的版本。
(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
修改;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
經常使用命令中,咱們有講到 dependencies
和 devDependencies
的命令分別是:
# 自動把模塊和版本號添加到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
安裝包的話,就會看到cache
和prefix
兩個路徑,以下圖:
第一步:
在欲更改的目錄下新建兩個文件夾,分別是:node_global_modules
和 node_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 build
和npm run start
命令了 ,並且npm run start
命令還能夠簡寫成npm start
。
注意:上面提到的簡寫,只有
npm run start
才能夠簡寫,並非全部script命令都支持這種簡寫的方式。除了
npm
外,還有一些包管理工具,主要是針對npm
的下載速度慢、node_modules
混亂等缺點設計的,例如yarn和 pnpm。
在後面會講到使用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)安裝Webpack
webpack
的安裝須要使用NPM
來完成,安裝命令以下:
## 全局安裝
npm install -g webpack
## 安裝到項目目錄中
npm install --save-dev webpack
複製代碼
安裝好以後,就可使用webpack
的命令了。
(2)安裝Webpack-cli
Webpack-cli是 Webpack
的 CLI
(Command-line interface)工具,若是在項目中,咱們可使用下面的方式安裝:
# 本地安裝
npm install webpack-cli --save-dev
# 全局安裝
npm install webpack-cli -g
複製代碼
因爲webpack
是用於項目構建和打包的工具,因此咱們在安裝時使用--save-dev
命令把webpack-cli
放到開發環境的字段下。
當咱們安裝好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
把整理後的資源放在哪裏。
webpack
主要有4個核心概念:
入口(entry
):項目入口,也是webpack
全部依賴關係圖的起點。
出口(output
):指定webpack
打包應用程序的目錄。
加載器(loader
):加載須要處理的模塊,對模塊進行轉換處理。
插件(plugins
):定義項目要用到的插件。
在前面的內容中,咱們已經瞭解到了,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
屬性默認是dis
,filename
屬性默認是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
中的key
(home
、search
、list
),最終輸出的結果是:
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 的函數 |
loader
是解析處理器,你們都知道,webpack
的任務就是把具備依賴關係的各個文件進行整合並打包,這些文件的類型有不少,好比.html
、.css
、.js
、.scss
、.jpg
等等。可是webpack
只認識JavaScript
文件,那如何識別其餘文件呢?loader
就解決了這個問題。好比,不少瀏覽器不支持ES6
語法,webpack
能夠經過loader
配置,將ES6
語法轉化爲ES5
的語法,還能夠將圖片轉化爲base64
的dataURL
,還能夠經過loader
直接在JavaScript
文件中使用import
引入css
和html
。
loader
在webpack
構建文件的過程當中起着相當重要的做用,實現能夠經過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
最新版本中已經廢棄了loaders
、loader
的寫法,改爲了rules
、use
。
plugin
在webpack
起着重要的做用,經過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
的編譯器,咱們在webpack
中可使用ES6
以上版本的語法寫代碼,可是目前主流的瀏覽器僅支持ES5
語法,經過Babel
能夠將ES6+
語法自動轉換成ES5
語法,來適配瀏覽器的JavaScript
解釋器。
好比說,咱們使用ES6
語法中的箭頭函數實現代碼:
(val) => (val + 1) ;
複製代碼
使用Babel
轉化成ES5
語法後:
function(val){
return val+1 ;
}
複製代碼
在項目中安裝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);
});
複製代碼
Babel
還支持配置文件的方式進行轉化操做,配置文件支持兩種形式:
(1)使用package.json
的babel
屬性
示例:
{
"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"]
}
複製代碼
第一步:安裝依賴包
# 安裝開發依賴
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.json
的 babel
字段。
webpack-dev-server
就是一個Express
的小型服務器,經過Express
的中間件 webpack-dev-middleware
和 Webpack
進行交互的。
在項目中安裝:
npm i webpack-dev-server
複製代碼
啓動服務:
npx webpack-dev-server
複製代碼
服務啓動成功後,在瀏覽器中訪問webpack-dev-server
的默認地址 localhost:8080
,就能夠默認的index.html
頁面,若是沒有該頁面,就會顯示文件目錄。
將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.json
的scripts
裏面,來簡化服務啓動命令:
{
"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
命令。
熱加載也叫模塊熱替換( 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-server
的cli
功能只須要經過執行下面命令,就能夠開啓自動刷新功能:
webpack-dev-server --hot --inline
複製代碼
執行上面命令會自動將webpack.HotModuleReplacementPlugin
這個插件添加到 Webpack
的配置中去。這種是最簡單的配置方式了。
常見配置以下:
# 修改端口號和 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
項目的文件夾,在項目根目錄下打開命令提示符,執行初始化命令,生成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.html
到 dist
文件夾下。
首先是安裝 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
複製代碼
(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
中修改內容,保存後會看到瀏覽器內自動更新,效果以下圖:
Create React App
是FaceBook
的React
團隊官方出的一個構建React
單頁面應用的腳手架工具。它自己集成了Webpack
,並配置了一系列內置的loader
和默認的npm
的腳本,能夠很輕鬆的實現零配置就能夠快速開發React
的應用。
create-react-app
是React
中最簡單的建立單頁面程序的方式,安裝命令以下:
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
的知識遠遠比這篇教程中的內容要多,不過對於項目開發來講,掌握這些基礎知識就夠用了。你們必定要培養獨立思考和解決問題的能力,在項目構建過程當中,若是遇到了問題,根據所學的知識尋找解決問題的方法,經過實踐來提高本身的編程能力,你們加油!