如何缓存Bact React App?在React应用程序中缓存清除的一种简单方法
这篇文章也交叉发布在 –
DEV – 缓存Busting React App
TL; DR – SemVer您的应用程序并在每个构建上生成一个不会被浏览器缓存的meta.json文件。当版本不匹配时,使缓存无效并重新加载应用程序。注意:本文中的示例和说明是基于React的。但该策略适用于任何Web应用程序/框架。
和缓存一样重要 – 缓存失效现在已经很长时间了。使浏览器中加载的Web应用程序的缓存无效。但是,将保存到主屏幕的Web应用程序的缓存无效甚至更难。
快速入门 –
服务器缓存:Web服务器首次请求时缓存资源。第二次,资源从服务器缓存提供。还有更多内容 – CDN,原始服务器,边缘服务器等,但我们不会全力以赴。由于我们可以控制服务器和每次新部署,因此我们可以自动或手动清除旧缓存,因此使服务器缓存无效是非常简单的。
浏览器缓存:浏览器还以自己的方式缓存资源。当用户的浏览器第一次加载网站时,浏览器决定在本地缓存一些资源(主要是图像,js和css等资源),下次用户访问同一网站时,浏览器会提供资源。本地缓存。由于我们无法控制用户的浏览器,因此在用户的浏览器中清除缓存在过去一直都是一个难题。使用缓存标头和像webpack这样的构建工具在每个构建上生成独特的块,它变得更容易管理,但仍然,它不是没有陷阱。
以下是浏览器缓存的一些问题 –
- 如果站点在同一选项卡中刷新,浏览器往往会忽略缓存验证 – 如果用户固定选项卡,即使清除了服务器缓存,也很有可能从浏览器缓存加载站点。
- 如果您的应用程序正在注册服务工作者,则仅当用户在新选项卡中打开该站点时,服务工作者缓存才会失效。如果从不关闭选项卡,则用户将永远停留在服务工作缓存中。
- 如果用户将站点添加到移动设备/平板电脑的主屏幕,则仅当用户明确退出应用程序时,浏览器缓存才会失效 – 这与在浏览器中打开相同选项卡几乎相同。我知道几个月没有退出主屏幕应用程序的人。
理想情况下,缓存有助于加快网站加载速度。禁用缓存不是答案。它也不可靠,因为您无法控制用户浏览器的行为。我们想要找到一种方法来在每次将新版本的应用程序部署到服务器时清除浏览器或服务工作者缓存。
一种简单而有效的方法
- SemVer你的部署
- 将应用程序版本捆绑到应用程序中
- 在每个构建上使用应用程序版本生成meta.json文件
- 在加载时获取meta.json并比较版本
- 当版本不匹配时强制清除缓存和硬重新加载
SemVer你的部署
使用SemVer对所有部署进行版本控制。我个人使用这三个npm命令自动增加包版本并创建一个git提交以及相应的版本标记。
- npm版本补丁 – 适用于仅修复错误的版本
- npm版本minor – 适用于具有新功能的版本,或者没有错误修复
- npm版主要 – 主要版本或突破功能
记得用–tag属性推送你的提交 – git push origin master –tags
将应用程序版本捆绑到应用程序中
在webpack构建(或相关构建工具)期间解析包版本并在应用程序中设置全局变量,以便您可以方便地在浏览器控制台中检查版本以及使用它来与最新版本进行比较。
从'{root-dir} /package.json'导入packageJson;
global.appVersion = packageJson.version;
设置完成后,您可以通过键入appVersion在浏览器控制台中检查应用程序版本。
在每个构建上使用应用程序版本生成meta.json文件
运行脚本以在应用程序的公共目录中生成meta.json文件。
添加prebuild npm脚本,该脚本将在每次构建之前生成meta.json文件。
/ * package.json * /
{
“脚本”:{
“generate-build-version”:“node generate-build-version”,
“prebuild”:“npm run generate-build-version”,
//其他脚本
}
} / * generate-build-version.js * /
const fs = require('fs');
const packageJson = require('./ package.json');
const appVersion = packageJson.version;
const jsonData = {
版本:appVersion
};
var jsonContent = JSON.stringify(jsonData);
fs.writeFile('。/ public / meta.json',jsonContent,'utf8',function(err){
if(错误){
console.log('将JSON Object写入meta.json'时发生错误);
return console.log(err);
}
console.log('meta.json文件已保存最新版本号');
});
在每次构建之后,一旦部署了应用程序,就可以使用路径/meta.json访问meta.json,并且可以像REST端点一样获取json。它不会被浏览器缓存,因为浏览器不会缓存XHR请求。因此,即使您的包文件被缓存,您也将始终获得最新的meta.json文件。
因此,如果捆绑文件中的appVersion小于meta.json中的版本,那么我们知道浏览器缓存是陈旧的,我们需要使其无效。
您可以使用此脚本来比较语义版本 –
//来自`meta.json`的版本 – 第一个参数
//捆绑文件中的版本 – 第二个参数
const semverGreaterThan =(versionA,versionB)=> {
const versionsA = versionA.split(/ ./ g);
const versionsB = versionB.split(/ ./ g);
while(versionsA.length || versionsB.length){
const a = Number(versionsA.shift());
const b = Number(versionsB.shift());
// eslint-disable-next-line no-continue
如果(a === b)继续;
// eslint-disable-next-line no-restricted-globals
返回a> b || isNaN(b)中;
}
返回false;
};
您也可以在我的GitHub示例中找到此代码
在加载时获取meta.json并比较版本
安装App时,获取meta.json并将当前版本与服务器中的最新版本进行比较。
当版本不匹配=>强制清除缓存和硬重载时版本相同=>渲染应用程序的其余部分
我已经构建了一个CacheBuster组件,它将强制清除缓存并重新加载站点。该逻辑适用于大多数站点,但可以根据应用程序调整自定义案例。
/ * CacheBuster组件* /
从'../package.json'导入packageJson;
global.appVersion = packageJson.version;
const semverGreaterThan =(versionA,versionB)=> {
//来自上面代码段的代码就在这里
}
export default class CacheBuster扩展React.Component {
构造函数(道具){
超级(道具);
this.state = {
loading:true,
isLatestVersion:false,
refreshCacheAndReload:()=> {
console.log('清除缓存和硬重载…')
if(caches){
//应使用caches.delete()清除服务工作者缓存
caches.keys()。then(function(names){
for(let name of names)caches.delete(name);
});
}
//删除浏览器缓存和硬重新加载
window.location.reload(真);
}
};
}
componentDidMount(){
取( '/ meta.json')
.then((response)=> response.json())
.then((meta)=> {
const latestVersion = meta.version;
const currentVersion = global.appVersion;
const shouldForceRefresh = semverGreaterThan(latestVersion,currentVersion);
if(shouldForceRefresh){
console.log(`我们有一个新版本 – ${latestVersion}。应该强制刷新`);
this.setState({loading:false,isLatestVersion:false});
} else {
console.log(`你已经有了最新版本 – ${latestVersion}。不需要缓存刷新。);
this.setState({loading:false,isLatestVersion:true});
}
});
}
render(){
const {loading,isLatestVersion,refreshCacheAndReload} = this.state;
return this.props.children({loading,isLatestVersion,refreshCacheAndReload});
}
}
我们可以使用此CacheBuster组件来控制App组件中的渲染
/ *应用程序组件* /
class App扩展Component {
render(){
回来(
{({loading,isLatestVersion,refreshCacheAndReload})=> {
if(loading)返回null;
if(loading &&isLatestVersion){
//您可以决定强制重新加载的方式和时间
refreshCacheAndReload();
}
回来(
缓存Busting – 示例
捆绑版 – V {} global.appVersion
);
}}
);
}
}
您还可以在此处找到这两个组件的代码 –
缓存无效化 – CacheBuster.js
当版本不匹配时强制清除缓存和硬重新加载
每次加载应用程序时,我们都会检查最新版本。根据应用程序版本是否陈旧,我们可以决定以不同方式清除缓存。
例如,
- 您可以在渲染应用程序之前进行硬重新加载
- 您可以显示模态/弹出窗口,要求用户单击按钮并触发硬重载
- 当应用程序空闲时,您可以进行硬重新加载
- 您可以使用setTimeout()在几秒钟后重新加载
您可以在此repo – cache-busting示例中找到此帖子中的完整代码和一个工作示例
这就是所有人。如果您对此方法有任何反馈(好的和坏的),请在评论中告诉我。
缓存破坏很有趣。 ?
最初发布于https://dineshpandiyan.com。