webpack--性能优化之打包构建速度和代码调试优化
前言
本文来总结写webpack 在性能方面常见的优化方案。
正文
本文分别总结开发环境和生产环境中在打包构建速度和代码调试功能方面的优化方案,如下:
1、开发环境性能优化
(1)优化打包构建速度
a、HMR: hot module replacement ,热模块替换,作用:当一个模块发生变化的时候,只会重新打包发生变化的模块,并不会打包所有模块,极大的提升了代码构建速度。
只需要在webpack.config.js中的devserver中添加:
devServer: {
// contentBase: resolve(__dirname, "build"),// 这个配置在新版本的webpack中使用下面的方式配置,否则会报错
static: { // static: ['assets']
directory: resolve(__dirname, "build")
},
// 启用gzip压缩
compress: true,
// 端口号
port: 3000,
open:true,// 自动打开浏览器
hot:true// 开启HMR功能
},
执行 npx webpack-dev-server命令,然后修改其中的文件,会发现控制台提示修改的文件,如下:
经测试发现总结:
样式文件:可以使用HRM功能,因为style-loader 内部实现了
js文件:默认不能使用HRM功能,(解决方法:修改js代码,添加支持)
html 文件:默认不能使用HRM 功能,同时会导致html文件不能热更新了(解决方法:修改入口文件entry的引入即可,如下:)开发中不需要做
//入口文件
entry: ["./src/index.js","./src/index.html"],
(2)优化代码调试性能
source-map:是一种提供源代码到构建后代码的映射技术(如果构建后代码出错,通过映射关系能够追溯到源代码错误)
只需要在webpack.config.js中添加如下:
devtool:"eval-source-map"
参数:[ inline -|hidden-| eval- ] [ nosources- ] [cheap- [module-]] source-map
source-map:默认外部,能够准确提示文件报错的具体位置和准确信息
inline-source-map:内联。只生成一个内联的source-map,能够准确提示文件报错的具体位置和准确信息。但是体积较大
hidden-source-map:外部,提示错误代码信息,不能追踪到源代码错误位置,只能提示到构建后代码错误位置。
eval-source-map:内联,每个文件都会生成对应的source-map ,都在eval(),能够准确提示文件报错的具体位置和准确信息,不过多了源代码文件名加了hash值。
nosources-source-map:外部,能够找到错误信息,但是没有任何源代码错误位置信息。
cheap-source-map:外部,能够准确提示文件报错的具体位置和准确信息,只能精确到代码行。
cheap-module-source-map:外部,能够准确提示文件报错的具体位置和准确信息,只能精确到代码行。但是module会将loader的 source-map 加入进来
内联和外部的区别:外部生成了文件,而内联没有,内联构建速度更快。
使用方法: 开发环境:速度快优先,便于调试( eval > inline > cheap > 其他),因此 eval-source-map最优
生产环境:源代码要不要隐藏,调试要不要友好,nosources-source-map 或者 hidden-source-map
2、生产环境性能优化
(1)优化打包构建速度
(2)优化代码调试性能
a、oneOf:在loader中配置了很多个用于处理不同的文件,但是针对不同文件不能全部使用多个loader,只能使用其中一个或者几个,每次使用不需要都对loader检查一遍,因此可以对loader中代码进行改造。由于对js文件即使用了eslint-loader 又使用了babel-loader,所有把eslint-loader 提取到外部即可。如下:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules
enforce: "pre", // 优先执行,先检查eslint 再执行babel-loader
loader: "eslint-loader",
options: {
fix: true, // 自动修复eslint错误
},
},
{
oneOf: [
{
test: /\.css$/,
use: [
// "style-loader", // 创建style标签将样式放入
//这个loader取代style-loader ,作用是将提取js中的css成单独的文件
MiniCssExtractPlugin.loader,
"css-loader", // 将css文件整个到js中
/* CSS兼容性处理:postcss ==>postcss-loader postcss-preset-env
帮助postcss扎到packae.json 中browserslist里的配置,通过配置加载指定的css兼容样式
"browserlist":{
// 开发环境==》设置node环境变量:process.env.NODE_ENV="development"
"development":[
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
// 生产环境 默认是生产环境
"production":[
">0.2%",
"not dead",
"not op_mini all"
]
}*/
// 使用loader的默认配置
// post-loader
// 修改loader配置
{
loader: "postcss-loader",
// options:{
// ident:"postcss",
// plugins:()=>{
// require("postcss-preset-env")
// }
// }
},
],
}, {
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/, // 排除node_modules
options: {
// 预设:指示babel做哪些兼容性处理
presets: [
// "@babel/presets-env",
{
useBuiltins: "usage", // 按需加载
corejs: {
version: 3, // 指定corejs版本
},
targets: {
// 指定兼容到哪些浏览器
chorme: "60",
firefox: "60",
ie: "9",
safiri: "10",
edge: "17",
},
},
],
},
},
// 这种方式无法处理html文件中的图片
{
test: /\.(jpg|png|gif)$/,
loader: "url-loader",
options: {
// 图片大小小于8kb,会被解析为base64处理,优点减少请求数量减轻服务器压力,缺点是图片体积更大,文件请求速度更慢
limit: 8 * 1024,
esModule: false,
// 这样可以修改图片名称,[hash:10]表示取hash值的前十位,[ext]表示原文件扩展名
name: "img/[hash:8].[name].[ext]",
},
},
{
// 因为url-loader默认适用了es6模块解析,而html-loader 引入图片适用commonJS处理,解析时会出现[object Module],需要关闭url-loader的es6模块化解析
test: /\.html$/,
// 处理html 文件的img文件
loader: "html-loader",
},
{
// 打包其他资源(除了css,js,html,less,json资源以外的资源)
exclude: /\.(css|js|html|less|json)$/,
loader: "file-loader",
},
],
},
],
},
b、缓存优化
<1>babel缓存优化
babel缓存指在通过babel实现 js 兼容性处理的时候,默认我们每次会对所有的js代码进行babel处理,而实际构建过程中,我们并不hi修改全部js的代码,因此只需要对我们修改的js代码进行babel兼容性处理即可,没有修改的可以使用缓存的处理就行。
只需要在babel的配置中添加配置,如下即可:
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/, // 排除node_modules
options: {
//... 其他处理
// 开启babel缓存,第二次构建时,会读取之前的缓存
cacheDirectory: true,
},
},
<2>打文件资源的优化
给生成的文件添加hash值(webpack每次打包生成的唯一值),每次通过对比hash值的变化来确定是否使用缓存的文件。但是问题是:因为js和css同时使用一个hash值,重新打包,会导致所有缓存失效,无法满足缓存使用。
给生成的文件添加 chunkhash :根据生成的hash值,如果打包来源于同一个chunk,那么hash值就一样。但是问题是:因为css是在js中引入的,所有同属于一个chunk。
给生成的文件添加contenthash :根据文件的内容生成的hash值,不同文件hash值一定不一样。只需要在filename中添加如下代码:
output: {
// 输出文件名
filename: "js/build.[contenthash:10]js",
// 输出路径
// __dirname 是node.js的变量,代表当前文件的目录的绝对路径
path: resolve(__dirname, "build"), // 代表输出到当前目录下创建的build文件夹下
},
c、tree shaking:去除无用代码(js和css)
前提:1、使用es6 模块化 2、开启production环境
作用:减少打包代码体积
需要在package.json 中配置如下:这样可以把一些没有使用的副作用文件保存在构建包中,比如没有css,less文件
"sideEffects":[
"*.css",
"*.less"
]
d、code split代码分割
在分割之前,js文件是打包成为一个文件,然后在html中引入,无法实现我们的按需加载,对性能影响很大。
(1)设置多入口,只要有一个入口,最终就会输出一个bundle ,通过拆分入口实现生成多个bundle
entry:{
main:"./src/js/index.js",
test:"./src/js/index.js"
},
(2)在webpack.config.js中添加如下配置,对项目依赖单独打包
// 可以将node_modules中代码单独打包一个chunk输出
// 自动分析多个入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk
optimization:{
splitChunks:{
chunks:"all"
}
},
不使用如上配置,当我们的代码中A.js 和 B.js 两个文件同时引入了 jquery 依赖的时候,都会生成对应的AB打包的文件,这两个文件中就会重复存在jquery的打包文件,这时就需要单独分离出依赖文件,单独进行打包即可。
(3)如果不想设置多个入口文件,可以通过js代码将某个文件单打包成一个chunk
import (/*webpackChunkName:"test"*/"./test.js")
.then((res)=>{
// 文件加载成功
console.log(res);
})
.catch(()=>{
console.log("文件加载失败");
})
通过上面的 import动态导入语法, test.js 文件就会被单独打包
e、懒加载和预加载
懒加载是使用上面提到的import动态导入语法,将代码放在一个异步的函数中,如下:
document.getElementById("btn").onclick = function () {
import(/*webpackChunkName:"test"*/ "./test.js")
.then((res) => {
// 文件加载成功
console.log(res);
})
.catch(() => {
console.log("文件加载失败");
});
};
在index.js 文件中,点击btn按钮,进行test.js 文件 的懒加载,再次点击的时候,不会重复加载test文件,此时会利用缓存里的test文件即可。
预加载prefetch,会在使用之前提前加载js文件,在使用的时候直接在缓存里面取,代码如下:
document.getElementById("btn").onclick = function () {
import(/*webpackChunkName:"test",webpackPrefetch:true*/ "./test.js")
.then((res) => {
// 文件加载成功
console.log(res);
})
.catch(() => {
console.log("文件加载失败");
});
};
正常加载可以认为是并行加载,同一时间加载多个文件,预加载prefetch是等其他资源加载完毕,浏览器空闲的时候取加载其他资源。极大提高性能和用户体验。但是预加载兼容性较差,谨慎使用。
f、PWA (Progressive Web App),即渐进式WEB应用。
可以添加至主屏幕,点击主屏幕图标可以实现启动动画以及隐藏地址栏
实现离线缓存功能,即使用户手机没有网络,依然可以使用一些离线功能
实现了消息推送
使用workbox技术 ===》workbox-webpack-plugin配置插件
首先下载workbox-webpack-plugin库
npm i workbox-webpack-plugin -D
在plugins中添加配置
new WorkboxWebpackPlugin.GenerateSW({
/**
* 1.帮助serviceworker快速启动
* 2.删除旧的serviceworker
*
* 生成一个serviceworker配置文件~
*/
clientsClaim:true,
skipWaiting:true
})
在入口文件或者html文件中可以添加如下代码注册serviceworker
// 注册serviceworker
// 处理兼容性问题
/**
* 1、eslint不能识别window.navigator这些变量,需要加package.json中的eslintConfig中配置
* "eslintConfig": {
"extends": "airbnb-base",
"env":{
"browser": true
}
},
2、 serviceworker 代码必须运行在服务器上
==》通过node.js部署
==》npm i serve -g 安装serve,然后serve -s build启动服务器,将build目录下所有资源作为静态资源暴露出去
*/
if("serviceWorker" in navigator){
window.addEventListener("load",()=>{
navigator.serviceWorker.register("/service-worker.js")// 该js文件由插件生成
.then(()=>{
console.log("注册成功");
})
.catch(()=>{
console.log("注册失败");
})
})
}
g、thread-loader多进程打包
安装loader:
npm i thread-loader -D
经常给babel-loader使用:
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules
use: [
{
// 开启多进程打包 进程开启大概600ms,进程通信也要花时间开销
loader:"thread-loader",
options:{
workers:2,// 两个进程打包
}
},
{
loader: "babel-loader",
options: {
// 预设:指示babel做哪些兼容性处理
presets: [
// "@babel/presets-env",
{
useBuiltins: "usage", // 按需加载
corejs: {
version: 3, // 指定corejs版本
},
targets: {
// 指定兼容到哪些浏览器
chorme: "60",
firefox: "60",
ie: "9",
safiri: "10",
edge: "17",
},
},
],
// 开启babel缓存,第二次构建时,会读取之前的缓存
cacheDirectory: true,
},
},
],
},
h、externals
在webpack.cinfig.js 添加入下中配置
externals:{
// 拒绝jQuery 被打包进来
jquery:"jQuery"
}
这样jQuery这个包就不会用过npm的方式被打包到项目中,可以通过cdn的方式引入,比如在index.html 文件中插入jQuery 的script标签。通过cdn的引入,提升性能
i、dll 对代码库进行单独打包
创建单独的js文件,比如webpack.dll.js
/**
* 使用dll技术,对某些(第三方库:jquery、react、vue...)进行单独打包,同时生成一个manifest.json文件,提供了之间的映射关系
* 当运行webpack指令 默认运行的是webpack.config.js配置文件,需要通过webpack --config webpack.dll.js 指令运行webpack.dll.js配置文件
*/
const { resolve } = require("path");
const webpack = require("webpakck"); module.exports = {
entry: {
// 最终打包生成的[name] ==>jquery
jquery: ["jquery"],
},
output: {
filename: "[name].js",
path: resolve(__dirname, "dll"),
library: "[name]_[hash]", // 打包的库里面向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个manifest.json 文件(该文件提供映射关系)
new webpack.DllPlugin({
name: "[name]_[hash]", // 映射库的暴露的内容名称
path: resolve(__dirname, "dll/manifest.json"), // 输出文件路径
}),
],
mode: "production",
};
通过上面的指令,会将jquery单独进行打包。
然后在webpack.config.js 中引入新的插件,告诉webpack不去打包哪些依赖(忽略jquery依赖)
plugins: [
// 告诉webpack那些库不参与打包,同时使用时的名称也得改变
new webpack.DllPlugin({
manifest:resolve(__dirname,"dll/mainfest.json")
}),
],
然后执行下面命令下载add-asset-html-webpack-plugin
npm i add-asset-html-webpack-plugin -D
继续如下配置(再将之前dll.js 文件打包的jquery引入进来):
plugins: [
// 将某个文件打包输出,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,"dll/jquery.js")
})
],
通过上面的配置优化了jquery重复打包的过程提高了性能。
写在最后
以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长之路会持续更新一些工作中常见的问题和技术点。
webpack--性能优化之打包构建速度和代码调试优化的更多相关文章
- vscode调试webpack的启动和打包部署过程,nodejs调试
launch.json ``` { // 使用 IntelliSense 了解相关属性. // 悬停以查看现有属性的描述. // 欲了解更多信息,请访问: https://go.micr ...
- Android 项目优化(一):项目代码规范优化
项目代码规范为主要包含:类,常量,变量,ID等命名规范:注释规范:分包规范:代码风格规范. 项目代码规范是软件开发过程中非常重要的优化环节. 目前的开发社区提供了很多的开发规范文档,阿里巴巴推出了&l ...
- webpack 性能优化小结
背景 如今前端工程化的概念早已经深入人心,选择一款合适的编译和资源管理工具已经成为了所有前端工程中的标配,而在诸多的构建工具中,webpack以其丰富的功能和灵活的配置而深受业内吹捧,逐步取代了gru ...
- [译] 优化 WEBPACK 以更快地构建 REACT
原文地址:OPTIMIZING WEBPACK FOR FASTER REACT BUILDS 原文作者:Jonathan Rowny 译文出自:掘金翻译计划 本文永久链接:https://githu ...
- Webpack5构建速度提升令人惊叹,早升级早受益
为什么要升级? webpack4用的好好的,运行稳定,为什么要升级到webpack5, 每次升级,都要经历一场地震,处理许多loader和plugin API的破坏性改变. 请给我们一个充分的升级理由 ...
- 嵌入式程序设计中C/C++代码的优化
虽然使软件正确是一个工程合乎逻辑的最后一个步骤,但是在嵌入式的系统开发中,情况并不总是这样的.出于对低价产品的需求,硬件的设计者需要提供刚好足够的存储器和完成工作的处理能力.所以在嵌入式软件设计的最后 ...
- 嵌入式实时程序设计中C/C++代码的优化
1 引言 计算机技术和信息技术的高速发展的今天,计算机和计算机技术大量应用在人们的日常生活中,嵌入式计算机也得到了广泛的应用.嵌入式计算机是指完成一种或多种特定功能的计算机系统,是软硬件的紧密结合体. ...
- 优化 Webpack 的构建速度
1.使用高版本的 Webpack 和 Node.js 2.多进程/多实例构建:HappyPack(不维护了).thread-loader 3.压缩代码 webpack-paralle-uglify-p ...
- webpack 性能优化 dll 分包
webpack 性能优化 dll 分包 html-webpack-externals-plugin DLLPlugin https://www.webpackjs.com/configuration/ ...
随机推荐
- ApacheCN 人工智能知识树 v1.0
贡献者:飞龙 版本:v1.0 最近总是有人问我,把 ApacheCN 这些资料看完一遍要用多长时间,如果你一本书一本书看的话,的确要用很长时间.但我觉得这是非常麻烦的,因为每本书的内容大部分是重复的, ...
- Openfeign与Ribbon
Ribbon和OpenFeign我个人为其实算是两个东西,Ribbon侧重于做服务调用时的负载均衡,而OpenFeign侧重于面向接口进行服务调用. 在只引入Ribbon依赖的时候,可以使用restT ...
- Token+Redis实现接口幂等性
一.什么是 幂等性 在编程中,幂等性的特点就是其任意多次执行的效果和一次执行的效果所产生的影响是一样的. 二.Token+Redis的实现思路 1.数据提交前要向服务的申请 token(用户登录时可以 ...
- 关于setInterval方法中function的定义方法
使用window对象的setInterval方法,作为第一个参数传递的function必须在全局作用域中定义,否则会出现报错而无法执行. 具体如下: 在下面的代码中,试用jQuery方式在回调函数中使 ...
- push自定义动画
// // ViewController.m // ViewControllerAnimation // // Created by mac on 15/5/26. // Copyright ...
- PlatformIO 创建 libopencm3 + FreeRTOS 项目
PlatformIO: libopencm3 + FreeRTOS 以下步骤基于常见的 Bluepill STM32F103C8T6, 也适用于其它 libopencm3 支持的MCU型号 方案一: ...
- 继承及属性查找+super()和mro()+多态
继承及属性查找+super()和mro()+多态 一. ★继承 1. 什么是继承? 继承就是新建类的一种方式,新建的类我们称为子类或者叫派生类,被继承的类我们称为父类或者基类 子类可以使用父类中的属性 ...
- 6U VPX i7 刀片计算机
一.产品概述 该产品是一款基于第三代Intel i7双核四线程(或四核八线程)的高性能6U VPX刀片式计算机.产品提供了可支持全网状交换的高速数据通道,其中P1,P2各支持4个PCIe x4 Gen ...
- 以Docker容器的形式运行GVM-11
OpenVAS(Open Vulnerability Assessment System)是在nessus基础上发展起来的一个开源的漏洞扫描程序,其核心部件是一套漏洞测试程序,可以检测远程系统和应用程 ...
- kali linux 中python2不带pip的解决方法
在使用kali2020版本时,发现pip只能安装python3的模块,没办法安装python2模块,但是我有需要用到python2来运行脚本,在此贴出解决办法 https://bootstrap.py ...