【你應該掌握的】webpack4介紹&配置項詳解

skFeTeam  本文做者:李鍵css

引言

做爲一名前端開發,按時按質實現業務需求只是基礎條件,瞭解一些webpack相關的配置,除了可以幫助咱們提高一下本身的技術能力(不侷限於知足業務需求),也可以幫助咱們更好的維護項目、搭建適合本身團隊的web站點。html

但願經過本文能讓你們對webpack4的相關配置項有一個直觀的瞭解,以例子的形式幫助你們更好&更快的掌握相關知識點。前端

webpack4介紹

  • webpack是一個JS應用打包器,它將應用中的各個模塊打成一個或者多個bundle文件。藉助loaders和plugins,它能夠改變、壓縮和優化各類各樣的文件。它的輸入是不一樣的資源,好比:js、css、圖片、字體和html文件等等,而後將它們輸出成瀏覽器能夠正常解析的文件。
  • 2018.8.25,正式發佈webpack4,相比於webpack3,帶來不少的新特性更新和改善,讓webpack配置更加簡單
  • webppack4是目前比較主流打包工具之一,跟其餘的打包工具相比,好比gulp,rollup等,webpack4優點:社區活躍度高,使用的人多,官方更新迭代快速。

webpack4配置項

準備工做

  • 安裝node,webpack,而後新建文件夾–npm初始化
//webpack安裝通常是不-g全局安裝的,由於同時會進行好幾個項目,有時候這幾個項目的webpack版本都是不同的,所以都是根據項目來局部安裝,只在獨立的項目中有效。
npm install webpack-cli webpack --save-dev 
//能夠一路回車,初始化(項目名字,版本號,描述等默認就好,須要更改的能夠在package.json文件中更改)
npm init/npm init -y 
複製代碼

mode屬性

  • mode屬性能夠設置爲:development(代碼不壓縮)/production(代碼壓縮),在開發模式的時候能夠提供更加詳細的錯誤日誌和提示,在生產環境打包的時候能夠webpack專一項目的打包,去除掉開發階段的運行的代碼,是打包的生產環境的包文件更小。

entry/output

  • 入口和打包成功的出口–基本配置
//webpack打包的時候會默認找webpack.config.js文件
//使用path,首先須要引入
const path = require('path')
module.exports = {
    mode: 'development',//開發模式
    entry: './index.js',//指定入口文件
    output: {
        filename: 'bundle.js',//給成功打包的文件定義名字
        path: path.resolve(__dirname,'dist'),//__dirname--相對webpack.config.js這個文件同級根目錄,生成的打包文件dist目錄下面
    }
}
entry: {
    main: './src/index',
    sub: './src/index'
}
output: {
    publicPath: ''---若是須要加域名的話能夠這樣配置
    filename: '[name].js',---name佔位符對應着entry中的key值
    path: resolve.path(__dirname,'dist')
}
複製代碼
  • 代碼演示—1
npx webpack -v
npx webpack index.js
//在package.js的script能夠配置運行打包命令
"script": {
    "build": "webpack"
}
npm run build
複製代碼
  • 代碼運行成功後–package.json中的默認配置,npm webpack index.js成功後生成後,Hash–惟一的hash值,version–webpack版本,Time–打包耗費的時間,built中,asset–打包後的文件,size–打包文件的大小,chunks–每一個打包文件對應的id值,chunk Names–打包文件名,main–對應着打包入口文件

img

img

img

loader

  • 什麼是loader,webpack對不是js後綴的文件是不能進行處理的,這時候須要藉助loader,loader其實就是一個打包方案,webpack對不是js後綴的文件不知道怎麼去打包,可是loader是知道的,因此這時候webpack就要依賴loader來執行打包文件。
  • file-loader 圖片/字體文件打包loader,這時候須要在webpack.config.js中增長圖片/字體打包規則
//webpack.config.js
module.exports = {
    ...
    module: {
    //規則數組類型--有不少不一樣類型的打包規則
        rules: [
            {
                test: /\.(jpg|png|jpeg)$/,
                use: {
                    loader: 'file-loader',
                    options: {
                    //placehold--佔位符 name--文件名,hash--hash值,ext-文件後綴名
                        name: '[name]_[hash].[ext]',
                        //回把圖片打包到dist目錄下image文件夾裏
                        outputPath: "./image"
                    }
                }
            },{
                test:/\.(eot|ttf|svg)$/,
                use: {
                    loader: 'file-loader',
                    ...
                }
            }
        ]
    }
}
複製代碼
  • url-loader 其包含了file-loader的圖片打包的功能,區別:就是不加任何配置項的時候,默認把圖片打包成base64字符放在打包的js文件中,優點,加載js文件完成以後圖片也加載好了,減小一次http請求,很差的地方就是當圖片文件過大的時候,那麼被放入圖片的打包js文件也會很大,那麼在加載技js文件的時候,加載耗時較長,也面回停留空白頁的時間過長,所以增長配置項limit,
rules: [
  {
      test:/\.(jpg|jepg|png)$/,
      use: {
          loader: 'url-loader',
          options: {
              filename: '[name]_[hash].[ext]',
              outputPath: './image',
              limit: 20480, //==20480個字節==20kb
              //大於20kb就會打包成圖片放在dist目錄下面,小於則打包成base64字符串放在打包的js文件裏面
          }
      }
  }
]
複製代碼
  • 代碼演示–2 –使用url先後加了limit配置以後的對比
//使用file-loader ,url-loader 須要安裝
npm install file-loader --save-dev
npm install url-loader --save-dev
複製代碼

img
img
img
img

style-loader css-loader sass-loader postcss-loader

  • 一樣的對css,scss打包的時候,webpack都是不知道怎麼去打包,因此須要藉助相關的loader來執行打包,要同時安裝css-loader,style-loader,css-loader只負責處理css文件,在獲得css-loader處理而且合併以後的css內容文件時,須要使用style-loader掛在到頁面header部分,這樣樣式的打包纔會在頁面生效,一樣的若是sass文件時,還須要安裝sass-loader,node-sass ,由於sass-loader是依賴於node-sass來執行解析sass文件的,因此執行順序是,先是sass-loader將scss文件解析成css文件,其次css-loader處理這些被解析成的css文件,而後再有style-loader將這些內容掛在到頁面的header部分,postcss-loader就是增長廠商前綴的,是最早執行的。
//安裝loader
npm install style-loader css-loader sass-loader node-sass postcss-loader --save-dev
//在使用postcss-loader的時候須要藉助插件
//autoprefixer
npm install autoprefixer -D
//使用postcss-loader還須要增長配置文件
//postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}
//webpack.config.js
module: {
    rules: [
        {
            test: /\.css$/,
            use: [
                "style-loader",
                <!--"css-loader",-->
                {
                    loader: "css-loader",
                    options: {
                        //表示css文件中又引入css文件,這樣配置項可使每一層均可以走到(下-上,右-左)
                        importLoader: 2,
                        //配置支持css模塊化,避免樣式渲染全局,name.類名的方式調用
                        <!--modules: true-->
                    }
                }
                "postcss-loader"
            ]
        },{
            test: /\.scss$/,
            use:[
                  "style-loader",
                <!--"css-loader",-->
                {
                    loader: "css-loader",
                    options: {
                        importLoader: 2,
                        <!--modules: true-->
                    }
                },
                "sass-loader",
                "postcss-loader"
            ]
        }
    ]
}
複製代碼
  • 代碼演示–3

img

img

img

img

img

img

img

img

plugins

  • html-webpack-plugin: 做用就是幫咱們自動生成一個html,而且把打包好生成的js文件引入到html中,同時能夠在src目錄下建立一個html模板,而後能夠設置配置項,根據這個html模板自動生成html放在dist目錄下,,在打包完成以後開始執行
  • clean-webpack-plugin:做用就是把以前打包的dist目錄刪除掉,這個是在打包以前開始執行的
//首先安裝html-webpack-plugin hlean-webpack-plugin
npm install html-webpack-plugin clean-webpack-plugin -D

//在webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new CleanWebpackPlugin('./dist')
    ]
}
複製代碼
  • 代碼演示 – 4 TypeError: CleanWebpackPlugin is not a constructor

img

img
img

//因此引用這個插件必需要使用對象結構
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
//這個插件使用默認配置就行了,若是要傳入參數的話,必須以對象的形式
new CleanWebpackPlugin()/ new CleanWebpackPlugin({})
複製代碼

img

sourceMap的配置

  • 這個是什麼呢?,這個配置就是幫咱們作一個打包以後和源代碼之間的一個映射關係,當打包的時候出現問題的時候,咱們並非要知道打包文件哪一行出現錯誤,而是要知道源代碼的哪一行出現錯誤。
//webpack.config.js
module.exports = {
    //基本配置
    devtool: "source-map"
    //能夠提示比較全面的錯誤信息,具體到哪一行哪一列第幾個字符,而且映射文件會打包到打包文件裏面
    devtool: "inline-source-map"
    //開發環境配置推薦
    devtool: "cheap-module-eval-source-map"
    //生產環境
    devtool: "cheap-module-source-map"
}
複製代碼

webpackDevServer

  • 能夠幫咱們監聽文件的改動,還能夠模擬服務器的一些特性,一旦src目錄下的內容發生改變就會自動幫咱們打包文件而且自動刷新頁面,
//先安裝webpack-dev-server
npm install webpack-dev-server -D

//package.json
"scripts": {
    "watch": "webpack --watch",
    "start": "webpack-dev-server",
}
    
//webpack.config.js
devServer: {
    contentBase: './dist',//本地服務器加載的目錄
    open: true,//打包完成以後自動幫咱們啓動一個本地服務器,端口默認是8080,
    port: "",//端口能夠自定義
    ...
}
複製代碼

Hot Module Replace–HMR:熱更新模塊

  • 使用webpack-dev-server啓動項目,幫咱們啓動一個本地服務器,而且還會自動幫咱們打包,打包文件是放在內存當中,這樣打包的速度更快,性能更好。
  • webpack自帶的一個熱更新模塊插件 –HotModuleReplacementPlugin,可是做用於css和js的過程當中,相交於css熱更新,js須要多一下代碼,緣由是css-loader已經幫咱們寫好了,像vue框架熱更新也是同樣,已經內置已經寫好的代碼,react框架也是藉助babel的preset的配置來處理的
// weebpack.config.js
const webpack = require('webpack');

module.exports = {
    devServer: {
        contentBase: './dist',
        port: 8080,
        open: true,
        hot: true,//--開啓熱更新功能
        hotOnly: true,//阻止頁面自動刷新,即便hot更新功能不起做用,瀏覽器也不自動刷新頁面
    }
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
}
//js
if(module.hot) {
    module.hot.accept('./number',() => {
        document.body.removeChild(document.getElementById('id'))
        number()//從新執行一下這個模塊的函數
    })
}
複製代碼
  • 代碼演示–5
  • sourceMap
    img
    img
    img
    img
    img

babel處理es6語法

  • 對於普通瀏覽器目前是不支持es6語法的,可是支持es5語法代碼,所以須要藉助babel插件來作轉換,這裏能夠查Babel的官方文檔—這裏省略一萬步—這裏面有使用場景的選擇–選擇webpack使用場景
//安裝插件 --@babel/core是babel核心庫
npm install babel-loader @babel/core -D
//同時要按裝,babel-loader只是打通webpack的一個橋樑,並不會轉義代碼,須要藉助@babel/preset-env 來作語法的轉換
npm install @babel/preset-env -D
//還有繼續安裝@babel/polyfill -- 做用是幫助低版本的瀏覽器彌補缺失的變量以及函數,同時能夠在options配置,根據業務代碼來作低版本的缺失彌補,這樣打包代碼能夠作到精簡,注意的是,這個插件只適合作業務代碼帶包,由於會污染全局
npm install @babel/polyfill -D
//新建.babelrc文件,options配置能夠放在這個文件裏面
{
    presets: [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "chrome": "67"
                },
                "useBuiltIns": "usage"// 按需加載
            }
        ]
    ]
}
//webpack.config.js
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
<!--options: {-->
<!-- presets: [['@babel/preset-env',{targets: {chrome: "67",},useBuiltIns: 'usage'}]]--> <!--}--> //test code --es6 import '@babel/polyfill' const arr = [ new Promise(() => {}), new Promise(() => {}) ] arr.map(item => { console.log(item) }) 複製代碼

webpack實現對react框架代碼的打包

  • 須要藉助@babel/preset-react插件,在轉換react框架代碼以後仍是要插件@babel/preset-env轉換es6語法。
//使用安裝插件
npm install react react-dom --save-dev
npm install @babel/preset-react --save-dev
//.babelrc中去引用插件
presets:[
    "@babel/preset-react"
]
//js--test-code
import React ,{ Component } from 'react'
import ReactDom from 'react-dom'
class App extends Compnent {
    render() {
        return(<div>herllo world</div>)
    }
}
ReactDom.render(<App/>,document.getElementById('root'));
複製代碼

Tree shaking

  • 做用:這是webpack自帶的一個功能,當引入一個模塊的時候,不須要引入所有的代碼,只須要引入被須要的代碼,–就是搖樹的意思,把沒必要要的葉子所有搖掉。
  • 可是webpack中的tree shaking僅支持esmodule這種引入方式。
//webpack.config.js
module.exports = {
    plugins: [],
    optimization: {
        usedExports:true//只是在開發環境須要配置,在生產環境把不須要配置
    }

}
//package.json中 開發環境是會保留這段代碼的
"sideEffects": ['*.css']---忽略相關模塊不作tree shaking
複製代碼

development和production模式的區分打包,webpack.dev.js,webpack.pord.js,webpack.common.js –能夠把文件放到build文件中

//須要下載 webpack-merge
npm install webpack-merge -D
//dev
const webpack = require('webpack');
const devConfig = {
    mode: 'development',
    devtool: 'cheap-module-source-map',
    devServer: {
        contentBase: '../dist',//本地服務器加載的目錄
        open: true, //打包完成以後自動打開瀏覽器
        // port: 8080,
        hot: true,//開啓模塊熱更新更能
        hotOnly: true,//阻止頁面刷新,即便熱更新功能失效,也不會刷新頁面
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ], 
    optimization: {
        usedExports:true,
    },
}
module.exports = devConfig;
//pord
const pordConfig = {
mode: 'production',//production 
}
module.exports = pordConfig;
//common
const path = require('path');
const merge = require('webpack-merge')
const devConfig = require('./webpack.dev.js');
const prodConfig = require('./webpack.prod.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const commonConfig = {
    entry: {
        main: './src/index.js'
    },
    module: {
        //規則數組類型--有不少不一樣類型的打包規則
        rules: [
            // {
            // test: /\.(jpg|png|jpeg)$/,
            // use: {
            // loader: 'file-loader',
            // options: {
            // //placehold--佔位符 name--文件名,hash--hash值,ext-文件後綴名
            // name: '[name]_[hash].[ext]',
            // //回把圖片打包到dist目錄下image文件夾裏
            // outputPath: "./image"
            // }
            // }
            // },
            {
                test: /\.js$/,
                exclude:/node_modules/,
                loader: 'babel-loader'
            },
            {
                test: /\.(jpg|png|jpeg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                    //placehold--佔位符 name--文件名,hash--hash值,ext-文件後綴名
                        name: '[name]_[hash].[ext]',
                        //回把圖片打包到dist目錄下image文件夾裏
                        outputPath: "./image",
                        limit: 204800,
                    },
                }
            },{
                test:/\.(eot|ttf|svg)$/,
                use: {
                    loader: 'file-loader',
                }
            },{
                test: /\.css$/,
                use: [
                    "style-loader",
                    "css-loader",
                    "postcss-loader"
                ]
            },{
                test: /\.scss$/,
                use: [
                    "style-loader",
                    "css-loader",
                    "sass-loader",
                    "postcss-loader"
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        // * All files inside webpack's output.path directory will be removed once, but the
        // * directory itself will not be. If using webpack 4+'s default configuration,
        // * everything under <PROJECT_DIR>/dist/ will be removed.
        new CleanWebpackPlugin({ verbose: true,cleanOnceBeforeBuildPatterns:['**/*']}),
    ],
    output: {
        filename: 'bundle.js',//打包成功後的文件名
        path: path.resolve(__dirname,'../dist'),//__dirname---表示跟web.config.js的同級根目錄,打包以後的文件夾
    }
}

module.exports = (env) =>  {
    if(env&&env.production) {
        return merge(commonConfig,prodConfig)
    }else{
        return merge(commonConfig, devConfig)
    }
}
//package.js
"script": {
    "start": "webpack-dev-server --config ./build/webpack.common.js",
    "build": "webpack --env.production --config ./build/webpack.common.js",
    "dev": "webpack --env.development --config ./build/webpack.common.js"
}
複製代碼
  • 代碼演示 -6
    img
    img
    img

webpack和code Splitting:

  • 代碼分割是webpack至關重要的一個特性,可讓代碼分割到不一樣的文件中,一邊按需加載或者並行加載這些文件,這樣能夠優化加載性能,以及用戶體驗會更好。
  • 代碼分割其實只是在webpack中去實現代碼分割,兩種方式,同步代碼分割只需optimization中配置便可,異步代碼分割,webpack代碼分割默認配置就是對異步代碼進行代碼分割,可是須要babel插件來作翻譯,瀏覽器對異步的這種語法規則不支持。
//異步代碼分割,安裝babel插件,babel-plugin-dynamic-import-webpack
npm install babel-plugin-dynamic-import-webpack -D
//同步代碼分割的話須要在optimization中配置splitChunks
//---在.babelrc中去配置一個plugins,
presets: [], 
plugins: ["dynamic-import-webpack"]
//webpack.common.js
optimization: {
    splitChunks: {
        chunks: 'all'//對同步代碼和異步代碼同時作代碼分割
        chunks:'aysnc'//對異步代碼作分割
    }
}
//test-code--index.js
function getComponent() { 
    return import('lodash').then(({default:_}) => {
        var element = document.createElement('div');
        element.innerHTML = _.join(['dell','lee'],'_');
        return element
    })
}
getComponent().then(element => {
    document.body.appendChild(element);
})
複製代碼
  • splitChunksPlugin的底層配置中,異步代碼會自動打包成一個文件0.js,這裏須要指定引入異步代碼文件的名字可使用魔法註釋,這裏就須要這個插件@babel/plugin-syntax-dynamic-import來作異步代碼的轉化,不能使用上面那個插件babel-plugin-dynamic-import-webpack,/webpackChuunkName:‘lodash’/,
  • chunks:aysnc這種異步代碼能夠解決打包文件過大,加載時間過長,分出第三方庫和插件,須要的時候在進行按需加載和並行加載,提供加載性能。
npm install @babel/plugin-syntax-dynamic-import --save-dev
splitChunks: {
    chunks: async //--若是是async的話,只是對異步代碼作代碼分割,all是對異步和同步分都作代碼分割
    minSize: 30000===30kb //大於30kb就會作代碼分割,小於的話就作代碼分割
    maxSize:0//可配可不配 --若是是50000===50kb, 會作二次分割 lodash 打包成1mb ,會拆成20個50kb代碼分割
    minChunks: 1,//當這個模塊使用幾回的話在作代碼分割,小於的設置的次數就不作代碼分割
    maxAsyncRequests: 5,//同時加載的模塊是5個,在打包前五個會幫你打包作代碼分割,超過五個的話就不作代碼分割
    maxInitialRequests: 3,//指整個網站首頁進行加載的時候或者是入口文件進行加載的時候,入口文件會引入其餘庫,也只能最多三個,超過三個就不會作代碼分割了
    automaticNameDelimiter: '~',//文件生成的時候,文件的中間會有一些鏈接符,
    name: true, ---//起什麼名字,讓cacheGroups中的名字有效
    cacheGroups: {//若是是同步的話會走完chunks以後會走這個配置,緩存組
        vendors: {
            test: /[\\/]node_modules[\\/]/,//--是同步代碼發現是從node_modules引入的話,那麼符合這個組會被打包成單獨文件
            priority: -10
            filename: 'vendors.js'//是打包文件的名字
        }
        default: {
            priority: -20,//假設同時符合兩個組,經過這個配置來設置優先級,值越大,優先級越高
            reuseExistingChunk: true,若是一個模塊a,b,若是a使用了b,符合代碼分割的要求,而後又符合default這個組,就不打包以前打包過的內容
            filename: 'common.js'
        }
    }
}
複製代碼
  • lazy loading—就是支持esmodule這種語法,按需加載。
  • css代碼分割: filename與chunkFilename區別:官網的代碼分割插件:作的事情就是把css文件單獨打包,不直接打包到js文件裏面,這個插件不支持HMR,因此css代碼分割插件通常應用到生產環境.
//安裝插件
npm install mini-css-extract-plugin --save-dev
//線上環境單獨生成的css文件須要作代碼壓縮合並
npm install optimize-css-assets-webpack-plugin -D
//optimization
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require(' optimize-css-assets-webpack-plugin')
//配置作更改
//開發環境使用規則默認
//線上環境
module: {
    rules: [
            use: ['MiniCssExtractPlugin.loader'] //全部使用style-loader所有替換,不使用style-loader 
        ]
},
optimization: {minimizer: [new OptimizeCssAssetsWebpackPlugin({})]},
plugins: [new MiniCssExtractPlugin({
    filename: '[name].css',//被文件直接引用走這個配置
    chunkFilename: '[name].chunk.css'//被間接引用的話是走這個配置項
})]
output: {
    filename: '[name].js',
    chunkFilename: '[name].chunk.js'//就是被js間接引用的打包文件就會走這個配置內容,
    path: path.resolve(__dirname,'../dist')
}
複製代碼

但願本文對你們有幫助。

想了解skFeTeam更多的分享文章,能夠點這裏,謝謝~

相關文章
相關標籤/搜索