Webpack中的高级特性

news2024/9/17 8:56:38

自从webpack4以后,官方帮我们集成了很多特性,比如在生产模式下代码压缩自动开启等,这篇文章我们一起来探讨一下webpack给我们提供的高级特性助力开发。

探索webpack的高级特性

特性:treeShaking

顾名思义treeShaking,就是摇树,那么体现在代码模块里面就是摇掉那些没有被外部成员引用的代码,指的注意的是在生产环境下treeShaking会自动开启。

treeShaking初体验

比如我们在代码中引入lodash库,我们只用到了once方法,那关于lodash其他的功能模块,在生产环境下打包,并不会输出到bundle.js文件里面,比如我们在bundle.js里面去找lodash的一个方法debounce,他是完全可以找得到的。

image.png

delelopment模式下打包的bundle.js

在这里插入图片描述

production模式下打包的bundle.js

image.png 在这里你可能会说了production模式下会开启n多插件,处理打包结果,怎么就能说明是treeShaking做的呢,确实这种做法不能说明是treeShaking做的,我们可以把mode设置为none再试一下,不过这里需要我们手动去开启treeShaking,开启的方式如下。

// webpack.config.js
module.exports = {
    ...
    optimization: {
        usedExports: true, // 只导出外部成员引用模块
        // 此属性用于模块导入合并,因为单独的模块导入要使用_webpack_require_函数。
        // 此属性就是可以利用_webpack_require_一次性导入所有模块,也叫作用域提升。
        concatenateModules: true, 
        minimize: true, // 开启代码压缩
    }
    ...
}
none模式下打包的bundle.js

所以none模式下,打包的结果依然如此。

在这里插入图片描述

扩展

因为treeShaking是依赖于ESM的,如果项目中有配合使用babel-loader那么treeShaking是不是会失效呢?我们可以在配置文件里面添加babel-loader来辅以测试。

// 安装
npm i babel-loader @babel/core @babel/preset-env -D
// webpack.config.js
module.exports = {
    ...
    module:[
        {
            test:/\.js$/,
            use:{
                loader:'babel-loader',
                options:{
                    presets:[
                        ['@babel/preset-env']
                    ]
                }
            }
        }
    ]
}
文件效果

我们可以看到没有使用的代码,依然是被移除掉了。

image.png

原因分析

因为babel-loader禁用了对ESM转化插件,所以经过babel-loader处理生成的依旧是ESM代码,如果你想使用代码转换功能,那你就需要像下面这样配置,只不过这样treeShaking就会失效了。

// 安装
npm i babel-loader @babel/core @babel/preset-env -D
// webpack.config.js
module.exports = {
    ...
    module:{
        rules:[
            {
                test:/\.js$/,
                use:{
                    loader:'babel-loader',
                    options:{
                        presets:[
                            // 强制使用commonjs转换
                            ['@babel/preset-env', {modules: 'commonjs'}]
                        ]
                    }
                }
            }
        ]
    }
}

那么treeShaking失效了,应该怎么办?不要怕,即使失效了还会有其他插件提供了类似treeShaking功能,比如代码压缩。

特性: sideEffect

sideEffect表示的意思就是副作用,理解起来并不难,比如外部成员引用了当前模块,那么当前模块肯定是不会被treeShaking的,如果在当前模块里面写了冗余的代码,那么sideEffect就是去除这些冗余代码的,以达到更高的提效能力。

sideEffect的基础实践

这里我们应该在webpack.config.js里面开启sideEffect,在package.json里面指定具有副作用的模块。

// webpack.config.js
module.exports = {
    ...
    optimization: {
        sideEffect: true
    }
    ...
}

// package.json

{
    "scripts": {},
    "sideEffect": [
        // 告知webpack此文件具有副作用
        "./src/app.js",
        // *通配符css文件
        "*.css"
    ]
}

特性: CodeSplitting分包策略

CodeSplitting分包策略旨在解决单入口打包导致bundle.js文件过大,从而导致浏览器http加载速度过慢造成页面短暂白屏情况,分包策略具有三种常见实施方式。

  • 根据项目背景,多入口打包。
  • 结合ESMDynamic import特性,按需加载模块。
  • 对第三方包使用拆包策略。

参考 webpack面试题详细解答

多入口打包的具体实践

多入口打包体现在多页应用,每一个页面依赖于一个打包文件,对于模块中的公共代码进行提取到公共结果中。

module.exports = {
    entry: {
            index: "./src/index.js",
            add: "./src/add.js",
    },
    optimization: {
        splitChunks: {
            // 自动提取到一个公共的bundle.js中
            chunks: "all"
        }
    }
    plugins:[
        ...
        new HtmlWebpackPlugin({
            filename: 'anout.html',
            template: './aout.html',
            chunks:['add']
        }),
        new HtmlWebpackPlugin({
            titie: 'title',
            template: './index.html',
            meta:{
                viewport: 'width=device-widt, initial-scale=2.0'
            },
            filename: 'index.html',
            publicPath: './',
            scriptLoading: 'module',
            chunks:['index']
        })
        ...
    ],
    ...
}

比如在index.js、add.js里面抖音用到了once方法,webpack就会提取公共的lodash到单的文件里面,在两个页面里面会通过script引入。 image.png

Dynamic import的按需加载实践

在选项卡切换场景下,在应用程序运行的过程中,只有当用户点击某个模块,才会对应去加载某个模块,大大的减少了启动时需要加载模块的体积,降低了浏览器网路的带宽的占用,提高了应用的响应率。

const hash = window.location.hash;
const container = document.getElementById('app');
switch(hash){
    case 'title_1': 
    import('./title_1.js').then({default:title_1}=>{
        container.appednChild(title_1())
    });
    break;
    case 'title_2': 
    import('./title_2.js').then({default:title_1}=>{
        container.appednChild(title_2())
    });
    break;
    case 'title_3': 
    import('./title_3.js').then({default:title_1}=>{
        container.appednChild(title_3())
    });
    break;
    default:
}

按需加载确实不需要在首屏的时候一次性把文件全部加载完毕,因为首屏并不需要所有模块,加载了也是浪费

第三方包拆包策略

所谓三方包,在在多入口里面也提到过optimization.splitChunks只是一种提取三方包的方式,我们现在要讲的是插件层面的DllPluginDllReferencePlugin,这个插件的意义更为广阔一点,比如类似vuereact等三方包,配合着我们的项目代码,只需要初次构建一次,再次构建webpack就会跳过这些依赖包,只要我们不手动升级依赖包,那将会是永久性的缓存。

使用步骤
  1. 新建webpck.dll.config.js文件,写上如下内容。
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');

module.exports = {
  // 入口文件
  mode: "development",
  entry: {
    // 项目中用到该两个依赖库文件
    lodash: ['lodash'],
  },
  // 输出文件
  output: {
    // 文件名称
    filename: '[name].dll.js', 
    // 将输出的文件放到dist目录下
    path: path.resolve(__dirname, 'vandor'),

    /*     存放相关的dll文件的全局变量名称,比如对于lodash来说的话就是 _dll_lodash, 在前面加 _dll     是为了防止全局变量冲突。    */
    library: '_dll_[name]'
  },
  plugins: [
    // 使用插件 DllPlugin
    new DllPlugin({
      /*       该插件的name属性值需要和 output.library保存一致,该字段值,也就是输出的 manifest.json文件中name字段的值。       比如在jquery.manifest文件中有 name: '_dll_jquery'      */
      name: '_dll_[name]',

      /* 生成manifest文件输出的位置和文件名称 */
      path: path.join(__dirname, 'vandor', '[name].manifest.json')
    })
  ]
};
  1. 在package.json里面新增命令 => "dll": "webpack --config webpack.dll.config.js"并执行,生成文件。

在这里插入图片描述

  1. 引入文件的依赖关系
const webpack = require('webpack');
module.exports = {
    plugins:[
        ...
        new webpack.DllReferencePlugin({
           manifest: require('./vandor/lodash.manifest.json')
        }),
        ...
    ]
}

特性: 魔法注释

在分包或者定义其他模块的时候,我们想给模块定义一个名称,那就可以使用如下方式。

/* webpackChunkName:'<chunkName>' */

探索webpack带来的前端性能优化

在前几篇文章里面我们就知道了webpack通过mode来提供了nonedevelopmentproduction三种预设配置。每一种配置都会选择性的加载某些插件来优化项目的构建,但是作为一个开发者我们应当去关注非自动的功能配置,下面我们来一起探索一下在开发中使用到的配置能带来一定的性能优化

为什么要进行性能优化

性能优化是前端开发的永久性话题,高性能应用的开发这是我们的目标,但是目标总就是目标,具体实施还是要一步一块板砖,webpack在实践如此多的新特性的同时,会给我们的打包结果带来具有影响的内容,比如sourceMap,上有政策下有对策,那么我们的种种可优化的点就是解决问题的对策。

具体对策

那么我们应该怎么样来提高构建速度与打包结果呢?
实际的开发中你总会见到我们会对不同的环境配置不同的文件,根据env的不同来启用不同的配置。

// webpack.development.config.js
module.exports = {
    mode:"development",
    detool:"source-map"
    ...
}

// webpack.production.config.js
module.exports = {
    mode:"production",
    detool:"nosources-source-map"
    ...
}

// webpack.config.js

module.exports = (env, args) => {
    // 公共配置
    const config = {
        module:{},
        plugins:[],
        ...
    }
   env === "development" ? require('./webpack.development.config.js'):require('./webpack.production.config.js')
   return config;
}
  • DefinePlugin定义全局变量,可用作baseUrl

    ...
    plugin:[
        new webpack.DefinePlugin({
            API_BASEURL:'https://www.yixizhishi.com'
        })
    ]
    ...
    
  • MiniCssExtractplugin用来从js代码中提取css代码。

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

...
plugin:[
    new MiniCssExtractPlugin()
],
module:{
    rules:[
        {
            test:/\.css/,
            use:[
                // 通过link标签引入到页面中
                MiniCssExtractPlugin.loader,
                cssloader
            ]
        }
    ]
}
  • optimizeCssAssetsWebpackPlugin,用来压缩css代码。

    • webpack中所谓压缩就是压缩js文件的,而css文件,需要我们单独处理。
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

...
// 非plugin中使用
optimization:[
    minimizer:[
        new OptimizeCssAssetsWebpackPlugin()
        new terser-webpack-plugin()
    ]
]
  • terser-webpack-plugin用于压缩js代码。
    • 如果在optimization选项中开启了minimizer属性,则会覆盖掉webpack本身的压缩功能,所以我们需要手动添加压缩插件。
const terserWebpackPlugin = require('terser-webpack-plugin');

...
optimization:[
    minimizer:[
        // 压缩css
        new OptimizeCssAssetsWebpackPlugin()
        // 压缩js
        new terserWebpackPlugin()
    ]
]

当然还有一些其他的配置呀,比如。

  • splitChunks的一些配置呀,也就是按你的需求拆包呀。
splitChunks: {
    cacheGroups: {
        commons: {
            chunks: "initial",//相同的chunks提出来
            minChunks: 2,//依赖了两个以上的关系
            minSize: 0 //这个依赖最小体积为0
        },
        vendor: {
            test: /node_modules/,
            // 默认选项,表示只要有依赖的第三方包就要拆出去,跟all差不多
            chunks: "initial",
            name: "vendor",
            enforce: true
        }
    },
}
  • cdn的引入三方包呀。
module.exports = {
    ...
    // 通过外部引入第三方包
    externals:['jQuery','lodash']
    ...
}
  • 多线程打包的开启呀,比如happyPack
    • happyPack的工作原理就是把loader加载分配多个线程去处理,最后在统一调度起来,处理完成之后通知webpack进行chunks的组合,输出bundle.js注意:并不是说多进程打包就一定好,因为创建多线程的时候也会有性能开销,所以还是斟酌而行。
  • 使用include避免webpack处理不需要处理的模块文件,提高编译效率。
  • webpack5提供了webpack资源模块,来代替一般的loader处理文件,好处是能够处理不同类型的文件并且不再需要针对性的配置loader

image.png

  • resolve模块一般被人们忘掉了,不过在vue/react的脚手架中还是看见过它的身影,一般用于告诉webpack以什么样的形式去处理文件,比如。
    • 别名:alias
    • 文件类型:extensions
    • 解析的模块范围:modules
module.exports = {
    resolve: {
        alias:{
            '@':'root/src' // 指定别名@,通过@可以找到文件目录
        },
        extensions:{
            ['.jsx', '.tsx', '.vue'] // 指定webpack需要解析哪些类型的文件
        },
        modules:{
            ['node_modules', 'root/src'] // 指定webpack需要解析那些范围的文件
        }
    }
}

写在最后

因为上面的一些优化手段涵盖了webpack5以及webpack5以前的特性,那么在这里提及一下webapck5中开箱即用的特性以及不再维护的老版本的特性吧。

  • 持久化缓存,使用cache之后我们便不需要使用dll拆包、cache-loader了,而且是webpack5中提供的功能。
module.exports = {
    cache: {
      type: 'filesystem', // 文件系统
    },
}
  • thread-loader开启多线程打包,上述代码中提到了happypack,不过在webpack5当中,已经不再去维护happypack了,我们就应该使用thread-loader来加快构建进程。

总结

上述讲解的内容均是在开发环境下的的配置的一步步实现,当然在mode:"production"webpack会自动帮我们做,所以在不依赖别人的情况下,还是自己配比较好玩。下一章我们就一起来探索一下各大成熟框架是怎么配置webpack

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

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

相关文章

C++ Reference: Standard C++ Library reference: Containers: deque: deque: swap

C官网参考里链接&#xff1a;https://cplusplus.com/reference/deque/deque/swap-free/ 函数模板 <deque> std::swap (deque) template <class T, class Alloc> void swap (deque<T,Alloc>& x, deque<T,Alloc>& y); 交换两个双端队列容器的…

【ESP32调试-快速入门】

文章目录ESP32调试一. 环境搭建二. 运行OpenOCD1. 烧入blink2. 找到芯片型号对应的脚本文件&#xff0c;并运行脚本命令三. 运行GDBESP32调试 一. 环境搭建 ESP_IDF环境搭建 二. 运行OpenOCD 1. 烧入blink 如&#xff1a;安装环境中的examples中的blink 路劲&#xff1a;安装…

华为机试 - 探索地块建立

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 给一块n*m的地块&#xff0c;相当于n*m的二维数组&#xff0c;每个元素的值表示这个小地块的发电量&#xff1b; 求在这块地上建立正方形的边长为c的发电站&#xff0c;发电量满足目标电量k的地块数量…

汽车保养app开发,扩充汽车服务市场发展商机

从汽车市场规模来看&#xff0c;从2017年开始始终保持增长的发展趋势&#xff0c;在2021年市场规模达到140877.18亿元。互联网时代发展下&#xff0c;汽车后市场大力推广电子商务&#xff0c;将互联网技术与汽车保养服务相结合是汽车服务行业强大的必由之路。二者的结合可以让消…

centos7下搭建rabbitmq的开发环境

我们在项目开发的时候都不可避免的会有异步化的问题,比较好的解决方案就是使用消息队列,可供选择的队列产品也有很多,比如轻量级的redis, 当然还有重量级的专业产品rabbitmq,rabbitmq好就好在是用erlang(二郎神)开发的,它那天生的OTP并行计算框架,轻而易举的进程间通…

阿里云ssl免费证书申请

目录为什么申请SSL证书SSL证书申请支持的域名类型ssl免费证书申请过程为什么申请SSL证书 由于web服务部署需要使用https安全协议&#xff0c;因此需要申请相应域名的SSL证书用于部署。测试阶段&#xff0c;为节省成本&#xff0c;使用阿里云提供的免费SSL证书。 SSL证书申请支…

在Web服务器(IIS)上安装SSL证书并绑定网站

以windows server 2016为例 一、安装中间证书 1.下载中间证书文件 如果是RSA加密算法类的&#xff0c;下载此处。 如果是ECC加密算法类的&#xff0c;下载此处。 2.安装 双击下载好的文件进行安装&#xff0c;注意&#xff0c;安装过程中&#xff0c;存储位置要设”为本地…

搜题接口系统

搜题接口系统 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转&#xff09; 题库…

分类预测 | MATLAB实现ELM极限学习机多特征分类预测(二分类)

分类预测 | MATLAB实现ELM极限学习机多特征分类预测(二分类) 目录 分类预测 | MATLAB实现ELM极限学习机多特征分类预测(二分类)效果一览基本介绍程序设计学习总结参考资料效果一览 训练集正确率Accuracy = 89%(445/500) 测试集正确率Accuracy = 86.9565%(60/69) 基本介绍 MATLA…

加载器、反射、xml、DTD、schema、注解、单元测试

一、什么是类加载器 类加载器 类加载器&#xff1a;负责将.class文件&#xff08;存储的物理文件&#xff09;加载在到内存中 类加载的过程 类加载时机 类在什么时候会被加载到内存中呢&#xff1f; 类加载时机 创建类的实例&#xff08;对象&#xff09;调用类的类方法 访问…

微服务自动化【idea插件一键部署】

目录​​​​​​​ 1. Docker结合Idea插件使用 2. 私服搭建 registry 3. 私有仓库的使用 4. idea一键项目部署单独Docker镜像 5. idea一键项目部署Docker标记镜像【私库】 1. Docker结合Idea插件使用 1. 修改Docker服务文件,注释掉"ExecStart"这一行&#x…

火爆的超级人工智能ChatGPT,唯独鄙视中国人

ChatGPT你听说了吗&#xff1f;如果ChatGPT你还没有听说&#xff0c;作为一名程序员&#xff0c;那可能你就out了。使用ChatGPT受阻&#xff0c;为什么不让我们用&#xff1f;它是一款神器&#xff0c;很有意思&#xff0c;当前被大家众星捧月&#xff0c;初次用起来确实很神奇…

微服务框架 SpringCloud微服务架构 22 DSL 查询语法 22.5 相关性算分

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构22 DSL 查询语法22.5 相关性算分22.5.1 复合查询22.5.2 相关性算分22.5.3 …

前端精准测试实践

作者&#xff1a;京东云质量部 背景 随着前端技术发展&#xff0c;已经转变为数据绑定为主流的框架方式&#xff0c;与后端服务一样&#xff0c;前端代码实现也会涉及相互依赖&#xff0c;引用这些场景&#xff0c;那么应该如何准确的评估前端代码改动的影响范围&#xff1f;…

2小时开发《点球射门游戏》,动画演示思路(上),代码已开源

唠两句 最近被疫情关在家&#xff0c;时间多运动少&#xff0c;真的很无聊呀&#xff01;也许是天意为之&#xff0c;居然来世界杯了&#xff0c;虽然这届世界杯很「冷」&#xff0c;但是多少还是为无聊的我们增加了一些无聊的趣事&#xff0c;比如勇哥在等世界杯开幕式的过程…

关于影响编码效果的画质调优总结

1、背景&#xff1a; 调试一个新项目&#xff0c;要求视频帧率为20fps、码率1.5m下&#xff0c;和竞品机对比效果。发现动态场景下的效果比竞品机差距比较明显&#xff08;做的是安防类的监控相机&#xff0c;比较关注视频的效果&#xff09;&#xff0c;比如对着运动的车流时…

红队隧道应用篇之Netsh端口转发(一)

简介 netsh是从Windows 2000开始就有的一个用于配置网络设备的命令行工具 其中netsh interface portproxy是一个配置网络代理的命令, 可以配置ipv4或ipv6的端口转发代理以及双向端口转发代理 学习隧道应用前必须了解的知识:https://blog.csdn.net/xf555er/article/details/1…

softmax回归从零开始实现

1. 引入Fashion-MNIST数据集 并设置数据迭代器的批量大小为256 import torch from IPython import display from d2l import torch as d2lbatch_size 256 # 每次随机读256张图片&#xff0c;返回训练集和测试集的迭代器 train_iter, test_iter d2l.load_data_fashion_mnist…

职场日常:测试人员如何快速熟悉新业务?

身处职场&#xff0c;学习新业务在所难免&#xff0c;尤其是测试人员&#xff0c;具备良好的业务知识是我们做好质量保障的前提&#xff0c;不管是职场「新人」还是「老人」&#xff0c;快速熟悉业务的能力都是不可或缺的&#xff0c;这是我们安身立命的根本。 但&#xff0c;…

【第一章 Linux目录结构,网络连接三种模式,vi和vim】

第一章 Linux目录结构&#xff0c;网络连接三种模式&#xff0c;vi和vim 1.Linux和Unix&#xff1a; ①Unix针对于大型&#xff0c;高性能主机或服务器&#xff1b; ②Linux适用于个人计算机。 2.网络连接的三种模式&#xff1a; ①桥接模式&#xff1a;虚拟系统可以和外部系…