Adding CDN Caching to a Vite Build

Content delivery networks, or CDNs, allow you to improve the delivery of your website’s 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’s 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.

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

Setting up a CloudFront CDN distribution

Let’s jump right in and set up our CloudFront CDN distribution.

For any serious project, you should be setting up your serverless infrastructure with code, using something like the Serverless Framework, or AWS’s CDK. But to keep things simple, here, we’ll set up our CDN using the AWS console.

Head on over to the CloudFront homepage. At the top right, you should see an orange button to create a new distribution.

CloudFront CDN Distributions screen.

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.

CloudFront CDN distribution creation screen.

Next, scroll down and find the Response headers policy dropdown, and choose “CORS-With-Preflight.”

CloudFront response headers settings.

Lastly, click the Create Distribution button at the bottom, and hopefully you’ll see your new distribution.

CloudFront CDN distribution overview screen.

Integrating the CDN with Vite

It’s one thing for our CDN to be set up and ready to serve our files. But it’s another for our site to actually know how to request them from our CDN. I’ll walk through integrating with Vite, but other build systems, like webpack or Rollup, will be similar.

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

Open up your vite.config.ts file. First, we’ll need to know if we’re on the live site (production) or in development (dev).

const isProduction = process.env.NODE_ENV === "production"; 

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

Next we tell Vite to draw our assets from our CDN like so, setting the base property of our config object:

export default defineConfig({
  base: isProduction ? process.env.REACT_CDN : "",

Be sure to set your REACT_CDN 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:

https://distributiondomainname.cloudfront.net

Watch your VitePWA settings!

As one final piece of cleanup, if you happen to be using the VitePWA plugin, be sure to reset your base property like this:

VitePWA({
  base: "/",

Otherwise, your web.manifest file will have invalid settings and cause errors.

Let’s see the CDN work

Once you’re 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.

Showing the assets served via CDN caching in DevTools. Each file name includes a unique random string of letters and numbers.

From there, you can peek into the response headers of any one of those files, and you should see some CloudFront data in there:

Screenshot of a response header.

Cache busting

It’s hard to talk about CDNs without mentioning cache busting. CDNs like CloudFront have functionality to manually “eject” items from cache. But for Vite-built assets, we get this “for free” since Vite adds fingerprinting, or hash codes, to the filenames of the assets it produces.

So Vite might turn a home.js file into home-abc123.js during a build, but then if you change that file and rebuild, it might become home-xyz987.js. That’s good, as it will “break the cache,” and the newly built file will not be cached, so the CDN will have to turn to our host domain for the actual content.

CDN caching for other static assets

JavaScript, CSS, and font files aren’t the only kinds of assets that can benefit from CDN caching. If you have an S3 bucket you’re serving images 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 provide.

Advanced CDN practices

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.

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.

Conclusion

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’re 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.


Adding CDN Caching to a Vite Build originally published on CSS-Tricks. You should get the newsletter.

The Vite Ecosystem

Matias Capeletto covers the breadth of Vite, from the technological shoulders it stands on, to the peers exploring similar territory, to the other technologies it supports, to the frameworks that now use it primarily, and more. The fact that that a post that is this thick like this exists is a testament to Vite’s meteoric rise.

One of the strongest points in Vite is the ecosystem around it. Vite took responsibilities from frameworks (common web patternsglob importsHMR APISSR primitivesbuild optimizations), freeing other maintainers from reinventing the wheel each time by offering a common ground where to collaborate, fostering a lot of explorations in the space. Maintainers from several popular frameworks have chosen Vite as their recommended build tool, and are now deeply involved in Vite core development, participating in discussions and directly working on fixes and features. 

The first commit to Vite was for gosh sakes.

I think Matias is right. When you take responsibility away from other technology and say I got this part, it’s commodity stuff anyway, you focus on what makes you special, that’s the right formula. Just like a good startup.

To Shared LinkPermalink on CSS-Tricks

Vite + _____

Vite, “Next Generation Frontend Tooling” from Evan You, has been capturing a lot of attention. I’ve heard rave reviews from developers, even in private chats (you gotta try this!). Being from Evan, Vite works great with Vue, but Vue doesn’t seem to be the only first-class citizen of Vite. The plugins support Vue and React just the same and it looks like configurations for lit, Preact, and Svelte are easy.

It’s interesting to see other technologies try to get on the bandwagon, almost certainly for the wicked speed. I believe it uses esbuild, which is known for speed, for… some things?… under the hood, but not bundling. Just noting some of this bandwagon stuff happening like…

Hey, people like speed and good DX. Always worth noting when you see this much movement.


The post Vite + _____ appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Hack the “Deploy to Netlify” Button Using Environment Variables to Make a Customizable Site Generator

If you’re anything like me, you like being lazy shortcuts. The “Deploy to Netlify” button allows me to take this lovely feature of my personality and be productive with it.

Deploy to Netlify

Clicking the button above lets me (or you!) instantly clone my Next.js starter project and automatically deploy it to Netlify. Wow! So easy! I’m so happy!

Now, as I was perusing the docs for the button the other night, as one does, I noticed that you can pre-fill environment variables to the sites you deploy with the button. Which got me thinking… what kind of sites could I customize with that?

Ah, the famed “link in bio” you see all over social media when folks want you to see all of their relevant links in life. You can sign up for the various services that’ll make one of these sites for you, but what if you could make one yourself without having to sign up for yet another service?

But, we also are lazy and like shortcuts. Sounds like we can solve all of these problems with the “Deploy to Netlify” (DTN) button, and environment variables.

How would we build something like this?

In order to make our DTN button work, we need to make two projects that work together:

  • A template project (This is the repo that will be cloned and customized based on the environment variables passed in.)
  • A generator project (This is the project that will create the environment variables that should be passed to the button.)

I decided to be a little spicy with my examples, and so I made both projects with Vite, but the template project uses React and the generator project uses Vue.

I’ll do a high-level overview of how I built these two projects, and if you’d like to just see all the code, you can skip to the end of this post to see the final repositories!

The Template project

To start my template project, I’ll pull in Vite and React.

npm init @vitejs/app

After running this command, you can follow the prompts with whatever frameworks you’d like!

Now after doing the whole npm install thing, you’ll want to add a .local.env file and add in the environment variables you want to include. I want to have a name for the person who owns the site, their profile picture, and then all of their relevant links.

VITE_NAME=Cassidy Williams
VITE_PROFILE_PIC=https://github.com/cassidoo.png
VITE_GITHUB_LINK=https://github.com/cassidoo
VITE_TWITTER_LINK=https://twitter.com/cassidoo

You can set this up however you’d like, because this is just test data we’ll build off of! As you build out your own application, you can pull in your environment variables at any time for parsing with import.meta.env. Vite lets you access those variables from the client code with VITE_, so as you play around with variables, make sure you prepend that to your variables.

Ultimately, I made a rather large parsing function that I passed to my components to render into the template:

function getPageContent() {
  // Pull in all variables that start with VITE_ and turn it into an array
  let envVars = Object.entries(import.meta.env).filter((key) => key[0].startsWith('VITE_'))

  // Get the name and profile picture, since those are structured differently from the links
  const name = envVars.find((val) => val[0] === 'VITE_NAME')[1].replace(/_/g, ' ')
  const profilePic = envVars.find((val) => val[0] === 'VITE_PROFILE_PIC')[1]
  
  // ...
  
  // Pull all of the links, and properly format the names to be all lowercase and normalized
  let links = envVars.map((k) => {
    return [deEnvify(k[0]), k[1]]
  })

  // This object is what is ultimately sent to React to be rendered
  return { name, profilePic, links }
}

function deEnvify(str) {
  return str.replace('VITE_', '').replace('_LINK', '').toLowerCase().split('_').join(' ')
}

I can now pull in these variables into a React function that renders the components I need:

// ...
  return (
    <div>
      <img alt={vars.name} src={vars.profilePic} />
      <p>{vars.name}</p>
      {vars.links.map((l, index) => {
        return <Link key={`link${index}`} name={l[0]} href={l[1]} />
      })}
    </div>
  )

// ...

And voilà! With a little CSS, we have a “link in bio” site!

Now let’s turn this into something that doesn’t rely on hard-coded variables. Generator time!

The Generator project

I’m going to start a new Vite site, just like I did before, but I’ll be using Vue for this one, for funzies.

Now in this project, I need to generate the environment variables we talked about above. So we’ll need an input for the name, an input for the profile picture, and then a set of inputs for each link that a person might want to make.

In my App.vue template, I’ll have these separated out like so:

<template>
  <div>
    <p>
      <span>Your name:</span>
      <input type="text" v-model="name" />
	</p>
    <p>
      <span>Your profile picture:</span>	
      <input type="text" v-model="propic" />
    </p>
  </div>

  <List v-model:list="list" />

  <GenerateButton :name="name" :propic="propic" :list="list" />
</template>

In that List component, we’ll have dual inputs that gather all of the links our users might want to add:

<template>
  <div class="list">
    Add a link: <br />
    <input type="text" v-model="newItem.name" />
    <input type="text" v-model="newItem.url" @keyup.enter="addItem" />
    <button @click="addItem">+</button>

    <ListItem
      v-for="(item, index) in list"
      :key="index"
      :item="item"
      @delete="removeItem(index)"
    />
  </div>
</template>

So in this component, there’s the two inputs that are adding to an object called newItem, and then the ListItem component lists out all of the links that have been created already, and each one can delete itself.

Now, we can take all of these values we’ve gotten from our users, and populate the GenerateButton component with them to make our DTN button work!

The template in GenerateButton is just an <a> tag with the link. The power in this one comes from the methods in the <script>.

// ...
methods: {
  convertLink(str) {
    // Convert each string passed in to use the VITE_WHATEVER_LINK syntax that our template expects
    return `VITE_${str.replace(/ /g, '_').toUpperCase()}_LINK`
  },
  convertListOfLinks() {
    let linkString = ''
    
    // Pass each link given by the user to our helper function
    this.list.forEach((l) => {
      linkString += `${this.convertLink(l.name)}=${l.url}&`
    })

    return linkString
  },
  // This function pushes all of our strings together into one giant link that will be put into our button that will deploy everything!
  siteLink() {
    return (
      // This is the base URL we need of our template repo, and the Netlify deploy trigger
      'https://app.netlify.com/start/deploy?repository=https://github.com/cassidoo/link-in-bio-template#' +
      'VITE_NAME=' +
      // Replacing spaces with underscores in the name so that the URL doesn't turn that into %20
      this.name.replace(/ /g, '_') +
      '&' +
      'VITE_PROFILE_PIC=' +
      this.propic +
      '&' +
      // Pulls all the links from our helper function above
      this.convertListOfLinks()
    )
  },
}, 

Believe it or not, that’s it. You can add whatever styles you like or change up what variables are passed (like themes, toggles, etc.) to make this truly customizable!

Put it all together

Once these projects are deployed, they can work together in beautiful harmony!

This is the kind of project that can really illustrate the power of customization when you have access to user-generated environment variables. It may be a small one, but when you think about generating, say, resume websites, e-commerce themes, “/uses” websites, marketing sites… the possibilities are endless for turning this into a really cool boilerplate method.


The post Hack the “Deploy to Netlify” Button Using Environment Variables to Make a Customizable Site Generator appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Building Large Projects With Vue, Vite, and Lerna

Introduction

Today we’d like to present a blueprint for large Vue JS projects. It uses the new and exciting Vite build tool and Lerna monorepo manager. I’ve built large enterprise projects in a similar way, using Angular, Vue JS, webpack, and rollup. Vite, created by the Vue JS team, looks very promising so I wanted to give it a try.

There are plenty of Vite tutorials and demos, mostly the usual Hello World and Todo apps. But I needed something more useful. I wanted to see whether Vite can replace rollup and webpack in large real-life projects.