webpack的优点

webpack从配置的入口出发,可以打包所有前端资源,同时可以配置多种loader来处理不同类型文件的转换,并且可以配置plugin来扩展模块打包流程,满足更多构建中特殊的需求,开发过程中还可以使用HMR提升本地开发效率和体验,生产环境中可以利用代码压缩和代码分割来提升前端加载性能,总之就是既可以提升开发效率,又可以提升应用性能。

webpack中loader和plugin的区别

webpack中loader主要用于处理非JavaScript模块的转换,在固定的阶段中使用,本身只是一个函数,返回转换后的结果,因为webpack只能处理js;而plugin是用于处理特殊的构建需求,比如将css代码单独输出为一个文件、定义环境中的变量等,利用了webpack的hooks介入构建过程中不同的阶段,可以定制项目的构建流程。

开始编译,读取webpack配置,创建NormalModuleFactory,创建NormalModule(使用resolveLoader解析loader路径),开始编译模块(loader-runner)

如何利用webpack提升应用性能

webpack优化性能大概有三种方式:

代码压缩、代码分割、去除无用代码,主要的方向是减少请求体积,代码分割有的情况下还可以利用浏览器缓存,减少请求次数

  1. 代码压缩(主要就减少请求体积)

    我们可以对optimization下的minimize和minimizer配置项进行设置,配置TerserPlugin对js代码进行压缩处理,还可以使用插件如HTMLWebpackPlugin对html文件进行压缩。
  2. 代码分割(既减少一次的请求体积,使请求返回更快,有的情况还可以利用浏览器缓存,减少请求次数)

    我了解的大概几种方式,第一种是设置optimization下的splitChunks配置项、第二种css代码利用MiniCssExtractPlugin插件单独生成文件、第三是利用webpack的dllPlugin插件将第三方库打包成独立的文件。

    splitChunks可以将模块抽离为单独的文件,chunks可以设置为all/async/inital三个值的其中一个,all就是所有的模块都打包到一个chunk,async是把异步加载的模块打包到chunk中,如通过动态import加载的模块,initial是把同步加载的模块打包到chunk中。可以配合按需加载使用,按需加载使用ES动态加载语法import来加载模块,webpack会自动处理使用这种语法编写的模块,把模块单独分离成文件,可以减少大型应用初始化时需要加载的前端资源,提升用户体验。

    css代码利用plugin插件生成单独的文件,可以在后续请求中,利用浏览器缓存,如果是多页面应用,优点更明显,不用多次加载css。

    dllPlugin也是将部分模块抽离成单独的文件,但是它和splitChunks不同,在代码不变的情况下不用重复打包,可以单独写一个配置文件,运行打包,在后续项目的构建流程直接使用DLLReferencePlugin引用文件就可以,通常可以用来处理不太变动的第三方库,可以看出来这样不仅可以利用浏览器缓存,还能提高开发效率。
  3. 去除无用代码(减少请求体积)

    可以利用tree-shaking、还有sideEffects,将未使用的代码移除。

    要利用到tree-shaking就要使用分别导入、而不是整体导入,未引入和未使用的模块方法就不会被打包,sideEffects对没有副作用的模块也可以将模块中未使用到的代码不进行打包。

    还有webpack的IgnorePlugin插件,可以在打包中忽略掉某些依赖包中体积大但又不太需要的文件,如react脚手架生成的项目中就默认将moment的locale文件夹整个忽略掉,这个语言包会非常大,但是通常实际中不需要这些多语言的配置,单独引入需要的语言就可以。

webpack的热更新原理

热更新HMR就是不用刷新页面而将新变更的模块替换掉旧的模块,避免了频繁手动刷新页面、应用状态丢失,也减少了页面刷新时的等待。它的核心是客户端去服务端拉取更新后的文件。在DevServer开启hot后,webpack会往应用代码中添加websocket相关的代码,用于和服务器保持连接,等待更新动作,本地代码变更时通知浏览器做相应的处理;webpack还会往应用代码中添加HMR运行时的代码,用于定义应用更新时的API。当有更新时,webpack-dev-server发送更新信号给HMR运行时,然后HMR再请求所需要的更新数据,服务端返回一个json包含所有要更新的模块的hash值,对应模块再次请求获取到最新的模块代码,没有问题的话就进行应用更新。

应用更新的API常见的有module.hot.accept、module.hot.decline、module.hot.dispose等,accept是在应用特定代码模块更新时执行相应的callback;decline是对于指定的代码模块,拒绝进行更新;dispose用于添加一个处理函数,在模块代码被替换时运行(可用于移除之前添加的持久化资源或者相关状态)。

如何优化webpack的构建速度

总的来说方向就是减少webpack的工作量。

  • 首先在开发环境下使用配置mode为develpment,webpack本身就默认不配置一些压缩优化的插件,这样可以减少在优化操作上的时间消耗;
  • 其次提前处理一些文件资源,如使用imagemin或者其他工具提前压缩好图片,可以减少在图片处理上的耗时,一些不频繁更新的第三方库使用dllPlugin打包,在项目中直接引用,不打包到应用代码中,也可以大大减少构建所用时间;
  • 还可以通过配置resolve,设置适合的extensions、modules、mainFields、mainFiles的值,减少模块解析时路径的查询范围,配置module的rules使用loader处理不同的文件时,通过include和exclude限制处理范围,减少耗时;
  • 另外还可以使用thread-loader利用多进程加速loader执行,利用tree-shaking减少webpack处理打包的代码量,利用缓存提升二次构建速度,像babel-loader、terser-webpack-plugin都可以开启缓存。
  • 生产环境还可以配置devtool不输出sourcemap。
  • 如果项目非常大,涉及代码模块过多,在合适的情况下也可以根据一定的粒度,把不同的业务代码拆分到不同的代码库去维护和管理,减少webpack处理的代码量。

如何开发一个webpack的plugin

plugin的实现可以是一个类或者函数,使用时传入相关配置来创建一个实例,plugin实例最重要的方法就是apply,在webpack compiler安装插件时会被调用,接收webpack的compiler对象实例的引用作为参数,在compiler对象实例上我们可以注册各种事件钩子函数hooks,在compiler的有些hooks中,还可以获取到compilation对象实例,在compilation对象实例上注册各种hooks,我们可以通过注册各种hooks来影响webpack的所有构建流程,以便完成更多其他构建任务。

hooks可以简单分为同步和异步两种,同步类型的hooks只能使用tap来注册事件,异步的还可以使用tapPromise和tapAsync来注册。

本地开发plugin,可以使自定义plugin对外暴露一个类,然后在webpack配置文件中引入,运行webpack构建查看结果就可以,可以使用node命令进行调试。

compiler一些hooks:entryOption、beforeRun、emit、compilation、thisCompilation、make(compilation完成编译后执行)、shouldEmit(控制是否输出对应的构建结果)、assetEmitted(在构建结果输出之后执行,可以获取输出内容的相关信息)、done、failed(构建失败时执行)

compilation一些hooks:buildModule、finishModules、chunkAsset(chunk 对应的一个输出资源添加到compilation时执行)、processAssets

如何开发一个webpack的loader

webpack loader本质就是一个实现转换功能的函数,接收content、map、meta三个参数。content就是要进行转化的资源内容,可以是字符串或者buffer,如图片、字体等文件,map是sourcemap对象。

通常webpack loader都是基于一个实现核心功能的类库来开发的,如果直接return一个值,这个值就是转换后的内容,如果要返回sourcemap对象或者其他数据,或是抛出一个异常,需要使用this.callback(err, content, map, meta)来传递这些数据;有些loader在执行过程中可能依赖外部I/O的结果,就需要使用异步的方式来处理,在loader执行时调用this.async()来标识该loader是异步处理的,this.async()会返回一个函数,然后我们可以调用这个函数用于返回loader的处理结果。

使用本地开发的loader有两种方式:一种是配置loader时使用本地的路径;另一种是在loader路径解析中加入本地开发loader的目录,具体是在loader所在目录下添加package.json文件并配置name字段,然后配置resolveLoader的modules将loader所在目录的路径添加进去,并在配置loader时使用package.json中name的值,这种比较适合多个loader的情况。

官方提供的一个工具库loader-utils可以帮助我们获取给loader传递的options,我们还可以使用官方提供的schema-utils对传入的options进行校验。

Webpack相关知识点的更多相关文章

  1. UITableView相关知识点

    //*****UITableView相关知识点*****// 1 #import "ViewController.h" // step1 要实现UITableViewDataSou ...

  2. Android开发涉及有点概念&相关知识点(待写)

    前言,承接之前的 IOS开发涉及有点概念&相关知识点,这次归纳的是Android开发相关,好废话不说了.. 先声明下,Android开发涉及概念比IOS杂很多,可能有很多都题不到的.. 首先由 ...

  3. IOS开发涉及有点概念&相关知识点

    前言,IOS是基于UNIX的,用C/C+/OC直通系统底层,不想android有个jvm. 首先还是系统架构的分层架构 1.核心操作系统层 Core OS,就是内存管理.文件系统.电源管理等 2.核心 ...

  4. IOS之UI--小实例项目--添加商品和商品名(使用xib文件终结版) + xib相关知识点总结

    添加商品和商品名小项目(使用xib文件终结版) 小贴士:博文末尾有项目源码在百度云备份的下载链接. xib相关知识点总结 01-基本使用 一开始使用xib的时候,如果要使用自定义view的代码,就需要 ...

  5. 学习记录013-NFS相关知识点

    一.NFS相关知识点 1.NFS常用的路径/etc/exports NFS服务主配置文件,配置NFS具体共享服务的地点/usr/sbin/exportfs NFS服务的管理命令,exportfs -a ...

  6. TCP/IP 相关知识点与面试题集

    第一部分:TCP/IP相关知识点 对TCP/IP的整体认 链路层知识点 IP层知识点 运输层知识点 应用层知识点 (这些知识点都可以参考:http://www.cnblogs.com/newwy/p/ ...

  7. Python开发一个csv比较功能相关知识点汇总及demo

    Python 2.7 csv.reader(csvfile, dialect='excel', **fmtparams)的一个坑:csvfile被csv.reader生成的iterator,在遍历每二 ...

  8. Caffe学习系列(二)Caffe代码结构梳理,及相关知识点归纳

    前言: 通过检索论文.书籍.博客,继续学习Caffe,千里之行始于足下,继续努力.将自己学到的一些东西记录下来,方便日后的整理. 正文: 1.代码结构梳理 在终端下运行如下命令,可以查看caffe代码 ...

  9. php正则相关知识点

    关于正则,其实简单就是搜索和匹配.php,java,python等都是支持正则的,php正则兼容perl.好多同学觉得正则比较难,比较抽象,其实正则是非常简单的,主要是一个熟悉和反复练习的结果,还有一 ...

  10. MySQL自增列(AUTO_INCREMENT)相关知识点总结

      MySQL的自增列(AUTO_INCREMENT)和其它数据库的自增列对比,有很多特性和不同点(甚至不同存储引擎.不同版本也有一些不同的特性),让人感觉有点稍微复杂.下面我们从一些测试开始,来认识 ...

随机推荐

  1. 文心一言 VS 讯飞星火 VS chatgpt (66)-- 算法导论6.5 5题

    五.试分析在使用下列循环不变量时,HEAP-INCREASE-KEY 的正确性:在算法的第4~6行 while循环每次迭代开始的时候,子数组 A[1..A.heap-size]要满足最大堆的性质.如果 ...

  2. HBase Compaction 原理与线上调优实践

    作者:vivo 互联网存储技术团队- Hang Zhengbo 本文对 HBase Compaction 的原理.流程以及限流的策略进行了详细的介绍,列举了几个线上进行调优的案例,最后对 Compac ...

  3. Django: 获取头信息

    如何获取请求头信息 使用如下函数request.META.get("HTTP_请求头函数"),需要注意的是,请求头变量需要全部大写. 其他注意事项如下所示: 如果headerkey ...

  4. Typescript: 当出现错误时,不编译文件成js文件

    在tsconfg.json文件中添加如下选项 "noEmitOnError": true, /* Disable emitting files if any type checki ...

  5. IOS Safari、微信小程序 img或者其他标签元素出现黑边、黑线阴影

    这个问题最开始出现在小程序上,然后在社区找到一个一样得案例 案例:https://developers.weixin.qq.com/community/develop/doc/000608420706 ...

  6. start_HTTPServer

    alias alias wser='sh /Users/enzhao/suanec/libs/envs/start_HTTPServer.sh' /Users/enzhao/suanec/libs/e ...

  7. 一起来自定义loader吧

    loader 在 webpack 编译中起到非常重要的作用,用于对模块的源代码进行转换,比如 css-loader 将 css 代码处理成字符串,style-loader 创建 style 标签将 c ...

  8. 【python笔记】高阶函数map、filter、reduce

    前言 map().reduce().filter()是python的三个高阶函数.所谓高阶函数,指的是将函数作为参数并返回函数作为结果的函数.下面代码的sing_ready只是一个简单高阶函数示例: ...

  9. Git-入门使用资料

    一.Git入门教程 Git入门视频,针对于小白快速入门,时常约2~3小时 Git入门视频 相关课件资料: https://pan.baidu.com/s/1U-s4OmkToXJ5Y7BbJ7w2Ww ...

  10. Vue【原创】千位符输入框(不仅只是过滤器哦)

    最近和一个做金融的朋友讨论到千位符输入的问题,后来一想貌似自己项目中也会经常碰到金额数字这种输入框,要么自己做一个吧. 首先肯定要有一个正则表达式,也就是过滤器的方案里面常用的正则: 1 filter ...