一文彻底读懂webpack常用配置

开发环境

const webpack = require("webpack");
const path = require('path')
module.exports = {
    // entry: {
        // a: './src/0706/a.js',
        // c: './src/0706/c.js',
    // },
    entry: "./src/0707/reactDemo.js",
    output: {
        filename: '[name]_dist.js',
        path: path.resolve(__dirname, 'dist3'),
    },
    mode: 'development',
    devtool: 'source-map',
    module: {
        rules: [
            {
                test:/.js$/,
                use: 'babel-loader',
            },
            {
                test: /.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test:/.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /.(png|jpg|gif|jpeg)$/,
                use: 'file-loader'
            },
            {
                test: /.(png|jpg|jpeg|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        limit: 10240 * 10
                    }
                }
            },
            {
                test: /.(woff|woff2|eot|ttf|otf)$/,
                use: 'file-loader'
            }
        ],
    },
    // plugins: [
        // new webpack.HotModuleReplacementPlugin()
    // ],
    // 在使用devServer的时候,如果hot为true的话,会自动帮我们添加HotModuleReplacementPlugin
    // 如果使用自己实现的服务器,就需要自己添加
    devServer: {
        contentBase: './dist3',
        hot: true
    }
}

生产环境

const webpack = require("webpack");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// minicssextractplugin 推荐使用cssminimizerwebpackplugin来压缩css
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
// 根据模板生产html,并插入相应的chunk,同时也可以压缩html
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 清除构建产物的插件,注意这里的引入方式
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');
module.exports = {
    // entry: {
        // a: './src/0706/a.js',
        // c: './src/0706/c.js',
    // },
    entry: "./src/0707/reactDemo.js",
    output: {
        // 文件指纹 chunkhash chunk改变就会重新生成
        // hash 整个项目有文件改变就会重新生成
        // contenthash 文件内容改变才会重新生成
        filename: '[name]_[chunkhash:8].js',
        path: path.resolve(__dirname, 'dist3'),
    },
    mode: 'production',
    optimization: {
        minimizer: [
            // 压缩CSS
            new CssMinimizerPlugin(),
            // webpack5内置了terser-plugin,但是上面的插件会覆盖掉默认的terser-plugin,所以通过下面的一行来将默认的插件加回去
            '...'
        ]
    },
    module: {
        rules: [
            {
                test:/.js$/,
                use: 'babel-loader',
            },
            {
                test: /.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            },
            {
                test:/.less$/,
                use: [
                    // 使用miniCssExtractPlugin提取css后,这里需要替换成它的loader
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /.(png|jpg|gif|jpeg)$/,
                use: {
                    loader: 'file-loader',
                    options: {
                        name: '[name]_[hash:8].[ext]'
                    }
                }
            },
            {
                test: /.(png|jpg|jpeg|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        limit: 10240 * 10
                    }
                }
            },
            {
                test: /.(woff|woff2|eot|ttf|otf)$/,
                use: 'file-loader'
            }
       ],
    },
     plugins: [
        new MiniCssExtractPlugin({
            // 使用contenthash 这样如果只改变了js的话css也无需重新生成
            filename: '[name]_[contenthash:8].css'
        }),
        new HtmlWebpackPlugin({
            // 模板所在路径
            template: path.resolve(__dirname, 'src/index.html'),
            // 生成的html的名字
            filename: 'index2.html',
            // 用到了哪个chunk
            // chunks: ['a']
            // 压缩选项
            minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: true
            }
        })
    ]
}

自动添加CSS前缀

  • 使用postcss-loader + autoprefixer
  • 添加postcss.config.js 新版本直接在webpack配置文件里添加会报错,所以需要写到一个独立的配置文件里
module.exports = {
    plugins: [
        require('autoprefixer')({
            overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
        })
    ]
}
  • 添加loader
{
    test: /.css$/,
    use: [
        MiniCssExtractPlugin.loader,
        'css-loader',
        'postcss-loader' // 这里为新加的loader
    ]
},

移动端适配 css px自动转rem

  • 使用手淘lib-flexible 动态计算font-size
// 将lib-flexible静态内联到html上,因为要最先执行计算
// 在头部加入如下代码
// 使用了raw-loader,相当于在对应的位置是插入字符串
// 需注意raw-loader新老版本引入的差异
<script type="text/javascript"
<%=require('raw-loader!babel-loader!./node_modules/lib-flexible/flexible.js')%>
</script>
  • 使用px2rem-loader 将px转成rem
{
    test: /.less$/
    use: [
        'style-loader',
        'css-loader',
        'less-loader',
        {
            loader: 'px2rem-loader',
            options: {
                // 以设计稿宽度750px为例,1rem = 75px
                remUnit: 75,
                // 转换后的小数点后保留位数
                remPrecision: 8,
            }
        }
    ]
}
  • 代码里面直接按设计稿一样写px
// 下面的px最后会被转成em,如果有些特殊的地方不想转,可写成大写PX
.box {
    width: 100px;
    height: 100px;
    // 写成大写则不会被转换
    border: 1PX;
}

代码分割

  • 利用splitChunks plugin将公共代码抽离
optimization: {
    splitChunks: {
        cacheGroups: {
            vendors: {
                chunks: 'all',
                name: 'vendors',
                // 将react和react-dom提取出一个包
                test: /(react|react-dom)/
            },
            common: {
                name: 'common',
                chunks: 'all',
                minSize: 0,
                // 被引用两次以上的提取出一个包
                minChunks: 2
            }
        }
    }
}

参考 前端进阶面试题详细解答

动态import 懒加载

  • 通过ES6的动态import + babel插件@babel/plugin-syntax-dynamic-import
//babel配置里增加
plugins: [
    '@babel/plugin-syntax-dynamic-import'
]
// 代码里按需引入
import('xxx').then(res => res.default);

webpack结合eslint

  • 以react为例,用到几个插件eslint eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-a11y
  • 安装解析器babel-eslint
  • 用airbnb的规则,需安装eslint-config-airbnb
  • 安装eslint-loader
  • 增加eslint配置 eslintrc.js
module.exports = {
    // 使用babel-eslint作为解析器
    "parser": "babel-eslint",
    // 继承airbnb的规则
    "extends": ["airbnb"],
    // 指定环境,这样使用全局变量的时候不会报错
    "env": {
        "browser": true,
        "node": true
    },
    // 自定义规则覆盖默认规则
    "rules": {
        // 使用4个空格缩进,否则error
        "indent": ["error", 4]
    }
}

webpack打包库

  • 代码写好后,webpack配置如下
const path = require('path');
module.exports = {
    // 同时提供未压缩和压缩的版本
    entry: {
        'mylibrary': './src/entry.js',
        'mylibrary.min': './src/entry.js'
    },
    output: {
        path: path.resolve(__dirname, 'lib'),
        // mylibrary.js mylibrary.min.js
        filename: '[name].js',
        // 对外暴露的库的名称
        library: 'mylibrary',
        // 支持cjs, ejs, script脚本等引入方式
        libraryTarget: 'umd',
        // 不加这个的话,使用的时候可能需要mylibrary.default
        libraryExport: 'default'
    }
}
  • 添加terser-webpack-plugin进行压缩

const TerserPlugin = require(‘terser-webpack-plugin’);

optimization: {
    minimize: true,
    minimizer: [
        new TerserPlugin({
            // 只对min版本压缩
            test: /.min.js/
        })
    ]
}
  • package.json 指定入口文件
"main": "index.js"
  • index.js里面做环境判断
if(process.env.NODE_EVN === 'production') {
    module.exports = require('./lib/mylibrary.min.js');
} else {
    module.exports = require('./lib/mulibrary.js');
}

主动捕获异常

  • 通过插件主动捕获异常
plugins: [
    function() {
        this.hooks.done.tap('done', (stats) => {
            if(stats.compilation && stats.compilation.errors.length > 1) {
                console.log('error')
            }
        })
    }
]

构建优化

速度优化:

  • speed-measure-webpack-plugin分析构建速度
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');
const spm = new SpeedMeasureWebpackPlugin();
module.exports = spm.wrap({...});
  • thread-loader开启多进程,放在需要的loader上面
module: {
    rules: [
        {
            test: /.js$/
            use: [
                {
                    loader: 'thread-loader',
                    options: {
                        workers: 3
                    }
                }
            ]
        }
    ]
}
  • include exclude缩小构建目标
  • resolve减少文件搜索范围
modules.exports = {
    ...
    resolve: {
        // 指定node_modules的路径,减少模块搜索层级
        modules: [path.resolve(__dirname, 'node_modules')]// import react的时候直接从指定的路径去找
        alias: {
            react: path.resolve(__dirname, './node_modules/react/dist/react.min.js')
        },
        // import xx from 'a'的时候,只找.js后缀的
        // 高频文件后缀名放前面
        extensions: ['.js'],
        // 指定入口,避免不必要的分析
        mainFields: ['main']
    }
}
  • 开启babel-loader缓存
// 仅需加个url参数
module: {
    rules: [
        {
            test: /.js$/,
            use: ['babel-loader?cacheDirectory=true'
        }
    ]
}
  • terser-webpack-plugin开启缓存
// webpack5之后不再用这种方式
new TerserWebpackPlugin({
    cache: true
})
  • cache-loader缓存
  • hard-source-webpack-plugin缓存,减少二次构建时间
plugins: [new HardSourceWebpackPlugin()]
  • terser-webpack-plugin默认开启了JS多进程压缩
optimization: {
    minimizer: [
        new TerserWebpackPlugin({
            // 指定进程数量
            parallel: 4
        })
    ]
}
  • 使用DLLPlugin进行分包

先构建出单独的包

// 单独的配置文件用于生成包
module.exports = {
    entry: {
        // 将react react-dom抽离出单独的包
        library: ['react', 'react-dom']
    },
    output: {
        filename: '[name].dll.js',
        path: path.resolve(__dirname, 'dist3/lib')
        library: '[name]'
    },
    plugins: [
        // 使用DLLPlugin抽离,生成manifest
        new webpack.DllPlugin({
            name: '[name]_2',
            path: path.resolve(__dirname, 'dist3/lib/[name].json'),
        }),
        // new CleanWebpackPlugin(),
    ]
}

再通过manifest关联抽离的包

// webpack.prod.config.js
new webpack.DllReferencePlugin({
    manifest: require('./dist3/lib/library.json')
})

最后将抽离的包插入html模板中

  • noParse 对完全不需要解析的库进行忽略 (不去解析但仍会打包到 bundle 中,注意被忽略掉的文件里不应该包含 import、require、define 等模块化语句)

体积优化

  • webpack-bundle-analyzer分析体积
plugins: [
    new WebpackBundleAnalyzer()
]
  • 图片压缩

使用image-webpack-loader

rules: [{
    test: /\.(gif|png|jpe?g|svg)$/i,
    use: [
        'file-loader',
        {
            loader: 'image-webpack-loader',
            options: {
                mozjpeg: {
                    progressive: true,
                },
                // optipng.enabled: false will disable optipng
                optipng: {
                    enabled: false,
                },
                pngquant: {
                    quality: [0.65, 0.90],
                    speed: 4
                },
                gifsicle: {
                    interlaced: false,
                },
                // the webp option will enable WEBP
                webp: {
                    quality: 75
                }
            }
        },
    ],
}]
  • 对CSS 进行tree shaking

使用purgecss-webpack-plugin,要配合mini-css-extract-plugin一起使用

const purgecssPath = path.join(__dirname, 'src');
const glob = require('glob');
new PurgecssPlugin({
    paths:
    glob.sync(`${purgecssPath}/**/*`, { nodir: true }),
}),
  • 动态polyfill

根据浏览器的user agent 动态下发polyfill

<script src="https://polyfill.io/v3/polyfill.min.js"></script>

或者可以自建CDN

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/1618.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python图像处理【10】基于离散余弦变换的图像压缩

基于离散余弦变换的图像压缩0. 前言1. 离散余弦变换基础2. 基于离散余弦变换的图像压缩3. 图像 JPEG 压缩3.1 JPEG 压缩原理3.2 JPEG 压缩实践小结系列链接0. 前言 由于图像中相邻像素间的相关性引起的空间冗余、图像序列中不同帧之间存在相关性引起的时间冗余&#xff0c;因此…

【全网唯一】 自己动手实现 FreeRTOS-metal-SU

前言 FreeRTOS 是一个开源的实时操作系统&#xff08;RTOS&#xff09;&#xff0c;适用于微控制器和小型嵌入式系统。它提供了多任务处理、内存管理、定时器、软件定时器、消息队列和信号量等功能&#xff0c;以帮助开发人员构建可靠和高效的嵌入式系统。 FreeRTOS 的设计原则…

Nginx学习笔记(三)Linux环境下Nginx的安装和部署

目录一、官网下载二、配置基本信息1.上传 Linux2.解压3.安装编译环境4.配置基本信息4.1 配置失败原因(1)&#xff1a;没有安装C编译环境4.2 配置失败原因(2)&#xff1a;没有安装 PCRE 依赖4.3 配置失败原因(3)&#xff1a;没有安装 zlib 依赖5.查看文件列表三、编译安装四、配…

PostMan工具的使用

PostMan工具的使用 1 PostMan简介 代码编写完后&#xff0c;我们要想测试&#xff0c;只需要打开浏览器直接输入地址发送请求即可。发送的是GET请求可以直接使用浏览器&#xff0c;但是如果要发送的是POST请求呢? 如果要求发送的是post请求&#xff0c;我们就得准备页面在页…

利用Sklearn框架实现简单线性回归,用于预测房价

前言&#xff1a;什么是sklearn框架和其他机器学习框架有何不同 Scikit-learn&#xff08;简称sklearn&#xff09;是一个基于Python编程语言的机器学习框架。它提供了丰富的机器学习算法和工具&#xff0c;可以帮助开发人员快速实现机器学习任务&#xff0c;例如分类、回归、…

用 ChatGPT 辅助学好机器学习

文章目录一、前言二、主要内容&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、前言 探索更高效的学习方法可能是有志者共同的追求&#xff0c;用好 ChatGPT&#xff0c;先行于未来。 作为一个人工智能大语言模型&#xff0c;ChatGPT 可以在帮助初…

学习 Python 之 Pygame 开发魂斗罗(十二)

学习 Python 之 Pygame 开发魂斗罗&#xff08;十二&#xff09;继续编写魂斗罗1. 修改玩家扣减生命值2. 解决玩家下蹲子弹不会击中玩家而是直接让玩家死亡的问题3. 完善地图4. 增加产生敌人函数&#xff0c;解决一直产生敌人的问题5. 给玩家类增加计算玩家中心的方法继续编写魂…

REDIS18_

①. ZipList是一种特殊的"双端链表" ,由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作, 并且该操作的时间复杂度为 O(1) ②. ZipList中的Entry并不像普通链表那样记录前后节点的指针,因为记录两个指针要占用16个字节,浪费内存。而是采用了下面的…

Linux系统中内核态、用户态和零拷贝技术解析

​目录 ​第一&#xff1a;存储介质的性能 ​第二&#xff1a;内核态和用户态 第三&#xff1a;内核态和用户态是怎么控制数据传输的&#xff1f; ​第四&#xff1a;什么是 DMA ? ​第五&#xff1a;零拷贝技术实现的方式 第六&#xff1a;mmap write 第七&#xff1…

JAVA进阶(IO流) —— 高级流

通过之前我们对于 JAVA进阶&#xff08;IO流&#xff09; —— 基本流 中字节流与字符流的学习&#xff0c;但是基本流中的四大流均是抽象类&#xff0c;不可以实例化&#xff0c;在实际开发中使用的都是其子类。 而这篇文章所要学习得高级流其实就是在基本流的基础上添加缓冲…

vue基于vant封装可精确到秒的时间选择器

前言 在移动开发中&#xff0c;时间选择的控件比比皆是&#xff0c;但却鲜有类似的组件可以精确到秒级别的&#xff0c;官方可能是考虑到小屏幕手机的显示问题&#xff0c;也可能是使用的场景寥寥无几&#xff0c;但是少不代表没有&#xff0c;所以最近花了点时间基于 vant 组件…

vue的diff算法?

文章目录是什么比较方式原理分析Diff算法的步骤&#xff1a;首尾指针法比对顺序&#xff1a;是什么 diff 算法是一种通过同层的树节点进行比较的高效算法 其有两个特点&#xff1a; 比较只会在同层级进行, 不会跨层级比较 在diff比较的过程中&#xff0c;循环从两边向中间比较…

我的创作纪念日——一年的时间可以改变很多

机缘 不知不觉来到CSDN已经创作一年了。打心底讲&#xff0c;对于在CSDN开始坚持创作的原因&#xff0c;我用一句话来概括最合适不过了——“无心插柳柳成荫” 为什么这么说呢&#xff1f; 这要从我的一篇博客说起——《输入命令Javac报错详解》&#xff1a; 那也是我第一次…

使用Python突破某网游游戏JS加密限制,进行逆向解密,实现自动登录

兄弟们天天看基础看腻了吧 今天来分享一下如何使用Python突破某网游游戏JS加密限制&#xff0c;进行逆向解密&#xff0c;实现自动登录。 逆向目标 目标&#xff1a;某 7 网游登录主页&#xff1a;aHR0cHM6Ly93d3cuMzcuY29tLw接口&#xff1a;aHR0cHM6Ly9teS4zNy5jb20vYXBpL…

深入理解KMP算法

看这个算法之前&#xff0c;希望你做过&#xff1a;"leetcode-28-找出字符串中第一个匹配项的下标" 这一道题。题目描述&#xff08;直接上例子&#xff09;&#xff1a;主串&#xff08;T&#xff09;&#xff1a;leetcode字串&#xff08;P&#xff09;&#xff1a…

【JavaEE】如何将JavaWeb项目部署到Linux云服务器?

写在前面 大家好&#xff0c;我是黄小黄。不久前&#xff0c;我们基于 servlet 和 jdbc 完善了博客系统。本文将以该系统为例&#xff0c;演示如何将博客系统部署到 Linux 云服务器。 博客系统传送门&#xff1a; 【JavaEE】前后端分离实现博客系统&#xff08;页面构建&#…

开发也可以很快乐,让VSCode和CodeGPT带给你幸福感

CodeGPT 是一款 Visual Studio Code 扩展&#xff0c;可以通过官方的 OpenAI API 使用 GPT-3 (预训练生成式转换器) 模型&#xff0c;在多种编程语言中生成、解释、重构和文档化代码片段。CodeGPT 可用于各种任务&#xff0c;例如代码自动完成、生成和格式化。它还可以集成到代…

【Hello Linux】进程间通信

作者&#xff1a;小萌新 专栏&#xff1a;Linux 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;介绍Linux进程间通信 进程间通信进程间通信概念进程间通信的目的进程通信的本质进程通信的分类管道什么是管道匿名管道匿名管道是什么匿…

浅谈C库函数——memcpy、memmove、memcmp、memset函数

&#x1f48c;内容专栏&#xff1a;【C语言】进阶部分 &#x1f48c;本文概括&#xff1a;理解C库函数memcpy、memmove、memcmp、memset内存函数 &#x1f48c;本文作者&#xff1a;花 碟 &#x1f48c;发布时间&#xff1a;2023.3.19 目录 一、memcpy函数 1.函数声明 2.函数…

【日志包】go语言如何设计日志包 - 基于zap封装适合自己的日志包

文章目录前言一、自己设计log包的重要性二、日志包的基本需求1. 全局logger和传递参数的logger的用法2. 日志包的基本需求logger最基本的功能3. 日志debug、info、error等级别的使用场景日志打印的实践经验三、生产环境中的日志系统架构四、自定义log包1. 自定义log的options2.…
最新文章