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
相关文章
相关标签/搜索