When service workers met framesets

Oh boy, do I have some obscure browser behaviour for you!

To set the scene…

I’ve been writing here in my online journal for almost twenty years. The official anniversary will be on September 30th. But this website has been even online longer than that, just in a very different form.

Here’s the first version of adactio.com.

Like a tour guide taking you around the ruins of some lost ancient civilisation, let me point out some interesting features:

  • Observe the .shtml file extension. That means it was once using Apache’s server-side includes, a simple way of repeating chunks of markup across pages. Scientists have been trying to reproduce the wisdom of the ancients using modern technology ever since.
  • See how the layout is 100vw and 100vh? Well, this was long before viewport units existed. In fact there is no CSS at all on that page. It’s one big table element with 100% width and 100% height.
  • So if there’s no CSS, where is the border-radius coming from? Let me introduce you to an old friend—the non-animated GIF. It’s got just enough transparency (though not proper alpha transparency) to fake rounded corners between two solid colours.
  • The management takes no responsibility for any trauma that might befall you if you view source. There you will uncover JavaScript from the dawn of time; ancient runic writing like if (navigator.appName == "Netscape")

Now if your constitution was able to withstand that, brace yourself for what happens when you click on either of the two links, deutsch or english.

You find yourself inside a frameset. You may also experience some disorienting “DHTML”—the marketing term given to any combination of JavaScript and positioning in the late ’90s.

Note that these are not iframes, they are frames. Different thing. You could create single page apps long before Ajax was a twinkle in Jesse James Garrett’s eye.

If you view source, you’ll see a React-like component system. Each frameset component contains frame components that are isolated from one another. They’re like web components. Each frame has its own (non-shadow) DOM. That’s because each frame is actually a separate web page. If you right-click on any of the frames, your browser should give the option to view the framed document in its own tab or window.

Now for the part where modern and ancient technologies collide…

If you’re looking at the frameset URL in Firefox or Safari, everything displays as it should in all its ancient glory. But if you’re looking in Google Chrome and you’ve visited adactio.com before, something very odd happens.

Each frame of the frameset displays my custom offline page. The only way that could be served up is through my service worker script. You can verify this by opening the framest URL in an incognito window—everything works fine when no service worker has been registered.

I have no idea why this is happening. My service worker logic is saying “if there’s a request for a web page, try fetching it from the network, otherwise look in the cache, otherwise show an offline page.” But if those page requests are initiated by a frame element, it goes straight to showing the offline page.

Is this a bug? Or perhaps this is the correct behaviour for some security reason? I have no idea.

I wonder if anyone has ever come across this before. It’s a very strange combination of factors:

  • a domain served over HTTPS,
  • that registers a service worker,
  • but also uses framesets and frames.

I could submit a bug report about this but I fear I would be laughed out of the bug tracker.

Still …the World Wide Web is remarkable for its backward compatibility. This behaviour is unusual because browser makers are at pains to support existing content and never break the web.

Technically a modern website (one that registers a service worker) shouldn’t be using deprecated technology like frames. But browsers still need to be able support those old technologies in order to render old websites.

This situation has only arisen because the same domain—adactio.com—is host to a modern website and a really old one.

Maybe Chrome is behaving strangely because I’ve built my online home on ancient burial ground.

Update: Both Remy and Jake did some debugging and found the issue…

It’s all to do with navigation preloads and the value of event.preloadResponse, which I believe is only supported in Chrome which would explain the differences between browsers.

According to this post by Jake:

event.preloadResponse is a promise that resolves with a response, if:

  • Navigation preload is enabled.
  • The request is a GET request.
  • The request is a navigation request (which browsers generate when they’re loading pages, including iframes).

Otherwise event.preloadResponse is still there, but it resolves with undefined.

Notice that iframes are mentioned, but not frames.

My code was assuming that if event.preloadRepsonse exists in my block of code for responding to page requests, then there’d be a response. But if the request was initiated from a frameset, it is a request for a page and event.preloadRepsonse does exist …but it’s undefined.

I’ve updated my code now to check this assumption (and fall back to fetch).

This may technically still be a bug though. Shouldn’t a page loaded from a frameset count as a navigation request?

Responses

Andy Davies

Look at a WPT waterfall, in the requests there’s an undefined.gif and undefined.gif that get redirected to the 404 page Wonder if that’s the source of the issue?

# Posted by Andy Davies on Thursday, March 11th, 2021 at 12:16pm

6 Likes

# Liked by Dominik Schwind on Thursday, March 11th, 2021 at 11:31am

# Liked by Martin Auswöger on Thursday, March 11th, 2021 at 12:24pm

# Liked by Chris Burnell on Thursday, March 11th, 2021 at 3:05pm

# Liked by Marty McGuire on Thursday, March 11th, 2021 at 5:40pm

# Liked by Marc Görtz on Thursday, March 11th, 2021 at 9:20pm

# Liked by Viorel Mocanu on Wednesday, March 17th, 2021 at 12:14pm

Related posts

Trust

I’m trying to understand why developers would trust third-party code more than a native browser feature.

Going offline with microformats

The h-entry microformat and the Cache API are a perfect pairing for offline pages.

Navigation preloads in service workers

A little performance boost for your network-first service worker strategy.

The trimCache function in Going Offline …again

There’s a bug in the cache-trimming code I wrote.

Timing out

A service worker strategy for dealing with lie-fi.

Related links

minimum interesting service worker

An interesting idea from Tantek for an offline page that links off to an archived copy of the URL you’re trying to reach—useful for when you’re site goes down (though not for when the user’s internet connection is down).

Tagged with

Tagged with

How to make MPAs that are as fast as SPAs | Go Make Things

The headline is a little misleading because if you follow this advice, your multi-page apps will be much much faster than single page apps, especially when you include that initial page load of a single page app.

Here’s a quick high-level summary of what I do…

  1. Serve pre-rendered, mostly static HTML.
  2. Inline everything, including CSS and JavaScript.
  3. Use mostly platform-native JavaScript, and as little of it as possible.
  4. Minify and gzip all the things.
  5. Lean heavily on service workers.

That’s an excellent recipe for success right there!

Tagged with

Add a Service Worker to Your Site | CSS-Tricks - CSS-Tricks

Damn, I wish I had thought of giving this answer to the prompt, “What is one thing people can do to make their website better?”

If you do nothing else, this will be a huge boost to your site in 2022.

Chris’s piece is a self-contained tutorial!

Tagged with

Getting Started with PWAs [Workshop]

The slides from Aaron’s workshop at today’s PWA Summit. I really like the idea of checking navigator.connection.downlink and navigator.connection.saveData inside a service worker to serve different or fewer assets!

Tagged with

Previously on this day

4 years ago I wrote A curl in every port

Postel’s port numbers.

5 years ago I wrote T minus one

‘Twas the night before Web@30, and not a particle was stirring, not even a meson.

8 years ago I wrote Accessible progressive disclosure

Using ARIA attributes to power JavaScript functionality.

10 years ago I wrote Return of the Responsive Day Out

It’s baaa-ack!

11 years ago I wrote Off-canvas horizontal lists

Sharing a pattern that didn’t quite work.

13 years ago I wrote Drupalcon in Chi-town

Back in Chicago.

15 years ago I wrote Texapalooza

South by Southwest bound.

19 years ago I wrote Austin update

I’ve arrived in Austin. The South by SouthWest festival hasn’t started yet and I’m already having a great time meeting some wonderful people.

21 years ago I wrote My glamourous life

The last couple of weeks have been pretty busy for me.

22 years ago I wrote Cat Hospital starring Frank the Cat

You can keep an eye on the progress of poor Frank the cat who has become something of a celebrity: