当前位置: 首页 > news >正文

一文彻底读懂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: [// 压缩CSSnew 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后,这里需要替换成它的loaderMiniCssExtractPlugin.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 = 75pxremUnit: 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.jsfilename: '[name].js',// 对外暴露的库的名称library: 'mylibrary',// 支持cjs, ejs, script脚本等引入方式libraryTarget: 'umd',// 不加这个的话,使用的时候可能需要mylibrary.defaultlibraryExport: '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抽离,生成manifestnew 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 optipngoptipng: {enabled: false,},pngquant: {quality: [0.65, 0.90],speed: 4},gifsicle: {interlaced: false,},// the webp option will enable WEBPwebp: {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.lryc.cn/news/41105.html

相关文章:

  • 大环境不好,找工作太难?三面阿里,幸好做足了准备,已拿offer
  • C++ 手撸简易服务器(完善版本)
  • 【Python入门第三十四天】Python丨文件处理
  • 【Linux】写一个基础的bash
  • 图解如何一步步连接远程服务器——基于VScode
  • element - - - - - 你不知道的loading使用方式
  • C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题的排查
  • IntelliJIDEA 常用快捷键
  • Python自动化抖音自动刷视频
  • 使用vite创建vue3工程
  • 嵌入式学习笔记——STM32的时钟树
  • Python学习(2)-NumPy矩阵与通用函数
  • 剑指 Offer II 035. 最小时间差
  • Spark SQL函数定义【博学谷学习记录】
  • 模拟实现STL容器之vector
  • ChatGPT-4.0 : 未来已来,你来不来
  • Java反射(详细学习笔记)
  • 学习 Python 之 Pygame 开发魂斗罗(十二)
  • Linux下字符设备驱动开发以及流程介绍
  • Web自动化框架断言方法实现
  • 8大核心语句,带你深入python
  • 【批处理】- 批处理自动安装Mysql与Redis
  • 聊聊华为的工作模式
  • 燕山大学-面向对象程序设计实验-实验6 派生与继承:多重派生-实验报告
  • 分割两个字符串得到回文串[抽象--去除具体个性取共性需求]
  • 【LeetCode】1609. 奇偶树、1122. 数组的相对排序
  • 【C++初阶】4. Date类的实现
  • ES6新特性--变量声明
  • 【Django】缓存机制
  • 我的创作纪念日——一年的时间可以改变很多