衆所周知,webpack進入第4個大版本已經有2個月的時間了,並且webpack團隊升級更新的速度也是很是的驚人css
在寫下以下內容的時候webpack已經出到了4.6的版本了,劍指5.0應該是指日可待了,固然這些都是我的的臆想,並不表明任何意見html
既然咱們已經迎接了webpack4的到來了,那麼就一塊兒來使用一下,即便你沒用過以前的版本,不要緊,咱們從新出發,將工做中經常使用到的配置寫給你們來看前端
非友情提示:因爲webpack使用起來並不能僅看代碼就方便理解,因此有圖有真相的纔是正解,因而乎本文配圖不少,真的是不少vue
首先,既來之,則安之node
安裝webpack
- 須要先在項目中npm init初始化一下,生成package.json
- 建議node版本安裝到8.2以上
// webpack4中除了正常安裝webpack以外,須要再單獨安一個webpack-cli npm i webpack webpack-cli -D
★ npm i -D 是 npm install --save-dev 的簡寫,是指安裝模塊並保存到 package.json 的 devDependencies中,主要在開發環境中的依賴包react
0配置了什麼
webpack4能夠支持0配置打包,這裏所說的0配置又是什麼呢?固然在開發者眼中0配置的東西,那根本是沒法用的,由於不夠智能,那麼咱們就來看看作到了哪些0配置jquery
在使用webpack進行打包的時候,默認狀況下會將src下的入口文件(index.js)進行打包webpack
// node v8.2版本之後都會有一個npx // npx會執行bin裏的文件 npx webpack // 不設置mode的狀況下 打包出來的文件自動壓縮 npx webpack --mode development // 設置mode爲開發模式,打包後的文件不被壓縮
當執行npx webpack命令的時候,webpack會自動查找項目中src目錄下的index.js文件,而後進行打包,生成一個dist目錄並存在一個打包好的main.js文件web
這些算是0配置的操做了,名字都是定義好的,不能變,想一想也很雞肋npm
webpack的使用仍是在咱們的配置方面,下面就進入咱們的常規操做環節
webpack是基於Node的
在項目下建立一個webpack.config.js(默認,可修改)文件來配置webpack
module.exports = {
entry: '', // 入口文件 output: {}, // 出口文件 module: {}, // 處理對應模塊 plugins: [], // 對應的插件 devServer: {}, // 開發服務器配置 mode: 'development' // 模式配置 }
以上就是webpack的正常配置模塊
★ 啓動devServer須要安裝一下webpack-dev-server
npm i webpack-dev-server -D
按照項目的結構,咱們就從0開始去寫一下配置吧
// webpack.config.js
const path = require('path'); module.exports = { entry: './src/index.js', // 入口文件 output: { filename: 'bundle.js', // 打包後的文件名稱 path: path.resolve('dist') // 打包後的目錄,必須是絕對路徑 } }
上面就能夠說是實現了最簡單的webpack配置了,那接下來就打包一下看看
配置執行文件
工做當中咱們打包編譯的時候通常都執行npm run dev這樣的命令,既然是經過npm執行的命令,咱們就應該找到package.json裏的執行腳本去配置一下命令,這裏以下圖所示
npm run build就是咱們打包後的文件,這是生產環境下,上線須要的文件
npm run dev是咱們開發環境下打包的文件,固然因爲devServer幫咱們把文件放到內存中了,因此並不會輸出打包後的dist文件夾
經過npm run build以後會生成一個dist目錄文件夾,就和上面打包後的樣子同樣了
多入口文件
多個入口能夠有兩種實現方式進行打包
- 一種是沒有關係的可是要打包到一塊兒去的,能夠寫一個數組,實現多個文件打包
- 另外一種就是每個文件都單獨打包成一個文件的
- 下面就來看看這兩種方式的寫法
let path = require('path'); module.exports = { // 1.寫成數組的方式就能夠打出多入口文件,不過這裏打包後的文件都合成了一個 // entry: ['./src/index.js', './src/login.js'], // 2.真正實現多入口和多出口須要寫成對象的方式 entry: { index: './src/index.js', login: './src/login.js' }, output: { // 1. filename: 'bundle.js', // 2. [name]就能夠將出口文件名和入口文件名一一對應 filename: '[name].js', // 打包後會生成index.js和login.js文件 path: path.resolve('dist') } }
這時候執行npm run build後,會生成打包好的兩個js文件,如圖所示
配置Html模板
文件都打包好了,可是咱們在使用的時候不能在dist目錄下去建立一個html文件,而後去引用打包後的js吧,這不合理,實際開發中也不會這樣
咱們須要實現html打包功能,能夠經過一個模板實現打包出引用好路徑的html來
這就須要用到一個經常使用的插件了,html-webpack-plugin,用以前咱們來安一下它
npm i html-webpack-plugin -D
由於是個插件,因此須要在config.js裏引用一下的
let path = require('path'); // 插件都是一個類,因此咱們命名的時候儘可能用大寫開頭 let HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { // 添加hash能夠防止文件緩存,每次都會生成4位的hash串 filename: 'bundle.[hash:4].js', path: path.resolve('dist') }, plugins: [ // 經過new一下這個類來使用插件 new HtmlWebpackPlugin({ // 用哪一個html做爲模板 // 在src目錄下建立一個index.html頁面當作模板來用 template: './src/index.html', hash: true, // 會在打包好的bundle.js後面加上hash串 }) ] }
經過上面的配置後,咱們再npm run build打包看一下如今是個什麼樣子了
多頁面開發,怎麼配置多頁面
若是開發的時候不僅一個頁面,咱們須要配置多頁面,那麼須要怎麼來搞呢?不用擔憂,html-webpack-plugin插件自有辦法,咱們來觀望一下
let path = require('path'); let HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // 多頁面開發,怎麼配置多頁面 entry: { index: './src/index.js', login: './src/login.js' }, // 出口文件 output: { filename: '[name].js', path: path.resolve('dist') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html', chunks: ['index'] // 對應關係,index.js對應的是index.html }), new HtmlWebpackPlugin({ template: './src/login.html', filename: 'login.html', chunks: ['login'] // 對應關係,login.js對應的是login.html }) ] }
繼續npm run build看打包後的樣子
上面基本介紹完了html和js的打包配置了,如今咱們還缺一個好兄弟css,webpack對css的解析須要用到loader,因此咱們先提早安裝好,待會好方便使用
引用CSS文件
能夠在src/index.js裏引入css文件,到時候直接打包到生產目錄下
須要下載一些解析css樣式的loader
npm i style-loader css-loader -D // 引入less文件的話,也須要安裝對應的loader npm i less less-loader -D
下面咱們來看一下如何配置css文件的解析
// index.js
import './css/style.css'; // 引入css import './less/style.less'; // 引入less console.log('這裏是打包文件入口-index.js'); // webpack.config.js module.exports = { entry: { index: './src/index.js' }, output: { filename: 'bundle.js', path: path.resolve('dist') }, module: { rules: [ { test: /\.css$/, // 解析css use: ['style-loader', 'css-loader'] // 從右向左解析 /* 也能夠這樣寫,這種方式方便寫一些配置參數 use: [ {loader: 'style-loader'}, {loader: 'css-loader'} ] */ } ] } }
- 此時打包後的css文件是以行內樣式style的標籤寫進打包後的html頁面中,若是樣式不少的話,咱們更但願直接用link的方式引入進去,這時候須要把css拆分出來
- extract-text-webpack-plugin插件相信用過的人都知道它是幹什麼的,它的功效就在於會將打包到js裏的css文件進行一個拆分
拆分CSS
// @next表示能夠支持webpack4版本的插件 npm i extract-text-webpack-plugin@next -D
let path = require('path'); let HtmlWebpackPlugin = require('html-webpack-plugin'); // 拆分css樣式的插件 let ExtractTextWebpackPlugin = require('extract-text-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filaneme: 'bundle.js', path: path.resolve('dist') }, module: { rules: [ { test: /\.css$/, use: ExtractTextWebpackPlugin.extract({ // 將css用link的方式引入就再也不須要style-loader了 use: 'css-loader' }) } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', }), // 拆分後會把css文件放到dist目錄下的css/style.css new ExtractTextWebpackPlugin('css/style.css') ] }
此時拆分完css後,打包的html頁面就以link的方式去引入css了,這樣很好
引用圖片
- 處理圖片方面,也須要loader
npm i file-loader url-loader -D
若是是在css文件裏引入的如背景圖之類的圖片,就須要指定一下相對路徑
module.exports = {
module: {
rules: [
{
test: /\.css$/, use: ExtractTextWebpackPlugin.extract({ use: 'css-loader', publicPath: '../' }) }, { test: /\.(jpe?g|png|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192, // 小於8k的圖片自動轉成base64格式,而且不會存在實體圖片 outputPath: 'images/' // 圖片打包後存放的目錄 } } ] } ] } }
在css中指定了publicPath路徑這樣就能夠根據相對路徑引用到圖片資源了,以下圖所示
頁面img引用圖片
頁面中常常會用到img標籤,img引用的圖片地址也須要一個loader來幫咱們處理好
npm i html-withimg-loader -D
module.exports = {
module: {
rules: [
{
test: /\.(htm|html)$/, use: 'html-withimg-loader' } ] } }
這樣再打包後的html文件下img就能夠正常引用圖片路徑了
引用字體圖片和svg圖片
字體圖標和svg圖片均可以經過file-loader來解析
module.exports = {
module: {
rules: [
{
test: /\.(eot|ttf|woff|svg)$/, use: 'file-loader' } ] } }
這樣即便樣式中引入了這類格式的圖標或者圖片都沒有問題了,img若是也引用svg格式的話,配合上面寫好的html-withimg-loader就都沒有問題了
添加CSS3前綴
經過postcss中的autoprefixer能夠實現將CSS3中的一些須要兼容寫法的屬性添加響應的前綴,這樣省去咱們很多的時間
因爲也是一個loader加載器,咱們也須要先安裝一下
npm i postcss-loader autoprefixer -D
安裝後,咱們還須要像webpack同樣寫一個config的配置文件,在項目根目錄下建立一個postcss.config.js文件,配置以下:
module.exports = {
plugins: [require('autoprefixer')] // 引用該插件便可了 }
而後在webpack裏配置postcss-loader
module.exports = {
module: {
rules: [
{
test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] } ] } }
轉義ES6
在實際開發中,咱們在大量的使用着ES6及以後的api去寫代碼,這樣會提升咱們寫代碼的速度,不過因爲低版本瀏覽器的存在,不得不須要轉換成兼容的代碼,因而就有了經常使用的Babel了
Babel會將ES6的代碼轉成ES5的代碼
那麼再也不多說,既然要使用它,就先來安一下
npm i babel-core babel-loader babel-preset-env babel-preset-stage-0 -D
當把這些都安好後,咱們就開始配置,因爲要兼容的代碼不只僅包含ES6還有以後的版本和那些僅僅是草案的內容,因此咱們能夠經過一個.babelrc文件來配置一下,對這些版本的支持
// .babelrc
{
"presets": ["env", "stage-0"] // 從右向左解析 }
咱們再在webpack裏配置一下babel-loader既能夠作到代碼轉成ES5了
module.exports = {
module: {
rules: [
{
test:/\.js$/, use: 'bable-loader', include: /src/, // 只轉化src目錄下的js exclude: /node_modules/ // 排除掉node_modules,優化打包速度 } ] } }
在咱們每次npm run build的時候都會在dist目錄下建立不少打好的包,若是積累過多可能也會混亂
因此應該在每次打包以前將dist目錄下的文件都清空,而後再把打好包的文件放進去
這裏提供一個clean-webpack-plugin插件
npm i clean-webpack-plugin -D
let CleanWebpackPlugin = require('clean-webpack-plugin'); module.exports = { plugins: [ // 打包前先清空 new CleanWebpackPlugin('dist') ] }
啓動靜態服務器
啓動一個靜態服務器,默認會自動刷新,就是說你對html,css,js文件作了修改並保存後,瀏覽器會默認刷新一次展示修改後的效果
正常狀況下咱們都是在開發環境中開發項目,因此以前配置的腳本"dev"能夠派上用場了,在執行npm run dev命令後,會啓動靜態服務器,咱們訪問localhost:3000端口就能夠看到開發的頁面內容了
若是devServer裏open設爲true後,會自動打開瀏覽器
module.exports = {
devServer: {
contentBase: './dist', host: 'localhost', // 默認是localhost port: 3000, // 端口 open: true, // 自動打開瀏覽器 hot: true // 開啓熱更新 } }
固然在npm run dev命令下,打包的文件存在於內存中,並不會產生在dist目錄下
熱更新和自動刷新的區別
在配置devServer的時候,若是hot爲true,就表明開啓了熱更新
But這並沒那麼簡單,由於熱更新還須要配置一個webpack自帶的插件而且還要在主要js文件裏檢查是否有module.hot
下面就讓咱們直接看下代碼是如何實現的
// webpack.config.js
let webpack = require('webpack'); module.exports = { plugins: [ // 熱替換,熱替換不是刷新 new webpack.HotModuleReplacementPlugin() ], devServer: { contentBase: './dist', hot: true, port: 3000 } } // 此時還沒完雖然配置了插件和開啓了熱更新,但實際上並不會生效 // index.js let a = 'hello world'; document.body.innerHTML = a; console.log('這是webpack打包的入口文件'); // 還須要在主要的js文件裏寫入下面這段代碼 if (module.hot) { // 實現熱更新 module.hot.accept(); }
以上index.js中的內容,若是將變量a的值進行修改保存後,會在不刷新頁面的狀況下直接修改掉,這樣就實現了熱更新
那麼熱更新從如今看來和自動刷新瀏覽器的區別也不是太大嘛!自動刷新也是能夠接受的啊
其實否則,熱更新的好處可能在vue或者react中有更大的發揮,其中某一個組件被修改的時候就會針對這個組件進行熱更新了,這裏用到vue或react的同窗去實際體驗一下吧
resolve解析
在webpack的配置中,resolve咱們經常使用來配置別名和省略後綴名
module.exports = {
resolve: {
// 別名
alias: { $: './src/jquery.js' }, // 省略後綴 extensions: ['.js', '.json', '.css'] }, }
這個配置在webpack中比較簡單,咱們也就再也不敘述了,下面來看點乾貨
提取公共代碼
在webpack4以前,提取公共代碼都是經過一個叫CommonsChunkPlugin的插件來辦到的。到了4之後,內置了一個如出一轍的功能,並且起了一個好聽的名字叫「優化」
下面咱們就來看看如何提取公共代碼
// 假設a.js和b.js都同時引入了jquery.js和一個寫好的utils.js
// a.js和b.js
import $ from 'jquery'; import {sum} from 'utils';
那麼他們兩個js中其中公共部分的代碼就是jquery和utils裏的代碼了
能夠針對第三方插件和寫好的公共文件
module.exports = {
entry: {
a: './src/a.js', b: './src/b.js' }, output: { filename: '[name].js', path: path.resolve('dust') }, // 提取公共代碼 + optimization: { splitChunks: { cacheGroups: { vendor: { // 抽離第三方插件 test: /node_modules/, // 指定是node_modules下的第三方包 chunks: 'initial', name: 'vendor', // 打包後的文件名,任意命名 // 設置優先級,防止和自定義的公共代碼提取時被覆蓋,不進行打包 priority: 10 }, utils: { // 抽離本身寫的公共代碼,utils這個名字能夠隨意起 chunks: 'initial', name: 'utils', // 任意命名 minSize: 0 // 只要超出0字節就生成一個新包 } } } + }, plugins: [ new HtmlWebpackPlugin({ filename: 'a.html', template: './src/index.html', // 以index.html爲模板 + chunks: ['vendor', 'a'] }), new HtmlWebpackPlugin({ filename: 'b.html', template: './src/index.html', // 以index.html爲模板 + chunks: ['vendor', 'b'] }) ] }
經過以上配置,能夠把引入到a.js和b.js中的這部分公共代碼提取出來,以下圖所示
指定webpack配置文件
在package.json的腳步裏,咱們能夠配置調用不一樣的webpack配置文件進行打包,舉個栗子
這樣的好處在於能夠針對不一樣的需求進行一個特定的打包配置
就到這裏吧
關於webpack4的一些常規操做就說到這裏了,其實在工做當中更多時候,也並不須要咱們去配置這些內容
不過咱們要爭作優秀的前端兒,因此就必須掌握這些必備的技能,必須會,沒有之一!
好了,就寫到這裏吧,想必你們也看累了吧,辛苦你們了,哈哈。