{"id":364166,"date":"2022-04-04T11:25:23","date_gmt":"2022-04-04T18:25:23","guid":{"rendered":"https:\/\/css-tricks.com\/?p=364166"},"modified":"2022-04-04T11:25:25","modified_gmt":"2022-04-04T18:25:25","slug":"adding-cdn-caching-to-a-vite-build","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/adding-cdn-caching-to-a-vite-build\/","title":{"rendered":"Adding CDN Caching to a Vite Build"},"content":{"rendered":"\n

Content delivery networks, or CDNs, allow you to improve the delivery of your website\u2019s static resources, most notably, with CDN caching. They do this by serving your content from edge locations, which are located all over the world. When a user browses to your site, and your site requests resources from the CDN, the CDN will route that request to the nearest edge location. If that location has the requested resources, either from that user\u2019s prior visit, or from another person, then the content will be served from cache. If not, the CDN will request the content from your underlying domain, cache it, and serve it.<\/p>\n\n\n\n

There are countless CDNs out there<\/a>, but for this post we\u2019ll be using AWS CloudFront. We\u2019ll look at setting up a CloudFront distribution to serve all our site\u2019s assets: JavaScript files, CSS files, font files, etc. Then we\u2019ll see about integrating it into a Vite<\/a> build. If you\u2019d like to learn more about Vite, I have an introduction here<\/a>.<\/p>\n\n\n\n\n\n\n

Setting up a CloudFront CDN distribution<\/h3>\n\n\n

Let\u2019s jump right in and set up our CloudFront CDN distribution.<\/p>\n\n\n\n

For any serious project, you should be setting up your serverless infrastructure with code, using something like the Serverless<\/a> Framework, or AWS\u2019s CDK. But to keep things simple, here, we\u2019ll set up our CDN using the AWS console.<\/p>\n\n\n\n

Head on over to the CloudFront homepage. At the top right, you should see an orange button to create a new distribution.<\/p>\n\n\n\n

\"CloudFront<\/figure>\n\n\n\n

The creation screen has a ton of options, but for the most part the default selections will be fine. First and foremost, add the domain where your resources are located.<\/p>\n\n\n\n

\"CloudFront<\/figure>\n\n\n\n

Next, scroll down and find the Response headers policy<\/strong> dropdown, and choose \u201cCORS-With-Preflight.\u201d<\/p>\n\n\n\n

\"CloudFront<\/figure>\n\n\n\n

Lastly, click the Create Distribution<\/strong> button at the bottom, and hopefully you\u2019ll see your new distribution.<\/p>\n\n\n\n

\"CloudFront<\/figure>\n\n\n

Integrating the CDN with Vite<\/h3>\n\n\n

It\u2019s one thing for our CDN to be set up and ready to serve our files. But it\u2019s another for our site to actually know<\/em> how<\/em> to<\/em> request them from our CDN. I\u2019ll walk through integrating with Vite, but other build systems, like webpack or Rollup, will be similar.<\/p>\n\n\n\n

When Vite builds our site, it maintains a \u201cgraph\u201d of all the JavaScript and CSS files that various parts of our site import, and it injects the appropriate <script><\/code> tags, <link><\/code> tags, or import()<\/code> statements to load what\u2019s needed. What we need to do is tell Vite to request these assets from our CDN when in production. Let\u2019s see how.<\/p>\n\n\n\n

Open up your vite.config.ts<\/code> file. First, we\u2019ll need to know if we\u2019re on the live site (production) or in development (dev).<\/p>\n\n\n\n

const isProduction = process.env.NODE_ENV === \"production\"; <\/code><\/pre>\n\n\n\n

This works since Vite sets this environment variable when we run vite build<\/code>, which is what we do for production, as opposed to dev mode with hot module reloading.<\/p>\n\n\n\n

Next we tell Vite to draw our assets from our CDN like so, setting the base<\/code> property of our config object:<\/p>\n\n\n\n

export default defineConfig({\n  base: isProduction ? process.env.REACT_CDN : \"\",<\/code><\/pre>\n\n\n\n

Be sure to set your REACT_CDN<\/code> environment variable to your CDN’s location, which in this case, will be our CloudFront distribution’s location. Mine looks something (but not exactly) like this:<\/p>\n\n\n\n

https:\/\/distributiondomainname.cloudfront.net<\/code><\/pre>\n\n\n

Watch your VitePWA settings!<\/h3>\n\n\n

As one final piece of cleanup, if you happen to be using the VitePWA plugin<\/a>, be sure to reset your base<\/code> property like this:<\/p>\n\n\n\n

VitePWA({\n  base: \"\/\",<\/code><\/pre>\n\n\n\n

Otherwise, your web.manifest<\/code> file will have invalid settings and cause errors.<\/p>\n\n\n

Let’s see the CDN work<\/h3>\n\n\n

Once you\u2019re all set up, browse to your site, and inspect any of the network requests for your script or CSS files. For starters, the protocol should be h2.<\/p>\n\n\n\n

\"Showing<\/figure>\n\n\n\n

From there, you can peek into the response headers of any one of those files, and you should see some CloudFront data in there:<\/p>\n\n\n\n

\"Screenshot<\/figure>\n\n\n

Cache busting<\/h3>\n\n\n

It\u2019s hard to talk about CDNs without mentioning cache busting. CDNs like CloudFront have functionality to manually \u201ceject\u201d items from cache. But for Vite-built assets, we get this \u201cfor free\u201d since Vite adds fingerprinting, or hash codes, to the filenames of the assets it produces.<\/p>\n\n\n\n

So Vite might turn a home.js<\/code> file into home-abc123.js<\/code> during a build, but then if you change that file and rebuild, it might become home-xyz987.js<\/code>. That\u2019s good, as it will \u201cbreak the cache,\u201d and the newly built file will not be cached, so the CDN will have to turn to our host domain for the actual content.<\/p>\n\n\n

CDN caching for other static assets<\/h3>\n\n\n

JavaScript, CSS, and font files aren\u2019t the only kinds of assets that can benefit from CDN caching. If you have an S3 bucket you\u2019re serving images<\/em> out of, consider setting up a CloudFront distribution for it as well. There are options specifically for S3 which makes it a snap to create. Not only will you get the same edge caching, but HTTP\/2 responses, which S3 does not<\/em> provide.<\/p>\n\n\n

Advanced CDN practices<\/h3>\n\n\n

Integrating a CDN here was reasonably straightforward, but we’re only enjoying a fraction of the potential benefits. Right now, users will browse to our app, our server will serve our root HTML file, and then the user’s browser will connect to our CDN to start pulling down all our static assets. <\/p>\n\n\n\n

Going further, we would want to serve our entire site from a CDN. That way, it can communicate with our web server as needed for non-static and non-cached assets.<\/p>\n\n\n

Conclusion<\/h3>\n\n\n

CDNs are a great way to improve the performance of your site. They provide edge caching and HTTP\/2 out of the box. Not only that, but they\u2019re reasonably easy to set up. Now you have a new tool in your belt to both set up a CDN and integrate it with Vite.<\/p>\n","protected":false},"excerpt":{"rendered":"

Content delivery networks, or CDNs, allow you to improve the delivery of your website\u2019s static resources, most notably, with CDN caching. They do this by serving your content from edge locations, which are located all over the world. When a user browses to your site, and your site requests resources from the CDN, the CDN […]<\/p>\n","protected":false},"author":250838,"featured_media":364178,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"Adding CDN Caching to a Vite Build by @AdamRackis","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[4],"tags":[633,18951],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/02\/vite-cloudfront.jpg?fit=1200%2C600&ssl=1","jetpack-related-posts":[{"id":365413,"url":"https:\/\/css-tricks.com\/setting-up-cloudfront-to-host-your-web-app\/","url_meta":{"origin":364166,"position":0},"title":"Setting Up CloudFront to Host Your Web App","date":"April 28, 2022","format":false,"excerpt":"In my last article, we went over how to set up a web app that serves chunks and bundles of CSS and JavaScript from CloudFront. We integrated it into Vite so that when the app runs in a browser, the assets requested from the app\u2019s root HTML file would pull\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/04\/aws-cloudfront-webapp.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":351259,"url":"https:\/\/css-tricks.com\/improve-largest-contentful-paint-lcp-on-your-website-with-ease\/","url_meta":{"origin":364166,"position":1},"title":"Improve Largest Contentful Paint (LCP) on Your Website With Ease","date":"September 9, 2021","format":false,"excerpt":"Optimizing the user experience you offer on your website is essential for the success of any online business. Google does use different user experience-related metrics to rank web pages for SEO and has continued to provide multiple tools to measure and improve web performance. In its recent attempt to simplify\u2026","rel":"","context":"In "Sponsored"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/09\/LCP-Blog-Banner.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":311500,"url":"https:\/\/css-tricks.com\/how-i-used-brotli-to-get-even-smaller-css-and-javascript-files-at-cdn-scale\/","url_meta":{"origin":364166,"position":2},"title":"How I Used Brotli to Get Even Smaller CSS and JavaScript Files at CDN Scale","date":"June 5, 2020","format":false,"excerpt":"This article is about my experience using Brotli at production scale. Despite being really expensive and a truly unfeasible method for on-the-fly compression, Brotli is actually very economical and saves cost on many fronts, especially when compared with gzip or lower compression levels of Brotli.","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/05\/brotli-css.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":337113,"url":"https:\/\/css-tricks.com\/wordpress-caching-all-you-need-to-know\/","url_meta":{"origin":364166,"position":3},"title":"WordPress Caching: All You Need To Know","date":"April 1, 2021","format":false,"excerpt":"Here's Ashley Rich at Delicious Brains writing about all the layers of caching that are relevant to a WordPress site. I think we all know that caching is complicated, but jeez, it's a journey to understand all the caches at work here. The point of cache being speed and reducing\u2026","rel":"","context":"In "Link"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/4C07BF8E-841B-4FBD-A8CF-BF65C0E23B4D.jpeg?fit=1200%2C686&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":297595,"url":"https:\/\/css-tricks.com\/imagekit-io-image-optimization-that-plugs-into-your-infrastructure\/","url_meta":{"origin":364166,"position":4},"title":"ImageKit.io: Image Optimization That Plugs Into Your Infrastructure","date":"October 24, 2019","format":false,"excerpt":"Images are the most efficient means to showcase a product or service on a website. They make up for most of the visual content on our website. But, the more images a webpage has, the more bandwidth it consumes, affecting the page load speed - a raging factor having a\u2026","rel":"","context":"In "Sponsored"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/10\/Image-Optimization-Custom-Integration.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":338199,"url":"https:\/\/css-tricks.com\/why-netlify\/","url_meta":{"origin":364166,"position":5},"title":"Why Netlify?","date":"April 13, 2021","format":false,"excerpt":"I think it's fair to think of Netlify as a CDN-backed static file host. But it would also be silly to think that's all it is. That's why I think it's smart for them to have pages like this, comparing Netlify to GitHub Pages. GitHub Pages is a lot closer\u2026","rel":"","context":"In "Sponsored"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/04\/netlify-github-pages-comp.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]}],"featured_media_src_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/02\/vite-cloudfront.jpg?fit=1024%2C512&ssl=1","_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/364166"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/250838"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=364166"}],"version-history":[{"count":9,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/364166\/revisions"}],"predecessor-version":[{"id":365197,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/364166\/revisions\/365197"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/364178"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=364166"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=364166"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=364166"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}