webpack的配置与优化

webpack 启动命令配置

在package.json中配置启动命令 除了 npm start 外 运行dev和build都需要加 run 例:npm run build

 "scripts": {"start": "npm run dev",  //启动开发模式 简化命令"dev": "npx webpack serve --config ./config/webpack.dev.js",  //启动开发模式 "build": "npx webpack --config ./config/webpack.prod.js"   // 启动生产模式}

webpack.config.js文件拆分

webpack.config.js 根据生产环境不同拆分成了webpack.dev.js和webpack.prod.js 统一放在了config目录下。因为两各环境中,webpack工作的侧重点不同所以需要分开配置。

生产环境

生产模式是开发完成代码后,我们需要得到代码将来部署上线。这个模式下我们主要对代码进行优化,让其运行性能更好。优化主要从两个角度出发:

  1. 优化代码运行性能
  2. 优化代码打包速度

browserlist 浏览器兼容性设置

在package.json 中可以通过设置 browserlist:[]来控制css样式浏览器的兼容程度

 "browserslist": ["last 2 version", "> 1%", "not dead"]

表示所有浏览器只兼容 最近的两个版本,兼容市面上99%的浏览器,只兼容没有死掉的浏览器

OneOf

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

Exlude Include

可以用在loader、plugins中,目的是在使用这些loader或plugin时指定文件范围。比如一般node_modules中的文件我们不需要用babel-loader作处理,那么就可以用exlude排除

    {test: /\.js$/,exclude: /node_modules/, //排除node_modules中的文件不转译loader: 'babel-loader',}

Cache 缓存优化

每次打包js文件都要经过Eslint和Babel编译,速度比较慢,因此我们可以缓存之前的编译结果,提高下次打包速度。

  new ESlintWebpackPlugin({//指定检查文件的根目录context: path.resolve(__dirname, '../src'),//  include: path.resolve(__dirname, '../src')exclude: "node_modules",cache:true, //开启缓存//指定缓存文件路径cacheLocation:path.resolve(__dirname,'../node_modules/.cache/eslintcache')}),//babel-loader 配置{test: /\.js$/,exclude: /node_modules/, //排除node_modules中的文件不转译loader: 'babel-loader',options:{cacheDirectory:true,  //开启缓存cacheCompression:false //关闭缓存文件压缩}}    

Thread 多线程打包

当项目越来越庞大时,打包速度越来越慢,因此我们可以通过开启多线程打包来提升打包速度。webpack打包主要针对js文件,包括eslint、babel、terser(webpack内置插件,用于js压缩),因此我们主要对这三个工具开启多线程打包。

//安装线程包
npm i thread-load -d
//引入相关文件
const os = require('os')
const TerserPlugin = require('terser-webpack-plugin')
//创建threads线程
const threads = os.cpus().length

配置

//babel配置
{test: /\.js$/,exclude: /node_modules/, //排除node_modules中的文件不转译use: [{loader: 'thread-loader', //开启多线程options: {workers: threads}},{loader: 'babel-loader',options: {cacheDirectory: true,  //开启缓存cacheCompression: false //关闭缓存文件压缩}},]
}
//terser-plugin 配置optimization:{minimize:true,minimizer:[// css压缩也可以写到optimization.minimizer里面,效果一样的new CssMinmizerPlugin(),// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了new TerserPlugin({parallel:threads //terser开启多线程})]},
//eslint 配置new ESlintWebpackPlugin({//指定检查文件的根目录context: path.resolve(__dirname, 'src'),//include: path.resolve(__dirname, 'src')exclude: "node_modules",cache:true, //开启缓存//指定缓存文件路径cacheLocation:path.resolve(__dirname,'../node_modules/.cache/eslintcache'),threads  //开启多线程}),

Tree Shaking

webpack 5的生产模式默认启动,它的作用是忽略文件中那些没有引用到的代码,从而减小代码体积、提高打包速度

@babel/plugin-transform-runtime

需要先下载,然后再bable-loader中进行配置。他的作用是禁用babel对每个文件的runtime注入,而是统一从 一个文件中获取,从而减少代码体积

  {loader: 'babel-loader',options: {cacheDirectory: true,  //开启缓存cacheCompression: false, //关闭缓存文件压缩plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积}},

图片压缩 ImageMinizer

如果项目中图片很多会增加体积,因此需要压缩图片。如果图片是在线链接不用压缩。

下载包

npm i image-minimizer-webpack-plugin imagemin -D

还有剩下的包需要下载,有两种模式

  1. 无损模式
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D
  1. 有损模式
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D

提示:如果包下载不了,可以切换cnpm下载。

配置

    optimization:{minimize:true,minimizer:[  new ImageMinimizerPlugin({minimizer: {implementation: ImageMinimizerPlugin.imanpgeminGenerate,options: {plugins: [["gifsicle", { interlaced: true }],["jpegtran", { progressive: true }],["optipng", { optimizationLevel: 5 }],["svgo",{plugins: ["preset-default","prefixIds",{name: "sortAttrs",params: {xmlnsOrder: "alphabetical",},},],},],],},},}),]},

Code Split 代码分割

打包代码时js文件会打包到一个文件中导致文件体积太大加载速度缓慢,code splite就是把打包后的文件拆分,如此以来就可以根据页面需求按需加载,比如如果只要渲染首页,那么就只加载首页的相关代码。
代码分割做了两件事情

  1. 分割文件:将打包生成的文件进行分割,生成多个js文件。
  2. 按需加载:需要哪个文件就加载哪个文件。

多入口提取公共模块

如果我们设置多个入口文件并且在这些文件中分别引入了相同的模块,那么在打包之后重复的模块会被引入到各自打包后的bundle中,这样会造成代码冗余。通过配置splitChunks后,可将公用的部分抽取出来单独打包输出,并在输出的文件中引入分别引入它。这样可以避免代码生成重复代码,减小包的体积。

splitChunks: {chunks: "all", // 对所有模块都进行分割// 以下是默认值// minSize: 20000, // 分割代码最小的大小// minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0// minChunks: 1, // 至少被引用的次数,满足条件才会代码分割// maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量// maxInitialRequests: 30, // 入口js文件最大并行请求数量// enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)// cacheGroups: { // 组,哪些模块要打包到一个组//   defaultVendors: { // 组名//     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块//     priority: -10, // 权重(越大越高)//     reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块//   },//   default: { // 其他没有写的配置会使用上面的默认值//     minChunks: 2, // 这里的minChunks权重更大//     priority: -20,//     reuseExistingChunk: true,//   },// },// 修改配置cacheGroups: {// 组,哪些模块要打包到一个组// defaultVendors: { // 组名//   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块//   priority: -10, // 权重(越大越高)//   reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块// },default: {// 其他没有写的配置会使用上面的默认值minSize: 0, // 我们定义的文件体积太小了,所以要改打包的最小文件体积minChunks: 2,priority: -20,reuseExistingChunk: true,},},},

代码按需加载、动态导入

有一些代码页面加载的时候用不到,只有触发特定事件时才会调用,比如按钮绑定的点击事件、路由跳转事件等等,那么我们可以通过ES6的import语法动态导入、按需加载的方式引入代码,这样就会节省页面加载时间。

 document.getElementById('btn').onclick = function (){//import导入的是一个promise对象import('./sum.js').then(({sum})=>{alert(sum(4,6))console.log(sum(4,5))})}
//webpackChunkName:'count'也叫webpack魔法命名, 为打包输出的chunk命名为'count'  需要配合在output中配置 chunkFilename:'xxx/[name].js'  import(/*webpackChunkName: 'count' */'./js/count.js').then(({count})=>{alert(count(5,9))})

为静态资源文件统一命名

  output: {//文件输出路径 需要绝对路径  __dirname :nodejs的变量,代表当前文件夹的文件目录  可以用来动态获取当前文件所属目录的绝对路径path: path.resolve(__dirname, '../dist'),//文件名称filename: 'static/js/[name].js',//给打包的其他文件指定目录和文件名chunkFilename:'static/js/[name].js',//统一图片、字体等资源的命名方式assetModuleFilename:'static/media/[name].[hash][ext]',//每次重新打包自动清空上次的包clean: true},

Preload / Prefetch

当我们使用了按需加载、懒加载后,可能会出现一种情况,用户点击了某个按钮后动态加载的文件体积过大导致页面卡顿,响应延迟等现象,为了避免这种情况发生,我们可以通过preload/prefetch的方式来预加载这些动态文件存入缓存中,等到事件触发时在加载。

  • preload:告诉浏览器立即加载资源
  • prefetch:告诉浏览器空闲时加载资源。
    *** 他们的共同点 ***:
  • 都只会加载资源,并不执行。
  • 都有缓存。
  • 兼容性都不好,preload稍好。

Network Cache

将来开发时我们对静态资源会使用缓存来优化,这样浏览器第二次请求资源就能读取缓存了,速度很快。但是这样的话就会有一个问题, 因为前后输出的文件名是一样的,都叫 main.js,一旦将来发布新版本,因为文件名没有变化导致浏览器会直接读取缓存,不会加载新资源,项目也就没法更新了。所以我们从文件名入手,确保更新前后文件名不一样,这样就可以做缓存了。

fullhash(webpack4 是 hash)

每次修改任何一个文件,所有文件名的 hash 至都将改变。所以一旦修改了任何一个文件,整个项目的文件缓存都将失效。

chunkhash

根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。我们 js 和 css 是同一个引入,会共享一个 hash 值。

contenthash

根据文件内容生成 hash 值,只有文件内容变化了,hash 值才会变化。所有文件 hash 值是独享且不同的。

output: {path: path.resolve(__dirname, "../dist"), // 生产模式需要输出// [contenthash:8]使用contenthash,取8位长度filename: "static/js/[name].[contenthash:8].js", // 入口文件打包输出资源命名方式chunkFilename: "static/js/[name].[contenthash:8].chunk.js", // 动态导入输出资源命名方式assetModuleFilename: "static/media/[name].[hash][ext]", // 图片、字体等资源命名方式(注意用hash)clean: true,},

问题:

当我们修改 math.js 文件再重新打包的时候,因为 contenthash 原因,math.js 文件 hash 值发生了变化(这是正常的)。

但是 main.js 文件的 hash 值也发生了变化,这会导致 main.js 的缓存失效。明明我们只修改 math.js, 为什么 main.js 也会变身变化呢?

原因:

更新前:math.xxx.js, main.js 引用的 math.xxx.js
更新后:math.yyy.js, main.js 引用的 math.yyy.js, 文件名发生了变化,间接导致 main.js 也发生了变化

解决:

将 hash 值单独保管在一个 runtime 文件中。我们最终输出三个文件:main、math、runtime。当 math 文件发送变化,变化的是 math 和 runtime 文件,main 不变。runtime 文件只保存文件的 hash 值和它们与文件关系,整个文件体积就比较小,所以变化重新请求的代价也小。

 runtimeChunk: {name: (entrypoint) => `runtime~${entrypoint.name}`, // runtime文件命名规则},

Core.js js高级语法浏览器兼容性问题

babel-loader可以帮我处理一些js兼容性问题,他能把ES语法转换为Js语法,比如箭头函数,解构赋值等,但是如果是promise、asyc、数组的高级用法,它没办法处理,所以要彻底解决js的兼容性问题就需要用到Core.js。core-js 是专门用来做 ES6 以及以上 API 的 polyfill。polyfill翻译过来叫做垫片/补丁。就是用社区上提供的一段代码,让我们在不兼容某些新特性的浏览器上,使用该新特性。

  • 使用Core.js
    下载包
npm i core.js

手动全部引入

import "core-js";

全部引入会导致包的体积太大,所以可以采用按需引入

自动按需引入

在babel.config.js中加入如下代码

module.exports = {// 智能预设:能够编译ES6语法presets: [["@babel/preset-env",// 按需加载core-js的polyfill{ useBuiltIns: "usage", corejs: { version: "3", proposals: true } },],],
};

PWA

渐进式网络应用程序(prograssive web application)是一种可以提供类似于 native app(原生应用程序) 体验的 Web App 的技术。其中最重要的是,在 离线(offline) 时应用程序能够继续运行功能。内部通过 Service Workers 技术实现的。
下载包

npm i workbox-webpack-plugin -D

引入并配置文件

    const WorkboxPlugin = require("workbox-webpack-plugin");plugins:[new WorkboxPlugin.GenerateSW({// 这些选项帮助快速启用 ServiceWorkers// 不允许遗留任何“旧的” ServiceWorkersclientsClaim: true,skipWaiting: true,}),]

在main.js中添加如下代码

if ("serviceWorker" in navigator) {window.addEventListener("load", () => {navigator.serviceWorker.register("/service-worker.js").then((registration) => {console.log("SW registered: ", registration);}).catch((registrationError) => {console.log("SW registration failed: ", registrationError);});});}

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

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

相关文章

力扣刷题-二叉树-二叉树左叶子之和

404 左叶子之和 给定二叉树的根节点 root ,返回所有左叶子之和。 示例 1: 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24 思路 迭代法 迭代法理解…

【谭浩强C语言:前八章编程题(多解)】

文章目录 第一章1. 求两个整数之和(p7) 第二章2. 求三个数中的较大值&#xff08;用函数&#xff09;(p14、p107)3.求123...n(求n的阶乘&#xff0c;用for循环与while循环)(P17)1.循环求n的阶乘2.递归求n的阶乘(n< 10) 4.有M个学生&#xff0c;输出成绩在80分以上的学生的学…

C++11——可变参数模板

可变参数模板可以接收不定数量的参数&#xff0c;比如printf函数就是这样&#xff0c;可以传任意数量的参数 template<class ...Args> void test(Args... args) {//... } Args是一个函数模板参数包&#xff0c;args函数形参参数包 如何获取参数包的值 1.递归获取 void…

【算法】【动规】摆动序列

跳转汇总链接 &#x1f449;&#x1f517;动态规划算法汇总链接 2.2 摆动序列 &#x1f517;题目链接 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。仅有一个元素或…

Qt容器QStackedWidget小部件堆栈

# QStackedWidget QStackedWidget是Qt框架中的一个控件,用于在同一区域显示多个子控件,只有一个子控件可见。以下是一些常用的QStackedWidget函数: addWidget(QWidget *widget):向QStackedWidget中添加一个子控件。 insertWidget(int index, QWidget *widget):在指定位置…

外包干了3个月,技术退步明显。。。

先说一下自己的情况&#xff0c;本科生生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测…

LangChain学习三:链-实战

文章目录 上一节内容&#xff1a;LangChain学习二&#xff1a;提示-实战&#xff08;下半部分&#xff09;学习目标&#xff1a;明白链是什么&#xff1f;有哪些&#xff1f;怎么用&#xff1f;学习内容一&#xff1a;介绍学习内容二&#xff1a;有那些学习内容三&#xff1a;实…

C++初阶-queue的使用与模拟实现

queue的使用与模拟实现 一、queue的介绍和使用二、queue的使用三、queue的模拟实现3.1 成员变量3.2 成员函数3.2.1 push入队列3.2.2 pop出队列3.2.3 返回队头数据3.2.4 返回队尾数据3.2.5 返回队列的大小3.2.6 判断队列是否为空 四、完整代码4.1 queue.h4.2 test.h 五、deque的…

Linux:TCP 序列号简介

文章目录 1. 前言2. 什么是 TCP 序列号&#xff1f;3. TCP 序号 的 初始值设置 和 后续变化过程3.1 三次握手 连接建立 期间 客户端 和 服务端 序号 的 变化过程3.1.1 客户端 socket 初始序号 的 建立3.1.2 服务端 socket 初始序号 的 建立3.1.3 客户端 socket 接收 服务端 SAC…

vue使用el-tag完成添加标签操作

需求&#xff1a;做一个添加标签的功能&#xff0c;点击添加后输入内容后回车可以添加&#xff0c;并且标签可以删除 1.效果 2.主要代码讲解 鼠标按下后触发handleLabel函数&#xff0c;根据回车的keycode判断用户是不是按下的回车键&#xff0c;回车键键值为13&#xff0c;用…

【一种用opencv实现高斯曲线拟合的方法】

背景&#xff1a; 项目中需要实现数据的高斯拟合&#xff0c;进而提取数据中标准差&#xff0c;手头只有opencv库&#xff0c;经过资料查找验证&#xff0c;总结该方法。 基础知识&#xff1a; 1、opencv中solve可以实现对矩阵参数的求解&#xff1b; 2、线的拟合就是对多项…

leetcode:457. 环形数组是否存在循环

环形数组是否存在循环 存在一个不含 0 的 环形 数组 nums &#xff0c;每个 nums[i] 都表示位于下标 i 的角色应该向前或向后移动的下标个数&#xff1a; 如果 nums[i] 是正数&#xff0c;向前&#xff08;下标递增方向&#xff09;移动 |nums[i]| 步 如果 nums[i] 是负数&…

【23-24 秋学期】NNDL 作业11 LSTM

目录 习题6-4 推导LSTM网络中参数的梯度&#xff0c; 并分析其避免梯度消失的效果 习题6-3P 编程实现下图LSTM运行过程 &#xff08;一&#xff09;numpy实现 &#xff08;二&#xff09;使用nn.LSTMCell实现 &#xff08;三&#xff09; 使用nn.LSTM实现 总结 &#x…

dysmsapi

dysmsapi DY - SMS - API 短信服务接口 短信服务_SDK中心-阿里云OpenAPI开发者门户 <!-- 阿里dayu sms api短信群发接口 --><!-- https://mvnrepository.com/artifact/com.aliyun/dysmsapi20170525/2.0.24 --><dependency><groupId>com.aliyun&l…

Python学习笔记第七十四天(OpenCV安装)

Python学习笔记第七十四天 OpenCV安装安装Python安装OpenCV简单使用OpenCV 后记 OpenCV安装 在Windows系统下&#xff0c;安装Python和OpenCV可以按照以下步骤进行&#xff1a; 安装Python 下载Python&#xff1a;在Python官网下载最新的Python安装包&#xff0c;建议选择与…

JS匿名函数之函数表达式与立即执行函数

匿名函数是什么&#xff1f;和具名函数有什么区别&#xff1f;让我为大家介绍一下吧&#xff01; 没有名字的函数&#xff0c;无法直接使用 一.函数表达式 将匿名函数赋值给一个变量&#xff0c;并且通过变量名去调用&#xff0c;我们将这个称为函数表达式 语法&#xff1a; …

Java EE 网络之网络初识

文章目录 1. 网络发展史1.1 独立模式1.2 网络互连1.3 局域网 LAN1.4 广域网 WAN 2. 网络通信基础2.1 IP 地址2.2 端口号2.3 认识协议2.4 五元组2.5 协议分层2.5.1 什么是协议分层2.5.2 分层的作用2.5.3 OSI七层协议2.5.4 TCP/IP五层协议2.5.5 网络设备所在分层 2.6 分装和分用 …

Leetcode的AC指南 —— 链表:24. 两两交换链表中的节点

摘要&#xff1a; Leetcode的AC指南 —— 链表&#xff1a;24. 两两交换链表中的节点。题目介绍&#xff1a;给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能…

【OpenHarmony 北向应用开发】ArkTS语言入门(构建应用页面)

ArkTS语言入门 在学习ArkTS语言之前&#xff0c;我们首先需要一个能够编译并运行该语言的工具 DevEco Studio。 了解ArkTS ArkTS是OpenHarmony优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript&#xff08;简称TS&#xff09;生态基础上做了进一步扩展&#xff0c;继…

有两个循环单链表,链表头指针分别为 h1 和 h2,编写一个函数将 h2 链接到 链表h1 之后,要求处理完仍是一个循环单链表。

题目描述 &#xff1a;有两个循环单链表&#xff0c;链表头指针分别为 h1 和 h2&#xff0c;编写一个函数将 h2 链接到 链表h1 之后&#xff0c;要求处理完仍是一个循环单链表。 分析&#xff1a; 注意题目说的是头指针 h1 和 h2&#xff0c;所以这两个循环单链表并没有头结点…