什麼是webpack?
官網給出的概念是:本質上,webpack 是一個現代 JavaScript 應用程式的靜態模組打包器(module bundler)。當 webpack 處理應用程式時,它會遞迴地構建一個依賴關係圖(dependency graph),其中包含應用程式需要的每個模組,然後將所有這些模組打包成一個或多個 bundle。
為什麼要用webpack?
為什麼使用webpack,這應該和前端的發展是有關係的,因為計算機網路的飛速發展,導致前端也在迅猛發展,最初的實踐方案已經不能滿足我們的需求,加上新的技術和新思想框架的產生,為了節省開發的成本和效率,所以webpack的產生是一個必然的結果
相比gulp、grunt、Rollup,為什麼要使用webpack?
gulp和grunt的操作都是流式的,但是gulp是基於記憶體流,grunt是基於檔案流,所以相對來說,gulp的效能要高於grunt,而且他們都是需要定義一個個任務,然後自動將一個個任務執行。,而webpack是模組化的組織,模組化的依賴,然後模組化的打包,相對來說,webpack更強調模組化開發,而那些檔案合併壓縮、預處理等功能,不過是他的附帶功能。而且現在相對於前兩者,webpack的外掛也更為豐富
Rollup是在webpack流行後出現的替代品,Rollup和webpack類似,但是專注於ES6模組打包,相比webpack,Rollup功能和外掛都不如webpack完善,不過Rollup在用於打包JavaScript庫時比webpack更加有又是,因為其打包的程式碼更小更快。但也因為功能不完善,很多場景找不到現成的解決方案。
安裝與使用
因為現在webpack已經更新到到4.0+了,所以本篇就直接按4.0+的來講好了
建立package.json檔案
也叫初始化,可以手動建立,也可以使用命令自動建立,建議是命令建立
npm init
然後自己配置檔名、版本號等資訊
如果想要快捷安裝的話,使用下面的命令(-y 表示使用預設引數)
npm init -y
注意:1.package檔案裡面的name屬性的值如果用駝峰式命名的話,會報警告
2. 通過檔名我們就知道package.json檔案是json的物件,所以語法肯定是嚴格按照json的格式,不能新增註釋,屬性和值只能用雙引號不能用單引號,不能多新增逗號
package.json檔案說明:
安裝
webpack可以直接使用npm安裝,因為我們需要使用webpack這個命令,所以必須要全域性安裝
npm i webpack -g
然後在專案中安裝
npm i webpack -S
注意點:webpack 4+以上的,都需要安裝webpack-cli,所以還需要安裝webpack-cli
npm i webpack-cli -S
按著上面的步驟安裝好之後,等你配置好webpack.config.js檔案在終端輸入webpack時你可能會遇到下面這個問題
解決辦法:全域性安裝一下webpack-cli即可
npm i webpack -g
到此安裝步驟就已經搞定了,下面教大家如何使用
使用
建立src資料夾、public資料夾和webpack.config.js檔案
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"></div> <script src="bundle.js"></script> </body> </html>
配置webpack.config.js
module.exports = { mode:'development', // 當前的開發模式 entry: __dirname + "/src/main.js",// 入口檔案 output: { path: __dirname + "/dist",// 打包後的檔案存放的地方 filename: "bundle.js" // 打包後輸出檔案的檔名 } }
這些基礎配置完之後,我們在專案的終端輸入
webpack
就會輸出一下資訊
看到這樣的資訊的話,那麼恭喜你,你的第一個webpack專案完成了
此時你會看到資料夾目錄下會多了一個dist資料夾
OK,上面的檔案寫法我們還可以做一下改進,例如檔案的檔案路徑問題,我們需要寫成的是絕對路徑,node裡面有自帶一個path模組,我們可以換成下面的寫法
const path=require('path'); module.exports={ mode:'development', // 入口檔案 entry:'./src/main.js', // 出口檔案 output:{ filename:'bundle.js', path:path.resolve(__dirname,'public') } }
上面這個是單個入口檔案的寫法,有單個入口的話,那肯定是有多個入口的啊,下面這段就是多個入口檔案的寫法:
const path=require('path'); module.exports={ mode:'development', // 多個入口的話,在這邊配置 entry:{ index:'./src/js/1.js', admin:'./src/js/index.js', }, output:{ // 出口的名字就是上面entry定義的名字,上面定義的是index和admin,打包後在dist資料夾裡面的js就是index.min.js和admin.min.js filename:'[name].js', path:path.resolve(__dirname,'dist') } }
在出口檔案處的filename中,就不需要寫死bundle.js這些了,直接用name變數來接收,打包出來後的檔名字來源於entry中入口檔案中的定義的鍵,如上面的就是index和admin
資源管理
webpack本身只能處理javascript,如果要處理其他型別的檔案的話,就需要使用loader來進行轉換。下面我就列舉了我們經常用的幾個
css-loader---->引入css檔案
我們可以在src資料夾裡面新建一個css資料夾,然後在裡面新建一個main.css檔案。在webpack中,所有的檔案都是一個模組,所以要使用這個css檔案,就必須要先引入
在main.js檔案中引入css檔案
import './css/main.css'
然後在終端輸入webpack後發現報錯啦
這個時候呢,安裝一下css需要使用到的loader,然後在配置一下在試試
安裝
處理css需要使用到兩個loader,css-loader和style-loader
npm install --save-dev style-loader css-loader
在webpack.config.js中配置loader
module.exports={ // 當前的開發模式 // 開發模式:development,會保留我們開發時的一些必要資訊 // 生產模式:production會盡力壓縮,能壓多大就壓多大 // none:什麼也不幹,就只是打包 mode:'development', entry:'./src/js/main.js', output:{ filename:'bundle.js', path:path.resolve(__dirname,'dist') }, // 新增的module裡面的rules module:{ rules:[ { test:/\.css$/, // webpack的loader執行順序是反的,先執行css-loader後執行style-loader use:[ 'style-loader', 'css-loader' ] } ] } }
說明: loader都是在module裡面的rules中配置的,rules是一個陣列配置規則,該規則告訴webpack符合test的檔案,使用use後面的loader處理,所以該規則就是對所有的.css檔案使用css-loader、style-loader
注意點:loader的執行順序是由右向左執行的,先執行css-loader後在執行style-loader
在終端輸入webpack後,提示下面的資訊就是成功啦
常用的loader
資源 | loader名 |
圖片 | file-loader |
sass | saa-loader |
less | less-loader |
babel | babel-loader |
字型 | file-loader和url-loader |
載入圖片
安裝
npm install --save-dev file-loader
配置loader
rules:[ { test:/\.css$/, // webpack的loader執行順序是反的,先執行css-loader後執行style-loader use:[ 'style-loader', 'css-loader' ] }, + { + test: /\.(png|svg|jpg|gif)$/, + use: [ + 'file-loader' + ] + } + ]
載入字型
webpack.config.js中配置
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ 'file-loader' ] }
載入less
安裝
npm install --save-dev less-loader less
配置
{ test: /\.less$/, use: [{ loader: "style-loader" // creates style nodes from JS strings }, { loader: "css-loader" // translates CSS into CommonJS }, { loader: "less-loader" // compiles Less to CSS }] }
載入sass
安裝
npm install sass-loader node-sass --save-dev
配置:
{ test: /\.scss$/, use: [ "style-loader", // creates style nodes from JS strings "css-loader", // translates CSS into CommonJS "sass-loader" // compiles Sass to CSS, using Node Sass by default ] }] }
載入ES6及以上版本及jsx檔案
安裝:
npm install -D babel-loader @babel/core @babel/preset-env
配置:
{ test: /\.(js|jsx)$/i, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } }
總的配置集合
module:{ rules:[ // 載入css { test:/\.css$/, // webpack的loader執行順序是反的,先執行css-loader後執行style-loader use:[ 'style-loader', 'css-loader' ] }, // 載入圖片 { test: /\.(png|svg|jpg|gif)$/, use: [ 'file-loader' ] }, // 載入字型 { test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ 'file-loader' ] }, // 載入less { test: /\.less$/, use: [{ loader: "style-loader" // creates style nodes from JS strings }, { loader: "css-loader" // translates CSS into CommonJS }, { loader: "less-loader" // compiles Less to CSS }] }, // 載入sass { test: /\.scss$/, use: [ "style-loader", // creates style nodes from JS strings "css-loader", // translates CSS into CommonJS "sass-loader" // compiles Sass to CSS, using Node Sass by default ] }, // 載入base64 { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { limit: 8192 // 當圖片小於8192K之後轉為base64 } } ] }, // 載入資料 { test: /\.(csv|tsv)$/, use: [ 'csv-loader' ] }, { test: /\.xml$/, use: [ 'xml-loader' ] },
// 載入ES6以上版本 { test: /\.(js|jsx)$/i, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] }
Plugin
外掛(Plugin)是用來擴充套件webpack功能的,webpack可以實現loader所不能實現完成的複雜功能,使用plugin豐富的自定義API以及生命週期事件,可以控制webpack打包流程的每個環節,實現webpack的自定義功能擴充套件
html-webpack-plugin:生成html檔案
html-webpack-plugin
可以根據你設定的模板,在每次執行後生成對應的模板檔案,同時所依賴的 CSS/JS 也都會被引入,如果 CSS/JS 中含有 hash 值,則 html-webpack-plugin
生成的模板檔案也會引入正確版本的 CSS/JS 檔案。安裝
npm i html-webpack-plugin -D
修改配置檔案
const path=require('path'); const HtmlPlugin=require('html-webpack-plugin'); module.exports = { entry: __dirname + "/src/main.js",//已多次提及的唯一入口檔案 output: { path:path.resolve(__dirname, './dist'),//打包後的檔案存放的地方 filename: "bundle.js"//打包後輸出檔案的檔名 }, module:{ rules:[ // 載入css { test:/\.css$/, // webpack的loader執行順序是反的,先執行css-loader後執行style-loader use:[ 'style-loader', 'css-loader' ] }, // 載入圖片 { test: /\.(png|svg|jpg|gif)$/, use: [ 'file-loader' ] }, // 載入字型 { test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ 'file-loader' ] }, // 載入less { test: /\.less$/, use: [{ loader: "style-loader" // creates style nodes from JS strings }, { loader: "css-loader" // translates CSS into CommonJS }, { loader: "less-loader" // compiles Less to CSS }] }, // 載入sass { test: /\.scss$/, use: [ "style-loader", // creates style nodes from JS strings "css-loader", // translates CSS into CommonJS "sass-loader" // compiles Sass to CSS, using Node Sass by default ] }, // 載入base64 { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { outputPath: 'images/', limit: 8*1024 // 當圖片小於8192K之後轉為base64 } } ] }, // 載入資料 { test: /\.(csv|tsv)$/, use: [ 'csv-loader' ] }, { test: /\.xml$/, use: [ 'xml-loader' ] }, { test: /\.(js|jsx)$/i, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] }, plugins: [ new HtmlPlugin(), ] }
配置完之後,你會看到在dist資料夾下面會多了一個index.html檔案
如果你想打包一個固定的模板的話,你可以在例項化外掛的時候新增引數配置
plugins: [ new HtmlPlugin({ template: './public/index.html' // 模板的地址 }), ]
分離css檔案--MiniCssExtractPlugin
在webpack中,預設css檔案是一起打包進js檔案裡面去的,如果你希望打包後css在單獨的檔案中的話,name你就需要MiniCssExtractPlugin(ExtractTextPlugin在webpack4+版本中已經廢棄掉了,如果使用4以下的版本的話,可以自行官網查api,也是類似的寫法的)這個plugin了
安裝
npm i mini-css-extract-plugin -D
在webpack.config.js中的配置
const path=require('path'); const HtmlPlugin=require('html-webpack-plugin'); const MiniCssExtractPlugin=require('mini-css-extract-plugin'); module.exports = { entry: __dirname + "/src/main.js",//已多次提及的唯一入口檔案 output: { path:path.resolve(__dirname, './dist'),//打包後的檔案存放的地方 filename: "bundle.js"//打包後輸出檔案的檔名 }, module:{ rules:[ // 載入css { test:/\.css$/, // webpack的loader執行順序是反的,先執行css-loader後執行style-loader use:[ { loader: MiniCssExtractPlugin.loader, }, 'css-loader' ] }, ] }, plugins: [ new HtmlPlugin({ title:'webpack test', template:path.join(__dirname, './public/index.html') }), new MiniCssExtractPlugin({ filename:'[name].css', chunkFilename:'[id].css' }) ] }
配置完成後在終端輸入webpack,你會發現dist資料夾裡面會多了一個main.css檔案(前面已經在src目錄下的css資料夾中新建了main.css,並匯入到了main.js中),到這,css就已經抽離出來啦
構建執行環境
我們平時開發的時候,例如gulp都會區分開發環境還是生產環境,這兩個環境下所要配置的一些引數肯定是要不一樣的,而且我們在開發環境下,並不需要打包。在這種情況下,我們要這麼去區分執行環境呢?webpack提供了一個webpack-dev-server工具給我們搭建本地執行環境。有了這個外掛之後,我們可以配置命令指令碼快捷執行
安裝webpack-dev-server
npm i webpack-dev-server -D
然後在package.json配置中的script裡面指令碼命令
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack-dev-server ", "dev": "webpack-dev-server ", "build": "webpack" }
通過上面的程式碼,我們可以知道,在看法環境下才要執行專案環境,如果打包的時候就用build的那個命令來充當生產環境
開發環境命令使用
npm run start // 或 npm run dev
生產環境命令使用
生產環境下的話,我們需要做的是打包的工作
npm run build
瞭解npm 命令的話,我們應該知道,在npm的命令指令碼中,我們是可以新增引數的,我們可以通過新增引數來設定一下在開發環境下自動在預設瀏覽器中開啟專案
預設的埠是8080埠
修改預設埠
嗯,有些時候我們的埠可能被其他專案佔用著,所以為了專案得以執行,肯定是要改一下埠的啊。我們可以在配置命令指令碼的時候新增引數--port 埠號
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack-dev-server --open --port 3000", "dev": "webpack-dev-server ", "build": "webpack" },
此時的埠就已經改為了3000埠了
自動熱更新
我們每次修改完都要重啟一下執行環境,這樣的操作效率太低了,而且很浪費時間,我們要怎麼做到每次修改完他都會自動更新呢,當然是有解決方法的啊,新增--hot引數即可
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack-dev-server --open --port 3000 --hot", "dev": "webpack-dev-server ", "build": "webpack" }
開發的時候區分環境更專案配置的,可以檢視我的上一篇的使用webpack構建簡易的vue-cli框架的筆記