Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TroubleShooting Cache in Prod #38

Open
fayeah opened this issue Sep 27, 2020 · 0 comments
Open

TroubleShooting Cache in Prod #38

fayeah opened this issue Sep 27, 2020 · 0 comments

Comments

@fayeah
Copy link
Owner

fayeah commented Sep 27, 2020

线上有一个问题,然后在开发环境和测试环境都没有办法重现,那么就是用搜索引擎和Angular代码官方文档各种spike和research。

问题是什么

那么的问题是我们新加的一个navigation(导航)没有显示,但是当用户清除了该页面的缓存,重新刷新页面,问题依然存在。

image

只有当用户彻底清除了浏览器的cache之后,再次刷新页面,才得以看到新的feature。

image

问题之后的初步想法

当出现这个问题的时候,我脑袋里面第一个想法就是version没变。

以前遇到过一个icon在线上无法更新的问题,是因为文件名字没有改变,version也没有改变,所以图片会被浏览器缓存。那么解决的办法就是给图片加上hash,每次部署的时候改变hash值,从而更新图片内容。

Spike/Research

首先,我想要重现这个问题,但是本地始终无法重现。尝试重现的步骤:

  1. 运行了prod的build npm run build:prod,会在dist目录下生成bundle文件的列表

image

  1. 进入dist目录,使用http-server启动一个服务npx http-server,然后打开index.html即可看到build之后的网页

当我更新了代码,重复上述的步骤,发现我本地的bundle文件内容是更新了的,所以在本地无法重现的情况下,继续探索。

version 没有改变
我发现在build多次之后有些bundle文件的version改变了,比如main.{version_no}.js,但是有很多bundle文件却没有改变,比如那些我们使用懒加载的模块1.{version_no}.js等,而我去检查了angular的配置文件angular.json,对于version的改变是对于所有都要变的:

"configurations": {
  "production": {
    "optimization": true,
    "outputHashing": "all",        // Define the output filename cache-busting hashing mode.
    "sourceMap": false,
    "extractCss": true,
    "namedChunks": false,
    "aot": true,
    "extractLicenses": true,
    "vendorChunk": false,
    "buildOptimizer": true,
    "serviceWorker": true          // Generates a service worker config for production builds.
  }
}

解决办法
那么目前能想到的方案就是在build之后对bundle文件加一个timestring的query,使得每次build之后所有的bundle文件version都有所改变:

stage('Append version to js file') {
  sh 'cd dist' +
    ' && export version_time=$(date +%Y%m%d%H%M%S)' +
    ' && echo $version_time' +
    ' && sed -i \'s/.html"/.html?v=\'$version_time\'"/g\' ngsw.json' +
    ' && sed -i \'s/.js"/.js?v=\'$version_time\'"/g\' ngsw.json' +
    ' && sed -i \'s/.js"/.js?v=\'$version_time\'"/g\' runtime*.js' +
    ' && sed -i \'s/.js"/.js?v=\'$version_time\'"/g\' index.html'
}​

index.html的Cache-Control
对于index.html来说,我们希望每次build都要重新加载,所以对这个文件我们不需要缓存,而我们使用的是nginx进行代理,所以我们做了一件事情,就是在index.html的header加上no-cache的关键字:

location / {
  try_files $uri $uri/ /index.html;
}

location = /index.html {
  expires 0;
  add_header Cache-Control no-cache;
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  add_header X-Frame-Options "sameorigin";
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";
}​

Service Worker的影响
猜测可能与service worker有关系,但是无从得证。项目确实用到了service worker,但是也只是对静态资源assets/下面的资源进行缓存,而且service worker在得知app整个version变化之后也会重新更新资源。

总结一下,

  • 对build之后的 bundle 文件加version
  • 对 index.html 加上no-cache,不缓存
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant