question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cache problem during deployment to production with service workers

See original GitHub issue

šŸž bug report

Description

We have 2 problems:

We have an angular app with service workers. We deployed it months ago without any problem running ng build --configuration=production. We have IIS 10 (below I added it’s configuration). Now, every time we need to do an update, we delete all deployed files and we copy new ones in site root. After this operation we start getting problems. Site doesn’t load, we get black page with some errors (errors are described below) This happens only in production environment. We have another server where we deploy app for testing before deploy to production, and here we have no problem. The difference between two environments is only the presence of a CDN in production one. After every deploy in production we also invalidate entire CDN cache.

This problem occurs in production but also on developer server where we don’t have CDN. When we deploy an update (deleting all files in site root and then copying there new ones, we expect new version is loaded when user open site. Service workers should understand a new version has been deployed comparing its version with the new one through ngsw.json file, and finally ā€œinstallā€ the correct version. This happens only if a user delete browser cache or if user do a ctrl + f5. This doesn’t happens with a simple page refresh. And this happens on every browser.

šŸ”„ Exception or Error

Error for problem 1:


Refused to execute script from https://mysite/1.5960f4f...js/ because its MIME type (text/html/ is not executable, and strict MIME type checking is enabled
and same error on other js files that are other modules files.

Error screenshot Cattura

šŸŒ Your Environment

Angular Version:


Angular CLI: 7.3.9
Node: 10.16.0
OS: win32 x64
Angular: 7.2.15
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router
... service-worker

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.13.9
@angular-devkit/build-angular     0.13.9
@angular-devkit/build-optimizer   0.13.9
@angular-devkit/build-webpack     0.13.9
@angular-devkit/core              7.3.9
@angular-devkit/schematics        7.3.9
@angular/cdk                      7.3.7
@angular/cli                      7.3.9
@angular/material                 7.3.7
@angular/pwa                      0.8.7
@ngtools/webpack                  7.3.9
@schematics/angular               0.8.7
@schematics/update                0.13.9
rxjs                              6.3.3
typescript                        3.1.6
webpack                           4.29.0

Anything else relevant?

The site is under AWS CDN (CloudFront) CDN rules cache every image, js and css

Our ngsw-config.json:


{
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html",
          "/*.css",
          "/*.js",
          "/*.(woff2)"
        ]
      }
    }, {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/assets/**",
          "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|ani)"
        ]
      }
    }
  ]
}

Our index.html:

<!doctype html>
<html lang="it">

<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <style>
        .async-hide {
            opacity: 0 !important
        }
    </style>
    <script>(function (a, s, y, n, c, h, i, d, e) {
            s.className += ' ' + y; h.start = 1 * new Date;
            h.end = i = function () { s.className = s.className.replace(RegExp(' ?' + y), '') };
            (a[n] = a[n] || []).hide = h; setTimeout(function () { i(); h.end = null }, c); h.timeout = c;
        })(window, document.documentElement, 'async-hide', 'dataLayer', 4000,
            { 'XXXXXXX': true });</script>
    <meta charset="utf-8">
    <title>Title</title>
    <base href="/">

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
    <link rel="icon" type="image/x-icon" href="favicon.ico">

    <meta name="theme-color" content="#1976d2">

</head>

<body class="body">
    <app-root></app-root>
</body>

</html>
<script>
    if (global === undefined) {
        var global = window;
    }
    if (System === undefined) {
        var System = window;
    }
</script>

We deploy app under IIS

These are some relevant parts of web.config:

<httpProtocol>
	<customHeaders>
		<remove name="X-Content-Type-Options" />
		<add name="X-Content-Type-Options" value="nosniff" />
		<remove name="X-Powered-By" />
		<remove name="Vary" />
		<add name="Vary" value="Accept-Encoding,User-Agent" />
	</customHeaders>
</httpProtocol>

...

<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
	<scheme dll="%Windir%\system32\inetsrv\gzip.dll" name="gzip" staticCompressionLevel="9" />
	<dynamicTypes>
		<add mimeType="text/*" enabled="true" />
		<add mimeType="message/*" enabled="true" />
		<add mimeType="application/javascript" enabled="true" />
		<add mimeType="application/json" enabled="true" />
		<add mimeType="*/*" enabled="false" />
	</dynamicTypes>
	<staticTypes>
		<add enabled="true" mimeType="text/*" />
		<add enabled="true" mimeType="message/*" />
		<add enabled="true" mimeType="application/javascript" />
		<add enabled="true" mimeType="application/json" />
		<add enabled="false" mimeType="*/*" />
	</staticTypes>
</httpCompression>

...

<urlCompression doStaticCompression="true" doDynamicCompression="true" />

...

<staticContent>
	<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00" cacheControlCustom="public" />
	
	<remove fileExtension=".html" />
	<mimeMap fileExtension=".html" mimeType="text/html; charset=UTF-8" />
	<remove fileExtension=".css" />
	<mimeMap fileExtension=".css" mimeType="text/css" />
	<remove fileExtension=".js" />
	<mimeMap fileExtension=".js" mimeType="text/javascript" />
	<remove fileExtension=".png" />
	<mimeMap fileExtension=".png" mimeType="image/png" />
	<remove fileExtension=".jpg" />
	<mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
	<remove fileExtension=".json" />
	<mimeMap fileExtension=".json" mimeType="application/json" />
	<remove fileExtension=".rss" />
	<mimeMap fileExtension=".rss" mimeType="application/rss+xml; charset=UTF-8" />
	<remove fileExtension=".xml" />
	<mimeMap fileExtension=".xml" mimeType="application/xml; charset=UTF-8" />
	<!-- HTML5 Audio/Video mime types-->
	<remove fileExtension=".mp3" />
	<mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
	<remove fileExtension=".mp4" />
	<mimeMap fileExtension=".mp4" mimeType="video/mp4" />
	<remove fileExtension=".ogg" />
	<mimeMap fileExtension=".ogg" mimeType="audio/ogg" />
	<remove fileExtension=".ogv" />
	<mimeMap fileExtension=".ogv" mimeType="video/ogg" />
	<remove fileExtension=".webm" />
	<mimeMap fileExtension=".webm" mimeType="video/webm" />
	<!-- Proper svg serving. Required for svg webfonts on iPad -->
	<remove fileExtension=".svg" />
	<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
	<remove fileExtension=".svgz" />
	<mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
	<!-- HTML4 Web font mime types -->
	<!-- Remove default IIS mime type for .eot which is application/octet-stream -->
	<remove fileExtension=".eot" />
	<mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
	<remove fileExtension=".ttf" />
	<mimeMap fileExtension=".ttf" mimeType="application/x-font-ttf" />
	<remove fileExtension=".ttc" />
	<mimeMap fileExtension=".ttc" mimeType="application/x-font-ttf" />
	<remove fileExtension=".otf" />
	<mimeMap fileExtension=".otf" mimeType="font/opentype" />
	<remove fileExtension=".woff" />
	<mimeMap fileExtension=".woff" mimeType="application/font-woff" />
	<remove fileExtension=".woff2" />
	<mimeMap fileExtension=".woff2" mimeType="font/woff2" />
	<remove fileExtension=".crx" />
	<mimeMap fileExtension=".crx" mimeType="application/x-chrome-extension" />
	<remove fileExtension=".xpi" />
	<mimeMap fileExtension=".xpi" mimeType="application/x-xpinstall" />
	<remove fileExtension=".safariextz" />
	<mimeMap fileExtension=".safariextz" mimeType="application/octet-stream" />
	<!-- Flash Video mime types-->
	<remove fileExtension=".flv" />
	<mimeMap fileExtension=".flv" mimeType="video/x-flv" />
	<remove fileExtension=".f4v" />
	<mimeMap fileExtension=".f4v" mimeType="video/mp4" />
	<!-- Assorted types -->
	<remove fileExtension=".ico" />
	<mimeMap fileExtension=".ico" mimeType="image/x-icon" />
	<remove fileExtension=".webp" />
	<mimeMap fileExtension=".webp" mimeType="image/webp" />
	<remove fileExtension=".htc" />
	<mimeMap fileExtension=".htc" mimeType="text/x-component" />
	<remove fileExtension=".vcf" />
	<mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
	<remove fileExtension=".torrent" />
	<mimeMap fileExtension=".torrent" mimeType="application/x-bittorrent" />
	<remove fileExtension=".cur" />
	<mimeMap fileExtension=".cur" mimeType="image/x-icon" />
	<remove fileExtension=".webapp" />
	<mimeMap fileExtension=".webapp" mimeType="application/x-web-app-manifest+json; charset=UTF-8" />
</staticContent>

...

<location path="index.html">
	<system.webServer>
	  <staticContent>
		<clientCache cacheControlMode="DisableCache" cacheControlMaxAge="0.00:00:00" />
	  </staticContent>
		<httpProtocol>
			<customHeaders>
				<add name="Cache-Control" value="no-cache, no-store, must-revalidate" />
				<add name="Pragma" value="no-cache" />
				<add name="Expires" value="-1" />
			</customHeaders>
		</httpProtocol>  
	</system.webServer>
</location>

Our package.json:


{
  "name": "xxx",
  "version": "0.0.0",
  "scripts": {
    "ng": "node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng",
    "start": "npm run ng -- serve",
    "build": "npm run ng -- build",
    "test": "npm run ng -- test",
    "lint": "npm run ng -- lint",
    "e2e": "npm run ng -- e2e",
    "analyze": "webpack-bundle-analyzer dist/stats.json",
    "compodoc": "npx compodoc -p src/tsconfig.app.json",
    "build:stats": "ng build --stats-json"
  },
  "private": true,
  "dependencies": {
    "@agm/core": "1.0.0-beta.7",
    "@agm/js-marker-clusterer": "1.0.0-beta.3",
    "@angular/animations": "7.2.15",
    "@angular/cdk": "7.3.7",
    "@angular/common": "7.2.15",
    "@angular/compiler": "7.2.15",
    "@angular/core": "7.2.15",
    "@angular/forms": "7.2.15",
    "@angular/http": "7.2.15",
    "@angular/material": "7.3.7",
    "@angular/platform-browser": "7.2.15",
    "@angular/platform-browser-dynamic": "7.2.15",
    "@angular/platform-server": "7.2.15",
    "@angular/pwa": "0.8.7",
    "@angular/router": "7.2.15",
    "@angular/service-worker": "7.2.15",
    "@satispay/web-button-factory": "1.4.3",
    "angular4-social-login": "1.1.1",
    "braintree-web": "3.52.1",
    "braintree-web-drop-in": "1.20.1",
    "classlist.js": "1.1.20150312",
    "codice-fiscale-js": "2.1.0",
    "core-js": "2.5.4",
    "domino": "2.1.3",
    "express": "4.17.1",
    "font-awesome": "4.7.0",
    "hammerjs": "2.0.8",
    "js-marker-clusterer": "1.0.0",
    "lory.js": "2.3.3",
    "md5": "2.2.1",
    "moment-mini-ts": "2.20.1",
    "ng-lazyload-image": "5.1.2",
    "ng2-cookies": "1.0.12",
    "ngx-gallery": "4.1.2",
    "ngx-json-ld": "0.3.1",
    "ngx-loadable": "1.0.10",
    "ngx-responsive": "6.0.0",
    "ngx-swiper-wrapper": "4.9.0",
    "paypal-checkout": "4.0.285",
    "rxjs": "~6.3.3",
    "tslib": "1.9.0",
    "zone.js": "~0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "0.13.9",
    "@angular/cli": "7.3.9",
    "@angular/compiler-cli": "7.2.15",
    "@angular/language-service": "7.2.15",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "~8.9.4",
    "codelyzer": "~4.5.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~3.1.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "0.2.2",
    "node-ts": "5.0.1",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.11.0",
    "typescript": "3.1.6",
    "webpack-bundle-analyzer": "3.3.2"
  }
}

I suppose problem 1 is related to CDN, but I don’t understand why. It seems that somewhere (I think on user’s browsers, in service workers) something continue to have reference to old files (the ones we delete before copying there new app version). And this problem seems to be related to problem number 2, where it seems new version is not loaded the first time user access it.

Maybe we are doing something wrong, or we have an incorrect configuration, but we can’t find it.

Thanks for help

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:11 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
spock123commented, Jan 27, 2020

I have similar problem with Firebase hosting and when I search online I see other people reporting similar issues. Please keep us posted further updates about this.

Firebase hosting has a 1 hour default caching policy. If you don’t specifically specify that you do not want caching on the service worker files, you’ll get this 1 hour cache.

What you do is that in your firebase.json you insert the following in the headers section:

.... 
"headers": [ 
   ... other headers,
     {
       "source": "**/(ngsw-worker.js|ngsw.json)",
       "headers": [
         {
           "key": "Cache-Control",
           "value": "no-cache, no-store, must-revalidate"
         }
       ]
     },
0reactions
angular-automatic-lock-bot[bot]commented, Feb 27, 2020

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Strategies for Service Worker Caching for Progressive Web ...
This post goes through the issues with service worker caching, strategies that can be followed to have an ideal experience with service ......
Read more >
Expectations around service worker deployment
Problems arise in situations when unversioned static assets are cached during runtime using these strategies. If a website's functionality isĀ ...
Read more >
Service worker in production - Angular
The service worker either returns a cached response or sends the request to the server, depending on the state and configuration of the...
Read more >
Service Workers in Production - web.dev
This automatically triggers the service worker update flow, in which the new resources are cached and out of date resources are purged.
Read more >
What should I do to update service workers and cached PWA ...
The serviceworker.js needs to have a fixed file name (no hash in filename), meaning my CDN will cache that file for a long...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found