作为一名前端开发,你有没有过这样的经历:明明改了代码,运行结果却和没改一样?反复检查语法、重启项目甚至清空浏览器缓存都不管用,最后才发现是构建工具的缓存在“搞鬼”。今天就来聊聊我上周遇到的构建工具缓存未更新导致旧代码运行的踩坑经历,以及整理出的一套解决方案。
🔍 场景还原:改了代码却没生效
上周我负责优化一个电商项目的商品详情页,主要修改了商品价格的计算逻辑,从原来的固定折扣改为根据用户等级动态计算。本地开发环境测试一切正常,部署到预发环境后却发现,新用户等级的价格计算逻辑完全没生效,页面还是显示旧的固定折扣价格。
我第一反应是代码没部署成功,重新打包部署了一次,结果还是一样。查看预发环境的打包日志,显示最新的代码已经成功编译;查看浏览器控制台的网络请求,返回的JS文件也是最新的哈希值。但打开JS文件的源码,却发现里面还是旧的价格计算逻辑。
🧐 原因排查:构建工具缓存的“锅”
经过一番排查,我发现问题出在构建工具的缓存机制上。我们项目使用的是Webpack 5,它默认开启了持久化缓存功能,会将编译结果缓存到本地文件系统中。在打包过程中,Webpack会根据文件的内容哈希值来判断是否需要重新编译文件。
而这次的问题是,我修改的价格计算逻辑所在的文件,在Webpack的缓存策略中被判定为“未修改”。进一步查看Webpack的缓存配置发现,项目中自定义了缓存的哈希算法,使用的是文件的修改时间而不是内容哈希值。由于我在修改代码后,为了统一代码格式,用Prettier格式化了整个项目的代码,导致所有文件的修改时间都被更新了。Webpack在编译时,因为缓存的哈希值是基于修改时间生成的,所以认为所有文件都需要重新编译,生成了大量的缓存文件。
而预发环境的部署脚本中,为了加快部署速度,只上传了编译后的JS和CSS文件,没有清理旧的缓存文件。当Webpack在预发环境打包时,会优先读取本地的缓存文件,而这些缓存文件还是旧的代码,所以即使我修改了代码,打包出来的还是旧的逻辑。
🛠️ 解决方案:从根源解决缓存问题
找到了问题所在,我制定了一套从根源解决构建工具缓存未更新的解决方案:
1. 优化Webpack缓存配置
将Webpack的缓存哈希算法从基于文件修改时间改为基于文件内容哈希值,确保只有当文件内容真正发生变化时,才会重新编译文件。修改Webpack配置如下:
module.exports = {
cache: {
type: 'filesystem',
version: process.env.NODE_ENV,
cacheDirectory: path.resolve(__dirname, '.webpack-cache'),
store: 'pack',
buildDependencies: {
defaultWebpack: ['webpack/lib/'],
config: [__filename],
tsconfig: [path.resolve(__dirname, 'tsconfig.json')]
}
}
};2. 部署时清理旧缓存文件
在预发环境和生产环境的部署脚本中,增加清理旧缓存文件的步骤。可以使用rimraf工具来删除Webpack的缓存目录,确保每次部署都是全新的编译:
# 清理Webpack缓存目录
rimraf .webpack-cache
# 重新打包
npm run build
# 部署到服务器
scp -r dist/* user@server:/path/to/deploy
3. 增加缓存失效机制
在项目中增加缓存失效机制,比如在package.json中增加一个buildHash字段,每次发布新版本时更新这个字段。Webpack的缓存配置中可以引用这个字段,确保每次发布新版本时,缓存都会失效:
const packageJson = require('./package.json');
module.exports = {
cache: {
type: 'filesystem',
version: packageJson.buildHash,
// 其他缓存配置
}
};
4. 本地开发环境缓存调试工具
为了在本地开发环境快速排查缓存问题,我推荐使用Webpack的cache-loader插件和webpack-bundle-analyzer插件。cache-loader可以在控制台输出缓存的命中情况,webpack-bundle-analyzer可以可视化查看打包后的文件组成,帮助快速定位缓存问题。
这坑我也踩过,搞了半天才发现是缓存问题
webpack缓存真的坑,改配置折腾死我了
部署脚本居然不清理缓存,这谁写的啊🤔