不会webpack的前端可能是捡来的,万字总结webpack的超入门核心知识
一文了解webpack入門核心知識
- 🎨序言
- 📅一、webpack究竟是什么
- 1、寫在前面
- 2、什么是模塊打包工具?
- 📐二、如何用Webpack搭建環境
- 1、安裝node
- 2、創建項目
- 3、初始化項目
- 4、安裝webpack
- 5、安裝具體版本的webpack
- ??三、Webpack的配置文件
- 1、默認配置文件
- 2、用npm script來簡化我們的打包代碼
- 3、淺談webpack打包輸出內容
- 🔑四、Loader
- 1、引例闡述
- 2、什么是Loader
- 3、使用Loader打包靜態資源(圖片篇)
- (1)自定義命名圖片
- (2)打包各種類型的圖片文件
- (3)打包到image文件下
- (4)url-loader
- 4、使用Loader打包靜態資源(樣式篇)
- (1)打包css文件
- (2)打包sass文件
- (3)兼容性問題
- 5、增加配置項
- 6、如何使用webpack打包字體文件
- 🧲五、使用plugins讓打包更便攜
- 1、html-webpack-plugin
- 2、clean-webpack-plugin
- 🗞?六、Entry和Output
- 🗺?七、SourceMap
- 1、引例闡述
- 2、sourceMap
- 3、sourceMap常見配置
- 🧱八、使用WebpackDevServer提升開發效率
- 1、--watch
- 2、webpackDevServer
- (1)安裝webpackDevServer
- (2)配置package.json文件
- (3)配置 webpack文件
- (4)配置端口號
- 🌡?九、Hot Module Replacement 熱模塊更新
- 1、引例闡述
- 2、熱模塊更新配置
- 📀十、使用Babel處理ES6語法
- 1、ES6語法轉換為ES5語法
- 2、Babel-polyfill
- 📚十一、結束語
- 🐣彩蛋 One More Thing
- 往期推薦
- 番外篇
🎨序言
眾所周知,在前端工程化日趨復雜的今天,模塊化打包工具在我們的日常開發中起著越來越重要的作用,而其中, webpack 已然是前端打包構建的不二選擇。
說到 webpack ,可能很多小伙伴會覺得既熟悉又陌生,熟悉是因為在我們開發的每一個項目中,都會使用到它。而陌生在于, webpack 有著復雜的配置和五花八門的功能而感到陌生。
因此,我們有時候會被這復雜的配置先嚇到,從而被勸退學習。
然而,在技術更新迭代這么快的一個大環境下, webpack 還是很值得我們去學習的。
在下面的這篇文章中,將講解 webpack 的核心概念。一起來學習吧~🎬
📅一、webpack究竟是什么
1、寫在前面
當我們要寫一個網頁時,首先我們會先創建一個 index.html 文件,之后在可能還會有一些 js 文件,那么我們就會在 html 文件中,引入這些 js 文件。
試想一下,如果 js 文件很多,然后我們一個個引入,這樣如果遇到報錯了呢?會不會就很難定位到是哪個文件錯了,這樣就會使得開發效率非常低下了。
因此,就有了 webpack 。 webpack 會將我們所寫的代碼,進行一個翻譯,并將翻譯完的內容,進行一個模塊化的打包,使得項目變得工程化。
接下來,我們就來講解, webpack 究竟是什么以及怎么安裝使用。
2、什么是模塊打包工具?
webpack 有時候會被誤認為是一個 js 的翻譯器,但其實 webpack 稱不上是一個 js 的翻譯器。
因為它只認識 import 這樣類似的語句,而不認識其他的 js 高級語法。所以如果稱它是一個 js 的翻譯器,實際上是我們高看了它。
查看官方的定義我們可以發現, webpack 是一個模塊打包工具,同時 webpack 也可以支持 commonjs 的模塊打包規范。
然而,隨著時間的推移和技術的不斷更新, webpack 不再是只會打包 js 的模塊打包工具, webpack 現在還支持 css文件 、 jpg 、 png 等各種文件的打包。
📐二、如何用Webpack搭建環境
1、安裝node
webpack 是基于 nodejs 開發的模塊打包工具,本質上是由 node 實現的。因此我們要先安裝本機的 node 環境。這里附上官方網站的鏈接,建議大家下載穩定版本
之后查詢本機的 node 和 npm 版本,查看是否安裝成功。
node -v npm -v2、創建項目
先創建一個項目,假設命名為 webpack-demo 。之后在該項目下通過以下命令創建一個文件夾:
mkdir webpack-demo3、初始化項目
進入 webpack-demo 文件,初始化項目。命令行如下:
cd webpack-demo npm init 或 npm init -y //加-y表示默認自動配置項之后一路 Enter 回車即可。
大家可以看到項目結構,以上操作就是在 webpack-demo 文件下創建了一個 package.json 文件,之后我們把 package.json 文件的內進行改造。具體代碼如下:
{"name": "webpack-demo","version": "1.0.0","description": "",//將這個項目設置為私有"private":true,//"main": "index.js", //去掉入口文件"scripts": {"test": "echo \"Error: no test specified\" && exit 1"},//寫上作者名"author": "Monday",//保持項目私有"license": "ISC" }4、安裝webpack
第一種方式:全局安裝
npm install webpack webpack-cli -g第二種方式:當前項目下安裝
npm install webpack webpack-cli -D在這里的建議是選擇第二種方式進行安裝。那為什么呢?是因為全局安裝 webpack 有什么問題嗎?
事實上,全局安裝只會安裝一個版本。
那么假如我們現在要跑兩個項目,并且這兩個項目出現原先安裝的 webpack 版本不一樣,安裝低版本 webpack 的項目,就有可能會導致在我們的本機中運行不起來。所以建議是使用第二種方式進行安裝。
安裝完成之后,我們還要來查詢當前使用的 webpack 版本號,以確保我們是否已經安裝成功。具體命令行如下:
npx webpack -v這個時候就有小伙伴會有疑問說,為什么前面還要加個 npx 才能查找版本號。
原因在于,我們只在當前項目中安裝,所以 webpack 這個命令在全局中并沒有找到。而 node 提供了 npx ,這個時候 npx 就可以找到我們所運行項目目錄下的 node-module 中的 webpack 安裝包,所以這種方式是把我們的 webpack 安裝在我們的項目內,然后通過 npx 去運行 webpack 就可以了。
5、安裝具體版本的webpack
如果我們想要安裝具體版本號的 webpack ,那么我們先查看 webpack 的版本號信息。命令如下:
npm info webpack查到具體版本號以后,使用以下命令進行安裝:
npm install webpack@4.16.5 webpack-cli -D //4.16.5表示版本號??三、Webpack的配置文件
1、默認配置文件
很多時候,我們還沒寫配置文件,項目就成功跑起來了。這并不是因為不用寫,而是 webpack 團隊提前幫我們寫好了很多默認的配置文件,使得我們在運行項目時不用進行過多的配置就可以達到我們的使用需求。那下面,就跟著大家一起來寫一個配置文件。
我們先來了解下項目結構,在我們創建完項目時,我們的源代碼一般放在 src 文件夾下,并且打包后的文件一般放在 dist 文件下,同時 webpack 的配置文件命名為 webpack.config.js ,并且放在項目的根目錄下。
├── dist 放置打包后的文件 ├── src 放置項目源代碼 ├── webpack.config.js webpack配置文件 ├── package-lock.json ├── package.json看完項目結構,我們來了解一下 webpack 的配置文件具體需要怎么配置。具體代碼如下:
//node的核心模塊 const path = require('path');module.exports = {//設置為development時,代碼不會進行壓縮;設置為production時,代碼會進行壓縮。mode:'production',// 放置入口文件,明確怎么打包,要打包哪一個文件entry: './src/index.js',//entry: {// main: './src/index.js'//},// 輸出,表明webpack應該怎么輸出,輸出到哪個地方output: {filename: 'bundle.js',// 指打包后的文件要放在哪個文件下// __dirname表示該項目的根目錄path: path.resolve(__dirname, 'dist')} }了解完基本配置,此時可能有小伙伴心里有一個疑惑, webpack 配置文件的命名一定要命名為 webpack.config.js 嗎,是否可以命名為其他的呢?
答案是肯定可以的,不過我們需要進行一個特殊處理。平常如果我們命名為 webpack.config.js 時,可以直接使用 npm webpack 來跑我們的項目。如果不用這個命名時,假設命名為 webpackconfig.js ,那么我們可以通過以下命令行,來打包我們具體的項目。
npx webpack --config webpackconfig.js以上命令行的意思為:指讓 webpack 來幫我們打包,具體打包哪一個文件呢?以 webpackconfig.js 為配置文件,來幫我們打包。
2、用npm script來簡化我們的打包代碼
看完上面的內容,相信小伙伴們對 webpack 有了一個基礎的認識。
那試想以下,經常要使用 npx webpack 來幫我們打包文件,這樣是不是會有點略顯麻煩呢?
所以,我們來再了解一個內容:使用 npm script 來簡化我們的打包代碼。
再我們的項目根目錄下,會有一個 package.json 文件,這個文件的代碼如下:
{"name": "webpack-demo","version": "1.0.0","description": "","private": true,"main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"author": "Monday","license": "ISC","devDependencies": {"webpack": "^5.39.1","webpack-cli": "^4.7.2"} }大家定位到scripts部分,接下來,我們把script部分進行一個改造。具體代碼如下:
"scripts": {/* webpack 會先到node_module下面進行打包*/"bundle": "webpack"},改造完成以后,我們就相當于在 package.json 里面配置了一個 npm script ,上面的代碼意思為這個 script 對應的名字叫做 bundle ,之后呢, bundle 的底層會幫助我們執行 webpack ,并進行打包。
這么編寫之后,我們就不再需要使用 npx webpack 來做運行 webpack ,而是使用 npm run bundle 來做命令進行打包。
3、淺談webpack打包輸出內容
講解完上面的內容,我們來對 webpack 打包以后控制臺的一些輸出內容進行歸納總結。
| hash | 代表本次打包對應的唯一哈希值 |
| version | 代表此次打包使用的webpack的版本 |
| time | 當前項目整體打包的具體耗時 |
| assets | 打包后的文件具體是哪一個,比如:bundle.js |
| size | 打包后文件的大小 |
| chunks | 放置自己對應文件的id值以及對應文件所引入其他文件的id值 |
| chunk Names | 對應entry配置的main |
🔑四、Loader
1、引例闡述
Webpack 默認是知道如何打包 js 模塊的,但是它不知道 jpg 這種文件該怎么打包。
這個時候我們需要在 webpack.config.js 文件下做配置,配置 file-loader 。我們在配置中增加一個新的 module 。具體代碼如下:
module:{rules:[{test:/\.jpg$/,use:{loader:'file-loader'}}]},接下來我們來正向分析下 webpack 是如何打包 jpg 這種靜態文件的。
首先 webpack 會進入src 目錄, new 一個 index.js 文件,那么現在我們要對這個文件進行打包。
所以,我在命令行里,運行了 npm run bundle 。當你運行 npm run bundle 時,實際上在執行的是 package.json 里面的 script ,這個 script 幫我們運行 webpack ,然后呢, webpack 幫我們做打包。這個時候 webpack 就會去找它相對應的配置,根據這個配置幫我們做打包。
那么我們來看一下,如果我們遇到的是 js 文件,那么 webpack 默認會進行打包。但是呢?如果遇到的是一張 jpg 的圖片呢? webpack 這個時候就懵了, webpack 并不認識 jpg 這種格式的代碼。
因此,我們就可以引用一個模塊module,來幫我們打包。這個模塊叫 file-loader ,file-loader 這個 loader 就可以幫助我們完成打包的過程。
那么實際上, file-loader 的底層,幫我們做了什么事情呢?
當我們打包 jpg 文件時, webpack 會把 jpg 文件移動到 dist 文件下,并且對 jpg 文件賦予一個新的名稱。然后呢,它會把這個名稱作為一個返回值,返回給我們引入模塊的變量之中。
這就是 file-loader 底層處理打包文件的一個流程。
當然。 file-loader 不僅僅可以處理 jpg 這樣的文件圖片。理論上,它還可以處理很多種類型的靜態資源。
2、什么是Loader
闡述了 file-loader 之后,相信大家對 loader 有了一個基礎認識。那么我們現在就來對loader的基礎定義進行梳理。具體如下:
本身 webpack 對于一些文件是不知道如何處理的,但是 loader 知道。所以呢,當遇到一些 非js 文件時,一般去求助于 loader 就可以了。因此我們就需要讓 webpack 去求助 loader 模塊,來識別出 非js 的文件。
引用 webpack 官方中文文檔的一句話,文檔中說到: webpack 只能理解 JavaScript 和 JSON 文件,這是 webpack 開箱可用的自帶能力。loader 讓 webpack 能夠去處理其他類型的文件,并將它們轉換為有效模塊,以供應用程序使用,以及被添加到依賴圖中。本質上, loader 是導出為函數的 JavaScript 模塊。
3、使用Loader打包靜態資源(圖片篇)
(1)自定義命名圖片
如果我們現在要對打包后的圖片進行自定義命名,那該怎么做呢?
我們在 webpack.config.js 文件下的 module 再進行改進。具體代碼如下:
module:{rules:[{test:/\.jpg$/,use:{loader:'file-loader',options: {//placeholder 占位符name: '[name]_[hash].[ext]'}}}] }通過配置 options ,就可以達到圖片自定義命名的效果。
(2)打包各種類型的圖片文件
假設我們現在不局限于打包 jpg 文件,還想要打包其他的圖片文件。那么我們可以這樣配置:
module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'file-loader',options: {//placeholder 占位符name: '[name]_[hash].[ext]'}}}] }通過正則表達式的方式,來增加新的圖片類型。
(3)打包到image文件下
假設我們現在想要把打包后的文件放到 image 文件下,那該怎么做呢?具體代碼如下:
module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'file-loader',options: {//placeholder 占位符name: '[name]_[hash].[ext]',//將jpg、png和gif圖片文件,指定到dist目錄下的images文件下outputPath: 'images/'}}}] }(4)url-loader
在使用了 file-loader 之后,我們再來了解一個知識點: url-loader 。 url-loader 可以達到幾近 file-loader 的效果。具體使用方法如下:
npm i url-loader -D module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'url-loader',options: {name: '[name]_[hash].[ext]',outputPath: 'images/'}}}] }我們只要安裝上 url-loader ,并且在配置中將 file-loader 替換為 url-loader 即可。
但值得注意的是,使用 url-loader 進行打包,會有一些需要注意的事項。
當你去打包一個 jpg 文件的時候,與 file-loader 不一樣的是, url-loader 會將圖片轉換成一個 base64 的字符串,然后直接放到我們 dist 目錄下的 bundle.js 里面,而不是單獨生成一個圖片文件。
好處就是,直接訪問,而不用去文件夾下訪問,節省了一次 http 請求。
而帶來的壞處就是,如果這個 js 文件特別大,那么打包生成的js文件也將會特別大,隨之加載這個 js 的時間就會很長。
所以, url-loader 的最佳使用方式是什么呢?
如果說我們引入的圖片很小,只有 1~2KB 等小的體積,那么這個圖片以 base64 的形式打包到 js 文件里,是一個很好的選擇,就沒有必要讓這么小的圖片再去發一次 http 請求。
但假設這個圖片很大的話,那么盡量不要使用 url-loader ,而使用 file-loader ,把這個圖片打包到dist目錄下,不要打包到 bundle.js 里面。不然會使得 bundle.js 文件變得很大,使得加載時間變得很長,不利于維護。
還有一種方法就是,我們可以直接在 url-loader 下再加一個配置: limit 。具體代碼如下:
module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'url-loader',options: {name: '[name]_[hash].[ext]',outputPath: 'images/',//20480=>20KBlimit: 20480}}}] }通過以上代碼我們可以知道,當使用 url-loader 時,我們可以給其加一個 limit 屬性。那么上面代碼所要表達的意思就是,當圖片文件大小大于 20KB 時,我們使用 url-loader 打包。當大于 20KB 時,就將圖片文件放到 dist 的 images 文件下。
4、使用Loader打包靜態資源(樣式篇)
(1)打包css文件
比如說,我們現在想要讓一張圖片的大小為 150*150 ,那么我們就需要寫下樣式來修改這張圖片。那 webpack 如何打包 css 文件呢?
我們可以使用 css-loader 和 style-loader 來對文件進行打包。具體配置如下:
npm install sass-loader node-sass --save-dev module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'file-loader',options: {//placeholder 占位符name: '[name]_[hash].[ext]',outputPath: 'images/'}}},{test:/\.css$/,use:['style-loader', 'css-loader']}] }css-loader 會幫我們分析出,幾個 css 文件之間的關系,最終把一個 css 文件,合并成一個 css 。那 style-loader 的作用又是是什么呢?
在得到了 css-loader 生成的 css 文件之后, style-loader 會把這段內容掛載到頁面的 head 部分,并將樣式掛載到 head 中的 <style></style> 里面。
(2)打包sass文件
如果是要打包 sass 文件呢,則使用 sass-loader 、 style-loader 和 css-loader 這三個 loader 來對文件進行打包。具體配置如下:
npm install sass-loader node-sass --save-dev module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'file-loader',options: {//placeholder 占位符name: '[name]_[hash].[ext]',outputPath: 'images/'}}},{test:/\.scss$/,use:['style-loader', 'css-loader', 'sass-loader']}] }值得注意的是, loader 的執行順序是從下到上,從右到左。
所以當我們去執行一個 sass 文件時,首先會執行 sass-loader ,之后執行 css-loader ,最后才執行 style-loader 。
(3)兼容性問題
有時候我們如果想要兼容多個瀏覽器時,那么我們可能會在 css 文件里面添加 -webkit- 等廠商的前綴。但是呢,要知道 webpack 是沒辦法識別這些前綴的。這個時候我們了解一個新的 loader ,就是 postcss-loader ,這個loader可以自動地幫我們添加廠商前綴的信息。具體使用方式如下:
首先我們先安裝 postcss-loader 這個庫,具體代碼如下:
npm i postcss-loader -D安裝完成之后,我們在項目根目錄下創建一個新的文件,名字叫 postcss.config.js ,之后對這個文件進行配置,代碼如下:
首先安裝 autoprefixer :
npm install autoprefixer -D安裝完成之后,現在我們在 postcss.config.js 文件下來使用它,具體代碼如下:
module.exports = {Plugin:[require('autoprefixer')] }接下來我們在 webpack.config.js 文件下面,使用 postcss-loader 。具體代碼如下:
module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'file-loader',options: {//placeholder 占位符name: '[name]_[hash].[ext]',outputPath: 'images/'}}},{test:/\.scss$/,use:['style-loader', 'css-loader', 'sass-loader','postcss-loader']}] }通過以上方式, webpack 就可以在幫我們打包靜態文件時,把對應的需要加入廠商前綴的樣式給添加上前綴。
5、增加配置項
假設我們現在想要給某一個 loader 增加配置項,比如說我們要給 css-loader 增加配置項,那么我們可以對代碼進行如下處理。具體代碼如下:
module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'file-loader',options: {//placeholder 占位符name: '[name]_[hash].[ext]',outputPath: 'images/'}}},{test:/\.scss$/,use:['style-loader', {loader: 'css-loader',options: {//表明前面要先走sass-loader和postcss-loaderimportLoaders: 2}}, 'sass-loader','postcss-loader']}] }從以上代碼中我們可以看到,當我們想要給 css-loader 增加配置項時,那么不再使用字符串的形式,我們把字符串轉化成一個對象。在對象里面,我們填寫相應的 loader 和 options 配置,這樣就達到了我們想要的需求。
有時候我們在一個頁面上,如果全局引入 css ,可能會很容易導致樣式沖突問題。那這種情況該怎么處理呢?
為此我們可以借助 css-loader 中的 modules 來實現 css 的模塊化,旨在讓引入的 css 文件擁有它獨立的模塊。那具體該怎么使用呢?
module:{test:/\.scss$/,use:['style-loader', {loader: 'css-loader',options: {//表明前面要先走sass-loader和postcss-loaderimportLoaders: 2,modules: true}},'sass-loader','postcss-loader']}] }從以上代碼中我們可以知道,通過 modules:true 語句,就可以開啟 css 的模塊化打包。開啟之后,我們就可以在各種文件下引入。引入方式如下:
import style from './index.scss';var img = new Image(); img.src = bug; img.classList.add(style.bug);從上述代碼中我們可以看到,開啟 module 后,就可以隨心所欲的引用該 css 中的內容啦!
6、如何使用webpack打包字體文件
有時候我們在項目中有可能會遇到想要引入字體的問題,那 webpack 如何打包字體呢?具體代碼如下:
module:{rules:[{test: /\.(eot|ttf|svg)$/,use: {loader: 'file-loader',}}]},通過以上代碼我們可以知道,跟 webpack 相關的靜態文件格式為 eot、ttf和svg 等格式,所以需要需要把這幾種類型引入。同時,跟其相關的 loader 為 file-loader 。
學完關于如何打包靜態資源后,建議可以再用官方文檔的相關部分來進行復習,具體鏈接戳~
🧲五、使用plugins讓打包更便攜
1、html-webpack-plugin
在學習了如何使用 loader 來打包靜態文件之后,接下來我們一起來了解在 webpack 中,如何使用 plugins 讓打包更便捷。
我們在打包項目時, webpack 總是會把打包后的內容放到 dist 目錄下。這個時候我們可能還需要自行再去創建一個 index.html 來引入核心文件。那這樣會不會就顯得略有點麻煩了?
因此, webpack 給我們提供了 plugin 插件來解決這個問題。
首先,我們先來安裝 plugin ,具體命令行如下:
npm install html-webpack-plugin -D接下來我們將插件引入 webpack.config.js 當中,具體代碼如下:
const HtmlWebpackPlugin = require('html-webpack-plugin');plugins: [new HtmlWebpackPlugin({//表明要引用哪一個模板template: 'src/index.html'})]現在,我們來梳理一下 htmlWebpackPlugin 如何幫我們完成自動打包。
首先, htmlWebpackPlugin 會在打包結束后,自動生成一個 html 文件。之后呢,把打包生成的 js 文件自動引入到這個 html 文件中。
所以,從某種程度上來說就是, plugin 可以在 webpack 運行到某個時刻的時候,自動地幫你做一些事情。即當我們打包結束的這兒一時刻, plugin 會自動幫我們創建 html 文件以供我們直接使用。
2、clean-webpack-plugin
有時候我們有可能對 webpack.config.js 中的output所對應的filename進行修改,這就很容易導致在打包過程中遇到多文件沖突。
那么我們想要實現的就是,在打包時,先清空原來的dist文件夾,然后再生成一個新的dist文件夾。如何處理呢?請看下方。
首先我們先安裝依賴 clean-webpack-plugin ,具體命令行如下:
npm install clean-webpack-plugin -D接下來我們將插件引入 webpack.config.js 當中,具體代碼如下:
const CleanWebpackPlugin = require('clean-webpack-plugin');plugins: [new HtmlWebpackPlugin({//表明要引用哪一個模板template: 'src/index.html'}),new CleanWebpackPlugin(['dist'])]通過以上代碼,就可以在我們項目打包時,先刪除 dist 文件夾,之后再創建一個新的文件夾。
🗞?六、Entry和Output
接下來我們再來看 webpack 中的 entry 和 output 中幾個比較核心的配置。
module.exports = {mode:'development',// 放置入口文件,明確怎么打包entry:{main: './src/index.js',sub: './src/index.js'},plugins: [new HtmlWebpackPlugin({//表明要引用哪一個模板template: 'src/index.html'}),new CleanWebpackPlugin(['dist'])],// 輸出,表明webpack應該怎么輸出output: {//如果把資源放在cdn下,則引入cdnpublicPath: 'http://cdn.com.cn',//當entry有多個入口文件時,用[]可以輸出多個文件filename: '[name].js',// 指打包后的文件要放在哪個文件下path: path.resolve(__dirname, 'dist')} }🗺?七、SourceMap
1、引例闡述
有時候,我們在寫代碼時,總會莫名的出bug。看著控制臺那紅紅的報錯,心里總歸很不是滋味。同時,如果我們沒有配置好 webpack 的話,那錯誤找起來簡直是很恐怖的。
比如,在開發模式下,我們默認 webpack.config.js 像下面這樣配置,具體代碼如下:
module.exports = {mode:'development',devtool: 'none',entry:{//打包到dist目錄下的main.jsmain: './src/index.js'},output: {//用[]可以生成多個文件filename: '[name].js',// 指打包后的文件要放在哪個文件下path: path.resolve(__dirname, 'dist')} }然后呢,假設我們現在代碼里面錯把 console.log 寫成 consele.log 。那么現在控制臺的打印效果如下:
大家可以看到,此時的錯誤定位到打包后的 main.js 文件里面的第96行。那試想一下,如果我們的業務代碼特別多,報錯有可能就是在文件中的上前行了。
這樣的場景并不是我們想看到的。我們想做的事情呢就是,希望 webpack 打包完成之后就把錯誤直接拋給我們,并把其對應的具體文件地址顯示出來。也就是我們出錯的那個代碼文件,而不是打包后的文件 main.js 。
因此, webpack 給我們提供了 sourceMap 這個配置,來解決這個問題。
2、sourceMap
我們現在把 devtool 這個配置,改成 sourceMap 。具體代碼如下:
module.exports = {mode:'development',devtool: 'source-map',entry:{//打包到dist目錄下的main.jsmain: './src/index.js'},output: {//用[]可以生成多個文件filename: '[name].js',// 指打包后的文件要放在哪個文件下path: path.resolve(__dirname, 'dist')} }改完之后呢,我們來看一下控制臺的打印結果:
現在大家可以看到,改成 source-map 的配置之后,報錯的定位直接到了我們自己所編寫代碼的目錄下,即 index.js 。而不再是大海撈針似的在 main.js 里面找。
3、sourceMap常見配置
看完上面的例子之后,相信大家對 SourceMap 有了一定的了解。接下來我們來看一下 sourceMap 的一些常見配置。具體看看下方:
| inline-source-map | 報錯時將行和列都顯示出來 |
| cheap-inline-source-map | 報錯時只知道哪一行出錯了,不知道在哪一列 |
| cheap-module-source-map | 生產環境最佳實踐,不僅管自己的業務代碼錯誤,還要管其他的其他的錯誤,像loader、其他第三方模塊的錯誤等等 |
| eval | eval是打包速度最快的一種方式,但如果遇到業務代碼比較復雜的情況下,用eval提示出來的效果可能不太全面 |
| module-eval-source-map | 用module,表明不僅要顯示業務錯誤,還要顯示loader、第三方錯誤等等 |
| cheap-module-eval-source-map | 開發環境最佳實踐 |
🧱八、使用WebpackDevServer提升開發效率
1、–watch
事實上,如果我們不采用 WebpackDevServer 的方式來開發的話,那么我們每一次想要查看編譯后的運行結果,都需要先命令行編譯 npm run bundle 命令,之后再打開 dist 目錄下的 index.html 文件才能重新查看。這樣一來二往的,難免效率低下。我們期待的結果是什么呢?
我們把 package.json 文件里的 script 進行一番改造,具體代碼如下:
"scripts": {"watch": "webpack --watch","bundle": "webpack"},通過以上代碼大家可以看到,將 webpack 后面加上 --watch 字段,然后運行 npm run watch ,就可以每次修改完代碼后, webpack 實現自動監聽,而不用像以往那樣,每修改一次代碼都要對再重新運行命令來對 webpack 進行打包。
2、webpackDevServer
但是呢,這種方式可能還不夠友好,畢竟開發者總是懶惰的,能盡量讓程序來干活就不要用手工來干活。
實際上我們想要達到的效果是,當我們運行完 npm run watch 這行命令的時候,不僅能自動幫我們實現打包,同時還能幫我們打開控制臺,并且模擬一些服務器上的特性。那么我們就可以通過 webpackDevServer 來實現我們想要的效果。如何使用 webpckDevServer 呢?具體看下方。
(1)安裝webpackDevServer
我們現在項目中安裝webpackDevServer,具體命令行如下:
npm install webpack-dev-server -D(2)配置package.json文件
接下來我們來配置 package.json 文件的 script 。具體代碼如下:
"scripts": {"watch": "webpack --watch","start": "webpack-dev-server"},(3)配置 webpack文件
接下面我們來配置 webpack.config.js 文件,具體代碼如下:
module.exports = {mode:'development',devtool: 'source-map',// 放置入口文件,明確怎么打包entry:{main: './src/index.js'},devServer: {contentBase: './dist',// 當運行完npm run start時,會自動的幫我們打開瀏覽器open: true},output: {//用[]可以生成多個文件filename: '[name].js',// 指打包后的文件要放在哪個文件下path: path.resolve(__dirname, 'dist')} }那么現在,我們來看下, webpackDevServer 如何做到自動打開瀏覽器。詳情見下圖:
大家可以看到,通過 webpackDevServer ,它不但會監聽到我們的文件發生了改變,重新幫我們進行打包。同時它還會自動的幫我們重新刷新瀏覽器,并且會自動地幫我們打開瀏覽器。所以用它呢,可以大大提升我們的代碼開發效率。
(4)配置端口號
webpackDevServer 默認我們服務器的端口號是 8080 ,如果我們想要修改它為其他的端口號,該怎么做呢?
我們需要在來修改 webpack.config.js 文件下的 DevServer ,具體代碼如下:
module.exports = {mode:'development',devtool: 'source-map',// 放置入口文件,明確怎么打包entry:{main: './src/index.js'},devServer: {contentBase: './dist',// 當運行完npm run start時,會自動的幫我們打開瀏覽器open: true,//修改端口號port: 3000},output: {//用[]可以生成多個文件filename: '[name].js',// 指打包后的文件要放在哪個文件下path: path.resolve(__dirname, 'dist')} }我們只需要在 devServer 里面加上一個 port 的配置,即可實現自定義端口號。
同時值得注意的是,當我們在用 webpackDevServer 幫我們項目做打包時,它不會自動生成 dist 目錄,那這是為什么呢?用 webpackDevServer 打包后的項目會放在我們的電腦內存中,這在某種程度下可以有效的提升項目的打包速度,讓打包變得更快。
🌡?九、Hot Module Replacement 熱模塊更新
1、引例闡述
假設我們現在要實現一個新增元素的功能,這個功能所要達到的效果是每點擊一次按鈕,就新添加一次文本 item 。具體實現代碼如下:
index.js文件:
import './style.css';var btn = document.createElement('button'); btn.innerHTML = '新增'; document.body.appendChild(btn);btn.onclick = function(){var div = document.createElement('div');div.innerHTML = 'item';document.body.appendChild(div); }style.css文件:
div:nth-of-type(odd){background: yellow; }此時瀏覽器的顯示效果如下圖所示:
假設我們現在來給css的背景改個顏色,比如說改成紫色。具體代碼如下:
div:nth-of-type(odd){background: purple; }此時我們保存后瀏覽器會重新進行刷新,之后每一個 item 又要重新 append 進來。如下圖:
那這種情況下可能就不是我們想要的結果了。我們希望的是,所有的 item 不進行重新刷新,并且當 css 樣式改變的時候,對應的 item 顏色也可以得到改變。那么這就要引出 webpackDevServer 中的一個內容:熱模塊更新 Hot Module Replacement 。接下來我們來了解熱模塊更新相關的配置。
2、熱模塊更新配置
熱模塊更新,即Hot Module Replacement,簡稱為 HMR 。
接下來我們在 webpack.config.js 文件夾下進行配置。具體代碼如下:
//node的核心模塊 const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const webpack = require('webpack');module.exports = {mode:'development',devtool: 'source-map',// 放置入口文件,明確怎么打包entry:{main: './src/index.js'},devServer: {contentBase: './dist',// 當運行完npm run start時,會自動的幫我們打開瀏覽器open: true,port: 8080,// 讓我們的webpackDevServer開啟hotModuleReplacement這樣子的功能hot: true,// 即便HMR沒有生效,也不讓瀏覽器自動刷新hotOnly: true},module:{rules:[{test:/\.(jpg|png|gif)$/,use:{loader:'file-loader',options: {//placeholder 占位符name: '[name]_[hash].[ext]',outputPath: 'images/',limit: 10240}}},{test:/\.scss$/,use:['style-loader', {loader: 'css-loader',options: {//表明前面要先走sass-loader和postcss-loaderimportLoaders: 2,modules: true}}, 'sass-loader','postcss-loader']},{test:/\.css$/,use:['style-loader','css-loader','postcss-loader']}]},plugins: [new HtmlWebpackPlugin({//表明要引用哪一個模板template: 'src/index.html'}),new CleanWebpackPlugin(['dist']),new webpack.HotModuleReplacementPlugin()],// 輸出,表明webpack應該怎么輸出output: {// 下載middle:npm install express webpack-dev-middleware -DpublicPath: '/',//用[]可以生成多個文件filename: '[name].js',// 指打包后的文件要放在哪個文件下path: path.resolve(__dirname, 'dist')} }通過以上代碼我們可以知道,配置 devServer 下的 hot 和 hotOnly ,以及 plugins 下的 new webpack.HotModuleReplacementPlugin() ,來達到熱模塊更新的效果。
接下來我們來看一下,進行配置之后,瀏覽器的效果。詳情見下圖:
大家可以看到,加上這幾個配置之后, item 不會再重新刷新了,而是在原來的基礎上進行樣式修改。
📀十、使用Babel處理ES6語法
1、ES6語法轉換為ES5語法
繼續,接下來我們來了解,如何使用webpack和babel,來編寫ES6的語法。
大家都知道,ES6的語法規范是2015年才正式出版的。所以有時候,并不是所有的瀏覽器都支持ES6語法。因此,我們現在想要做的事情就是,在webpack打包時,能夠將ES6的語法轉換為ES5的語法。這樣,項目運行的時候,瀏覽器就不會報錯了。
那怎么實現這樣子的打包呢?接下來我們一起來了解一下。
首先我們打開babel的官方網站,按照步驟,我們一步步在 webpack 中使用 babel 。
第一步: 安裝 babel-loader 和 @babel/core 這兩個庫。具體代碼如下:
npm install --save-dev babel-loader @babel/corebabel-loader 是幫助webpack進行打包使用的一個工具,而 @babel/core 則是 babel 的一個核心庫,它能夠讓 babel 去識別 js 代碼里的內容,然后呢把 js 代碼轉換成 AST 抽象語法樹,之后再把抽象語法樹編譯成一些新的語法。
第二步: 在 webpack.config.js 文件下的配置項里增設規則。具體代碼如下:
module: {rules: [{test: /\.m?js$/,exclude: /node_modules/,use: {loader: "babel-loader",options: {presets: ['@babel/preset-env']}}}] }第三步: 安裝 @babel/preset-env 。具體代碼如下:
npm install @babel/preset-env --save-dev為什么要安裝這個模塊呢?實際上,當我們使用 babel-loader 處理文件時,實際上 babel-loader 只是 webpack 和 babel 之間做通信的一個橋梁,它只是幫我們打開了一個通道,但是它并不會幫我們把 ES6 的語法轉換為 ES5 的語法。所以,我們就還需要借助一些其他的模塊,來做這項工作。這個模塊就是前面我們說的,preset-env 。
babel/preset-env ,包含了所有 ES6 轉換為 ES5 的語法規則,當使用此模塊打包時,就可以把我們所有 js 中 ES6 的代碼轉換為 ES5 了。具體配置方式見以上第二步。
2、Babel-polyfill
通過以上的方式,我們可以達到將ES6語法轉換為ES5語法的效果。但是呢,我們還要考慮到的一個問題就是,如果遇到像promise這一類新的語法變量,或者時像數組里面map這一類的函數,低版本的瀏覽器里面,實際上還是不存在的。雖然我們做了語法解釋和語法翻譯,但也只是翻譯了一部分。還有一些對象和函數,在低版本的瀏覽器還是沒有的。
所以呢,這個時候我們不僅要使用 babel/preset-env 做語法轉換,還要把這些缺失的變量和函數補充到低版本的瀏覽器里面。
那怎么補充呢,這個時候我們就需要借助 babel-polyfill 這個工具來進行補充。接下來講解這個模塊的使用操作。
第一步: 定位到官方文檔,安裝 babel-polyfill 。具體代碼如下:
npm install --save @babel/polyfill第二步: 引入該模塊。具體代碼如下:
import "@babel/polyfill";通常情況下,這段代碼放到項目的 js 入口文件下。
第三步: 改造 webpack.cofig.js 文件下的 module ,減少打包大小。具體代碼如下:
module: {rules: [{test: /\.m?js$/,exclude: /node_modules/,use: {loader: "babel-loader",options: {presets: [['@babel/preset-env'],{useBuiltIns: 'usage'}]}}}] }這段代碼的意思就是,當用 babel-polyfill 填充低版本瀏覽器特性的時候,不是把是多有的特性都加進來,而是根據我們的業務代碼來決定到底到加什么。
同時, babel-preset 也有很多其他值得學習的配置屬性,這里不再進行講解。大家可以自行到官方文檔上進行查看~
📚十一、結束語
寫完這篇文章的時候,突然想起上次面試時的面試官。在最后的反問環節問他關于 webpack 的問題,他說 webpack 一般會讓對公司業務很熟悉的員工來處理,畢竟前端工程化不是兒戲。
當時我還沒有很大的感觸,但現在學到這里突然就想到了那個場景。確實是這樣,我這才學了不到它的冰山一角,就已經感到 webpack 的龐大工程了。如果在打包時候,但凡有一個小地方的配置出現問題,就有可能引發整個項目的不可收拾局面。(當然一般情況下不會出現這樣的情況,言重了……)
在學習 webpack 的過程中,要明確好自己所使用的webpack版本。比如周一剛開始迷迷糊糊的,感覺版本4和版本5都差不多。但對于 webpack 來說,這完全就是在跟它開玩笑。每一個依賴都有4和5對應的版本,而不是說想用哪個就哪個。如果胡亂使用的話,無形之中可能會報錯到懷疑人生……
因此,確定好此時用 webpack 打包時所使用的版本,并在使用 npm 依賴時也同樣要找到對應的版本來進行使用,降低錯誤的發生。
到這里,關于webpack的超入門知識就講到這里啦!希望對大家有幫助~
本文代碼已上傳至公眾號,后臺回復關鍵詞 webpack 即可獲取~
🐣彩蛋 One More Thing
往期推薦
- vuejs基礎知識系列
- vuejs原理分析系列
番外篇
-
關注公眾號星期一研究室,第一時間關注學習干貨,更多精選專欄待你解鎖~
-
如果這篇文章對你有用,記得留個腳印再走哦~
-
以上就是本文的全部內容!我們下期見!👋👋👋
總結
以上是生活随笔為你收集整理的不会webpack的前端可能是捡来的,万字总结webpack的超入门核心知识的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无花果叶汁液的功效与作用、禁忌和食用方法
- 下一篇: 甘草杏的功效与作用、禁忌和食用方法