352: Caching, Service Workers, and JavaScript with Scott Jehl

Download MP3

Scott Jehl is our guest and we're talking about accessibility, jQuery history, progressive enhancement in modern javascript, critical CSS, service workers, maintenance of a server, and other fun stuff.



Scott Jehl

Web · Social

Designer / developer at Filament Group. Author of Responsible Responsive Design.

Time Jump Links

  • 02:26 Guest introduction
  • 03:54 Accessibility coming to head in a new way
  • 17:43 Sponsor: Netlify
  • 19:47 Everything becomes a website
  • 23:14 A bit of jQuery history
  • 24:32 How does progressive enhancement look in modern javascript?
  • 35:54 Sponsor: Digital Ocean
  • 36:41 Critical CSS
  • 49:02 What about maintenance?
  • 52:42 Using service worker instead of cookies
  • 02:40 Grunticon


[Banjo music]

MANTRA: Just Build Websites!

Dave Rupert: Hola, Shop-o-maniacs. Bienvenido a ShopTalk Show, mi amo Dave Rupert y con mi amigo es el jefe de CSS-Tricks, el senior Chris Coyier.

Chris Coyier: Hey!

Dave: Hola, Chris.

Chris: Also, hola. Yeah.

Dave: Yeah.

Chris: Dave is just shaking the sand out of his sandals, back from a trip on the beach.


Dave: Always good times. How are you, Chris? Welcome back. Are we still talking about websites? Are they still around? [Laughter]

Chris: Uh, for better or worse, Dave, they still are, and we have somebody who probably shakes the sand out of his sandals every day down in Florida, Scott Jehl. Hey, Scott.

Scott Jehl: Hey. Hola, rather.


Chris: Indeed.

Dave: I've actually used all of the Spanish I possess, so we can switch. I apologize.

Scott: I was impressed.

Dave: All right.

Chris: I was too, dang it, and jealous a little bit, you know.

Scott: [Laughter]

Dave: Yeah.

Chris: What about your kids, Dave? Are you going to Spanish them up? Texas probably has lots of Spanish speaking action.

Dave: Oh, I should. Well, we should. More discerning parents send their kids to bilingual schools and set them on a path. Our kids are not. My son….

Chris: I didn't mean to shame you, Dave. I don't care that much. I just think it's interesting.

Dave: No, no. No, no. My son is the only kid story I'll share here. My son was like, "Hey, dad. I know how to say water in Spanish." I was like, "Oh, wow, man. I'm so glad they're teaching you. How do you say it?" He goes, [with an accent] "Water."


Dave: I was like, "That is not it."


Scott: Good effort, though. The interest is there.

Dave: Yeah, he just makes up Spanish words, which I don't know if that's good or bad. Then he also draws Chinese characters, like Japanese Kanji on his body as, like, tattoos, so who knows where he's going in life.

Chris: Five points for creativity. Low points for accuracy.

Scott: Yeah, yeah.

Chris: Yeah, I'll take creativity any day.

Scott: Yeah, exactly. Yeah.

Dave: He's an artist.

Chris: I just ran into Scott in Seattle.

Scott: Yeah.

Chris: We were there for An Event Apart, a little conference series kind of thing that we were both speaking at, so that was cool, huh?

Scott: Yeah, great conference. It was good.

Chris: This has been your kind of vibe for a while, maybe forever. You wrote a book also called "Responsible Responsive Design," which is thematically related. The name of your talk was Move Fast and Don't Break Things. Can you give us a sense of where you're at, what you like thinking and talking about when it comes to their making websites stuff?

Scott: Yeah, I mean I think, in the case of that book title, it's sort of an additive thing. It's not that responsive design was irresponsible, by default. [Laughter] It's more of integrating other aspects of the priorities that people should care about when they're building websites these days. Making an interface respond to different viewport sizes would be definitely one of those but, on top of that, I've been kind of focusing on the intersection of performance and accessibility with those other aspects of responsive design. I think that's kind of an interesting place to exist because they all sort of complement each other, but there are challenges that you have to make them all work together, I think.

Chris: It's an interesting time for the accessibility talk, too. It's always an issue.

Scott: Yes.

Chris: It always seems to be coming to ahead in a new way. Maybe the hot topics right now are, "Oh, is this new JavaScript heavy world of frontend development a kind of net loss for accessibility or is there potential for a net gain there? What's the conversation like that about?"

Scott: Right. Right.

Chris: Then there's this big WebAIM study that was published that basically just says, "Hey, it's been bad. Was bad. Has been bad. Is bad. Going to be bad."

Scott: Yeah, potentially getting worse. Right.

Chris: Yeah.

Scott: Yeah. Yeah, it's an interesting question. I think that the promise of any framework is that it should make things like accessibility easier to attain. I've seen that firsthand. I was on the jQuery mobile team for quite a while and we had a huge accessibility focus on that project. I would like to think that it helped people build apps on the Web that were more accessible, you know, more easily than it would have been if they were trying to build the same thing without any framework or helpers.

Chris: Sure. I remember there was a lot of sliding happening in that app.

Scott: Yeah. Yeah, at the time, it was kind of early stages of the same sort of transition we're seeing now into more--I don't know--single page kind of experiences where things animate and transition between views instead of a full refresh and all that. We were doing that.

Chris: Which is sometimes desirable because a native app can do that. I guess it's been proven to be a pretty nice design pattern. Because we literally can't do that, there is no way to do that if the whole page refreshes, which would be interesting if the native Web took that on as a possibility.

If you want to slide out one page and slide in another page, you're kind of in SPA territory. But with that comes this whole slew of performance challenges and accessibility challenges and stuff. You took them head on ages ago with jQuery mobile. That's interesting.

Scott: Yeah. I think we had a lot of people helping, so we had screen reader testing. I think it was definitely challenging, though, especially as soon as you introduce those aspects of sort of reproducing what a browser does well with JavaScript. You have to own a lot of behavior that you wouldn't otherwise need to do, right? [Laughter]

Chris: Right.

Scott: If you're refreshing the page, you have to update the URL in a way that makes sense and is deep linkable.

Chris: Right.

Scott: Notify the user of what changed in the interface. There's a whole lot the browser does for us, as you know. Once you start doing that--

Chris: Yeah, that all of a sudden you need to do yourself.

Scott: Right.

Chris: Lately, I've been thinking about -- I think this is -- let's say you're an HTML CSS person and you're taking your first steps into JavaScript. There are lots of people in this scenario, lots of people going through curriculum perhaps in school that's like this. I remember it pretty clearly back in the jQuery days as well. That was my first step into JavaScript. I remember how powerful it was when you learn how to change a class.

Scott: Right.

Chris: Toggle it on and off, change it from one class to another class, or whatever. If that's the one thing that you know how to do in JavaScript as a designer/developer, taking their first steps into JavaScript or whatever, it's so empowering, especially if you know CSS well. You're like, "Oh! Let me. Okay, that class is gone now, so I can slide away something. I can slide in something new. I can hide a tab and reveal another tab and add an active class on the actual tab part of the tab so I can have it have a special background color to signal that it's active."

I was thinking how cool that felt and how powerful now I am as a designer. Now I think back on that and be like, "I wonder if that was dangerous, in a way," because the minute you're into that, all you're doing is changing classes and worrying about what it looks like only to find out later that it's like, "I didn't deal with focus. I didn't deal with keyboard events. I didn't deal with ARIA roles that are relevant to this."

Scott: Right.

Chris: I didn't do any of that work.

Scott: Right. Yeah, it's almost maybe more of a useful model to think about styling against ARIA attributes these days or something that's just sort of like more tightly couples you to the accessible version of the thing already since classes are just not really exposed.

Chris: Even that worries me sometimes because there's this talking point. I don't mean to -- I almost feel unqualified here a little bit, but there's this -- I think it was even part of that report, too. Websites that use ARIA roles are generally worse that ones that don't.

Scott: Yeah. It takes a lot of work and I can't claim to have it down either, but it takes so much research and work to find the right patterns because, yeah, it just gives you so many tools to expose more meaning of what's going on, but it can be hard to figure out which particular combination of ARIA attributes are right for each situation. More often than not, I've found that, when we go into testing with people who use screen readers every day and also happen to have a development background, we end up refactoring to something simpler than we started with.

Chris: Oh, wow.

Dave: Yeah. You think the ARIA role equals menu would be super helpful to construct a menu. It is not. It is absolutely not for that….

Scott: Yeah. Yeah, collapsible elements that I always marked up as sort of a menu pattern, like you were talking about, and later realized that just a button that proceeds a div that shows and hides with relatively little information about that as long as the button says, "Toggle the thing that comes next," in so many words.

Dave: Yeah.

Scott: That can be preferable, you know, so it's hard to know those patterns. To your credit, the accessibility project site has some really good examples of patterns that you can start with.

Dave: Yeah. I think that was just born out of my own ignorance. I was just like, we have to boil this ocean and kind of come down to figure out how it actually works, you know?

Scott: Yeah. Yeah, it's tricky.

Dave: I was thinking, back to the "you have to do everything," like when you're in SPA territory. Even this morning, I was looking at this app with the hamburger menu on my phone.

Chris: Mm-hmm.

Dave: It's a Nuxt app. I click a link and I'm like, "Well, nothing happened." I was like, "Oh, it's all behind the hamburger menu." [Laughter] Now, instead of a page refresh, destroying everything and closing the hamburger, I have to go through and hook into the router or something and, on some page event thing, set the is menu expanded global state variable to none or false.

There's a tipping point where you're like, "Convenience, convenience, convenience. Oh, no, now everything is my responsibility."

Scott: Yeah, it's amazing how that adds up. It can start as such a simple problem and then you reach a certain point where, all of a sudden, you have all this complexity to manage. I've thought about even just the classic example of a custom select menu that, in the past, we would kind of make the decision of using a native selector not based on whether or not we needed to style the option elements in a certain way, like say with country flags or something like that that you just couldn't do otherwise, you know, putting icons in them, especially on mobile platforms.

We would go that route. Okay, we'll use an unordered list and we'll mark it up with ARIA and we'll start to toggle. All of a sudden, we've got 1,000-plus lines of JavaScript toggling everything and we basically have built an app just for this little component. [Laughter]

Chris: Right, and the keyboard stuff is tricky as well.

Scott: Yes, absolutely.

Chris: Those arrow keys need to work and the enter key needs to work. Is it always the enter key?

Scott: Right.

Chris: Does the escape key need to be bound or something, too? Then there's cross-browser differences with that. Very tricky.

I have an app right now that has a native select menu in it, which is great. I err on doing that. Wasn't it you who recently wrote a little bit, like, "Oh, it's actually gotten a lot better recently," kind of thing?

Scott: Yeah. Yeah, I did put an article up recently that it's sort of built on a past article that Todd from Filament had written that got it most of the way there. There were a couple workarounds that were required for Internet Explorer.

Chris: You've got to unset things, right?

Scott: Yeah.

Chris: Appearance none, kind of thing, and build it up from scratch.

Scott: Yeah.

Chris: But there are still problems with that.

Scott: Yeah, and some before and after kind of hacks. I believe that an early iteration even had a wrapper element or something around the select just to get a background.

Chris: Yeah.

Scott: Yeah, so that recent take was like, you know, how close are we now? Can we just style this stupid thing? [Laughter]

Chris: You can! You can!

Scott: …straight up.

Chris: It's such good work.

Scott: Yeah.

Chris: I remember using it that way when it came out.

Scott: [Laughter]

Chris: I was like, oh, I'm using it.

Scott: That's great. Yeah, so it's totally doable now. It falls back pretty well.

Chris: The situation I'm in is, here, look; we have this new -- I'm populating it with X number of things, right? There's a server call that what's in that dropdown menu is dynamic based on user generated content. We're trying to avoid ever writing queries that return X, that return infinite number of things, right?

Scott: Right.

Chris: Everything has got to be paginated or whatever, of course. Then what? It's kind of like you want to build this UI then that has ten items in it, but little arrows too, so that if you don't find the one you're looking for, you can paginate through them.

Scott: Yeah.

Chris: Then it's like, can we still get away with the native select or does that complicate things? To rip things out of a native select and put them back in, is that acceptable?

Scott: Yeah. Yeah, there are just those little features that always seem to put you over the hill into custom menu land. [Laughter] It's just a whole new problem, right?

I can picture a select that has multiselect, for example. You might want it at the bottom of the list to be able to clear all the checks or something like that with a little button.

Chris: Yeah, sure.

Scott: Stuff that's just really common in facetted search and any--

Chris: I was looking at one yesterday. I don't know why this is so pertinently perfect here. Atlassian has a style guide thing or a pattern library, and their select menu is hot.

Scott: Mm-hmm.

Chris: It's got all the stuff you could ever want: the keyboard stuff, theoretically the accessibility stuff. I can't vouch for that, so I'm sure if it really got drilled for accessibility, it could find problems, but it looked good to me. I was like, "Wow! These keyboard events work. It's got single select, multiselect, clearing the selects, country select." I was like, "Dang, this is slick."

Scott: Yeah. Yeah, I'm of the point of view now that if you have to creep into the custom select land then, really, we should be adopting something that's prebuilt and open source like that Atlassian one that's really been….

Chris: Right. Can you imagine listening to this conversation and be like, "I don't have any of these problems, y'all. I use Bootstrap, or I use whatever because I'm afraid of those problems and this framework has promised to delivery me freedom from those problems."

Scott: Yeah. Yeah. I mean, yeah, getting back to the whole question you started with, I think that's, hopefully, despite that WebAIM article and the findings. It was sort of damning to see that the impact of modern frameworks on accessibility has been negative so far. I would hope that, with a little change in priorities amongst the teams of those particular frameworks that it could be a dramatically good thing.

Chris: It might be. Yeah, maybe. We could at least hope that little changes of accessibility things can go further because of the massive adoption of them.

Scott: Right. Yeah.

Chris: Well, maybe.

Scott: Yeah.

Chris: Oh, gosh. So much to think about here.

[Banjo music]

Chris: This episode of ShopTalk Show was brought to you in part by Netlify. They're so good. I dang near tear up thinking about how good Netlify is sometimes.

It's like a host for your files but, of course, it just does so much more than that. If you just focus on that for a minute, I feel like most uses of it is kind of like repo-based. You tell Netlify, "Hey, I've got this repo of files. It's on GitHub," or wherever. You're like, "Just watch the master branch. If I push something to master branch," of course this is all configurable, "then just deploy it."

The deployment is like, they'll give you a URL that it's pointed at, of course, but you can map it to whatever URL you want, of course. Then it also gives you all these little immutable URLs for every push. You can have it build another branch for you, like, "Watch my feature brand," and it'll give you a little special URL to check out that. It's like your free little staging environment to check out before it goes live.

Their hosting is static in the best possible way. It's like even all your HTML, CSS, JavaScript files, whatever, JAMstack, yeah, are hosted on the edge, like in CDN, so they're just smokin' fast, these immutable deploys that are easy to roll back and change. No, well, not change because that's the point of immutability, but you know what I mean. Just push a new version of it. They just are these URLs that just last forever with every push you make. It's incredible.

It's JAMstack, so it's super-fast, but then could you host your React app there? Absolutely, because that's the JavaScript and APIs part, the first two letters of JAMstack. Then it hits some data source somewhere and gets the data that it needs and becomes the application it was meant to be. Or you're running a static site generator and you're just deploying the whole folder or the whole site. I've used it that way.

I have this kind of mini-site where I'm tracking all these upcoming conference that have to do with frontend Web design and development. It's built with 11ty. It's using Netlify CMS to help me manage the content on it. It's just such a beautiful setup. I love it. So, anyway, check out Netlify. It's sweet. You're definitely not going to regret it.

[Banjo music]

Chris: You talked about lots more stuff at your talk. One thing that was on my mind is when you mentioned that select menu and, basically, you're designing a whole app there. I thought of Dave's kind of jokey sentiment that comes up relative to, like, if you have a card component, basically it's a website.

Scott: [Laughter] Right. Yeah, it's funny. I think any developer has the same sort of mindset where you look at it. You look at the problem initially. You don't see the scope that it could become one day. You just see what it is at that moment and you think, "Oh, I could write a very small amount of code to handle this and it'll be really elegant." That's a dangerous place to start, I've learned, because it just grows with feature additions.

All of a sudden, you get to a point where your code that you've written has become difficult to maintain and you need, actually, something much fuller featured and it's a really painful point where you need to integrate that, you know, decide to integrate that framework or whatever it is.

Chris: We've been talking a lot about frameworks, but I think you occupy an interesting position in the JavaScript community, in a way. Respected JavaScript author, Scott Jehl, working on the Web for a long time; speaker at conferences all over; works at an agency that builds big websites for big clients and delivers. You're on a small team and all that stuff but are definitely not a framework guy. I don't think you've tossed your hat in the ring for any particular framework. In fact, if you hear Scott talking about JavaScript, it's usually about some lower level service workers or whatnot or something very fundamental performance related or something. That's just interesting.

Scott: Yeah. I guess that would be an accurate depiction of what we're doing these days. It's always very dependent.

We're an agency. We work for clients. Whatever our clients happen to be using at the time is the type of site that we will be either building fresh or most often just adding to and improving for them. At the moment, we don't have many clients who are doing React sites, for example, if that's the framework that we're referring to, or Vue or something like that.

We are using Vue more and more. I really like Vue for documentation.

Dave: Meh.

Scott: Not necessarily running Vue on the site side itself at the user facing side, but we use it in our docs to make all these little component pages really smart so the client can go in and configure things.

Chris: So, VuePress or your own deal?

Scott: Just little Vue one-off templates.

Chris: Okay.

Scott: Yeah. For our current clients, that's sort of the extent of it. I mean I've been on teams in the past. I was on the jQuery team. I made the jQuery logo. [Laughter] I was there since the very beginning.

Chris: Hey!

Scott: I'm not … framework in any way.

Chris: That's a fun fact that I didn't know.

Scott: [Laughter] Yeah.

Chris: The little crescent moons of love there is a Scott Jehl design?

Scott: Yeah. You may know this, but the original jQuery logo was a devo hat and it was new wave JavaScript. It at one point decided we needed to give it an evolution, and those crescent moons are in the negative space a devo hat, if you kind of look at it.

Chris: Oh, yeah.

Scott: With a certain eye.

Chris: Yes, I see.

Scott: Yeah, so it's still got that throwback to that band. [Laughter]

Dave: What does John Resig smell like?

Chris: [Laughter]

Dave: Sorry. I'm off topic.


Chris: Maybe he smells like Japanese ink.

Scott: I bet. Yeah.

Chris: Yeah.

Scott: Yeah, because he's always steeped in study with that stuff. Yeah, John is a wonderful guy. Been out of touch for a little while, actually. I'm trying to keep up. He's really into the GraphQL world these days, I think.

Dave: Yeah, with Khan.

Chris: Amen. So good.

Scott: Yeah.

Dave: I've been following Filament's work for quite a while. It's surely been mentioned here on ShopTalk multiple times. You very much embrace progressive enhancement. That's a very huge, I guess I would say, tenant of your agency.

Scott: Yeah. Mm-hmm.

Dave: Or it seems. This kind of series that we've been doing has kind of been about modern JavaScript and kind of touching on frameworks. As somebody who kind of does not necessarily prescribe to a framework, how does progressive enhancement and even frameworklessness, what does that look like in this modern JavaScript era?

Scott: Yeah, well, I mean just to sort of clarity, we would happily be working on any sort of framework project if that was the requirement or our recommendation for a particular site we're working on. I think there is a certain type of site and more and more types of sites that fit that model these days. A lot of our clients right now are in retail. They tend to be on platforms like Demandware, things like that.

Dave: Magento or something. Some sort of … components.

Scott: Yeah, exactly, so it's more of a traditional static sort of super heavy traffic CDN heavy kind of setup where really the page, once it's served, it's not a live app in the same way that you would need data binding throughout a whole page. That said, we have sections of these sites that are more data bound like that. In some cases, we'll use a framework for small sections like that. But, yeah, I think, more and more, it seems like the React and Vue kind of communities have really been embracing more of a progressive enhancement and performance priority with, like, server side rendering and all of that as a first class pattern that's just there.

Chris: It feels almost first class. I don't know if I'd call any of them totally first class yet, though.

Scott: Yeah. Yeah.

Chris: It'd be interesting to see a library that says, "We're SSR first," and then all this dynamic stuff.

Scott: Yeah, and I would love that, but it's a big step, I would think, from where these started. Even a few years ago, we were having this, especially with the Ember community. There was this pain point where all of the work was being done on the browser side and a lot of us were making a lot of noise about this and saying, "We're not capable of doing this work, but we would love to see it. [Laughter] From all these framework teams, we really need to see more of this work shifted to the server so that it can happen in both teams like Ember, React, and Vue. All of those support it.

Chris: There are performance concerns about it, too, which is good, but just yesterday I watched a video. I was like, "Oh, this is interesting." Google has released a video series called JavaScript SEO. It's Google employees sitting there talking about what's the true story of JavaScript rendered apps and their Web searcher. I'm like, "That's unusual."

I feel like you get little bites of information. Google will say, "Oh, yeah, we render JavaScript."

Scott: Right.

Chris: Or, "We don't," or whatever, but this is just a video and you can watch it. It's three minutes long, and it just says, "Look. Yes, there is a traditional Web crawler search. We look at the HTML. We look through it. We find the link. If we find the link, we start over and search through that link and whatever, and it's superfast. We've looked through literally trillions of individual Web URLs."

Scott: Mm-hmm.

Chris: Cool. That's really fast. We've gotten really good at that. "Then we determine if there's JavaScript doing rendering on that page. If there is, it goes into another bucket. This is really expensive and a lot harder for us to deal with."

Scott: Right.

Chris: "So, we're going to look at it, but later. It's just going to be slower and harder. It's just the way it is."

Scott: Yeah, and I'm not sure of the source of it, but I remember hearing or reading that it's somewhat like a one week delay or something.

Chris: A week! Wow. I wouldn't have even guessed that, but sure, and I could probably keep watching these.

Scott: Okay. Let's not cite that in the notes. [Laughter]

Chris: No. [Laughter]

Scott: Yeah, I remember it being long, though.

Chris: Yeah, and not only a week for that first time, but every time there's an update too. If you change content on the site, they're saying that's really slow too.

Scott: Yeah, right.

Chris: The quote from the video is, "We can't make any promises." I'm like, "Okay, well, if Google is literally telling that to our faces, this has now become a big deal.

I always kind of punted on the SEO thing and be like, "I don't know. It's Google. They make their jobs search. They've got to figure it out. Yeah, this is a big deal, so they'll figure it out.

But if they're straight up saying, "This is actually hard for us. We're talking a week between updates," and I know, don't put that in the show notes or whatever, but it's something like that. They literally said a delay or not at all. That's a big deal. If you're going to be like, "Oh, we're going to make our news side all client side rendered only, boy, you've got Google telling you, you're shooting yourself in the foot there.

Scott: Yeah, so there's that part and also out of Google and teams there, we've seen some articles recently like Addy Osmani posted about the delays we're seeing even when it is server side rendered, that delay between when you get the initial page and when it's what they call rehydrated. From my understanding, even if it's the same content, it still needs to be rehydrated in such a way that it can be bound to the data model, which means replacing a lot of the markup, the event-bound markup. Does that sound about right to you?

Chris: It does, but I wonder. That would be a whole new level of uh-oh if you could SSR but still get penalized because you eventually rehydrate. Ooh, that would suck.

Scott: Yeah, well, his article just highlighted, and he actually showed kind of a state where the page is actually blank.

Chris: Oh, right, SSR and then the page gets wiped out. I saw that too.

Scott: Yeah.

Chris: What's up with that? Why would it ever do that?

Scott: Yeah, I'm not sure if that was for illustration purposes or not because I've written about this, too, in a different context with client side A/B testing. You see this problem, actually, a lot. Most retail sites do personalization and things like that on their landing pages and home pages now. It is a huge problem.

You get these JavaScript files that are served to the client long after the page has already rendered. Once they spin up, they take up to ten seconds sometimes on a mobile device. Then they just completely wipe out a second of the page and replace it with something that's supposed to be more appropriate or contextual to whoever is browsing.

It works to a certain extent in conversion, but the cost there is huge. It actually does have a first rendering and then, much later, a second one that's different. That could be long after you started using the page.

Chris: Mm-hmm. Mm-hmm. It's kind of no wonder Netlify has made a bit of a hoopla about, like, "Hey, we can do this for you," at the--what do you call that--load balancer level kind of thing.

Scott: Yeah, that's very cool. I'm really interested in that pattern right now, like Cloudflare has.

Chris: That was even in your talk At Event Apart, right, this Cloudflare thing? Do you want to talk about that?

Scott: A little bit, yeah. We've experimented with it just a little bit. Cloudflare is the one CDN that we've used to try that pattern out for our clients. It's kind of neat because they have service worker support on their Edge servers, so you can kind of use them in that setting without any of the typical considerations that you would have if you're running a service worker in the browser, like browser support or having to download the thing and install it before it can actually work.

Chris: Whoa. Seriously? How does that work? A service worker gets executed even if you're in an ancient browser because it happens at some lower level?

Scott: Yeah. Yeah, it's basically just a middleware tier that happens to be written in JavaScript or a service worker syntax. It has nothing to do with -- the end browser just gets transformed HTML, but somewhere between the server and the browser is this little edge server that has a service worker running on it. You can do all sorts of fun things with it. Simple text swap, find and replace is the basic example they use.

Chris: Somehow, it has DOM access too?

Scott: Well, yeah, it depends what libraries you load in. I think there's a cap on the size of dependencies you can bring in. There is probably a latency issue there, too. What we've done is just sort of text in, text out. Just like a service worker, like on the browser side, you can get the text content of a response, like the body of a response and manipulate it in any way you want.

For our clients, we noticed this problem with A/B testing with the frameworks they were using on the client side that had these huge delays. We decided, okay, maybe we could get them a tagging system of sorts in their HTML that they could design these tests just using markup, and we could write a little service worker.

Chris: Oh, I see. You ship two divs. One of them is testing A and one of them is B. If it matches some regex or whatever.

Scott: Exactly. Yeah.

Chris: You just rip out one of the divs.

Scott: The worker just kind of looks for these marked up. They use HTML comments, just little marked up tests. It says, "Well, if they're in group B, then let's delete group A from this test and just send the HTML along to the browser."

Chris: Cool.

Scott: Yeah, so they're neat. I think it's a similar scenario to the cloud functions and all that kind of different functionality that you can use.

Chris: I didn't realize that the browser support had nothing to do with it.

Scott: Yeah.

Chris: You can reliably ship that anywhere. That's great.

Scott: Yeah, it's neat to be able to write in a service worker and not think about that part. [Laughter] It either has an error or it doesn't.

Chris: Yeah.

Scott: Right.

Chris: Very cool. Very cool.

[Banjo music]

Chris Enns: This episode is sponsored by Digital Ocean. Digital Ocean offers the simplest, most developer friendly cloud platform. It's optimized to make managing and scaling apps easy with an intuitive API, multiple storage options, integrated firewalls, load balancers, and more.

From predictable pricing to flexible configurations to world-class customer support, you'll get access to all the infrastructure services you need to grow. You'll be able to spend less time configuring servers. You can self-host your favorite stacks in one click. Get a ready to go LAMP, LEMP, Node.js, OpenFaaS, or a Django server up and running instantly on Digital Ocean, the cloud platform developers love. You can explore the growing library of 1-Click Apps on Digital Ocean Marketplace.

For ShopTalk Show listeners, you can get started today with a free $100 credit by visiting That's for your $100 credit to get started with Digital Ocean today. Our thanks to Digital Ocean for sponsoring this episode of ShopTalk Show.

[Banjo music]

Chris: You can get service workers. There's some interesting talk about it. We've talked on this show and maybe the Filament Group website uses it. Probably lots of websites are using it these days because I think performance tools like Lighthouse encourage its use, but it's this idea of critical CSS where somehow magically, and I know there are lots of ways to get to here, including automated ways, very manual ways, whatever. Imagine a small chunk of CSS, just enough CSS to make the top of one page look about right. [Laughter] You take that and, instead of it being in a style sheet that you link up and it has to make another request for, it's just chunked right into the HTML. That's called critical CSS, right?

Scott: Yeah. Yeah. Yeah, and we maintain one of several tools out there that will do that extraction for you. We'd never recommend going through your CSS and figuring out which rules seem important [laughter] manually. But, yeah, I think it's really powerful when you see it in play to be able to deliver an HTML file that carries along with it anything that it needs to render immediately when it hits the browser.

Chris: Right, and this is not only SEO stuff, but this is instant rendering, like just awesome for performance.

Scott: Yeah, because you start to pair your initial render time with really the time to first byte with your server. As soon as the HTML downloads and enough of it lands in the browser, it's ready to go. That's obviously not typical. Most websites on the Web, the HTML lands in the browser and the browser looks through it. It says, "Ah, okay. We can't render yet. We have to go get this style sheet and this JavaScript file. Hold up. We're going to go back to the server."

You know there's latency involved there. That's how we see the average time on really any website, taking multiple seconds because it's not ready to render even though most sites could render very, very quickly regardless of how heavy they are, if they carried what they need with them.

Yeah, you mentioned the critical CSS thing. That's really just something we recommend when the style sheet for the site is too heavy to just bring along with the page in full.

Chris: Probably most sites, though, right?

Scott: Sure. It depends.

Chris: Isn't it 15K kind of cap, maybe?

Scott: Yeah, I would say 20K-ish when it's compressed and minified is kind of the point at which it's like, eh, this is a little silly. You should start breaking this into chunks, so high priority, low priority. Then there are tools that can help do that.

Chris: If we're going to really get into the weeds here, the second step is, well, that's great if this HTML file can ship along with it everything it needs for the most part visually, like probably very little JavaScript, but a chunk of CSS, maybe, or the icons, too. We'll get into that in a minute.

Scott: Yeah.

Chris: If that's a thing. But there is some cost to that, too, in that now you have this kind of HTML file that's kind of bigger than it would be normally. It's got all this heavy chunks of code in it the browser needs to grab, parse out, and stuff. I think your recent premise or experiment or something you maybe even have proven out further than this is that, if we can just grab that chunk and throw it in cache, then the next time, we still kind of have our critical CSS ready to go, but it's not in line, right?

Scott: Yeah, exactly. I think the pattern you're talking about, I tend to call it inline cache.

Chris: Inline cache, that's nice.

Scott: Yeah. Jeremey Keith, after the talk, said, "I love that pattern, but really it's not inlining. It's embedding." I thought, uh, okay. [Laughter] Either way.

We were talking about CSS rules that are inside a style element, so whatever you want to call that. It's not the style equals attribute on a div, so yeah. I think that this particular pattern works best for files that are inlined in their entirety so, at least to me, it's not as useful for critical CSS because that particular pattern is sort of like a throwaway step, almost. You bring just the styles you need to render a good top portion of the page and then you also load the full style sheet in a way that doesn't block rendering.

Chris: I see. You never make a file literally called critical.css. A lot of times, that never even gets made.

Scott: We tend to have one per unique template on a site, so one for the landing template, one for the homepage template, one for a product detail template.

Chris: You're saying you really do make a file and then inject it in its entirety, though, then right?

Scott: Yeah, in its entirety would be four or five kilobytes.

Chris: Okay.

Scott: The full style sheet contains all those rules as well, right? There's a strict overlap there.

Chris: I see. It's repeated. Right.

Scott: It's a subset. Yeah, so once we get the full style sheet into the page, that critical CSS is no longer needed. It's kind of just a first visitor kind of step, right? But, to a lot of our clients, that matters a lot because they're coming from, say, a Google search or something like that straight to a product detail page. They may have never been to the site before, and we want to spin up that page as quickly as possible. It makes a big difference to have a really fast first load as opposed to optimizing for subsequent pages only.

Yeah, to get back to the pattern that you were talking about, I think it's really useful when you decide that you'd like to inline an entire file because, on subsequent pages, as you browse around the site, you're going to want to reuse that file again and you don't want to inline it every time because then it's kind of wasteful. It's being delivered over and over inside the HTML of all these different pages and it's bytes downloaded each time that you don't need to do.

What's nice about this pattern is the first time it's sent to the browser, there is a little five lines of JavaScript that says, "Find this style tag by its ID, get the contents of it, and toss it into a browser cache." Then on subsequent pages, page visits throughout the site, the templates can instead reference that file externally instead of inlining it.

Chris: It's just clever, and so we can dig deep into this because I'd love to talk about it in the context of SVG because we've been playing with that.

Scott: Yeah. Yeah. Mm-hmm.

Chris: Is it kind of provably good too? Can we watch the browser render faster, in a way, because it's not having to, or is there some theoretical purity that just feels good here? It certainly feels good to me.

Scott: Yeah. I think it's really going to vary. Inlining, in itself, is kind of a pattern that we're having to use less and less because, if we have access to HTTP2, we can push files instead from the server and reference them normally, externally from the HTML. More and more, that's what we're doing as our go-to first approach for CSS and JavaScript that's referenced in the head of the page. That's great.

To me, the case for this new pattern becomes more interesting when we get to files that are kind of further down the page that would be really useful to inline, but we don't want to put them. That's just because you can overuse server push. You can get to a point where it actually starts to slow down rendering of a page, which is the opposite of what you're trying to do when you push files. I think, like you mentioned SVG, that's a great example of something that I would probably never server push, right?

Chris: Well, if you have 15 icons on a page, the server push stuff, you know a heck of a lot more than I do. Dave, I'm sure you do too. Are you talking about just link rel preload or is there another? I don't totally understand server push, to be fair.

Scott: Yeah, so link rel preload is, in some server environments, the server knows to look for that in the markup of a page as a cue to push a file. That's sort of an implementation detail of different servers. I've never actually used it that way.

What we typically do is a little more manual, but you would have just an HTML file with a link to an external CSS file like any page on the Web. But on the server, say it's Apache, and you'd have one of those little htaccess files that we all have, it would just have a little directive that says, "If this is a request for an HTML file, then push site.css along with that HTML file."

Chris: Really?

Scott: It really is that simple. It's just a line or two. You'd typically qualify it to different pages and templates on a site, so you might want to only push.

Chris: That's pretty rad, but you're saying that if you do too much of that, if you put, say, "Hey, any time an HTML file is there, download these 20 icons too," you've 20x the size of that request and it's going to slow things down.

Scott: Yeah, because it clogs it up. They call come down at the same time at a super high priority. It's rare that you have that many things competing for initial render on a page, and I would think icons are probably not quite that high priority.

Dave: Is it like the browser, like if I push a style sheet, the browser is like, "Uh-oh, a style sheet is coming. Stop render," or does it kind of all work async?

Scott: Yeah. What's neat is, if you look at a waterfall that has push in play, ideally when the browser encounters a link to, say, that CSS file, it'll go to request it and find that it's already in cache because it's been pushed.

Dave: Yeah.

Scott: It kind of works that way. I wouldn't call it async.

Dave: Okay.

Scott: It gets pushed. It's much like inlining. This, to be clear, is above my level of where I work on the Web, too, like the server side of it. Yeah, that's my understanding at least.

Dave: Yeah, it's almost like server side bundling. If you already have the pieces of the bundle, it's like, yeah, I don't really actually care. I'll just use the one.

Scott: Right.

Dave: You can send it, but I'll just use the one.

Scott: Yeah, so I tend to think of it as a better way of inlining, like a more modern way.

Dave: Yeah. Interesting. Like maintenance, for me, it's like, okay, now I've got to maintain an Apache config. That's about as fun as a dentist appointment.


Dave: Now I have ten problems.

Scott: Sure.

Dave: Do you ever feel that? If I time stamped my CSS files, now I have to go and update the server config to get the right MD5 digest.

Scott: Yeah, I mean that's a great question and I think it would vary by how you're using it. The example that Chris brought up, the link rel preload in the markup is, I think, one way that it's sort of like a helpful shortcut to not have to do the server configuration update.

Dave: It's kind of the lazy person's….


Scott: Yeah, I mean I think it's a great pattern. The weird overlap for me with that is that link rel preload means something to the browser also. I think there is sort of like a gray area there where you're using it as a primitive for push. I'm not exactly sure how that line is drawn where you're saying, "Actually, I mean you should push that file but not use it as a client side preload," which is like a declarative way to fetch a file now.

Chris: What's so funny about this, too, is what you push or what you preload or whatever. It just gets a chunk of text into some cache, but there are all kinds of nuance after that. If we're talking fonts, that's a whole can of worms of how they get used even after it's cached or whatever. SVG is the same way. Oh, I can take my horse.svg file, chuck it in cache, so what. That means that if I put imagesource=horse, great, it's cached, but that's not how I want to use that icon anyway.

Scott: Right. Yeah.

Chris: What is it? Why is it useful? Depending on what you put in that cache, how you then use, it's not like there is one true way.

Scott: No. Yeah, I don't think there is, but that's kind of powerful, too, right? Once it's in cache, you can figure out how you want to reuse it.

Chris: Yes. Right, I'm not saying, "Don't use it," I'm saying that it's just so cool and interesting what you get after that.

Scott: Yeah, and it's been neat following. Just to clarify to the listeners, Chris has been kind of building on this inline cache pattern with SVG and texting me offline to see the progress. [Laughter] It's pretty neat, I think, inlining it first. I hope I'm not blowing up your blog post here. [Laughter]

Yeah, betting those icons into the page and subsequent pages is an interesting challenge. The first one that comes to mind is Ajaxing them from that external URL that'll actually come from cache. Ideally, we wouldn't want to.

Chris: Right. JavaScript dependent, but so is the service worker.

Scott: Yeah.

Chris: There you go.

Scott: Right. Yeah.

Chris: Well, what really opened this interesting possibility is that you brought up that there's this API called caches. It's just window.caches, isn't it? It's an amazing, high level thing.

Scott: Yeah. Yeah, and it's independent of service workers, even though I first learned about it--

Chris: Right, because remember we were talking about the DOM and all that. In a service worker, you really can't access the DOM.

Scott: Right.

Chris: I think, right?

Scott: Cache is just on the Window objects.

Chris: It's just on the Window.

Scott: You can just use it. Yeah. [Laughter]

Chris: Write in your JavaScript.

Dave: You don't even need a service worker. You can just put stuff in the cache and pop stuff out, list stuff, whatever.

Chris: Anywhere you want.

Scott: Yeah.

Chris: Anywhere you want.

Scott: Yeah, it's really neat because you can combine it, you know, use the cache's API along with service workers, too, and that's not a novel thing. That's been going on since service workers came out. That's kind of the primary thing people do with service workers is toss files into these caches, but it has led to some interesting things for us lately, like, instead of using cookies, for example, to identify whether someone has been to a site before or if they're a return visitor. We can instead use a service worker to say, "Are all the files that we care about, are they in cache?" If so, let's send a header, a custom header along with every request that goes out from the browser that says, "This visitor has what it needs in cache, so organize the page knowing that."

Chris: Provably. You're not even guessing. You're not even setting a cookie that's like, probably has cache.

Scott: Yeah, and that was always faulty.

Chris: Right.

Scott: A lot of the performance recommendations that we would make, Filament, and others would make through the critical CSS kind of patterns and things like that kind of relied on some sort of cookie or something that wasn't a personally identifiable kind of cookie like a tracking situation. It was more just, have you visited or not?

Dave: Do you have to fill out a GDPR for CSS? Yeah.

Scott: That's an open question, too. My understanding is, that style of cookie, which is used for -- you know, it's the same one for every visitor to the site and it's not used to identify a user is not really the kind that is called out in GDPR.

Dave: It's different. Yeah.

Scott: I don't know. I'm not a GDPR expert. I've asked GDPR experts about it and they said, "Yeah, it's not even specifically cookies, like this custom header pattern that I'm talking about." It's sort of reproducing the same thing that we would have done with cookies, just in a much better way, like a more reliable way that we can trust that if it says that files are cached locally, then we can sort of believe it.

Dave: Yeah, having access to this actual cache is kind of next level.

Chris: It's wild! This is how it works, people, if you can bear with some code explanation. Like pseudo code, you call this cache's API with just a string or whatever, and that string can be -- in the case that I've see Scott use it in and I've been playing with, you just grab a DOM element and go outer HTML. There is an inlined SVG icon? Great. Grab it. Grab the outer HTML. Now you have this chunk of SVG code. Now save it to caches at some -- it's like a key value pair. You save it at URL.

Scott: Yeah, icons.svg or whatever.

Chris: You save it at slash -- totally. Yeah, horse.svg or whatever it is. That probably should match a real file on the real file system.


Chris: It doesn't have to, but it would probably be smart to do that.

Scott: Yeah. It's sort of funny. I was thinking it would be fun to do an experiment that packages a full website in just the first HTML file you download.

Chris: Yeah.

Scott: Then explodes it out into local caches and make a browsable sites of files. [Laughter] I would never recommend doing that but, as an experiment, that would be kind of fun.

Chris: Yeah. It's almost offline, then.

Scott: Yeah. Yeah, because that's one of the great things about the service worker cache's API is that they do work offline, right?

Chris: Yeah. Yeah.

Scott: Yeah, it's interesting.

Chris: Anyway, this cache thing is so cool. You can just grab any text and just dump it in cache. Then if the browser requests that same URL, it will automatically pull from that cache. You don't have to tell it anything -- well, there is a little bit of an extra service worker step for that part.

Scott: There's a little. Yeah.

Chris: A little tiny one.

Scott: Yeah.

Chris: I'm not good at this stuff at all, and I was empowered to put a little repo together for this and I was fascinated by it. Then, just because I thought this would be impossible somehow, but I thought, "Maybe I'll try it," is to inline it at first, like an SVG icon, chuck that in cache, and then, on a subsequent page, not a subsequent page load, although you could do that, you just need a little server side something to differentiate whether it has the cache like Scott was just explaining. I just did it so that index.html does the caching and some other page benefits from the cache if it can, so like homepage subpage kind of thing.

The subpage then presumably has a cache. If it doesn't, it will just pull it from the file system, which is not the end of the world, but it will try to get it from cache first. It probably is in there, and it doesn't have to use JavaScript to Ajax for it and then put it on the page at first. It can just use the SVG use syntax to look into that cache, grab the little piece of the SVG that it needs and render it, which is kind of neat.

Scott: Yeah, that's really neat.

Chris: It just means that it can render right away. It has the same spirit of critical CSS and all that. It's like a critical icon.

Scott: Yeah. To be clear, you're talking about a use element with an href that goes straight to a file.

Chris: Exactly.

Scott: Right?

Chris: Right.

Scott: An external file.

Chris: Which is not something that anybody uses in production right now so much. The reason they mostly don't, I think, is because Edge never had support for it. It's just a special element in SVG land and it's meant to clone a piece of SVG, like go grab this fragment of SVG and re-render it. It has the ability to go out to a file to get that fragment. It's just, that one thing was never supported in Edge.

It is more commonly used to have this big chunk of icons on a page. Let's say you just toss it in the body, ten icons with a symbol element.

Scott: Sure.

Chris: Then reference that. That was kind of cool. I was a big supporter of that for a hot minute there. I kind of cooled off on it for various reasons. We could get all into that, but I don't know that we have time in this show.

Dave: Can I make a tiny distinction?

Chris: Yeah.

Dave: I think Edge has external SVG, but it fails on cross-origin.

Chris: Oh, really?

Dave: It doesn't have core support so, if you put stuff on a CDN, like most sites.

Chris: That's all it was, so this should work. Because it's reaching internally, it should be okay, but you can't set the core center.

Dave: Yeah but, in practice, it doesn't if you used CloudFront or Vue.

Chris: Right.

Scott: There are a lot of nuance to use support.

Chris: Yeah.

Scott: You need a website called "Can I Use" but the use has brackets around it.

Dave: Can I use use?


Chris: Oh! Solid. Solid.

Dave: …buying the domain….

Chris: Scott workshopped that yesterday in Slack, so that was awesome.

Scott: Yeah.

Chris: It went over well yesterday, so….


Dave: Oh, good….

Scott: Thanks for the 25-minute setup.


Chris: Anyway, inlining is way cooler. Even if you do this technique, you really should probably then Ajax for … anyway and replace it so that there is parity between how you're using that SVG file on all your different pages.

Scott: I think it's just SVG is tricky to get into a page right now from an external file because this isn't a problem for CSS. We can just have a link rel style sheet, href straight to the file, and it just loads it.

Chris: There's no SVG href. That's not a thing.

Scott: Yeah, that's unfortunate, right? That would be really cool, especially to be able to get the full HTML -- sorry, the full SVG markup into the DOM.

Chris: It would be without a Shadow DOM because that's the other weird thing about use is that the second you use use, you're in a Shadow DOM, and Shadow DOM -- getting through that is not a fleshed out story either. That would be an alternative for the Web platform to give us all the same Shadow DOM piercing possibilities.

Scott: [Laughter] Right. Yeah, and that is an area I have not gone very far into, SVG Shadow.

Dave: You haven't pierced the Shadow DOM, Scott?

Scott: Just in demos.

Chris: What's fascinating that can always is CSS custom properties. If you styled all of your SVGs and all the little parts of them to say, basically, style equals fill or stroke, and then reference the name of a CSS variable, you can style those right through the Shadow Dom, no problem.

Scott: Yeah, and that is really nice.

Chris: It is nice but talk about technical debt.

Scott: Yeah. [Laughter] Right.

Chris: Okay. Well, that's it. I just wanted to talk about SVG for a while. We didn't even mention Grunticon, another one of Scott's legacy projects, not legacy in that it's old or deprecated in any way, but just legacy as in famous.

Scott: It's been around a while. Yeah, well, internally at Filament, we've been asking that question. I think it's due for an update and we're trying to decide what parts are still useful to keep because more and more people are using the use sort of pattern, and we like that too. I don't know. There are a lot of really, really good build tools now.

Chris: It seems like everybody agrees that SVG icon systems start at the design dev level, a folder full of individual icons.

Scott: Yes. Yes, and there are quite a few patterns that get you from that, right? I'm not sure. I almost want to open up some feedback on that in the Grunticon issues just to see where people would like to see it go. We still have it. It works fine, still, so we still have it in play and it does its job. But, as a pattern that we'd want, I'm not sure.

Chris: Well, if the premise is that inlining SVG is good, that means Grunticon itself almost isn't enough or something. You need some kind of HTML templating thing in place that I'm not sure Grunticon can deliver all by itself.

Scott: Yeah.

Chris: As I was playing around with my little demo, I had to throw Nunjucks on there just to get it to pull, do an include. You need some kind of include syntax.

Scott: Yeah. Yeah, and Grunticon has a little thing like, so kind of the first pattern is just to put a class on something, like icon-horse, and that would reference a background image, really. As we know, that's pretty limiting if you want to animate the SVG background or something like that. You're kind of out of luck, so there is an attribute you can use with Grunticon. I think it's data Grunticon embed, something like that, and it's neat because, delivery wise, you download the icons once ever and it's in a CSS file as little data URIs of the SVG files. But if you put that attribute on an element, it'll actually pull the SVG markup out of the CSS object and just dump it right into the element that you specified, so you get the….

Chris: That's amazing. It doesn't even do a network request.

Scott: Right.

Chris: It already has the data, so it just kind of upgrades the icon to be inline.

Scott: Yeah.

Chris: It's genius.

Scott: Yeah, and the way we wrote the data URIs for that, they're not A64, so they're just escaped SVG right in the CSS file, so they can go right into the DOM very easily and be animated. We use that a lot. If you went to the website, there are a bunch of demos that have embed attributes like that and you can see the icons are animating and things like that. It's a possible pattern, but the downside is it happens after the page is enhanced, right?

Chris: Right.

Scott: The JavaScript comes in, it finds those elements with the attributes, and injects the icon into them, so there is a slight delay, however long that takes.

Chris: [Laughter] I wonder if HTML imports? There's some kind of story there or something.

Scott: Yeah. I think the idea of some sort of client side include that's really generic is just so necessary. [Laughter]

Chris: Why? I want to ask the Web platform gods, why does HTML not have a tag or something, some kind of native way to just put a chunk of HTML and another chunk of HTML? Is that so--?

Dave: Oh, Chris. Do you speak of HTML inputs? Oh, yes. Have you summoned me? Who summoned me?

Chris: No, not even that. Even more basic than that. I guess that is kind of that.

Scott: [Laughter] Yeah. That sort of pattern would solve a lot of these problems really nicely, I think.

Chris: They would.

Scott: Yeah.

Chris: There's got to be a reason it doesn't exist. You know? I don't know.

Scott: Yeah. For a long time, we maintained this project called Ajax Include, which had a jQuery dependency but, from an API perspective, I always found it really nice to work with because, really on any element in the page, you would say, "Data Ajax Include," and pass in a URL. It would just fetch that file and inject it right in. You could specify before or after, things like that, prepend, append.

Yeah, I would love if we had an attribute like that. That would be brilliant.

Chris: I just want it. Anyway, Scott, we've been talking for forever. Thanks so much for the chat. It's wonderful.

Scott: Thanks so much for having me.

Dave: Yeah.

Scott: This has been fun.

Dave: Yeah, thank you. Thanks for your load CSS, we didn't talk about, really, either that much, but just that if you want to play with that link rel preload as something and you want it to work in Firefox, I find it very useful.

Scott: Oh, yeah. Yeah, thanks for mentioning that.

Dave: One day.

Scott: Yeah, that's one of our fun, ongoing projects. I like to maintain that one.

Dave: Yeah, it's pretty helpful and pretty small. Thank you, and we should wrap it up. For people who aren't following you and giving you money, how can they do that?

Scott: Well, you could go to and talk to us if you have any needs for website building, development, or even performance audits and things like that.

As far as me, you could find me at or @ScottJehl on the various Twitter, GitHub, everything. [Laughter]

Dave: Cool. awesome. Thank you for coming on and thank you, dear listener, for downloading this in your podcatcher of choice. Be sure to star, heart, favorite it up. That's how people find out about the show. Follow us on Twitter, @ShopTalkShow, for tons of tweets a month.

If you hate your job, head over to and get a brand new one because people want to hire people like you.

Chris, do you have anything else you'd like to say?