资讯专栏INFORMATION COLUMN

Webpack 删除重复文件的一种优化思路

Little_XM / 2510人阅读

摘要:方法一中的插件就是在阶段删除目标文件夹。而想要优化该插件,思路就是在阶段删除上一次打包后留下的废弃文件。

场景

很多人使用webpack打包文件,为了防止浏览器缓存,经常会这样设置:

output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "bundle-[hash:5].js"
    }

给文件hash编码后加在文件名后面,只要文件修改,都会生成不同的文件名。但是,经过多次打包后,往往会遇到这样的情况:

/dist目录
|--  bundle-6ece9.js
|--  bundle-b41c3.js
|--  bundle-d303d.js
|--  index.html
|--  style-6ece9.css
|--  style-b41c3.css
|--  style-d303d.css

除了我们的index.html如海边的礁石一般巍然不动,js、css文件都仿佛拉帮结派,一茬一茬的。该怎么删除这些重复的文件呢?

解决方法一

很多人都推荐使用“clean-webpack-plugin”插件,它能在Webpack编译之前就删除所有文件。
优点:轻量级插件,配置简单。
缺点:在大型项目中,如果只改变了一个文件却需要删除其他所有未改变的文件,这些文件数量不定但对性能还是有一定影响,因此这个插件性能上还有提升空间。

解决方法二

写过Webpack插件的前端同行,可能知道compiler对象以及相关的事件钩子。

在此介绍两种与本文相关的钩子:

compile:开始编译,在创建 compilation 对象之前;

done:所有的编译过程已完成。

方法一中的clean-webpack-plugin插件就是在compile阶段删除目标文件夹。而想要优化该插件,思路就是在done阶段删除上一次打包后留下的废弃文件。

这时有一个新的问题,在done阶段,项目中所有文件都编译完成,存放在dist文件夹中了,怎么区分哪些是这次打包产生的新文件,哪些是上一次打包产生的旧文件呢?

这里,再介绍一下compilation对象。

compilation 对象代表了一次单一的版本 webpack 构建和生成编译资源的过程,compilation 对象可以访问所有的模块和它们的依赖(大部分是循环依赖)。

了解compilation对象的概念后,介绍一下它的一个属性assets。compilation.assets的值是一个对象,其中每一属性名都是本次打包产生的文件的文件名,打印出来如下:

assets:
{ 
    "bundle-a82da.js":
    {
        existsAt: "...distundle-a82da.js" 
    },
    "style-cc549.css":
        ConcatSource {
            children: [Object],
            existsAt: "...diststyle-cc549.css",
            emitted: true 
        },
    "index.html":
    { 
        source: [Function: source],
        size: [Function: size],
        existsAt: "...distindex.html",
        emitted: true 
    } 
}

因此,通过assets属性我们就解决了如何区分本次打包与之前打包产生的文件的问题。只需要遍历一次dist目录所有文件,若assets对象中不包含该文件的文件名,那就说明这是“前朝余孽”,直接斩立决。

核心代码如下:

buildDir = this.buildDir;
compiler.plugin("done", function (compat) {
    //获取资源数组对象
    const newlyCreatedAssets = compat.compilation.assets;
    const unlinked = [];
    fs.readdir(path.resolve(buildDir), (err, files) => {
        files.forEach(file => {
            //删除当前打包资源组中不存在的文件
            if (!newlyCreatedAssets[file]) {
                fs.unlink(path.resolve(buildDir + file));
                unlinked.push(file);
            }
        });
        if (unlinked.length > 0) {
            console.log("删除文件: ", unlinked);
        }
    });
});

使用时只需要传入目标文件夹的目录url即可,如“./dist/”。

插件

为了方便的使用,我做了一个插件上传到npm仓库。

1.初始化npm

npm init

2.安装模块

npm i webpack-remove-hashed-files --save-dev

3.修改webpack.config.js

const removeFiles = require("webpack-remove-hashed-files");
//你的打包目标文件夹
//your distnation folder
const buildDir = "./dist/";
//……修改plugins
//...modify plugins
plugins:[
    new removeFiles(buildDir)
]

源码请看我的github仓库

总结

我的方法主要是判断文件是否为本次打包产生来减少文件删除的时间,但是相比较于clean-webpack-plugin插件,功能还缺少删除白名单和文件名正则匹配等,这些都会在我有空的时间添加。

另外可能有的同行觉得clean-webpack-plugin不能满足某些需求,不妨试试我的这款插件,也许有意外之喜。

参考

看清楚真正的 Webpack 插件
如何编写一个插件?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90256.html

相关文章

  • webpack打包分析与性能优化

    摘要:打包分析与性能优化背景在去年年末参与的一个项目中,项目技术栈使用,生产环境全量构建将近三分钟,项目业务模块多达数百个,项目依赖数千个,并且该项目协同前后端开发人员较多,提高构建效率,成为了改善团队开发效率的关键之一。 webpack打包分析与性能优化 背景 在去年年末参与的一个项目中,项目技术栈使用react+es6+ant-design+webpack+babel,生产环境全量构建将...

    joy968 评论0 收藏0
  • 借助webpack对项目进行分析优化

    摘要:由于项目的不断扩大,只会影响我们定位功能和问题的速度,因此对冗余文件进行清理,是很重要的。我们在项目中使用的,自动将各个图标进行。 进入公司之后,接手的便是前人留下来的一个大项目。庆幸的是整个项目拥有完善的产品功能文档,但是由于项目过于庞大,老旧。包含了打包过慢,冗余文件过多等诸多问题。想要快速的解决这些问题,想要完全把功能重构一遍的话,成本太高了。一个一个文件来过,时间成本也比较大。...

    Me_Kun 评论0 收藏0
  • 前端面试题大集合:来自真实大厂的532道面试题(只有题,没有答案)

    答案自己谷歌或百度找。 一、来源背景 面试题是来自微博@牛客网发布的真实大厂前端面经题目,我一直在收集题目长期一个一个的记录下来的,可能会有重复,但基本前端的面试大纲和需要掌握的知识都在其中了,面试题仅做学习参考,学习者阅后也要用心钻研其中的原理,重要知识需要系统学习、透彻学习,形成自己的知识链。 二、532道前端真实大厂面试题 express和koa的对比,两者中间件的原理,koa捕获异常多种情...

    Kerr1Gan 评论0 收藏0
  • 前端面试题大集合:来自真实大厂的532道面试题(只有题,没有答案)

    答案自己谷歌或百度找。 一、来源背景 面试题是来自微博@牛客网发布的真实大厂前端面经题目,我一直在收集题目长期一个一个的记录下来的,可能会有重复,但基本前端的面试大纲和需要掌握的知识都在其中了,面试题仅做学习参考,学习者阅后也要用心钻研其中的原理,重要知识需要系统学习、透彻学习,形成自己的知识链。 二、532道前端真实大厂面试题 express和koa的对比,两者中间件的原理,koa捕获异常多种情...

    lushan 评论0 收藏0

发表评论

0条评论

Little_XM

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<