webpack的進階用法(一)

清理構建目錄:clean-webpack-plugin

因爲每次構建項目前並不會自動的清理目錄,會形成輸出文件愈來愈多。這時 咱們就得手動清理輸出目錄的文件的麻煩。javascript

通常狀況下也能夠經過npm scripts設置命令行的方式進行構建目錄的清理。
//package.json "scripts": { "build": "rm -rf ./dist && webpack" } 可是這樣實現的方式給人感受就不太優雅,這是,咱們能夠藉助clean-webpack-plugin 插件的形式清除構建目錄,默認會執行刪除output值得的輸出目錄。css

安裝clean-webpack-plugin插件並配置html

npm i clean-webpack-plugin -D
複製代碼
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.export = {
    plugins: [
        new CleanWebpackPlugin()
    ]
}
複製代碼

CSS3前綴補全:autoprefixer

因爲瀏覽器標準並無統一,例如Chrome對應的webkit,Firfox對應的Geko,IE對應的 Trident和Opera對應的Presto。因此部分的CSS3特性須要補全前綴已實現瀏覽器的兼容。前端

經過autoprefixer後處理的方式實現自動的CSS前綴補全。html5

安裝postcss-loader和autoprefixer並配置。java

npm i postcss-loader autoprefixer -D
複製代碼

經過package.json中browsersList字段配置須要兼容的瀏覽器版本號。node

"browserslist": [
    "last 2 version",
    ">1%",
    "IOS 7"
  ]
複製代碼
module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader'
                ]
            }
        ]
    }
}
複製代碼

根目錄新建postcss.config.js使用autoprefixer插件。react

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}
複製代碼

px自動轉rem:px2rem-loader

因爲移動端設備的普及及尺寸的不一致,因此須要實現不一樣尺寸的適配就須要 經過CSS媒體查詢等方式實現響應式佈局。可是這樣就須要爲不一樣的尺寸設置樣式, 相對繁瑣,而隨着W3C對移動設備尺寸的推動,提出了rem,其實現了頁面渲染時 能根據根元素font-size值進行相對大小的設置。webpack

經過px2rem-loader就能實現將px轉換爲rem實現移動端設備尺寸的適配。git

一、安裝px2rem-loader和lib-flexible(計算根元素font-size)

npm i px2rem-loader -D
npm i lib-flexible -S
複製代碼

二、配置webpack

module.exports = {
    module: {
        rules: [
            {
                loader:'px2rem-loader',
                options: {
                    remUnit: 75, //rem相對px的轉換,1rem = 75px
                    remPrecesion:8 // rem後的小數位數
                }
            }
        ]
    }
}
複製代碼

靜態資源內聯:raw-loader

資源內聯能夠實現頁面框架的初始化腳本,首屏css內聯能夠避免頁面閃動; 小圖片或者字體內聯能夠減小HTTP網絡請求數量等。

HTML和JS內聯可藉助raw-loader實現內聯。

安裝raw-loader@0.5.1並設置內聯
在index.html頁面引入meta標籤

// html-webpack-plugin默認是ejs模板的
${ require('raw-loader!./meta.html') }
複製代碼

在index.html引入flexible.js文件

<script>${ require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js') }</script>
複製代碼

CSS內聯可藉助style-loader或者html-inline-css-webpack-plugin

module.exports = {
    module: {
        rules: [
            {
                test:/\.less$/,
                use: [
                    {
                        loader: 'style-loader',
                        options: {
                            insertAt: 'top',//樣式插入到head
                            singleton: true //將全部style標籤合併一個
                        },
                    },
                    'css-loader',
                    'less-loader'
                ]
            }
        ]
    }
}
複製代碼

多頁面打包

多頁面的優點能夠作到頁面間解耦,由於會單獨打包成獨立的入口文件;而且對seo更加友好(傳聞,有待考究, 我的以爲除了能夠多配置meta關鍵字暫時沒有以爲seo的其餘優點)。

多頁面打包的通用方案通常經過設置entry多入口結合html-webpack-plugin動態獲取入口文件。並藉助glob 庫實現動態匹配規則獲取匹配的目錄,通常按照必定的源碼項目規則,例如每一個頁面對應的入口文件 爲src對應的文件夾下的index.js,模板爲src對應的文件夾下的index.html。

安裝glob並配置webpack

npm i glob -D
複製代碼
const glob = require('glob')

const setMPA = () => {
    const entry  = {}
    const htmlWebpackPlugins= []

    // 獲取entry入口文件
    const entryFiles = glob.sync(path.join(__dirname,'./src/*/index.js'))
    console.log(entryFiles)

    Object.keys(entryFiles).map(
        (index) => {
            const entryFile = entryFiles[index]
            const match = entryFile.match(/src\/(.*)\/index\.js/)
            const pageName = match && match[1]

            entry[pageName] = entryFile
            htmlWebpackPlugins.push(
                new HtmlWebpackPlugin({
                    template: path.join(__dirname, `src/${pageName}/index.html`),
                    filename: `${pageName}.html`,
                    chunks: [pageName],
                    inject: true,
                    minify: {
                        html5: true,
                        collapsableWhitespace: true,
                        preserveLineBreaks: false,
                        minifyJS: true,
                        minifyCSS: true,
                        removeComments: true
                    }
                })
            )
        }
    )

    return {
        entry,
        htmlWebpackPlugins
    }
}
const { entry, htmlWebpackPlugins } = setMPA()

module.exports = {
    entry: entry,
    plugins: [
        htmlWebpackPlugins
    ]
}
複製代碼

開發調試:source map

經過source map能夠定位到源代碼並進行代碼調試;經過開發環境開啓source map,線上 環境關閉能夠實現開發調試和避免源代碼泄漏。

啓動source map配置

// webpack.dev.js
module.exports = {
     devtool: 'source-map'
}
複製代碼

source map 類型

devtool 首次構建 二次構建 是否適合生產環境 能夠定位的代碼
(none) 很是快速 很是快速 yes 打包後的代碼
eval 很是快速 很是快速 no webpack生產的一個個模塊代碼
cheap-source-map 比較快 中等 no 通過loader轉換過的代碼(僅限行)
source-map no 原始源代碼

更多可參看devtool:www.webpackjs.com/configurati…

公共資源提取:SplitChunksPlugin

經過公共資源的提取和一些基礎庫分離,能夠把通用資源打包成一個來實現 減小加載資源,而且基礎庫的分離並經過cdn方式引入,也進一步減小資源加載。

經過html-webpack-externals-plugin進行基礎庫的分離,而且經過模板引入

npm i html-webpack-externals-plugin -D
複製代碼
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')

module.exports = {
    plugins: [
        new HtmlWebpackExternalsPlugin({
        externals: [
            {
                module:'react',
                entry:'https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/cjs/react.production.min.js',
                global:'React'
            },
            {
                module:'react-dom',
                entry:'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/cjs/react-dom.production.min.js',
                global:'ReactDOM'
            }
        ]
        })
    ]
}
複製代碼
//index.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> ${ require('raw-loader!./meta.html') } <title>index</title> <script>${ require('raw-loader!babel-loader!../../node_modules/lib-flexible/flexible.js') }</script> </head> <body> <div id="root"></div> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> </body> </html> 複製代碼

其中提到,webpack4.x版本後就剔除了以前一直使用的CommonsChunksPlugin進行 模塊抽取的插件,這個插件存在的緣由就有因爲共用模塊較多的時候會導致代碼包 過大,不利於首次加載等。於是,webpack4.x就內置了SplitChunksPlugin進行公共 腳本的分離和基礎包的分離,該插件實現了懶加載模塊的通用模塊單獨抽取,而並不會抽取到父級 上等優化性能。

利用SplitChunksPlugin進行基礎包分離,分離react和react-dom,並引入到對應的模板中

//webpack配置
module.exports = {
    optimization: {
            splitChunks: {
                cacheGroups: {
                    commons: {
                        test: /(react|react-dom)/,
                        name: 'vendors',
                        chunks: 'all'
                    }
                }
            }
        }
}
複製代碼

webpack配置HtmlWebpackPlugin插件添加chunks包名

new HtmlWebpackPlugin({
     template: path.join(__dirname, `src/${pageName}/index.html`),
     filename: `${pageName}.html`,
     chunks: ['vendors', pageName],
     inject: true,
     minify: {
         html5: true,
         collapsableWhitespace: true,
         preserveLineBreaks: false,
         minifyJS: true,
         minifyCSS: true,
         removeComments: true
     }
})
複製代碼

利用SplitChunksPlugin進行公共腳本的分離,並添加到模板中

//webpack配置
module.exports = {
    optimization: {
            splitChunks: {
                minSize: 0, // 設置最小size多少是才進行通用分離
                cacheGroups: {
                    name:'commons',
                    chunks: 'all', // all:全部引入的庫進行分離;async:異步引入的庫進行分離(默認);initial:同步引入的庫進行分離
                    minChunks:2//設置默認最少多少個引入才進行通用分離
                }
            }
        }
}
複製代碼
//webpack配置
new HtmlWebpackPlugin({
    chunks: ['commons', pageName],
})
複製代碼

更多配置可參考:www.webpackjs.com/plugins/spl…

demo代碼可查看:github.com/PCAaron/blo…

推薦閱讀

webpack的基本配置:juejin.im/post/5e1540…

什麼是source map?:www.ruanyifeng.com/blog/2013/0…

CommonsChunksPlugin與SplitChunksPlugin:www.jianshu.com/p/a1ccd6d1b…

求關注

關注個人博客,讓咱們一塊兒進步:

github.com/PCAaron/PCA…

關注公衆號[前端美食匯],持續爲你推薦精選技術和美食

https://user-gold-cdn.xitu.io/2020/1/8/16f830c0ee0c024f?imageView2/0/w/1280/h/960/format/webp/ignore-error/1
相關文章
相關標籤/搜索