webpack之性能优化(webpack4)

在讲解性能优化的方案之前,我们需要了解一下webpack的整个工作流程,

方案一:减少模块解析

也就是省略了构建chunk依赖模块的这几个步骤

如果没有loader对该模块进行处理,该模块的源码就是最终打包结果的代码。不对某个模块进行解析,可以缩短构建时间

哪些模块不需要解析?

模块中无其他依赖 webpack配置 配置module.noParse,它是一个正则,被正则匹配到的模块不会解析 module.exports = { mode: "development", module: { noParse: /test/ } }

方案二:优化loader

1.对于某些库,不使用loader

例如:babel-loader可以转换ES6或更高版本的语法,可是有些库本身就是用ES5语法书写的,不需要转换,使用babel-loader反而会浪费构建时间 通过module.rule.excludemodule.rule.include,排除或仅包含需要应用loader的场景,可以直接排除掉node_modules的所有包,也可以仅排除单独的包 module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/,// exclude: /lodash/ //或 // include: /src/, use: "babel-loader" } ] } }

2.利用cache-loader对模块进行缓存

如果某个文件内容不变,经过相同的loader解析后,解析后的结果也不变,所以可以将loader的解析结果保存下来,让后续的解析直接使用保存的结果 module.exports = { module: { rules: [ { test: /\.js$/, use: ['cache-loader', 'babel-loader'] }, ], }, }; 大家可能会感到疑惑,明明loader是从后往前执行的,那么cache-loader是怎么拿到babel-loader的结果的呢? 其实,每个loader上,还有一个pitch的静态方法 function loader(source){ return `new source` } loader.pitch = function(filePath){ // 可返回可不返回 // 如果返回,返回源代码 } module.exports = loader; loader真正执行的顺序是这样的: loader1.pitch => loader2.pitch => loader3.pitch => loader3 => loader2 => loader1 因此,以['cache-loader', 'babel-loader']为例, 第一次打包:

  • 先调用cache-loader.pitch,发现无缓存,往后执行,

  • 调用babel-loader.pitch,也发现无缓存,往后执行,

  • 读取当前需要处理的模块的代码

  • 调用babel-loader,返回修改成es5的代码

  • 调用cache-loader,返回babel-loader处理的结果代码并缓存

第二次打包:

  • 先调用cache-loader.pitch,发现有缓存,则返回源代码

  • 直接返回上次处理好的源代码,不会继续往后走了

当然对于babel-loader,使用它本身的配置也是可以缓存的 module.exports = { module: { rules: [ { test: /\.js$/, use: 'babel-loader?cacheDirectory' }, ], }, };

3.开启thread-loader

它会把后续的loader放到线程池的线程中运行,以提高构建效率 由于后续的loader会放到新的线程中,所以,后续的loader不能:

  • 使用 webpack api 生成文件 (loader上下文中的emitFile、emitError等api)

  • 无法使用自定义的 plugin api (某些插件提供了自身的plugin和loader,plugin会向webpack注入新的api,loader中会使用)

  • 无法访问 webpack的配置

注意,开启和管理线程需要消耗时间,在小型项目中使用thread-loader反而会增加构建时间

方案三:热替换

热替换并不能降低构建时间(可能还会稍微增加),但可以减少代码改动到效果呈现的时间 // webpack配置 module.exports = { devServer:{ hot:true // 开启HMR } } // index.js if(module.hot){ // 是否开启了热更新 module.hot.accept() // 接受热更新 }

方案四:动态链接库

什么情况下使用? 当打包出来的多个bundle.js文件都有重复的第三方代码,会增加文件的体积,不利于传输

打包的过程:

1.使用output.library配置公共模块的全局变量名

// webpack.dll.config.js module.exports = { mode: "production", entry: { jquery: ["jquery"], lodash: ["lodash"] }, output: { filename: "dll/[name].js", library: "[name]"// 每个buldle暴露的全局变量名 } }; 打包结果 // dist/dll/lodash var lodash=function(n){xxx} // dist/dll/jquery var jquery=function(n){xxx}

2.用DllPlugin创建资源清单(包含信息:全局变量名、node_modules对应包的路径)

// webpack.dll.config.js module.exports = { plugins: [ new webpack.DllPlugin({ path: path.resolve(__dirname, "dll", "[name].manifest.json"), //资源清单的保存位置 name: "[name]"//资源清单中,暴露的变量名 }) ] }; 打包生成的资源清单 // dll/lodash.manifest.json { "name": "lodash", "content": { "./node_modules/lodash/lodash.js": { xxx } } } // dll/jquery.manifest.json { "name": "jquery", "content": { "./node_modules/jquery/dist/jquery.js": { xxx } } }

3.用DllReferencePlugin使用资源清单

在页面中手动引入公共模块 重新设置clean-webpack-plugin 如果使用了插件clean-webpack-plugin,为了避免它把公共模块清除,需要做出以下配置,webpack.config.js配置(注意不是和output.library、DllPlugin在同一个配置文件中哦): new CleanWebpackPlugin({ // 要清除的文件或目录 // 排除掉dll目录本身和它里面的文件 cleanOnceBeforeBuildPatterns: ["**/*", '!dll', '!dll/*'] }) 使用DllReferencePlugin 找到对应的资源清单,根据暴露的变量名(output.library)匹配第三方库在node_modules中的路径,不需要将代码打包到bundle.js中,webpack.config.js: new webpack.DllReferencePlugin({ manifest: require("./dll/jquery.manifest.json") }), new webpack.DllReferencePlugin({ manifest: require("./dll/lodash.manifest.json") }) 打包过程:首先要根据webpack.dll.config.js配置文件打包一次,之后再根据webpack.config.js打包 最终打包结果的格式: (function(modules){ //... })({ // index.js文件的打包结果并没有变化 "./src/index.js": function(module, exports, __webpack_require__){ var $ = __webpack_require__("./node_modules/jquery/index.js") var _ = __webpack_require__("./node_modules/lodash/index.js") _.isArray($(".red")); }, // 由于资源清单中存在,jquery的代码并不会出现在这里 "./node_modules/jquery/index.js": function(module, exports, __webpack_require__){ module.exports = jquery; }, // 由于资源清单中存在,lodash的代码并不会出现在这里 "./node_modules/lodash/index.js": function(module, exports, __webpack_require__){ module.exports = lodash; } }) 优点:

  • 极大提升自身模块的打包速度

  • 极大的缩小了自身文件体积

  • 有利于浏览器缓存第三方库的公共代码

缺点:

  • 使用非常繁琐

  • 如果第三方库中包含重复代码,则效果不太理想

方案五:抽离公共代码

有多个模块都引用了公共模块,当一个模块加载时,访问了公共模块,并缓存下来,另一个模块加载就可以直接使用缓存的结果。 module.exports = { optimization: { splitChunks: { // 分包策略 chunks: "all", cacheGroups: { // 公共模块 common: { mixSize: 0, minChunks: 2, // 至少被几个文件引用 }, vendors: { test: /[\\/]node_modules[\\/]/, // 当匹配到相应模块时,将这些模块进行单独打包 priority: 1 // 缓存组优先级,优先级越高,该策略越先进行处理,默认值为0 }, } } } } 还可以抽离公共样式,使用MiniCssExtractPlugin module.exports = { optimization: { splitChunks: { chunks: "all", cacheGroups: { styles: { test: /\.css$/, // 匹配样式模块 minSize: 0, // 覆盖默认的最小尺寸,这里仅仅是作为测试 minChunks: 2 // 覆盖默认的最小chunk引用数 } } } }, module: { rules: [{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] }] }, plugins: [ new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: "[name].[hash:5].css", // chunkFilename是配置来自于分割chunk的文件名 chunkFilename: "common.[hash:5].css" }) ] } 通过cdn方式引入js、css文件,将不怎么需要更新的第三方库脱离webpack打包,不被打入bundle中,从而减少打包时间,但又不影响运用第三方库的方式,例如import方式等。 const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin'); module.exports = { plugins: [ new HtmlWebpackExternalsPlugin({ externals: [{ module: 'vue', entry: 'https://img.jcdi.cn/oss/d/file/2021-08-29/20e4955697901f0c3e824ad199ce44fe.js', global: 'Vue' }] }) ], } 最后看到在dist/index.html中动态添加了如下代码:

方案六:代码压缩

压缩js和css代码: const TerserPlugin = require('terser-webpack-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { optimization: { // 是否要启用压缩,默认情况下,生产环境会自动开启 minimize: true, minimizer: [ // 压缩时使用的插件 // 压缩js文件 new TerserPlugin({
parallel: true // 开启多线程压缩
}), // 压缩css文件 new OptimizeCSSAssetsPlugin() ], }, }; 使用compression-webpack-plugin插件对打包结果进行预压缩,可以移除服务器的压缩时间 new CmpressionWebpackPlugin({ test: /\.js/, minRatio: 0.5 })

https://www.jcdi.cn/qianduankaifa/127029.html

(0)

相关推荐

  • Webpack最详解

    WEB前端开发社区 昨天 JavaScript模块打包的概念已经出现一段时间了.RequireJS在2009年首次发声,之后Browserify粉墨登场.接着各种打包工具如雨后春笋纷纷涌现.而webp ...

  • vue 开发常用工具及配置六:认识各种 loader

    本文大约 2400 字. 目录 Webpack 的工作原理 loader 和 plugin 的区别 webpack 如何处理 css 文件 三种样式 sass/scss 和 less 的区别 另一种定 ...

  • webpack 5 带来的全新改变

    安装 webpack-dev-server npm install webpack-dev-server -D 在 webpack配置文件中配置服务: devServer:{ port: 8080, ...

  • vite —— 一种新的、更快地 web 开发工具

    前端技术优选 今天 以下文章来源于淘系前端团队 ,作者木偶 文末福利:开发者藏经阁 NO.1 vite 是什么 vite -- 一个由 vue 作者尤雨溪开发的 web 开发工具,它具有以下特点: 快 ...

  • Web 性能优化: 使用 Webpack 分离数据的正确方法

    WEB前端开发社区 昨天 制定向用户提供文件的最佳方式可能是一项棘手的工作. 有很多不同的场景,不同的技术,不同的术语. 在这篇文章中,我希望给你所有你需要的东西,这样你就可以: 了解哪种文件分割策略 ...

  • 干货:C 的性能优化

    前言 性能优化不管是从方法论还是从实践上都有很多东西,从 C++ 语言本身入手,介绍一些性能优化的方法,希望能做到简洁实用. 实例1 在开始本文的内容之前,让我们看段小程序: // 获取一个整数对应1 ...

  • Android 性能优化必知必会 · Android Performance

    做了这么久性能相关的工作,也接触了不少模块,说实话要做好性能这一块,真心不容易.为什么这么说? 是因为需要接触的知识实在是太多了, Android 是一个整体,牵一发而动全身,不是说只懂一个模块就可以 ...

  • 浅谈面向客户端的性能优化

    有朋友通过<智能音箱场景下的性能优化>一文找到了我,既然智能音箱的性能优化相当于一个超集,那么对其的一个子集--客户端系统如何进行性能优化呢? 反正隔离在家,不妨对客户端的性能优化梳理一下 ...

  • 智能音箱场景下的性能优化

    QCon是由InfoQ主办的综合性技术盛会,今年是Qcon举办的第10个年头,半吊子全栈工匠有幸作为演讲嘉宾分享一个近两年来的实践经验--智能音箱场景下的性能优化,隶属于曾波老师出品的"场景 ...

  • 如何配置Nginx压缩实现性能优化?怎么学Linux系统

    如何配置Nginx gzip压缩实现性能优化?是每个Linux运维管理人员都需要掌握的技能.互联网时代发展迅速,Linux运维技术的需求更多推进不少.市场对于Linux运维人才的需求也在逐渐加大.Li ...

  • Flutter 2.2发布:针对各平台的性能优化、完善生态支持

    局长 OSC开源社区 昨天 文 | 局长 出品 | OSC开源社区(ID:oschina2013) 谷歌在昨日举办的 Google I/O 2021 大会上宣布了 Flutter 2.2,其开发团队称 ...

  • Web性能优化之图片延迟加载

    来源:微信公众号CodeL 对于一些图片多,页面长的网页来说,如果每次打开页面加载全部的网页内容,页面加载速度势必会受到影响,如果每次打开网页只将网页可视区域的内容加载给用户 ,将大大提高网页浏览速度 ...

  • ASP.Net服务性能优化原则

    dotNET跨平台 今天 以下文章来源于老王Plus ,作者老王Plus的老王理理Asp.net性能相关的问题及注意事项. 以下这些内容,全部是经验之谈.如果你有别的建议,也可以从后台发给我. 服务器 ...