入門webpack,看這篇就夠了
- 2019 年 10 月 3 日
- 筆記
什麼是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框架的筆記(https://www.cnblogs.com/cythia/p/10672042.html)
統計編譯的時間
有時候我們在開發的時候需要做性能優化的時候,就肯定想要知道在編譯過程中哪些步驟耗時最長。這個時候我們可以使用–profile
"scripts": { "test": "echo "Error: no test specified" && exit 1", "start": "webpack-dev-server --open --port 3000 --hot --profile", "dev": "webpack-dev-server ", "build": "webpack" }