记录一次Webpack插件优化的经历

安全结
• 阅读 3246

去年12月份,我一个才毕业半年的前端新人接触了Webpack。跟着网上教程学习时,遇到了一个难题:文件名加上hash编码后,多次打包会有之前残留的文件。

当时看的那篇文章,并没有提到clean-webpack-plugin,所以我就傻傻的手动删除。还很奇怪为什么这么严重的问题没人说过……其实就是当时google的关键字有问题,没搜到正确的结果。

不过也是那次误打误撞,让我开始维护一个自己的Webpack插件——webpack-remove-hashed-files。具体功能可以看我之前的文章

本来这个插件吧,功能也不是很复杂,所以我开发好第一版后就没管了。只有后面收到一封邮件,按要求我新增了白名单的功能。接着就搁置了三个月吧。

不过呢,昨天在新项目里需要用到几个本地的图片,于是就发现了一个bug

就是说,我在项目中本来要用file-loader去处理js和css中引入的本地图片,将他们打包到dist文件夹下。然后呢,我打算把它们都放在dist/assets/images子文件夹下。于是就配置file-loader,option为{name: 'assets/images/[name].[ext]'}

然而就是这个配置导致我的删除插件出了问题。

本来我插件的设计是遍历dist目录,将所有文件的文件名与Webpack的compliation.assets的键名比较,如果文件名能够对应于某一个键名,说明是本次打包的内容,将其保留。其他的都删除。这是不考虑白名单的思路。

但是,不知道为什么,file-loader处理后的文件,在assets中是以类似于assets/images/a.jpg的键名保存的,这就导致遍历dist文件夹时,我是用a.jpgassets/images/a.jpg做比较。虽然这是同一个文件,但实际上被误认为两个文件,从而导致删除bug。

那么我该怎么解决呢?

首先要明确问题出现所涉及到的两个角色:file-loaderwebpack-remove-hashed-files。其次,能够修改的是file-loader的options与删除插件的源码。而我的目的就是要把所有图片都存放在dist/assets/images文件夹下,所以file-loader的options是不能修改的,应该重构插件的源码来适应file-loader的配置。

说实话,昨天想了一天才解决好这个问题。因为一直没明白,file-loader到底是怎么做到又改文件名又能创建个新文件夹的……

继续说怎么修改删除插件的源码吧。我苦思冥想N个小时后,决定推翻以前的判断逻辑。因为我想到了一个更简单的判断因素,而且这个因素才是删除插件的核心,只是一直被我忽略了。那就是【文件路径】。

compliation.assets中,每一键对应一个文件对象,其中有一个字段existsAt表明打包后的文件所在的绝对路径。那么我们先将这些路径保存到一个数组dirArrays中,然后在遍历dist下所有文件时,在dirArrays中搜索每个不在白名单中的文件的绝对路径,如果存在则保留;不存在则说明不是本次打包的内容,应该删除。

听上去是不是既不影响原有功能,而且还能解决file-loader的bug问题?另外还比之前的逻辑要简单一些。

至于为什么说文件路径是删除插件的核心?因为插件实质上做了两件事:比较assets与dist中所有文件、删除非本次打包产生的文件。原本只有在删除时才要调用fs.unlink方法,传入文件路径参数。而现在在比较的时候就使用了文件路径。说明它贯穿了本插件的所有流程,说是核心也不为过了。

以上就是本次优化插件的完整记录了,总结一下就是自己造的轮子要多测试多维护,这样才能有理由写推广的文章,让更多人去使用hhh。

另外,在遇到bug后我分析了一下竞品clean-webpack-plugin,发现它的思路跟去年我看得时候相比,还是默认在生命周期emit时遍历目标文件夹dist,如果文件不在白名单里就直接删除。这点也是它能够不受file-loader影响的原因。

但也是我一开始文章中说过的,本次打包与上一次打包也许只有一个文件被修改,实际上只要删除旧的这一个文件就行,但clean-webpack-plugin是将所有文件都删除了。我觉得这一点在大项目中还是会导致打包时间问题的,所以就自己造了个轮子。

还发现了一点,就是判断了是否有compiler.hooks,这是Webpack 4的新特性。后面我再修补下这个问题。

最后,感谢阅读。

点赞
收藏
评论区
推荐文章
晴空闲云 晴空闲云
4年前
webpack配置typescript详解
随着现在typescript使用越来越多,作为打包工具界的webpack怎么编译typescript呢?下面我把自己的实践记录一下,成功编译了typescript文件,并且引入typescript模块后,也可以成功编译。我们从新建webpack项目开始,在此之前先贴一下环境,经常环境不同会造成不同的状况,这边先贴上的环境:$nodevv14.15.4$
Wesley13 Wesley13
4年前
vite2 引入 vectorize
这个库在webpack中是正常的,但是在vite2项目中无法使用也不报错,只是结果总是空....看了下是个老项目了,依赖的也都是好几年没更新的库...看来webpack在兼容性方面还是要强不少的    尝试使用parcel打包后使用,不太行...用webpack打包后使用....也不行...有时间再研究研究,看看能不能写个类似的.
Wesley13 Wesley13
4年前
1、webpack入门例子。
在下面的例子中,简单使用webpack打包一个js。并且把这个js引用的其他js、json数据一起打包进去。官网:http://webpack.github.io/(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwebpack.github.io%2F)英文文档: http
可莉 可莉
4年前
'webpack' 不是内部或外部命令,也不是可运行的程序 或批处理文
运行项目时报错: 'webpack'不是内部或外部命令,也不是可运行的程序或批处理文因为当时报错到时候没截图,我这里就不放图片了报这个错时因为没有全局安装webpack,解决方法:1.确保nodeJS已安装2\.找到nodejs目录,我的目录是图片上这个,你的可能不一样,看下有没有以下两个文件,没有就新建!(https://
可莉 可莉
4年前
20k以上面试必问,Webpack原理和优化
我身边很多朋友都觉得Webpack不重要,认为只要团队里有人会就可以,而那个人不需要是自己。那么我就给你一个必须学它的理由:Webpack原理和优化工资20k以上的面试必问如果你想拿到高薪,Webpack就是你绕不过去的一道门槛。而即便不提面试,对于每一个前端工程师来说
Easter79 Easter79
4年前
TypeScript 文件引入 Html (ts import html webpack)
我们的目标是把html引入ts文件,webpack打包时就能把html打进js文件,减少文件加载啦1安装textloadernpminstalltextloadersavedev2webpack配置里新增textloader为文本加载器module:{rules:
Stella981 Stella981
4年前
React生产环境打包&&后台环境运行(有跨域+无跨域)
(1)打包项目1、yarnrunbuild或者2、npmrunbuild  打包后,webpack会自动在根目录生成build文件,里面存放着相关文件  !(https://img2020.cnblogs.com/blog/1291869/202004/1291869202004101706415171581206162.
Stella981 Stella981
4年前
IE9样式错乱,IE11无法正常加载v
1.第一步:安装babelployfill(已安装请跳过此步骤)yarnaddbabelployfill2.修改webpack打包配置文件:webpack.bash.conf.js//引入babelployfillvarbabelPloy
Easter79 Easter79
4年前
'webpack' 不是内部或外部命令,也不是可运行的程序 或批处理文
运行项目时报错: 'webpack'不是内部或外部命令,也不是可运行的程序或批处理文因为当时报错到时候没截图,我这里就不放图片了报这个错时因为没有全局安装webpack,解决方法:1.确保nodeJS已安装2\.找到nodejs目录,我的目录是图片上这个,你的可能不一样,看下有没有以下两个文件,没有就新建!(https://