【前端webpack5高级优化】提升打包构建速度几种优化方案

HotModuleReplacement(HMR/热模块替换)

开发时我们修改了其中一个模块代码,Webpack 默认会将所有模块全部重新打包编译,速度很慢

所以我们需要做到修改某个模块代码,就只有这个模块代码需要重新打包编译,其他模块不变,这样打包速度就能很快

使用HotModuleReplacement(HMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面

使用流程

1.基本配置

module.exports = {// 其他省略devServer: {host: "localhost", // 启动服务器域名port: "3000", // 启动服务器端口号open: true, // 是否自动打开浏览器hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了)},
};

此时 css 样式经过 style-loader 处理,已经具备 HMR 功能了。 但是 js 还不行

2.js配置

// main.js
import count from "./js/count";
import sum from "./js/sum";
// 引入资源,Webpack才会对其打包
import "./css/iconfont.css";
import "./css/index.css";
import "./less/index.less";
import "./sass/index.sass";
import "./sass/index.scss";
import "./styl/index.styl";const result1 = count(2, 1);
console.log(result1);
const result2 = sum(1, 2, 3, 4);
console.log(result2);// 判断是否支持HMR功能
if (module.hot) {module.hot.accept("./js/count.js", function (count) {const result1 = count(2, 1);console.log(result1);});module.hot.accept("./js/sum.js", function (sum) {const result2 = sum(1, 2, 3, 4);console.log(result2);});
}

上面这样写会很麻烦,所以实际开发我们会使用其他loader来解决。

比如:vue-loader, react-hot-loader


OneOf

打包时每个文件都会经过所有loader处理,虽然因为 test 正则原因实际没有处理上,但是都要过一遍,比较慢

使用OneOf:顾名思义就是只能匹配上一个 loader, 剩下的就不匹配了

使用流程

const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = {entry: "./src/main.js",output: {path: undefined, // 开发模式没有输出,不需要指定输出目录filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中// clean: true, // 开发模式没有输出,不需要清空输出结果},module: {rules: [{oneOf: [{// 用来匹配 .css 结尾的文件test: /\.css$/,// use 数组里面 Loader 执行顺序是从右到左use: ["style-loader", "css-loader"],},{test: /\.less$/,use: ["style-loader", "css-loader", "less-loader"],},{test: /\.s[ac]ss$/,use: ["style-loader", "css-loader", "sass-loader"],},{test: /\.styl$/,use: ["style-loader", "css-loader", "stylus-loader"],},{test: /\.(png|jpe?g|gif|webp)$/,type: "asset",parser: {dataUrlCondition: {maxSize: 10 * 1024, // 小于10kb的图片会被base64处理},},generator: {// 将图片文件输出到 static/imgs 目录中// 将图片文件命名 [hash:8][ext][query]// [hash:8]: hash值取8位// [ext]: 使用之前的文件扩展名// [query]: 添加之前的query参数filename: "static/imgs/[hash:8][ext][query]",},},{test: /\.(ttf|woff2?)$/,type: "asset/resource",generator: {filename: "static/media/[hash:8][ext][query]",},},{test: /\.js$/,exclude: /node_modules/, // 排除node_modules代码不编译loader: "babel-loader",},],},],},plugins: [new ESLintWebpackPlugin({// 指定检查文件的根目录context: path.resolve(__dirname, "../src"),}),new HtmlWebpackPlugin({// 以 public/index.html 为模板创建文件// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源template: path.resolve(__dirname, "../public/index.html"),}),],// 开发服务器devServer: {host: "localhost", // 启动服务器域名port: "3000", // 启动服务器端口号open: true, // 是否自动打开浏览器hot: true, // 开启HMR功能},mode: "development",devtool: "cheap-module-source-map",
};

Include/Exclude

开发时我们需要使用第三方的库或插件,所有文件都下载到 node_modules 中了。而这些文件是不需要编译可以直接使用的。

所以我们在对js文件处理时,要排除 node_modules 下面的文件

使用Include/Exclude

include
包含,只处理 xxx 文件

exclude
排除,除了 xxx 文件以外其他文件都处理

使用流程

const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = {entry: "./src/main.js",output: {path: undefined, // 开发模式没有输出,不需要指定输出目录filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中// clean: true, // 开发模式没有输出,不需要清空输出结果},module: {rules: [{oneOf: [{// 用来匹配 .css 结尾的文件test: /\.css$/,// use 数组里面 Loader 执行顺序是从右到左use: ["style-loader", "css-loader"],},{test: /\.less$/,use: ["style-loader", "css-loader", "less-loader"],},{test: /\.s[ac]ss$/,use: ["style-loader", "css-loader", "sass-loader"],},{test: /\.styl$/,use: ["style-loader", "css-loader", "stylus-loader"],},{test: /\.(png|jpe?g|gif|webp)$/,type: "asset",parser: {dataUrlCondition: {maxSize: 10 * 1024, // 小于10kb的图片会被base64处理},},generator: {// 将图片文件输出到 static/imgs 目录中// 将图片文件命名 [hash:8][ext][query]// [hash:8]: hash值取8位// [ext]: 使用之前的文件扩展名// [query]: 添加之前的query参数filename: "static/imgs/[hash:8][ext][query]",},},{test: /\.(ttf|woff2?)$/,type: "asset/resource",generator: {filename: "static/media/[hash:8][ext][query]",},},{test: /\.js$/,// exclude: /node_modules/, // 排除node_modules代码不编译include: path.resolve(__dirname, "../src"), // 也可以用包含loader: "babel-loader",},],},],},plugins: [new ESLintWebpackPlugin({// 指定检查文件的根目录context: path.resolve(__dirname, "../src"),exclude: "node_modules", // 默认值}),new HtmlWebpackPlugin({// 以 public/index.html 为模板创建文件// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源template: path.resolve(__dirname, "../public/index.html"),}),],// 开发服务器devServer: {host: "localhost", // 启动服务器域名port: "3000", // 启动服务器端口号open: true, // 是否自动打开浏览器hot: true, // 开启HMR功能},mode: "development",devtool: "cheap-module-source-map",
};

Cache

每次打包时 js文件都要经过Eslint检查 和Babel编译,速度比较慢。

我们可以缓存之前的 Eslint 检查 和Babel编译结果,这样第二次打包时速度就会更快了

使用Cache : 对Eslint检查 和Babel编译结果进行缓存

使用流程

const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = {entry: "./src/main.js",output: {path: undefined, // 开发模式没有输出,不需要指定输出目录filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中// clean: true, // 开发模式没有输出,不需要清空输出结果},module: {rules: [{oneOf: [{// 用来匹配 .css 结尾的文件test: /\.css$/,// use 数组里面 Loader 执行顺序是从右到左use: ["style-loader", "css-loader"],},{test: /\.less$/,use: ["style-loader", "css-loader", "less-loader"],},{test: /\.s[ac]ss$/,use: ["style-loader", "css-loader", "sass-loader"],},{test: /\.styl$/,use: ["style-loader", "css-loader", "stylus-loader"],},{test: /\.(png|jpe?g|gif|webp)$/,type: "asset",parser: {dataUrlCondition: {maxSize: 10 * 1024, // 小于10kb的图片会被base64处理},},generator: {// 将图片文件输出到 static/imgs 目录中// 将图片文件命名 [hash:8][ext][query]// [hash:8]: hash值取8位// [ext]: 使用之前的文件扩展名// [query]: 添加之前的query参数filename: "static/imgs/[hash:8][ext][query]",},},{test: /\.(ttf|woff2?)$/,type: "asset/resource",generator: {filename: "static/media/[hash:8][ext][query]",},},{test: /\.js$/,// exclude: /node_modules/, // 排除node_modules代码不编译include: path.resolve(__dirname, "../src"), // 也可以用包含loader: "babel-loader",options: {cacheDirectory: true, // 开启babel编译缓存cacheCompression: false, // 缓存文件不要压缩},},],},],},plugins: [new ESLintWebpackPlugin({// 指定检查文件的根目录context: path.resolve(__dirname, "../src"),exclude: "node_modules", // 默认值cache: true, // 开启缓存// 缓存目录cacheLocation: path.resolve(__dirname,"../node_modules/.cache/.eslintcache"),}),new HtmlWebpackPlugin({// 以 public/index.html 为模板创建文件// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源template: path.resolve(__dirname, "../public/index.html"),}),],// 开发服务器devServer: {host: "localhost", // 启动服务器域名port: "3000", // 启动服务器端口号open: true, // 是否自动打开浏览器hot: true, // 开启HMR功能},mode: "development",devtool: "cheap-module-source-map",
};

Thead

当项目越来越庞大时,打包速度越来越慢,甚至于需要一个下午才能打包出来代码。这个速度是比较慢的。

我们想要继续提升打包速度,其实就是要提升js的打包速度,因为其他文件都比较少。

而对 js 文件处理主要就是 eslintbabelTerser 三个工具,所以我们要提升它们的运行速度。

我们可以开启多进程同时处理 js 文件,这样速度就比之前的单进程打包更快了

使用Thead 多进程打包:开启电脑的多个进程同时干一件事,速度更快。

需要注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大约为600ms左右开销

使用流程

我们启动进程的数量就是我们 CPU 的核数

1.如何获取 CPU 的核数,因为每个电脑都不一样

// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;

2.下载包

npm i thread-loader -D

3.使用

const os = require("os");
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");// cpu核数
const threads = os.cpus().length;// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {return [MiniCssExtractPlugin.loader,"css-loader",{loader: "postcss-loader",options: {postcssOptions: {plugins: ["postcss-preset-env", // 能解决大多数样式兼容性问题],},},},preProcessor,].filter(Boolean);
};module.exports = {entry: "./src/main.js",output: {path: path.resolve(__dirname, "../dist"), // 生产模式需要输出filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中clean: true,},module: {rules: [{oneOf: [{// 用来匹配 .css 结尾的文件test: /\.css$/,// use 数组里面 Loader 执行顺序是从右到左use: getStyleLoaders(),},{test: /\.less$/,use: getStyleLoaders("less-loader"),},{test: /\.s[ac]ss$/,use: getStyleLoaders("sass-loader"),},{test: /\.styl$/,use: getStyleLoaders("stylus-loader"),},{test: /\.(png|jpe?g|gif|webp)$/,type: "asset",parser: {dataUrlCondition: {maxSize: 10 * 1024, // 小于10kb的图片会被base64处理},},generator: {// 将图片文件输出到 static/imgs 目录中// 将图片文件命名 [hash:8][ext][query]// [hash:8]: hash值取8位// [ext]: 使用之前的文件扩展名// [query]: 添加之前的query参数filename: "static/imgs/[hash:8][ext][query]",},},{test: /\.(ttf|woff2?)$/,type: "asset/resource",generator: {filename: "static/media/[hash:8][ext][query]",},},{test: /\.js$/,// exclude: /node_modules/, // 排除node_modules代码不编译include: path.resolve(__dirname, "../src"), // 也可以用包含use: [{loader: "thread-loader", // 开启多进程options: {workers: threads, // 数量},},{loader: "babel-loader",options: {cacheDirectory: true, // 开启babel编译缓存},},],},],},],},plugins: [new ESLintWebpackPlugin({// 指定检查文件的根目录context: path.resolve(__dirname, "../src"),exclude: "node_modules", // 默认值cache: true, // 开启缓存// 缓存目录cacheLocation: path.resolve(__dirname,"../node_modules/.cache/.eslintcache"),threads, // 开启多进程}),new HtmlWebpackPlugin({// 以 public/index.html 为模板创建文件// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源template: path.resolve(__dirname, "../public/index.html"),}),// 提取css成单独文件new MiniCssExtractPlugin({// 定义输出文件名和目录filename: "static/css/main.css",}),// css压缩// new CssMinimizerPlugin(),],optimization: {minimize: true,minimizer: [// css压缩也可以写到optimization.minimizer里面,效果一样的new CssMinimizerPlugin(),// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了new TerserPlugin({parallel: threads // 开启多进程})],},// devServer: {//   host: "localhost", // 启动服务器域名//   port: "3000", // 启动服务器端口号//   open: true, // 是否自动打开浏览器// },mode: "production",devtool: "source-map",
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

老王讲IT:函数基础

IT老王:函数基础 目标 函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数 01. 函数的快速体验 1.1 快速体验 所谓函数,就是把 具有独立功能的代码块 组织为一个小模块,在需要的时候 调用 函…

html加载后端数据较慢问题记载

标题: html加载后端数据较慢问题记载 日期: 2024-04-06 22:29:00 标签: [html, flask] 分类: [Python, Flask] 网站页面最近加载很慢,不知道为什么,这里记录一下,一步一步查问题的思路。 说下环境 python3.8 flask2.3.3 mysql5.7 问题 刷…

爬虫实战一、Scrapy开发环境(Win10+Anaconda3)搭建

#前言 在这儿推荐使用Anaconda进行安装,并不推荐大家用pythonpip安装,因为pythonpip的坑实在是太多了。 #一、环境中准备: Win10(企业版)Anaconda3-5.0.1-Windows-x86_64,下载地址,如果打不开…

每日OJ题_两个数组dp①_力扣1143. 最长公共子序列

目录 力扣1143. 最长公共子序列 解析代码 力扣1143. 最长公共子序列 1143. 最长公共子序列 难度 中等 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样…

尚硅谷html5+css3(2)CSS5基本知识

1.网页分为三个部分: 结构:HTML 表现:CSS 行为JavaScript CSS:层叠样式表,网页实际上是一个多层结构,通过CSS可以分别为网页的每一个层来设置样式,最终用户只看最上面的一层,总之&#xff0…

蚁群优化算法(Ant Colony Optimization Algorithm)

注意:本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 ([www.aideeplearning.cn]) 算法引言 蚁群算法,是一种模拟蚂蚁觅食行为的优化算法。想象一下,当你在野餐时,不小心洒了一些糖在地上。一…

AcWing26. 二进制中1的个数。三种解法Java

输入一个 3232 位整数,输出该数二进制表示中 11 的个数。 注意: 负数在计算机中用其绝对值的补码来表示。 数据范围 −100≤ 输入整数 ≤100 样例1 输入:9 输出:2 解释:9的二进制表示是1001,一共有2个…

免疫检查点信号转导和癌症免疫治疗(文献)

目录 基础 介绍 免疫检查点的表面调控(细胞膜层面) ​编辑 PD-1调节 PD-L1调节 CTLA-4 调节 检查点信号通路 关于靶点研究 展望 Immune checkpoint signaling and cancer immunotherapy - PubMed (nih.gov) 基础 【中英字幕】肿瘤免疫疗法之免…

分享10个免费高可用的GPT3.5和4.0网站并做功能测试【第一个】

1.介绍 网址:直接点:aicnn 或者 www.aicnn.cn 基于ChatGPT可以实现智能聊天、绘画生成、高清文本转语音、论文润色等多种功能,基于sd和mj实现的绘画功能,下面是功能测试: 博主从 1.GPT3.5是否完全免费/是否限制频率、…

MySQL学习笔记------事务

事务 事务是一组操作的集合,他是一个不可分割的单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败 事务操作 create table account(id int comment ID,name varchar(10) …

如何成为一名嵌入式C语言高手?

如何成为一名嵌入式C语言高手? 嵌入式系统是当今科技领域的核心,而C语言则是嵌入式系统开发中最常用的编程语言之一。成为一名嵌入式C语言高手需要长时间的学习和实践。下面将介绍一些方法和技巧,帮助你在嵌入式C语言领域获得突出的技能和能力。 一、打…

Spring 中类似 aBbb 单字母单词序列化与反序列问题

文章目录 前言代码准备问题排查lombok自定义生成 get、set 结合源码解析使用 lombok使用 lombok 自定义生成 user 对象 get、set 方法 如何解决使用注解 JsonProperty("aTest")自定义实现符合 Spring 规范的 get set 方法 个人简介 前言 最近在使用 spring boot mvc…

Linux下Qt生成程序崩溃文件

文章目录 1.背景2.Qt编译生成程序2.1.profile模式的本质 3.执行程序,得到core文件4.代码定位4.1.直接使用gdb4.2.使用QtCreator 5.总结6.题外话6.1.profile模式和debug模式的区别 1.背景 在使用Qt时,假如在windows,当软件崩溃时,…

【整数二分】难题选讲

对应洛谷题单里面【整数二分】几道同学们不太好理解的题目,写个解析 A-1数对题目链接 实际上本题方法很多,我先说个好做的办法 我们可以用map标记所有数的个数,枚举数字A[i],在map里面查找C-A[i]数字的个数,统计答案即可&#xff…

C++11右值引用

传统的C语法中就有引用的语法,而C11中新增了的右值引用语法特性,所以从现在开始我们之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。 左值与左值引用 左值是一个表示数据的表达式(如变量名或解引用的指针)&…

Qt-线程1-Run

0. 写在前面 一个应用程序一般只有一个线程,一个线程内的操作是顺序执行的,如果有某个比较耗时间的计算或操作,比如图像处理大数据图像、网络通信中的文件传输;在一个线程内操作时,用户界面就能冻结而不能及时响应。这…

34-2 SSRF(服务器端请求伪造)漏洞 - SSRF相关函数

简介 file_get_contents(): 功能: 该函数用于将整个文件读取到一个字符串中,可以用于获取本地或远程文件的内容。风险: 如果未经验证的用户输入作为参数传递给该函数,并且允许读取远程文件,则可能导致SSRF漏洞,攻击者可以利用该漏洞读取服务器内部的文件或者执行未经授权…

C++面试经典问题

常见问题:智能指针、多态、虚函数、STL原理、链表、排序、二叉树、设计模式、线程进程、内存 对象所有权 在接触智能指针之前首先要理解对象的所有权是什么,在这之前我们总是用new和delete来进行内存的申请与释放,在这种堆内存分配的方式中…

【退役之重学Java】关于lambda表达式和函数式接口

使用 lambda 表达式为作为实参,传递给形参,形参为函数式接口,此lambda表达式没有指定类型,如何能匹配函数式接口的形参类型呢? 函数式接口作为参数,实参可以直接用lambda表达式吗,是什么原理 函…