当前位置: 首页 > Web前端 > HTML

Webpack的运行环境从零配置React的第二部分-优化打包策略

时间:2023-04-02 22:38:49 HTML

项目地址https://github.com/jianjiache...大部分内部配置都有详细说明执行方式:cnpminstallcnpmrunstartcnpmrunbuild完成的功能[x]分离生产环境和开发环境[x]添加source-map方便调试[x]分析babel-polyfill不同导入方式的影响[x]代码拆分定义提取模块的方式分组[x]认识React语法和ES6[x]解决ES7装饰器不兼容的问题(@)Decorator[x]对于小于8k的图片,使用base64推送url减少requests[x]添加组件即可按需加载,而不是直接导入整个模块[x]添加less和sass处理[x]提取所有css样式文件[x]压缩JS代码和CSS代码[x]添加浏览器前缀的CSS自动补全,增强适配[x]完成字体、图片、媒体文件的基于大小的打包策略[x]生成HTML文件并主动添加JS文件[x]配置并删除生产环境的console.log[x]每次清空packagedist目录[x]增加代码热更新,修改代码自动编译[x]增加webpack多入口配置[x]增加包大小可视化分析工具,想实现babel功能caching我们每次执行构建都会重复编译所有文件。这样重复的工作能缓存吗?答案是肯定的。目前大多数加载器都提供了缓存配置项。比如在babel-loader中,可以通过设置cacheDirectory开启缓存,babel-loader?cacheDirectory=true会把每次编译结果写入硬盘文件(当然默认是node_modules/.cache/babel-loader目录)也可以自定义)使用动态链接库文件DLL如果不使用DLLPlugin插件,当引入第三方模块时,每个包都要解析,比较消耗包的性能。使用DLLPlugin提高打包速度。第一次打包时,将第三方模块单独打包生成一个文件vendors.dll.js,打包时直接从vendors.dll.js中导入之前打包好的第三方模块,速度会变快。要实现这个,需要做一些配置:首先配置webpack.dll.js文件,在package.json中添加脚本,配置webpack.common.js文件TreeShaking:只支持ESModule静态结构如import和export特性的介绍。导入模块时,不导入所有代码,只导入需要的代码happypack并发执行任务(包含在代码中,未启用)CDN(注释中添加方法)按需加载babel-plugin-import(添加但未启用))首屏渲染加载(方法已在备注中添加)需要使用Webpack自带的配置将打包后的js文件的名字改成不确定的名字使用自带的[hash]或[chunkhash]webpackconstmerge=require('webpack-merge');constcommon=require('./webpack.common.config.js');module.exports=merge(common,{mode:'production',output:{文件名:'js/[name].[chunkhash:8].bundle.js',},······});CodeSplittingWebpack内置了优化(optimizationfield)splitChunks来实现代码拆分。在大多数情况下,不需要配置,但您也可以进行个性化配置。比如要指定哪些代码应该分配到哪个组,可以使用cacheGroups配置module.exports={//...optimization:{splitChunks:{//把公共代码分开看具体配置官网chunks:'all',//有效值为all、async和initial。提供all可能特别强大,因为这意味着即使在异步和非异步块之间也可以共享块minSize:30000,maxSize:0,minChunks:1,cacheGroups:{//定义提取的模块如何分成组,否则公共代码全部打包成一个JS文件。vendors:{//第三方库提取优先级:1,//权重优先,第三方库提取test:/[\\/]node_modules[\\/]/,//选择从node_modules文件夹导入的模块,所以所有的第三方模块都会被拆分出来Recursivename:"vendor",enforce:true,},}}//...};自动编译打包安装webpack-dev-servernpminstallwebpack-dev-server--save-dev添加代码到webpack.dev.config.js:constpath=require('path');constmerge=require('webpack-merge');constcommon=require('./webpack.common.config.js');constwebpack=require('webpack');constHtmlWebpackPlugin=require('html-webpack-plugin');module.exports=merge(common,{mode:'development',输出:{filename:'js/[name].[hash:8].bundle.js',},devServer:{contentBase:path.resolve(__dirname,'../dist'),open:true,port:9000,compress:true,hot:true},plugins:[newHtmlWebpackPlugin({template:'public/index.html',inject:'body',hash:false}),newwebpack.HotModuleReplacementPlugin()]});HotModuleReplacementPlugin是webpack热更新的插件,将devServer.hot设置为true,在plugins中引入HotModuleReplacementPlugin插件即可。注意我们启用了hot,所以export不能使用chunkhash,需要换成hash。修改我们的package.json"scripts":{"test":"echo\"Error:notestspecified\"&&exit1","build":"webpack--config./config/webpack.prod.config.js",+"start":"webpack-dev-server--inline--config./config/webpack.dev.config.js"},修改代码自动运行执行代码npmrunstart自动开启一个端口to9000上面的网页就是我们写的页面内容,和我们的配置一一对应。现在你可以随意修改app.js中的代码,然后回到页面查看是否有变化,那么我们就成功集成了webpack-dev-server!其他需要使用的插件介绍terser-webpack-plugin可以配置删除console.lognpminstall--save-devterser-webpack-pluginclean-webpack-plugin只想要最新打包编译好的文件,需要先清除dist目录npminstall--save-devclean-webpack-pluginuglifyjs-webpack-plugin压缩代码npminstall--save-devuglifyjs-webpack-pluginmini-css-extract-pluginproposescssinsteadofembeddingnpminstall直接在页面中--save-devmini-css-extract-pluginwebpack-bundle-analyzer可视化包大小分析工具npminstall--save-devwebpack-bundle-analyzer其他优化打包的插件使用方法直接新建plugins字段中的instance,parameters是插件的配置项。我就不一一介绍了,直接配置一个完整的webpack.prod.configconstmerge=require('webpack-merge');//区分生产环境和开发环境constcommon=require('./webpack.common.config.js');//导入基础配置constHtmlWebpackPlugin=require('html-webpack-plugin');//插件为你生成HTML文件,主动加入JS文件constTerserPlugin=require('terser-webpack-plugin');//可以配置删除console.logconst{CleanWebpackPlugin}=require('clean-webpack-plugin');//只想要最新打包编译好的文件,需要先清空dist目录constUglifyJsPlugin=require('uglifyjs-webpack-plugin');//压缩代码constMiniCssExtractPlugin=require('mini-css-extract-plugin');//建议css而不是直接在页面嵌入constOptimizeCssAssetsPlugin=require('optimize-css-assets-webpack-plugin');//建议的css压缩constBundleAnalyzerPlugin=require('webpack-bundle-analyzer').BundleAnalyzerPlugin;//Bundle大小分析工具module.exports=merge(common,{mode:'production',output:{filename:'js/[name].[chunkhash:8].bundle.js',},module:{rules:[{test:/\.css$/,use:[MiniCssExtractPlugin.loader,//单独提出CSS'css-loader','postcss-loader'//css编译的工具可以:1.使用下一代的CSS语法2.自动补全浏览器前缀3.自动把px转为rem]},{test:/\.less$/,use:[MiniCssExtractPlugin.loader,'css-loader','postcss-loader','less-loader']},{测试:/\.(scss|sass)$/,使用:[MiniCssExtractPlugin.loader,'css-loader','postcss-loader','sass-loader']},]},plugins:[newHtmlWebpackPlugin({filename:'index.html',template:'public/index.html',//定义的h??tml生成为atemplateFindinjectfromtherootpath:'body',minify:{//压缩HTML文件removeComments:true,//删除注释collapseWhitespace:true,//删除空格},}),newCleanWebpackPlugin(),newUglifyJsPlugin(),newMiniCssExtractPlugin({filename:'css/[name].[hash].css',chunkFilename:'css/[id].[hash].css',}),newBundleAnalyzerPlugin({analyzerPort:9001,})],optimization:{//optimizeminimizer:[//minimizernewTerserPlugin({//减少代码的插件terserOptions:{compress:{drop_console:true,//删除console.log},}}),newOptimizeCssAssetsPlugin({//CompressCSSassetNameRegExp:/\.css$/g,cssProcessor:require("cssnano"),//压缩和优化CSS的处理器cssProcessorPluginOptions:{preset:['default',{discardComments:{removeAll:true}}]},canPrint:true})],splitChunks:{//分离公共代码具体配置,见官网chunks:'all',//值为all、async、initial提供all可能特别强大,因为这意味着即使在异步和非异步块之间也可以共享块minSize:30000,maxSize:0,minChunks:1,cacheGroups:{//定义提取的模块如何分成组,否则公共代码全部打包成一个JS文件。vendors:{//第三方库提取优先级:1,//权重优先,第三方库提取test:/[\\/]node_modules[\\/]/,//选择从node_modules文件夹导入的模块,所以所有的第三方模块都会被拆分出来Recursivename:"vendor",enforce:true,},}}}});打包图片字体媒体文件,并调试优化下载文件打包依赖npminstallfile-loaderurl-loader--save-devdebugdevtool填入cheap-module-eval-source-map,保存的时候可以直接找到报错下源文件个数直接给一个webpack.common.config配置constpath=require("path");module.exports={devtool:"cheap-module-eval-source-map",//方便fordebuggingentry:{//定义入口文件index:"./src/index.js"//index:['babel-polyfill','./src/index.js'],//添加polyfillshims(mountingES6+methodsandAPIsuchasPromise等)这是一种很古老的写法,会污染整个世界。现在preset-env内置了按需加载//framework:['react','react-dom'],//代码切分定义分组},output:{//编译打包后的文件名和路径filename:“js/bundle.js”,路径:path.resolve(__dirname,"../dist")},module:{//Compiler//noPars:/jquery/,//比如我引入了jquery,它不依赖其他包,所以不需要解析和直接打包规则:[{test:/\.(js|jsx)$/,//codeuse:"babel-loader",exclude:/node_modules///无需翻译},{test:/\.(jpg|png|gif)$/,//图片使用:{loader:"url-loader",options:{name:"[name].[ext]",outputPath:"images/",limit:8192//大于8Kb的file-loader(貌似是自动的,没有加fallback),小图标直接打包插入bundle.js,减少Http请求/*fallback:{loader:'file-loader',options:{name:'img/[name].[hash:8].[ext]'}*/}}},{test:/\.(eot|ttf|svg|woff|woff2)$/,//字体使用:{loader:"file-loader",options:{name:"[name]_[hash].[ext]",outputPath:"font/"}}},{test:/\.(mp4|webm|奥格|mp3|wav|flac|aac)(\?.*)?$/,//媒体文件使用:{loader:"file-loader",options:{name:"[name].[hash:8].[ext]",outputPath:"media/"}}},/*{test:/\.css$/,use:['style-loader',//最终计算出来的css会使用style-loader生成样式标签内容为最终解析的css代码,放在head标签中'css-loader'//css-loader加载器解析该文件,遇到“@import”等语句时导入对应的样式文件]}*/]}};完整目录结构WebpackReact├──config│├──webpack.common.config.js│├──webpack.dev.config.js│├──webpack.multipleEntry.config.js│└──webpack.prod.config.js├──dist├──distbackup│└──firstpackaging.js├──font│├──demo.css│├──demo_index.html│├──iconfont.css│├──iconfont.eot│├──iconfont.js│├──iconfont.json│├──iconfont.svg│├──iconfont.ttf│├──iconfont.woff│└──iconfont。woff2├──image│├──vscode.png│├──visualization.png│├──fastfood.png│├──food.png│└──bread.png├──package.json├──postcss.config.js├──public│└──index.html├──readme.md├──src│├──app.js│├──app.less│└──index.js├──video│└──110.mp4└──Notes.md参考文章https://webpack.js.org/guides...https://www.babeljs.cn/https://segmentfault.com/n/13...https://juejin.im/post/5aa3d2...https://juejin.im/post/5bf610...