webpack高级配置

news2025/7/21 4:31:51

摇树(tree shaking)

我主要是想说摇树失败的原因(tree shaking 失败的原因),先讲下摇树本身效果

什么是摇树?

举个例子

首先 webpack.config.js配置

const webpack = require("webpack");

/**
 * @type {webpack.Configuration}
 */
module.exports = {
  mode: "production"
};

在固定 a.js 用esm导出,b.js用commonjs导出不变动

// a.js
export function f1() {
  console.log("11111");
}
export function f2() {
  console.log("22222");
}

// b.js
exports.f3 = function () {
  console.log("33333");
};
exports.f4 = function () {
  console.log("44444");
};

例子1:import a.js 和 require b.js

// index.js
import { f1 } from "./a";
import { f3 } from "./b";
console.log(f1);
console.log(f3);

打包结果:a.j 和 b.js 都摇树了,只输出了 f1 和 f3。所以导入用import,导出esm和commonjs都可以

image.png

参考webpack视频讲解:进入学习

例子2:import a.js 和 import b.js

// index.js
import { f1 } from "./a";
const { f3 } = require("./b");
console.log(f1);
console.log(f3);

打包结果:a.js 摇,b.js 没摇,输出了 f1 、f3、f4。所以导入用require不成功

image.png

结论:

摇树只能import,导出用esm和commonjs都可以

因为摇树发生在编译阶段,只支持esm的import,不支持commonjs的require,因为esm是编译时,commonjs是运行时

摇树失败的原因

三方面可能导致失败:

1、代码没用import引入

2、webpack配置没开启摇树

3、副作用(sideEffects)

4、babel配置preset-env没写 module:false 参数

代码没用import引入

这一点上面已经说明,必须用 import 导入,导出用 esm 或者 commonjs 都行

webpack配置没开启摇树

开启摇树两步:

1、usedExports设置true,标记无用代码,esm导出的没使用到的导出函数标记为unused harmony export f2,commonjs导出的没使用的导出函数赋值为__webpack_unused_export__

2、terser-webpack-plugin插件做代码压缩去除无用代码,根据一步两种标记,压缩代码会去除

const webpack = require("webpack");

/**
 * @type {webpack.Configuration}
 */
module.exports = {
  mode: "none",
  optimization:{
    usedExports:true
  }
};
  • mode: production模式下,默认开启摇树,不用做任何配置,由源码看出nonedevelopment不会开启摇树,需要手动加这两步,注意要设置minimize:true,或者放到plugins中

看webpack源码默认配置,

image.png

副作用(sideEffects)

先来解释下什么是副作用:修改当前作用域之外的行为都叫副作用,比如在函数内部,修改dom,修改全局对象等等

这条主要是针对引入三方包,三方包package.json的sideEffects字段默认true表示有副作用,可以设置为false表示没有副作用,设置为数组列出有副作用的文件

webpack.config.js设置sideEffects:true表示检查三方包的sideEffects字段,webpack在用userExports标记无用代码时,如果判断不出库中代码是否有副作用,就不会标记,则压缩的时候也没法清除,如果判断有副作用,则更不会标记清除

  • mode: production模式下,默认开启摇树,不用做任何配置,usedExports: true
const webpack = require("webpack");
const TerserPlugin = require("terser-webpack-plugin");

/**
 * @type {webpack.Configuration}
 */
module.exports = {
  mode: "none",
  optimization:{
    sideEffects:true,
    usedExports:true
  },
  plugins:[    new TerserPlugin()  ]
};

babel配置preset-env没写 module:false 参数

在文章 我掌握的Babel配置 中详细讲解了 module: false 参数,简单说不设置false时,只针对babel相关的runtime包的引入会使用require,设置了false引入会使用import,就能让webpack去摇树,回到第一点上

module.exports = {
  presets: [    [      "@babel/preset-env",      {        modules: false      },    ],
  ]
};

拆包(splitChunks)

splitChunks是webpack配置下optimization下的配置,即优化。看单词理解意思就是拆分多个chunk。

什么是chunk

webpack的本质是把多个js模块合并到一个js中,即一个入口得到一个输出js文件(bundle.js)。

但是导致的问题是,如果这个bundle.js文件很大,那么浏览器请求的时候,导致请求时间很长,首屏长时间白屏。

所以优化手段就是把bundle.js文件拆分成多个小的js文件,同时请求,首屏当然就更快渲染显示。

所以入口文件,chunk文件,输出文件三者的关系从原来的一个入口文件对应一个chunk最后输出一个bundle文件改变为一个入口文件对应多个chunk最后输出多个bundle文件

三种方式获得chunk

  • 1、入口文件可以生成chunk,入口文件即webpack配置的entry选项;

  • 2、异步请求 import函数调用 或者 require.ensure 可以生成chunk;
    如:import函数即我们在写vue-router时写的异步请求路由方式,这里webpackChunkName可以魔法定义chunk名,也可不写

import(/* webpackChunkName: "AboutPage" */'./view/about.vue')
  • 3、webpack配置splitChunks手动拆分生成chunk,最后独立输出到js文件

splitChunks 配置

简单配置,把react相关包都单独提到一个文件

{
   optimization: {
    splitChunks: {
      chunks: "all", // initial、async和all
      cacheGroups: {
        react: {
          name: "react",
          test: /[\\/]react(\w)*[\\/]/i,
          priority: 10
        },
        lodash: {
          name: "lodash",
          test: /[\\/]lodash(\w)*[\\/]/i,
          priority: 20,
          minChunks:3
        },
      },
    },
  },
}

先来看下webpack默认的splitChunks参数

image.png

看图production非production模式下有参数不一样,下面这些参数表示自动拆包的条件:

  • chunks

重要:拆包的范围,默认async,只针对异步请求的,即上面第二条的import函数调用的chunk里面;initial表示只针对初始化入口entry的;all表示最大包含async + entry

  • cacheGroups

重要:自定义拆包规则,name是chunk名,test正则包名,priority优先级(因为同一个包可能符合多个拆包规则,会处理给优先级高的);看图可知,默认会有两个包规则,defaultVendors规则表示node_modules会拆到一个chunk包,default规则表示只有被两个即以上chunk引用就要拆到一个chunk包

  • minChunks

拆分前必须共享模块的最小 chunks 数,可以不用修改

  • maxAsyncRequests

浏览器发送异步请求时,最大不超过30个请求,即上面第二条的import函数调用,可以不用修改

  • maxInitialRequests

浏览器请求入口entry时,最大不超过30个,可以不用修改

热更新

我们主要是说明热更新的 module.hot.accept()

先来了解一下热更新怎么配置的?

热更新配置

装包

npm i -D webpack-dev-server html-webpack-plugin

webpack.config.js

const webpack = require("webpack");
const HtmlWebpackPlugin = require('html-webpack-plugin');

/**
 * @type {webpack.Configuration}
 */
module.exports = {
  mode: "development",
  devServer: {
    port: 3000,
    open: true,
    hot: true,
  },
  plugins: [    new HtmlWebpackPlugin(),  ]
};

package.json

"scripts": {
    "serve": "webpack serve",
},

结论

到此热更新配置完成,正常写代码,但是发现问题了,此时更新页面是整个刷新页面的,并不是局部刷新,怎么回事呢,原来需要在每个文件中最后加上module.hot.accept()才会触发局部更新,accept可以接受两个参数,依赖和回调

exports.f3 = function () {
  console.log("33333");
};
exports.f4 = function () {
  console.log("44444");
};
if (module.hot) {
  module.hot.accept();
}

随即产生了另一个疑问,这太麻烦了吧,每个文件文件都需要去加module.hot.accept(),但是我们在实际写下项目的时候怎么没有写这句呢?

原因是不论css、vue、react的loader都帮我们自动加了这句。

css有style-loader,react有react-hot-loader,vue有vue-loader。

对于jsx文件,有vue-jsx-hot-loader

{
    test:/\.jsx?$/,
    use:['babel-loader','vue-jsx-hot-loader']
}

按需加载

一段时间以来,我一直把tree shaking和按需加载混为一谈,其实应该分开理解,这里我主要是想说第三方包的按需加载,比如使用element-ui、lodash、vant

tree shaking的前提是使用import导入,但是按需加载并不需要

还有一个点需要注意:如果是我们封装的库,如组件库,导出格式根据文件类型不同,如是js文件可以为 commonjs + es5、esm + es5;如是vue或react文件,esm/commonjs + es6/es5 任意都行,因为我们用babel-loader时会排除node_modules目录不编译,vue-loader等会去编译vue文件

使用babel插件

npm install babel-plugin-component -D

babel.config.js

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: "usage",
        corejs: 2,
        modules: false,
      },
    ],
  ],
  plugins: [
    ["@babel/plugin-transform-runtime"],
    [
      "babel-plugin-import",
      {
        libraryName: "vant",
        libraryDirectory: "es",
        style: true,
      },
      "vant",
    ],
    [
      "babel-plugin-import",
      {
        libraryName: "antd",
        style: true, // or 'css'
      },
    ],
    [
      "babel-plugin-import",
      {
        "libraryName": "lodash",
        "libraryDirectory": "",
        "camel2DashComponentName": false,  // default: true
      },
      "lodash",
    ],
    [
      "babel-plugin-component",
      {
        libraryName: "element-ui",
        styleLibraryName: "theme-chalk",
      },
      "element-ui",
    ],
  ],
};

完毕!

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

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

相关文章

Educational Codeforces Round 138 (Rated for Div. 2)

A:思维 题意:给一定的N*N的板子,里面放有一些乌鸦,这些乌鸦会攻击自己的所在行与所在列,问给定一个数量的乌鸦,问是否能够移动某只乌鸦,使得形成和平局面? 方法:我们发现…

股票涨跌量化怎样进行策略分析?

股票涨跌量化其实是通过Python调用Tushare库计算深证成指实时,对股票的成交量涨跌幅,主要是通过相关分析选择合适的成交量涨跌幅来计算的一种量化策略分析方法,也可以根据绘制股票的成交量涨跌幅度与当日股价的涨跌幅描绘出来。如果我们想快速…

目标检测论文解读复现之八:基于YOLOv5s的滑雪人员检测研究

前言 此前出了目标改进算法专栏,但是对于应用于什么场景,需要什么改进方法对应与自己的应用场景有效果,并且多少改进点能发什么水平的文章,为解决大家的困惑,此系列文章旨在给大家解读最新目标检测算法论文&#xff0c…

Unity使用NaveMesh实现第一人称视角移动

系列文章目录 Navemesh寻路系列文章 文章目录 目录 系列文章目录 文章目录 前言 一、NavMeshPath是什么? 二、使用步骤 1.引入库 2.读入数据 总结 前言 navemesh已经大量使用到游戏中,但大部分寻路都是使用SetDestination函数,给予一个目标…

SpringBoot+Vue项目大学校园防疫与服务系统的设计与实现

文末获取源码 开发语言:Java 使用框架:spring boot 前端技术:JavaScript、Vue 、css3 开发工具:IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库:MySQL 5.7/8.0 数据库管理工具:phpstudy/Navicat JDK版…

C++初阶 Vector模拟实现

q. > 作者:小萌新 专栏:C初阶 作者简介:大二学生 希望能和大家一起进步 本篇博客介绍:本篇博客会模拟Vector实现 学习目标 模拟默认函数实现模拟迭代器实现模拟容器大小相关函数模拟修改内容相关函数模拟访问容器相关函数 我…

xss挑战之旅11-19关

文章目录前言第11关:referer第12关:User-Agent第13关:cookie第14关:exif xss第15关:ng-include第16关第17关第18关第19关:flash xss前言 靶场:XSS挑战之旅 1-10关 11-20关 第11关:r…

『LeetCode|每日一题』---->颜色填充

目录 1.每日一句 2.作者简介 『LeetCode|每日一题』颜色填充 1.每日一题 2.解题思路 2.1 思路分析(DFS) 2.2 核心代码 2.3 完整代码 2.4 运行结果 1.每日一句 我的宇宙为你藏着无数个星球 2.作者简介 🏡个人主页:XiaoXiaoChe…

Git之路

文章目录指南介绍实战任务一:sb项目任务二:idea实战任务三:分支实战(待续)指南 如果你想在简历上写“会常用的Git的命令“,那么这篇文章值得你要看,那我们需要掌握什么呢?其实会简单的操作就行&#xff0c…

Matplotlib绘图-快速上手可视化工具

Matplotlib快速上手一、初识Matplotlib1.1 认识Matplotlib的图像结构1.2 绘制一个折线图二、给图像添加修饰2.1 自定义x的刻度2.2一图多线2.3一图绘制多个坐标系子图三、主流图形的绘制3.1绘制柱状图一、初识Matplotlib 是Python最常见的可视化工具之一 1.1 认识Matplotlib的…

csrf跨站请求伪造

文章目录csrf跨站请求伪造1、前戏2、csrf校验2.1、from表单如何符合校验2.2、ajax如何符合校验3、csrf相关装饰器FBVCBVcsrf跨站请求伪造 1、前戏 """ 钓鱼网站搭建一个跟正规网站一摸一样的界面(中国银行)用户进入到我们的网站&#x…

HyperLynx(三十)高速串行总线仿真(二)

高速串行总线仿真(二) 仿真实例 1.探索多层板中的PCI-E串行通道 2.设置叠层以减小损耗 3.分析通道的不同配置对损耗的影响 4.检测驱动端规范 5.检查接收器规范 6.通过仿真得出整个通道的驱动约束限制 1.探索多层板中的PCI-E串行通道 在本节练习中&…

人工智能学习:Microsoft COCO数据集读取(7)

Microsoft COCO(Common Objects in Context)是微软研发维护的一个大型的数据集。包含了30多万张图片和91个目标分类。可用于目标识别(Object Detection)、场景感知(Penoptic Segmentation)、语义分割&#…

【数据结构】——单链表

目录 1.链表 1.1 链表的概念及结构 1.2 链表的分类 1. 单向或者双向 2. 带头或者不带头 3. 循环或者非循环 1.3实现一个单链表(无头单项非循环链表增删查改的实现) 1.链表结构的创建 2.创建一个节点 3.创建一个链表 4.打印链表 5…

解读JVM级别本地缓存Caffeine青出于蓝的要诀 —— 缘何会更强、如何去上手

大家好,又见面了。 在前面的几篇文章中,我们一起聊了下本地缓存的动手实现、本地缓存相关的规范等,也聊了下Google的Guava Cache的相关原理与使用方式。比较心急的小伙伴已经坐不住了,提到本地缓存,怎么能不提一下“地…

软考 - 程序语言设计

程序设计语言基本概述 程序设计语言是为了书写计算机程序而人为设计的符号语言,用于对计算过程进行 描述、组织和推导。 低级语言:机器语言(计算机硬件只能识别0和1的指令序列),汇编语言。 高级语言:功能…

从http请求过程分析为何不同业务的http请求都可以使用默认的缺省端口80,8080等

问题: http上传请求时url地址中一般无显示指定端口号,这时会使用默认的80端口;但是可能不止一个业务需要用到http请求,技术上web服务端那边肯定无法根据业务逻辑的数据格式去分别解析区分它们;因为业务是事先无法预知的&#xff…

【Spring Cloud实战】Consul服务注册与发现

个人博客上有很多干货,欢迎访问:https://javaxiaobear.gitee.io/ 1、简介 https://www.consul.io/docs/intro Consul is a service mesh solution providing a full featured control plane with service discovery, configuration, and segmentation f…

Flink-经典案例WordCount快速上手以及安装部署

2 Flink快速上手 2.1 批处理api 经典案例WordCount public class BatchWordCount {public static void main(String[] args) throws Exception {//1.创建一个执行环境ExecutionEnvironment env ExecutionEnvironment.getExecutionEnvironment();//2.从文件中读取数据//得到…

[附源码]java毕业设计基于Web留学管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…