workbox icon indicating copy to clipboard operation
workbox copied to clipboard

How to cancel downloading media such as videos when navigating away

Open PlopTheReal opened this issue 3 years ago • 5 comments

Library Affected: workbox 5.1.4 (via next-offline 5.0.5)

Browser & Platform: Google Chrome 90.0.4430.85

Issue: When running without the service worker, fetch requests made by the browser are automatically canceled when the DOM element that contains a video or an image is removed from the DOM. With the service worker running, it starts streaming the entire files even when you navigate away from the element (such as a large video). This can end up in situations where you can download a lot of things in the background.

The following screenshot illustrate the issue: image

How could we mitigate that or simply filter out media from the service worker with workbox options?

My current settings are the following (but I'm feeling a bit lost):

	workboxOpts: {
		swDest: process.env.NEXT_EXPORT
		? 'service-worker.js'
		: 'static/service-worker.js',
		exclude: [/_error.*/, /admin.*/, /signin.*/, 'react-loadable-manifest.json', 'build-manifest.json', "_buildManifest.js"],
		navigateFallbackDenylist: [/_error.*/, /admin.*/, /signin.*/],
		// As of Workbox v5 Alpha there isn't a well documented way to move workbox runtime into the directory
		// required by Next. As a work around, we inline the tree-shaken runtime into the main Service Worker file
		// at the cost of less cacheability
		inlineWorkboxRuntime: true,
		runtimeCaching: [
			{
				urlPattern: /^https?.*/,
				handler: 'NetworkFirst',
				options: {
					cacheName: 'offlineCache',
					expiration: {
						maxEntries: 300
					}
				}
			},
			{
				urlPattern: /\.(?:jpeg|webp)$/,
				handler: 'cacheFirst',
				options: {
					cacheName: 'offlineCache',
					expiration: {
						maxEntries: 300
					}
				}
			}
		]
	},

PlopTheReal avatar Apr 29 '21 07:04 PlopTheReal

Hello @PlopTheReal!

I'm not sure what the right solution to this is, and I'll try to dig around a bit more to see if there's something triggered by Workbox's logic, or if this is something that would be an issue for any site that used a service worker to intercept Range requests for video bytes.

Before I do that, could you clarify what you mean by "navigate away from the element"? Are you talking about a scenario in which playback starts, and then the browser makes a real navigation request to a new URL on the same site, loading an entirely new page from scratch? Or are you talking about a scenario in which playback starts, and then a SPA-style transition happens, or JavaScript is used to remove the <video> element from the DOM, but the same document stays loaded?

jeffposnick avatar May 03 '21 20:05 jeffposnick

Thanks for such a feedback! Sorry I was not clear, technically it's a SPA: <video> elements are removed / added to the DOM (same document). It's not a real navigation to a new URL. So far the only solution that I was thinking about is excluding '.mp4' but it seems that my setup isn't working :

exclude: [/_error.*/, /\.map$/, 'react-loadable-manifest.json', 'build-manifest.json', "_buildManifest.js", /\.mp4$/],

The video elements looks like the following:

   <video muted={isSafari} playsInline autoPlay loop autobuffer="true" preload="auto" >
              <source src={`${video.name}.mp4#t=0.001`} type='video/mp4; codecs="avc1.640032,mp4a.40.2"' />
    </video>

To 'try' to force a cancel when the video is removed from the document, the best I've found so far is clearing the source via Javascript:

   video.pause()
   video.childNodes[0].src = ''
   delete video.childNodes[0].src
   delete video.src
   video.removeChild(video.firstChild)
   video.load()

This seems to work well on Chrome with a regular (no service worker) fetch scenario.

PlopTheReal avatar May 04 '21 07:05 PlopTheReal

Library Affected:

workbox 5.1.4 (via next-offline 5.0.5)

Browser & Platform:

Google Chrome 90.0.4430.85

Issue:

When running without the service worker, fetch requests made by the browser are automatically canceled when the DOM element that contains a video or an image is removed from the DOM.

With the service worker running, it starts streaming the entire files even when you navigate away from the element (such as a large video).

This can end up in situations where you can download a lot of things in the background.

The following screenshot illustrate the issue:

image

How could we mitigate that or simply filter out media from the service worker with workbox options?

My current settings are the following (but I'm feeling a bit lost):


	workboxOpts: {

		swDest: process.env.NEXT_EXPORT

		? 'service-worker.js'

		: 'static/service-worker.js',

		exclude: [/_error.*/, /admin.*/, /signin.*/, 'react-loadable-manifest.json', 'build-manifest.json', "_buildManifest.js"],

		navigateFallbackDenylist: [/_error.*/, /admin.*/, /signin.*/],

		// As of Workbox v5 Alpha there isn't a well documented way to move workbox runtime into the directory

		// required by Next. As a work around, we inline the tree-shaken runtime into the main Service Worker file

		// at the cost of less cacheability

		inlineWorkboxRuntime: true,

		runtimeCaching: [

			{

				urlPattern: /^https?.*/,

				handler: 'NetworkFirst',

				options: {

					cacheName: 'offlineCache',

					expiration: {

						maxEntries: 300

					}

				}

			},

			{

				urlPattern: /\.(?:jpeg|webp)$/,

				handler: 'cacheFirst',

				options: {

					cacheName: 'offlineCache',

					expiration: {

						maxEntries: 300

					}

				}

			}

		]

	},

alfodei22 avatar Jun 15 '21 20:06 alfodei22

Any update regarding this issue? It's tagged as "Need More Info". Do you need extra details?

PlopTheReal avatar Oct 01 '21 07:10 PlopTheReal

Sorry about that!

Okay, so let's take a step back and discuss two possible approaches:

Easier: ensure that the service worker doesn't intercept your .mp4 requests.

Based on what I can see from your service worker config and Network panel traffic, I don't think your .mp4 files are being precached. It looks like that first runtime caching route you have configured, that match urlPattern: /^https?.*/, is picking up everything (since that pattern will match any URL), and applying a NetworkFirst strategy to it. You could confirm this by checking in the Cache Storage Viewer in the Applications DevTools tab—I think you'll see those URLs listed under offlineCache, not the cache used for precaching.

This also means that your second runtime caching route, urlPattern: /\.(?:jpeg|webp)$/, presumably isn't getting a chance to match anything, since the first matching route takes precedence.

If you take the route that's currently uses urlPattern: /^https?.*/ to match requests and narrow it down to something more focused, you should be able to avoid responding to .mp4 requests from your service worker at all. Can you let me know what your goal is for that route—what types of traffic were you hoping to apply a NetworkFirst strategy to? Once I know that, I should be able to offer some advice about narrowing down the criteria.

You should note that in addition to supporting RegExps, the urlPattern option can take in any function that follows the matchCallback interface. This means you could provide criteria like urlPattern: ({request}) => request.destination === 'script' to, e.g., only apply the route to requests for script files. There's more info in the guide to routing.

Harder: use abortable fetch to signal from the window context to the service worker to stop a fetch() request before all of the bytes have been transferred.

This is theoretically possible, but would require writing a lot of manual code, so it wouldn't work with your current config-based service worker generation. I'd recommend going with the first approach.

jeffposnick avatar Oct 01 '21 19:10 jeffposnick