What does the ‘h’ stand for in Vue’s render method?

If you’ve been working with Vue for a while, you may have come across this way of rendering your app — this is the default in the latest version of the CLI, in main.js:

new Vue({ render: h => h(App)
}).$mount('#app')

Or, if you’re using a render function, possibly to take advantage of JSX:

Vue.component('jsx-example', { render (h) { return <div id="foo">bar</div> }
})

You may be wondering, what does that h do? What does it stand for? The h stands for hyperscript. It’s a riff of HTML, which means Hypertext Markup Language: since we’re dealing with a script, it’s become convention in virtual DOM implementations to use this substitution. This definition is also addressed in the documentation of other frameworks as well. Here it is, for example, in Cycle.js.

In this issue, Evan describes that:

Hyperscript itself stands for “script that generates HTML structures”

This is shortened to h because it’s easier to type. He also describes it a bit more in his Advanced Vue workshop on Frontend Masters.

Really, you can think of it as being short for createElement. Here would be the long form:

render: function (createElement) { return createElement(App);
}

If we replace that with an h, then we first arrive at:

render: function (h) { return h(App);
}

…which can then be shortened with the use of ES6 to:

render: h => h (App)

The Vue version takes up to three arguments:

render(h) { return h('div', {}, [...])
}
  1. The first is type of the element (here shown as div).
  2. The second is the data object. We nest some fields here, including: props, attrs, dom props, class and style.
  3. The third is an array of child nodes. We’ll then have nested calls and eventually return a tree of virtual DOM nodes.

There’s more in-depth information in the Vue Guide here.

The name hyperscript may potentially be confusing to some people, given the fact that hyperscript is actually the name of a library (what isn’t updated these days) and it actually has a small ecosystem. In this case, we’re not talking about that particular implementation.

Hope that clears things up for those who are curious!

The post What does the ‘h’ stand for in Vue’s render method? appeared first on CSS-Tricks.

Native-Like Animations for Page Transitions on the Web

Some of the most inspiring examples I’ve seen of front-end development have involved some sort of page transitions that look slick like they do in mobile apps. However, even though the imagination for these types of interactions seem to abound, their presence on actual sites that I visit do not. There are a number of ways to accomplish these types of movement!

Here’s what we’ll be building:

Demo Site

GitHub Repo

We’ll build out the simplest possible distillation of these concepts so that you can apply them to any application, and then I’ll also provide the code for this more complex app if you’d like to dive in.

Today we’ll be discussing how to create them with Vue and Nuxt. There are a lot of moving parts in page transitions and animations (lol I kill me), but don’t worry! Anything we don’t have time to cover in the article, we’ll link off to with other resources.

Why?

The web has come under critique in recent years for appearing “dated” in comparison to native iOS and Android app experiences. Transitioning between two states can reduce cognitive load for your user, as when someone is scanning a page, they have to create a mental map of everything that’s contained on it. When we move from page to page, the user has to remap that entire space. If an element is repeated on several pages but altered slightly, it mimics the experience we’ve been biologically trained to expect — no one just pops into a room or changes suddenly; they transition from another room into this one. Your eyes see someone that’s smaller relative to you. As they get closer in proximity to you, they get bigger. Without these transitions, changes can be startling. They force the user to remap placement and even their understanding of the same element. It is for this reason that these effects become critical in an experience that helps the user feel at home and gather information quickly on the web.

The good news is, implementing these kind of transitions is completely doable. Let’s dig in!

Prerequisite Knowledge

If you’re unfamiliar with Nuxt and how to work with it to create Vue.js applications, there’s another article I wrote on the subject here. If you’re familiar with React and Next.js, Nuxt.js is the Vue equivalent. It offers server-side rendering, code splitting, and most importantly, hooks for page transitions. Even though the page transition hooks it offers are excellent, that’s not how we’re going to accomplish the bulk of our animations in this tutorial.

In order to understand how the transitions we’re working with today do work, you’ll also need to have basic knowledge around the <transition /> component and the difference between CSS animations and transitions. I’ve covered both in more detail here. You’ll also need basic knowledge of the <transition-group /> component and this Snipcart post is a great resource to learn more about it.

Even though you’ll understand everything in more detail if you read these articles, I’ll give you the basic gist of what’s going on as we encounter things throughout the post.

Getting Started

First, we want to kick off our project by using the Vue CLI to create a new Nuxt project:

# if you haven’t installed vue cli before, do this first, globally:
npm install -g @vue/cli
# or
yarn global add @vue/cli # then
vue init nuxt/starter my-transitions-project
npm i
# or
yarn # and
npm i vuex node-sass sass-loader
# or
yarn add vuex node-sass sass-loader

Great! Now the first thing you’ll notice is that we have a pages directory. Nuxt will take any .vue files in that directory and automatically set up routing for us. Pretty awesome. We can make some pages to work with here, in our case: about.vue, and users.vue.

Setting Up Our Hooks

As mentioned earlier, Nuxt offers some page hooks which are really nice for page to page transitions. In other words, we have hooks for a page entering and leaving. So if we wanted to create an animation that would allow us to have a nice fade from page to page, we could do it because the class hooks are already available to us. We can even name new transitions per page and use JavaScript hooks for more advanced effects.

But what if we have some elements that we don’t want to leave and re-enter, but rather transition positions? In mobile applications, things don’t always leave when they move from state to state. Sometimes they transition seamlessly from one point to another and it makes the whole application feel very fluid.

Step One: Vuex Store

The first thing we’ll have to do is set up a centralized state management store with Vuex because we’re going to need to hold what page we’re currrently on.

Nuxt will assume this file will be in the store directory and called index.js:

import Vuex from 'vuex' const createStore = () => { return new Vuex.Store({ state: { page: 'index' }, mutations: { updatePage(state, pageName) { state.page = pageName } } })
} export default createStore

We’re storing both the page and we create a mutation that allows us to update the page.

Step Two: Middleware

Then, in our middleware, we’ll need a script that I’ve called pages.js. This will give us access to the route that’s changing and being updated before any of the other components, so it will be very efficient.

export default function(context) { // go tell the store to update the page context.store.commit('updatePage', context.route.name)
}

We’ll also need to register the middleware in our nuxt.config.js file:

module.exports = { ... router: { middleware: 'pages' }, ...
}

Step Three: Register Our Navigation

Now, we’ll go into our layouts/default.vue file. This directory allows you to set different layouts for different page structures. In our case, we’re not going to make a new layout, but alter the one that we’re reusing for every page. Our template will look like this at first:

<template> <div> <nuxt/> </div>
</template>

And that nuxt/ tag will insert anything that’s in the templates in our different pages. But rather than reusing a nav component on every page, we can add it in here and it will be presented consistently on every page:

<template> <div> <app-navigation /> <nuxt/> </div>
</template>
<script>
import AppNavigation from '~/components/AppNavigation.vue' export default { components: { AppNavigation }
}
</script>

This is also great for us because it won’t rerender every time the page is re-routed. It will be consistent on every page and, because of this, we cannot plug into our page transition hooks but instead we can build our own with what we built between Vuex and the Middleware.

Step Four: Create our Transitions in the Navigation Component

Now we can build out the navigation, but I’m also going to use this SVG here to do a small demo of basic functionality we’re going to implement for a larger application

<template> <nav> <h2>Simple Transition Group For Layout: {{ page }}</h2> <!--simple navigation, we use nuxt-link for routing links--> <ul> <nuxt-link exact to="/"><li>index</li></nuxt-link> <nuxt-link to="/about"><li>about</li></nuxt-link> <nuxt-link to="/users"><li>users</li></nuxt-link> </ul> <br> <!--we use the page to update the class with a conditional--> <svg :class="{ 'active' : (page === 'about') }" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 447 442"> <!-- we use the transition group component, we need a g tag because it’s SVG--> <transition-group name="list" tag="g"> <rect class="items rect" ref="rect" key="rect" width="171" height="171"/> <circle class="items circ" key="circ" id="profile" cx="382" cy="203" r="65"/> <g class="items text" id="text" key="text"> <rect x="56" y="225" width="226" height="16"/> <rect x="56" y="252" width="226" height="16"/> <rect x="56" y="280" width="226" height="16"/> </g> <rect class="items footer" key="footer" id="footer" y="423" width="155" height="19" rx="9.5" ry="9.5"/> </transition-group> </svg> </nav>
</template>
<script>
import { mapState } from 'vuex' export default { computed: mapState(['page'])
}
</script>

We’re doing a few things here. In the script, we bring in the page name from the store as a computed value. mapState will let us bring in anything else from the store, which will handy later when we deal with a lot of user information.

In the template, we have a regular nav with nuxt-links, which is what we use for routing links in Nuxt. We also have class that will be updated on a conditional based on the page (it will change to .active when it’s the about page.

We’re also using the <transition-group> component around a number of elements that will change positions. The <transition-group> component is a bit magical because it applies the concepts of FLIP under the hood. If you’ve heard of FLIP before, you’re going to be super excited to hear this because it’s a really performant way of animating on the web but usually takes a lot of calculations to implement. If you haven’t heard of FLIP before, it’s definitely good to read up to understand how it works, and maybe more importantly, all of the stuff you no longer have to do to make this kind of effect work! Can I get a “Hell yeah!”

Here is the CSS that makes this work. We basically state how we’d like all of the elements to be positioned on that “active” hook that we made. Then we tell the elements to have a transition applied if something changes. You’ll notice I’m using 3D transforms even if I’m just moving something along one X or Y axis because transforms are better for performance than top/left/margin for reducing paint and I want to enable hardware acceleration.

.items,
.list-move { transition: all 0.4s ease;
} .active { fill: #e63946; .rect { transform: translate3d(0, 30px, 0); } .circ { transform: translate3d(30px, 0, 0) scale(0.5); } .text { transform: rotate(90deg) scaleX(0.08) translate3d(-300px, -35px, 0); } .footer { transform: translateX(100px, 0, 0); }
}

Here is a reduced codepen without the page transitions, but just to show the movement:

See the Pen layout transition-group by Sarah Drasner (@sdras) on CodePen.

I want to point out that any implementations I use here are choices that I’ve made for placement and movement- you can really create any effect you like! I am choosing SVG here because it communicates the concept of layout in a small amount of code, but you don’t need to use SVG. I’m also using transitions instead of animation because of how declarative they are by nature- you are in essence stating: “I want this to be repositioned here when this class is toggled in Vue”, and then the transition’s only job is to describe the movement as anything changes. This is great for this use-case because it’s very flexible. I can then decide to change it to any other conditional placement and it will still work.

Great! This will now give us the effect, smooth as butter between pages, and we can still give the content of the page a nice little transition as well:

.page-enter-active { transition: opacity 0.25s ease-out;
} .page-leave-active { transition: opacity 0.25s ease-in;
} .page-enter,
.page-leave-active { opacity: 0;
}

I’ve also added in one of the examples from the Nuxt site to show that you can still do internal animations within the page as well:

View GitHub Repo

Ok, that works for a small demo, but now let’s apply it to something more real-world, like our example from before. Again, the demo site is here and the repo with all of the code is here.

It’s the same concept:

  • We store the name of the page in the Vuex store.
  • Middleware commits a mutation to let the store know the page has changed.
  • We apply a special class per page, and nest transitions for each page.
  • The navigation stays consistent on each page but we have different positions and apply some transitions.
  • The content of the page has a subtle transition and we build in some interactions based on user events

The only difference is that this is a slightly more involved implementation. The CSS that’s applied to the elements will stay the same in the navigation component. We can tell the browser what position we want all the elements to be in, and since there’s a transition applied to the element itself, that transition will be applied and it will move to the new position every time the page has changed.

// animations
.place { .follow { transform: translate3d(-215px, -80px, 0); } .profile-photo { transform: translate3d(-20px, -100px, 0) scale(0.75); } .profile-name { transform: translate3d(140px, -125px, 0) scale(0.75); color: white; } .side-icon { transform: translate3d(0, -40px, 0); background: rgba(255, 255, 255, 0.9); } .calendar { opacity: 1; }
}

That’s it! We keep it nice and simple and use flexbox, grid and absolute positioning in a relative container to make sure everything translates easily across all devices and we have very few media queries through this project. I’m mainly using CSS for the nav changes because I can declaratively state the placement of the elements and their transitions. For the micro-interactions of any user-driven event, I’m using JavaScript and GreenSock, because it allows me to coordinate a lot of movement very seamlessly and stabilizes transform-origin across browsers, but there are so many ways you could implement this. There are a million ways I could improve this demo application, or build on these animations, it’s a quick project to show some possibilities in a real-life context.

Remember to hardware accelerate and use transforms, and you can achieve some beautiful, native-like effects. I’m excited to see what you make! The web has so much potential for beautiful movement, placement, and interaction that reduces cognitive load for the user.

The post Native-Like Animations for Page Transitions on the Web appeared first on CSS-Tricks.

VuePress Static Site Generator

VuePress is a new tool from Vue creator Evan You that spins up Vue projects that are more on the side of websites based on content and markup than progressive web applications and does it with a few strokes of the command line.

We talk a lot about Vue around here, from a five-part series on getting started with it to a detailed implementation of a serverless checkout cart

But, like anything new, even the basics of getting started can feel overwhelming and complex. A tool like VuePress can really lower the barrier to entry for many who (like me) are still wrapping our heads around the basics and tinkering with the concepts.

There are alternatives, of course! For example, Nuxt is already primed for this sort of thing and also makes it easy to spin up a Vue project. Sarah wrote up a nice intro to Nuxt and it’s worth checking out, particularly if your project is a progressive web application. If you’re more into React but love the idea of static site generating, there is Gatsby.

Direct Link to Article — Permalink

The post VuePress Static Site Generator appeared first on CSS-Tricks.

Methods, Computed, and Watchers in Vue.js

One of the reasons I love working with Vue is because of how useful methods, computed, and watchers are, and the legibility of their distinction. Until understanding all three, it’s difficult to leverage the functionality of Vue to its full potential. Still, the majority of people I see confused about this framework tend to also be confused about the differences here, so let’s dig in.

In case you need a quick answer and don’t have time to read through the entire article, here’s a small TL;DR:

  • Methods: These are exactly what they sound like they might be (yay, naming!). They’re functions that hang off of an object—typically the Vue instance itself or a Vue component.
  • Computed: These properties may at first look like they’d be used like a method, but are not. In Vue, we use data to track changes to a particular property that we’d like to be reactive. Computed properties allow us to define a property that is used the same way as data, but can also have some custom logic that is cached based on its dependencies. You can consider computed properties another view into your data.
  • Watchers: These are allowing you a peek into the reactivity system. We’re offered some hooks with which to observe any properties that are stored by Vue. If we want to add a bit of functionality each time something changes, or respond to a particular change, we could watch a property and apply some logic. This means that the name of the watcher has to match what we’re trying to observe.

If any of this sounds confusing, don’t worry! We’ll dive in further below and hopefully address any confusion. If you’re familiar with vanilla JavaScript already, methods may be pretty obvious to you, aside from one or two caveats. It might then behoove you (I love that phrase) to skip to the Computed and Watchers sections.

Methods

Methods are likely something you’re going to use a lot while working with Vue. They’re aptly named as, in essence, we’re hanging a function off of an object. They’re incredibly useful for connecting functionality to directives for events, or even just creating a small bit of logic to be reused like any other function. You can call a method within another method, for example. You can also call a method inside a lifecycle hook. They’re very versatile.

Here’s a simple demo to demonstrate:

See the Pen Slim example of methods by Sarah Drasner (@sdras) on CodePen.

<code class="language-css"><div id="app"> <button @click="tryme">Try Me</button> <p>{{ message }}</p>
</div>
new Vue({ el: '#app', data() { return { message: null } }, methods: { tryme() { this.message = Date() } }
})

We could have also executed the logic in the directive itself like <button @click="message = Date()">Try Me</button>, which works very well for this small example. However, as the complexity of our application grows, it’s more common to do as we see above to break it out to keep it legible. There’s also a limit to the logic that Vue will allow you to express in a directive—for instance, expressions are allowed but statements are not.

You may notice that we’re be able to access this method within that component or Vue instance, and we can call any piece of our data here, in this case, this.message. You don’t have to call a method like you’d call a function within a directive. For example, @click=”methodName()” is unnecessary. You can reference it with @click=”methodName”, unless you need to pass a parameter, such as @click=”methodName(param)”.

Using directives to call methods is also nice because we have some existing modifiers. One such example that’s very useful is .prevent, which will keep a submit event from reloading the page, used like this:

<form v-on:submit.prevent="onSubmit"></form>

There are many more, here are just a few.

Computed

Computed properties are very valuable for manipulating data that already exists. Anytime you’re building something where you need to sort through a large group of data and you don’t want to rerun those calculations on every keystroke, think about using a computed value.

Some good candidates include, but are not limited to:

  • Updating a large amount of information while a user is typing, such as filtering a list
  • Gathering information from your Vuex store
  • Form validation
  • Data visualizations that change depending on what the user needs to see

Computed properties are a vital part of Vue to understand. They are calculations that will be cached based on their dependencies and will only update when needed. They’re extremely performant when used well and extraordinarily useful. There are many large libraries that handle this kind of logic that you can now eliminate with only a few lines of code.

Computed properties aren’t used like methods, though at first, they might look similar- you’re stating some logic in a function and returning- but the name of that function becomes a property that you’d then use in your application like data.

If we needed to filter this big list of names of heroes based on what the user was typing, here’s how we would do it. We’re keeping this really simple so you can get the base concepts down. Originally our list would output in our template using names, which we store in data:

new Vue({ el: '#app', data() { return { names: [ 'Evan You', 'John Lindquist', 'Jen Looper', 'Miriam Suzanne', ... ] } }
})
<div id="app"> <h1>Heroes</h1> <ul> <li v-for="name in names"> {{ name }} </li> </ul>
</div>

Now let’s create a filter for those names. We’ll start by creating an input with v-model that will originally be an empty string, but we’ll eventually use to match and filter through our list. We’ll call this property findName and you can see it referenced both on the input and in the data.

<label for="filtername">Find your hero:</label>
<input v-model="findName" id="filtername" type="text" />
data() { return { findName: '', names: [ 'Evan You', 'John Lindquist', ... ] }
}

Now, we can create the computed property that will filter all of the names based on what the user has typed into the input, so anything in our findName property. You’ll note that I’m using regex here to make sure that mismatched capitalization doesn’t matter, as users will typically not capitalize as they type.

computed: { filteredNames() { let filter = new RegExp(this.findName, 'i') return this.names.filter(el => el.match(filter)) }
}

And now we’ll update what we’re using in the template to output from this:

<ul> <li v-for="name in names"> {{ name }} </li>
</ul>

…to this:

<ul> <li v-for="name in filteredNames"> {{ name }} </li>
</ul>

And it filters for us on every keystroke! We only had to add a couple of lines of code to make this work, and didn’t have to load any additional libraries.

See the Pen Filter a list with Computed- end by Sarah Drasner (@sdras) on CodePen.

I can’t tell you how much time I save by using them. If you’re using Vue and haven’t explored them yet, please do, you’ll thank yourself.

Watchers

Vue has nice abstractions, and anyone who has been a programmer for a while will usually tell you that abstractions can be a pain because you’ll eventually get to a use case they can’t solve. However, this situation is accounted for, because Vue grants us some deeper access to into the reactivity system, which we can leverage as hooks to observe anything that’s changing. This can be incredibly useful because, as application developers, most of what we’re responsible for are things that change.

Watchers also allow us to write much more declarative code. You’re no longer tracking everything yourself. Vue is already doing it under the hood, so you can also have access to changes made to any properties it’s tracking, in data, computed, or props, for example.

Watchers are incredibly good for executing logic that applies to something else when a change on a property occurs (I first heard this way of putting it from Chris Fritz, but he says he might have also heard it from someone else ☺️). This isn’t a hard rule- you can absolutely use watchers for logic that refers to the property itself, but it’s a nice way of looking at how watchers are immediately different from computed properties, where the change will be in reference to the property we intend to use.

Let’s run through the most simple example possible so you get a taste of what’s happening here.

new Vue({ el: '#app', data() { return { counter: 0 } }, watch: { counter() { console.log('The counter has changed!') } }
})

As you can see in the code above, we’re storing counter in data, and by using the name of the property as the function name, we’re able to watch it. When we reference that counter in watch, we can observe any change to that property.

Transitioning State With Watchers

If the state is similar enough, you can even simply transition the state with watchers. Here’s an example I built from scratch of a chart with Vue. As the data changes, the watchers will update it and simply transition between them.

SVG is also good for a task like this because it’s built with math.

See the Pen Chart made with Vue, Transitioning State by Sarah Drasner (@sdras) on CodePen.

watch: { selected: function(newValue, oldValue) { var tweenedData = {} var update = function () { let obj = Object.values(tweenedData); obj.pop(); this.targetVal = obj; } var tweenSourceData = { onUpdate: update, onUpdateScope: this } for (let i = 0; i < oldValue.length; i++) { let key = i.toString() tweenedData[key] = oldValue[i] tweenSourceData[key] = newValue[i] } TweenMax.to(tweenedData, 1, tweenSourceData) }
}

What happened here?

  • First we created a dummy object that will get updated by our animation library.
  • Then we have an update function that is invoked on each tween step. We use this to push the data.
  • Then we create an object to hold the source data to be tweened and the function pointer for update events.
  • We create a for loop, and turn the current index into a string
  • Then we can tween over the our target dummy object, but we’ll only do this for the specific key

We could also use animation in watchers to create something like this time difference dial. I travel a bit and all my coworkers are in different areas, so I wanted a way to track what local time we were all in, as well as some signification of the change from daytime/nighttime as well.

See the Pen Vue Time Comparison by Sarah Drasner (@sdras) on CodePen.

Here we’re watching the checked property, and we’ll fire different methods that contain timeline animations that change the hue and saturation and some other elements based on the relative association to the current time. As mentioned earlier- the change occurs on the dropdown, but what we’re executing is logic that’s applied elsewhere.

watch: { checked() { let period = this.timeVal.slice(-2), hr = this.timeVal.slice(0, this.timeVal.indexOf(':')); const dayhr = 12, rpos = 115, rneg = -118; if ((period === 'AM' && hr != 12) || (period === 'PM' && hr == 12)) { this.spin(`${rneg - (rneg / dayhr) * hr}`) this.animTime(1 - hr / dayhr, period) } else { this.spin(`${(rpos / dayhr) * hr}`) this.animTime(hr / dayhr, period) } }
},

There are also a number of other interesting things about watchers, for instance: we’re given access to both the new and old versions of the property as parameters, we can specify deep if we’d like to watch a nested object. For more detailed information, there’s a lot of good information in the guide.

You can see how watchers can be incredibly useful for anything that’s updating—be it form inputs, asynchronous updates, or animations. If you’re curious how reactivity in Vue works, this part of the guide is really helpful. If you’d like to know more about reactivity in general, I really enjoyed Andre Staltz’ post and the Reactivity section of Mike Bostock’s A Better Way to Code.

Wrapping Up

I hope this was a helpful breakdown on how to use each, and speeds up your application development process by using Vue efficiently. There’s a stat out there that we spend 70% of our time as programmers reading code and 30% writing it. Personally, I love that, as a maintainer, I can look at a codebase I’ve never seen before and know immediately what the author has intended by the distinction made from methods, computed, and watchers.

The post Methods, Computed, and Watchers in Vue.js appeared first on CSS-Tricks.

Vue Design System

We talk a lot about Vue around here, including some practical applications of it, but haven’t gotten deep into designing for it. In this post, Viljami Salminen describes his Vue design process and the thinking that led him to build the Vue Design System:

A design system can help establish a common vocabulary between everyone in an organization and ease the collabo­ration between different disciplines. I’ve seen it go the other way around too when important decisions have been made in a rush. To avoid that, Vue Design System introduces the following framework for naming that I’ve found working well in the past…

Viljami lists Design Principles, Tokens, Elements, Patterns, and Templates as the way in which he structures a system and I think it’s a pretty interesting approach and a parallel to Lucas Lemonnier’s post on creating design systems in Sketch, using Atomic Design as the structure. I particularly like how Viljami fits everything together in the example style guide that’s provided.

Direct Link to Article — Permalink

The post Vue Design System appeared first on CSS-Tricks.

Let’s Build a Custom Vue Router

Plenty of tutorials exist that do a great job in explaining how Vue’s official routing library, vue-router, can be integrated into an existing Vue application. vue-router does a fantastic job by providing us with the items needed to map an application’s components to different browser URL routes.

But, simple applications often don’t need a fully fledged routing library like vue-router. In this article, we’ll build a simple custom client-side router with Vue. By doing so, we’ll gather an understanding of what needs to be handled to construct client-side routing as well as where potential shortcomings can exist.

Though this article assumes basic knowledge in Vue.js; we’ll be explaining things thoroughly as we start to write code!

Routing

First and foremost: let’s define routing for those who may be new to the concept.

In web development, routing often refers to splitting an application’s props to dictate the information that should be displayed. Here’s a Pen that shows just this:

See the Pen Vue Pokemon by Hassan Dj (@itslit) on CodePen.

Though the app would functionally work, it misses a substantial feature that’s expected from most web applications—responding to browser navigation events. We’d want our Pokémon app to be accessible and to show different details for different pathnames: /charizard, /blastoise, and /venusaur. This would allow users to refresh different pages and keep their location in the app, bookmark the URLs to come back to later, and potentially share the URL with others. These are some of the main benefits of creating routes within an application.

Now that we have an idea of what we’ll be working on, let’s start building!

Preparing the App

The easiest way to follow along step-by-step (if you wish to do so) is to clone the GitHub repo I’ve set up.

Download on GitHub

When cloned, install the project dependencies with:

npm install

Let’s take a brief look within the project directory.

$ ls
README.md
index.html
node_modules/
package.json
public/
src/
static/
webpack.config.js

There also exists the hidden files, .babelrc and .gitignore within the project scaffold.

This project is a simple webpack-configured application scaffolded with vue-cli, the Vue command line interface.

index.html is where we declare the DOM element—#app— with which we’ll use to mount our Vue application:

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.5.3/css/bulma.css"> <link rel="stylesheet" href="../public/styles.css" /> <title>Pokémon - Routing</title> </head> <body> <div id="app"></div> <script src="/dist/build.js"></script> </body>
</html>

In the <head> tag of the index.html file, we introduce Bulma as our application’s CSS framework and our own styles.css file that lives in the public/ folder.

Since our focus is on the usage of Vue.js, the application already has all the custom CSS laid out.

The src/ folder is where we’ll be working directly from:

$ ls src/
app/
main.js

src/main.js represents the starting point of our Vue application. It’s where our Vue instance is instantiated, where we declare the parent component that is to be rendered, and the DOM element #app with which our app is to be mounted to:

import Vue from 'vue';
import App from './app/app'; new Vue({ el: '#app', render: h => h(App)
});

We’re specifying the App component, from the src/app/app.js file, to be the main parent component of our application.

In the src/app directory, there exists two other files – app-custom.js and app-vue-router.js:

$ ls src/app/
app-custom.js
app-vue-router.js
app.js

app-custom.js denotes the completed implementation of the application with a custom Vue router (i.e. what we’ll be building in this article). app-vue-router.js is a completed routing implementation using the vue-router library.

For the entire article, we’ll only be introducing code to the src/app/app.js file. With that said, let’s take a look at the starting code within src/app/app.js:

const CharizardCard = { name: 'charizard-card', template: ` <div class="card card--charizard has-text-weight-bold has-text-white"> <div class="card-image"> <div class="card-image-container"> <img src="../../static/charizard.png"/> </div> </div> <div class="card-content has-text-centered"> <div class="main"> <div class="title has-text-white">Charizard</div> <div class="hp">hp 78</div> </div> <div class="stats columns is-mobile"> <div class="column">&#x1f525;<br> <span class="tag is-warning">Type</span> </div> <div class="column center-column">199 lbs<br> <span class="tag is-warning">Weight</span> </div> <div class="column">1.7 m <br> <span class="tag is-warning">Height</span> </div> </div> </div> </div> `
}; const App = { name: 'App', template: ` <div class="container"> <div class="pokemon"> <pokemon-card></pokemon-card> </div> </div> `, components: { 'pokemon-card': CharizardCard }
}; export default App;

Currently, two components exist: CharizardCard and App. The CharizardCard component is a simple template that displays details of the Charizard Pokémon. The App component declares the CharizardCard component in its components property and renders it as <pokemon-card></pokemon-card> within its template.

We currently only have static content with which we’ll be able to see if we run our application:

npm run dev

And launch localhost:8080:

To get things started, let’s introduce two new components: BlastoiseCard and VenusaurCard that contains details of the Blastoise and Venusaur Pokémon respectively. We can lay out these components right after CharizardCard:

const CharizardCard = { // ... }; const BlastoiseCard = { name: 'blastoise-card', template: ` <div class="card card--blastoise has-text-weight-bold has-text-white"> <div class="card-image"> <div class="card-image-container"> <img src="../../static/blastoise.png"/> </div> </div> <div class="card-content has-text-centered"> <div class="main"> <div class="title has-text-white">Blastoise</div> <div class="hp">hp 79</div> </div> <div class="stats columns is-mobile"> <div class="column">&#x1f4a7;<br> <span class="tag is-light">Type</span> </div> <div class="column center-column">223 lbs<br> <span class="tag is-light">Weight</span> </div> <div class="column">1.6 m<br> <span class="tag is-light">Height</span> </div> </div> </div> </div> `
}; const VenusaurCard = { name: 'venusaur-card', template: ` <div class="card card--venusaur has-text-weight-bold has-text-white"> <div class="card-image"> <div class="card-image-container"> <img src="../../static/venusaur.png"/> </div> </div> <div class="card-content has-text-centered"> <div class="main"> <div class="title has-text-white">Venusaur</div> <div class="hp hp-venusaur">hp 80</div> </div> <div class="stats columns is-mobile"> <div class="column">&#x1f343;<br> <span class="tag is-danger">Type</span> </div> <div class="column center-column">220 lbs<br> <span class="tag is-danger">Weight</span> </div> <div class="column">2.0 m<br> <span class="tag is-danger">Height</span> </div> </div> </div> </div> `
}; const App = { // ... }; export default App;

With our application components established, we can now begin to think how we’ll create routing between these components.

router-view

To establish routing, we’ll start by buiding a new component that holds the responsibility to render a specified component based on the app’s location. We’ll create this component in a constant variable named View.

Before we create this component, let’s see how we might use it. In the template of the App component, we’ll remove the declaration of <pokemon-card> and instead render the upcoming router-view component. In the components property; we’ll register the View component constant as <router-view> to be declared in the template.

const App = { name: 'App', template: ` <div class="container"> <div class="pokemon"> <router-view></router-view> </div> </div> `, components: { 'router-view': View }
}; export default App;

The router-view component will match the correct Pokémon component based on the URL route. This matching will be dictated in a routes array that we’ll create. We’ll create this array right above the App component:

const CharizardCard = { // ... };
const BlastoiseCard = { // ... };
const VenusaurCard = { // ... }; const routes = [ {path: '/', component: CharizardCard}, {path: '/charizard', component: CharizardCard}, {path: '/blastoise', component: BlastoiseCard}, {path: '/venusaur', component: VenusaurCard}
]; const App = { // ... }; export default App;

We’ve set each Pokémon path to their own respective component (e.g. /blastoise will render the BlastoiseCard component). We’ve also set the root path / to the CharizardCard component.

Let’s now begin to create our router-view component.

The router-view component will essentially be a mounting point to dynamically switch between components. One way we can do this in Vue is by using the reserved <component> element to establish Dynamic Components.

Let’s create a starting point for router-view to get an understanding of how this works. As mentioned earlier; we’ll create router-view within a constant variable named View. So with that said, let’s set up View right after our routes declaration:

const CharizardCard = { // ... };
const BlastoiseCard = { // ... };
const VenusaurCard = { // ... }; const routes = [ // ...
]; const View = { name: 'router-view', template: `<component :is="currentView"></component>`, data() { return { currentView: CharizardCard } }
}; const App = {
// ... }; export default App;

The reserved <component> element will render whatever component the is attribute is bound to. Above, we’ve attached the is attribute to a currentView data property that simply maps to the CharizardCard component. As of now, our application resembles the starting point by displaying CharizardCard regardless of what the URL route is.

Though router-view is now appropriately rendered within App, it’s not currently dynamic. We need router-view to display the correct component based on the URL pathname upon page load. To do this, we’ll use the created() hook to filter the routes array and return the component that has a path that matches the URL path. This would make View look something like this:

const View = { name: 'router-view', template: `<component :is="currentView"></component>`, data() { return { currentView: {} } }, created() { this.currentView = routes.find( route => route.path === window.location.pathname ).component; }
};

In the data function, we’re now instantiating currentView with an empty object. In the created() hook, we’re using JavaScript’s native find() method to return the first object from routes that matches route.path === window.location.pathname. We can then get the component with object.component (where object is the returned object from find()).

Inside a browser environment, window.location is a special object containing the properties of the browser’s current location. We grab the pathname from this object which is the path of the URL.

At this stage; we’ll be able to see the different Pokémon Card components based on the state of our browser URL!

The BlastoiseCard component now renders at the /blastoise route.

There’s something else we should consider. If a random URL pathname is entered, our app will currently error and present nothing to the view.

To avoid this, let’s introduce a simple check to display a “Not Found” template if the URL pathnamedoesn’t match any path existing in the routes array. We’ll separate out the find() method to a component method named getRouteObject() to avoid repetition. This updates the View object to:

const View = { name: 'router-view', template: `<component :is="currentView"></component>`, data() { return { currentView: {} } }, created() { if (this.getRouteObject() === undefined) { this.currentView = { template: ` <h3 class="subtitle has-text-white"> Not Found :(. Pick a Pokémon from the list below! </h3> ` }; } else { this.currentView = this.getRouteObject().component; } }, methods: { getRouteObject() { return routes.find( route => route.path === window.location.pathname ); } }
};

If the getRouteObject() method returns undefined, we display a “Not Found” template. If getRouteObject()returns an object from routes, we bind currentView to the component of that object. Now if a random URL is entered, the user will be notified:

The “Not Found” view is rendered if the URL pathname does not match any of the values in the routes array.

The “Not Found” template tells the user to pick a Pokémon from a list. This list will be the links we’ll create to allow the user to navigate to different URL routes.

Awesome! Our app is now responding to some external state, the location of the browser. router-view determines which component should be displayed based on the app’s location. Now, we need to construct links that will change the location of the browser without making a web request. With the location updated, we want to re-render our Vue app and rely on router-view to appropriately determine which component to render.

We’ll label these links as router-link components.

router-link

In web interfaces, we use HTML <a> tags to create links. What we want here is a special type of <a> tag. When the user clicks on this tag, we’ll want the browser to skip its default routine of making a web request to fetch the next page. Instead, we just want to manually update the browser’s location.

Let’s compose a router-link component that produces an <a> tag with a special click binding. When the user clicks on the router-link component, we’ll use the browser’s history API to update the browser’s location.

Just like we did with router-view, let’s see how we’ll use this component before we build it.

In the template of the App component, let’s create three <router-link> elements within a parent <div class="pokemon-links"></div> element. Rather than using the href attribute in <router-link>, we’ll specify the desired location of the link using a to attribute. We’ll also register the upcoming router-link component (from a Link constant variable) in the App components property:

const App = { name: 'App', template: ` <div class="container"> <div class="pokemon"> <router-view></router-view> <div class="pokemon-links has-text-centered"> <router-link to="/charizard"></router-link> <router-link to="/blastoise"></router-link> <router-link to="/venusaur"></router-link> </div> </div> </div> `, components: { 'router-view': View, 'router-link': Link }
};

We’ll create the Link object that represents router-link right above the App component. We’ve established the router-link component should always be given a to attribute (i.e. prop) that has a value of the target location. We can enforce this prop validation requirement like so:

const CharizardCard = { // ... };
const BlastoiseCard = { // ... };
const VenusaurCard = { // ... }; const routes = [ // ... ]; const View = { // ... }; const Link = { name: 'router-link', props: { to: { type: String, required: true } }
}; const App = { // ... }; export default App;

We can create the template of router-link to consist of an <a> tag with an @click handler attribute. Upon trigger, the @click handler will call a component method, labeled navigate(), that navigates the browser to the desired location. This navigation will occur with the use of the history.pushState() method. With that said, the Link constant object will be updated to:

const Link = { name: 'router-link', props: { to: { type: String, required: true } }, template: `<a @click="navigate" :href="to">{{ to }}</a>`, methods: { navigate(evt) { evt.preventDefault(); window.history.pushState(null, null, this.to); } }
};

Within the <a> tag, we’ve bound the value of the to prop to the element text content with {{ to }}.

When navigate() is triggered, it first calls preventDefault() on the event object to prevent the browser from making a web request for the new location. The history.pushState() method is then called to direct the user to the desired route location. history.pushState() takes three arguments:

  • a state object to pass serialized state information
  • a title
  • the target URL

In our case, there is no state information that’s needed to be passed, so we’ve left the first argument as null. Some browsers (e.g. Firefox) currently ignore the second parameter, title, hence we’ve left that as null as well.

The target location, the to prop, is passed in to the third and last parameter. Since the to prop contains the target location in a relative state, it will be resolved relative to the current URL. In our case, /blastoise will resolve to http://localhost:8080/blastoise.

If we click any of the links now, we’ll notice our browser updates to the correct location without a full page reload. However, our app will not update and render the correct component.

This unexpected behaviour happens because when router-link is updating the location of the browser, our Vue app is not alerted of the change. We’ll need to trigger our app (or simply just the router-view component) to re-render whenever the location changes.

Though there’s a few ways to accomplish this behaviour, we’ll do this by using a custom EventBus. An EventBus is a Vue instance responsible in allowing isolated components to subscribe and publish custom events between each other.

At the beginning of the file, we’ll import the vue library and create an EventBus with a new Vue() instance:

import Vue from 'vue'; const EventBus = new Vue();

When a link has been clicked, we need to notify the necessary part of the application (i.e. router-view) that the user is navigating to a particular route. The first step is to create an event emitter using the EventBus‘s events interface in the navigate() method of router-link. We’ll give this custom event a name of navigate:

const Link = { // ..., methods: { navigate(evt) { evt.preventDefault(); window.history.pushState(null, null, this.to); EventBus.$emit('navigate'); } }
};

We can now set the event listener/trigger in the created() hook of router-view. By setting the custom event listener outside of the if/else statement, the created() hook of View will be updated to:

const View = { // ..., created() { if (this.getRouteObject() === undefined) { this.currentView = { template: ` <h3 class="subtitle has-text-white"> Not Found :(. Pick a Pokémon from the list below! </h3> ` }; } else { this.currentView = this.getRouteObject().component; } // Event listener for link navigation EventBus.$on('navigate', () => { this.currentView = this.getRouteObject().component; }); }, // ...
};

When the browser’s location changes by clicking a <router-link> element, this listening function will be invoked, re-rendering router-view to match against the latest URL!

Great! Our app now navigates appropriately as we click each of the links.

There’s one last thing we need to consider. If we try to use the browser back/forward buttons to navigate through the browser history, our application will not currently re-render correctly. Although unexpected, this occurs because no event notifier is emitted when the user clicks browser back or browser forward.

To make this work, we’ll use the onpopstate event handler.

The onpopstate event is fired each time the active history entry changes. A history change is invoked by clicking the browser back or browser forward buttons, or calling history.back() or history.forward() programmatically.

Right after our EventBus creation, let’s set up the onpopstate event listener to emit the navigate event when a history change is invoked:

window.addEventListener('popstate', () => { EventBus.$emit('navigate'); });

Our application will now respond appropriately even when the browser navigation buttons are used!

And there we have it! We’ve just built a custom Vue router using an EventBus and dynamic components. Even with the tiny size of our app we can enjoy a noticeable performance improvement. Avoiding a full page load also saves hundreds of milliseconds and prevents our app from “blinking” during the page change.

Conclusion

I love Vue. One reason as to why – it’s incredibly easy to use and manipulate Vue components just like we saw in this article.

In the introduction, we mentioned how Vue provides the vue-router library as the official routing library of the framework. We’ve just created simple versions of the same main items that are used in vue-router:

  • routes: the array responsible in mapping components to respective URL pathnames.
  • router-view: the component that renders a specified app component based on the app’s location
  • router-link: the component that allows the user to change the location of the browser without making a web request.

For very simple applications, the routing we’ve built (or a variation thereof like this one built by Chris Fritz) can do the minimal amount of work needed to route our applications.

The vue-router library, on the other hand, is built in a more complicated manner and introduces incredibly useful capabilities, often needed in larger applications like:

  • Consistency between different browsers
  • Nested Routes
  • Navigation Guards
  • Transition Effects

Though the vue-router library does come with additional boilerplate, it’s fairly easy to integrate once your application is composed of well isolated and distinct components. If you’re interested, you can see the components of vue-router being used to enable routing in this application here.

Hopefully this was as enjoyable to you as it was for me in compiling this post! Thanks for reading!


This article is an adapted (and summarized) segment from the upcoming book, Fullstack Vue, that I’m working on with the Fullstack.io team! Having the opportunity to work with the folks at Fullstack has been nothing short of being a blast. In true Fullstack fashion, the book covers numerous facets of Vue including but not restricted to routing, simple state management, form handling, Vuex, server persistence, and testing. If this is something that piques your interest or if you have any questions at all, follow (or message) me on twitter (@djirdehh)! If the above doesn’t pique your interest, you can still follow me anyway. 😛


Let’s Build a Custom Vue Router is a post from CSS-Tricks

Routing and Route Protection in Server-Rendered Vue Apps Using Nuxt.js

This tutorial assumes basic knowledge of Vue. If you haven’t worked with it before, then you may want to check out this CSS-Tricks guide on getting started.

You might have had some experience trying to render an app built with Vue on a server. The concept and implementation details of Server-Side Rendering (from Github.

Why Should I Render to a Server?

If you already know why you should server-render and just want to learn about routing or route protection, then you can jump to Setting Up a Nuxt.js App from Scratch section.

Sarah Drasner wrote a great post on what Nuxt.js is and why you should use it. She also showed off some of the amazing things you can do with this tool like page routing and page transitions. Nuxt.js is a tool in the Vue ecosystem that you can use to build server-rendered apps from scratch without being bothered by the underlying complexities of rendering a JavaScript app to a server.

Nuxt.js is an option to what Vue already offers. It builds upon the Vue SSR and routing libraries to expose a seamless platform for your own apps. Nuxt.js boils down to one thing: to simplify your experience as a developer building SSR apps with Vue.

We already did a lot of talking (which they say is cheap); now let’s get our hands dirty.

Setting Up a Nuxt.js App from Scratch

You can quickly scaffold a new project using the Vue CLI tool by running the following command:

vue init nuxt-community/starter-template <project-name>

But that’s not the deal, and we want to get our hands dirty. This way, you would learn the underlying processes that powers the engine of a Nuxt project.

Start by creating an empty folder on your computer, open your terminal to point to this folder, and run the following command to start a new node project:

npm init -y # OR yarn init -y

This will generate a package.json file that looks like this:

{ "name": "nuxt-shop", "version": "1.0.0", "main": "index.js", "license": "MIT"
}

The name property is the same as the name of the folder you working in.

Install the Nuxt.js library via npm:

npm install --save nuxt # OR yarn add nuxt

Then configure a npm script to launch nuxt build process in the package.json file:

"scripts": { "dev": "nuxt"
}

You can then start-up by running the command you just created:

npm run dev # OR yarn dev

It’s OK to watch the build fail. This is because Nuxt.js looks into a pages folder for contents which it wills serve to the browser. At this point, this folder does not exist:

Exit the build process then create a pages folder in the root of your project and try running once more. This time your should get a successful build:

The app launches on Port 3000 but you get a 404 when you try to access it:

Nuxt.js maps page routes to file names in the pages folder. This implies that if you had a file named index.vue and another about.vue in the pages folder, the will resolve to / and /about, respectively. Right now, / is throwing a 404 because, index.vue does not exist in the pages folder.

Create the index.vue file with this dead simple snippet:

<template> <h1>Greetings from Vue + Nuxt</h1>
</template>

Now, restart the server and the 404 should be replaced with an index route showing the greetings message:

Project-Wide Layout and Assets

Before we get deep into routing, let’s take some time to discuss how to structure your project in such a way that you have a reusable layout as sharing global assets on all pages. Let’s start with the global assets. We need these two assets in our project:

  1. Favicon
  2. Base Styles

Nuxt.js provides two root folder options (depending on what you’re doing) for managing assets:

  1. assets: Files here are webpacked (bundled and transformed by webpack). Files like your CSS, global JS, LESS, SASS, images, should be here.
  2. static: Files here don’t go through webpack. They are served to the browser as is. Makes sense for robot.txt, favicons, Github CNAME file, etc.

In our case, our favicon belongs to static while the base style goes to the assets folder. Hence, create the two folders and add base.css in /assets/css/base.css. Also download this favicon file and put it in the static folder. We need normalize.css but we can install it via npm rather than putting it in assets:

yarn add normalize.css

Finally, tell Nuxt.js about all these assets in a config file. This config file should live in the root of your project as nuxt.config.js:

module.exports = { head: { titleTemplate: '%s - Nuxt Shop', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: 'Nuxt online shop' } ], link: [ { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Raleway' }, { rel: 'icon', type: 'image/x-icon', href: 'https://cdn.css-tricks.com/favicon.ico' } ] }, css: ['normalize.css', '@/assets/css/base.css']
};

We just defined our title template, page meta information, fonts, favicon and all our styles. Nuxt.js will automatically include them all in the head of our pages.

Add this in the base.css file and let’s see if everything works as expected:

html, body, #__nuxt { height: 100%;
} html { font-size: 62.5%;
} body { font-size: 1.5em; line-height: 1.6; font-weight: 400; font-family: 'Raleway', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #222;
}

You should see that the font of the greeting message has changed to reflect the CSS:

Now we can talk about layout. Nuxt.js already has a default layout you can customize. Create a layouts folder on the root and add a default.vue file in it with the following layout content:

<template> <div class="main"> <app-nav></app-nav> <!-- Mount the page content here --> <nuxt/> </div>
</template>
<style>
/* You can get the component styles from the Github repository for this demo */
</style> <script>
import nav from '@/components/nav';
export default { components: { 'app-nav': nav }
};
</script>

I am omitting all the styles in the style tag but you can get them from the code repository. I omitted them for brevity.

The layout file is also a component but wraps the nuxt component. Everything in the this file is shared among all other pages while each page content replaces the nuxt component. Speaking of shared contents, the app-nav component in the file should show a simple navigation.

Add the nav component by creating a components folder and adding a nav.vue file in it:

<template> <nav> <div class="logo"> <app-h1 is-brand="true">Nuxt Shop</app-h1> </div> <div class="menu"> <ul> <li> <nuxt-link to="/">Home</nuxt-link> </li> <li> <nuxt-link to="/about">About</nuxt-link> </li> </ul> </div> </nav>
</template>
<style>
/* You can get the component styles from the Github repository for this demo */
</style>
<script>
import h1 from './h1';
export default { components: { 'app-h1': h1 }
}
</script>

The component shows brand text and two links. Notice that for Nuxt to handle routing appropriately, we are not using the <a> tag but the <nuxt-link> component. The brand text is rendered using a reusable <h1> component that wraps and extends a <h1> tag. This component is in components/h1.vue:

<template> <h1 :class="{brand: isBrand}"> <slot></slot> </h1>
</template>
<style>
/* You can get the component styles from the Github repository for this demo
*/
</style>
<script>
export default { props: ['isBrand']
}
</script>

This is the output of the index page with the layout and these components added:

When you inspect the output, you should see the contents are rendered to the server:

Implicit Routing and Automatic Code Splitting

As mentioned earlier, Nuxt.js uses its file system to generate routes. All the files in the pages directory are mapped to a URL on the server. So, if I had this kind of directory structure:

pages/
--| product/
-----| index.vue
-----| new.vue
--| index.vue
--| about.vue

…then I would automatically get a Vue router object with the following structure:

router: { routes: [ { name: 'index', path: '/', component: 'pages/index.vue' }, { name: 'about', path: '/about', component: 'pages/about.vue' }, { name: 'product', path: '/product', component: 'pages/product/index.vue' }, { name: 'product-new', path: '/product/new', component: 'pages/product/new.vue' } ]
}

This is what I prefer to refer to as implicit routing.

On the other hand, each of these pages are not bundled in one
bundle.js. This would be the expectation when using webpack. In plain Vue projects, this is what we get and we would manually split the code for each route into their own files. With Nuxt.js, you get this out of the box and it’s referred to as automatic code splitting.

You can see this whole thing in action when you add another file in the pages folder. Name this file, about.vue with the following content:

<template> <div> <app-h1>About our Shop</app-h1> <p class="about">Lorem ipsum dolor sit amet consectetur adipisicing ...</p> <p class="about">Lorem ipsum dolor sit amet consectetur adipisicing ...</p> <p class="about">Lorem ipsum dolor sit amet consectetur adipisicing ...</p> <p class="about">Lorem ipsum dolor sit amet consectetur adipisicing ...</p> ... </div>
</template>
<style>
...
</style>
<script>
import h1 from '@/components/h1';
export default { components: { 'app-h1': h1 }
};
</script>

Now click on the About link in the navigation bar and it should take you to /about with the page content looking like this:

A look at the Network tab in DevTools will show you that no pages/index.[hash].js file was loaded, rather, a pages/about.[hash].js:

You should take out one thing from this: Routes === Pages. Therefore, you’re free to use them interchangeably in the server-side rendering world.

Data Fetching

This is where the game changes a bit. In plain Vue apps, we would usually wait for the component to load, then make a HTTP request in the created lifecycle method. Unfortunately, when you are also rendering to the server, the server is ready way before the component is ready. Therefore, if you stick to the created method, you can’t render fetched data to the server because it’s already too late.

For this reason, Nuxt.js exposes another instance method like created called asyncData. This method has access to two contexts: the client and the server. Therefore, when you make request in this method and return a data payload, the payload is automatically attached to the Vue instance.

Let’s see an example. Create a services folder in the root and add a data.js file to it. We are going to simulate data fetching by requesting data from this file:

export default [ { id: 1, price: 4, title: 'Drinks', imgUrl: 'http://res.cloudinary.com/christekh/image/upload/v1515183358/pro3_tqlsyl.png' }, { id: 2, price: 3, title: 'Home', imgUrl: 'http://res.cloudinary.com/christekh/image/upload/v1515183358/pro2_gpa4su.png' }, // Truncated for brevity. See repo for full code.
]

Next, update the index page to consume this file:

<template> <div> <app-banner></app-banner> <div class="cta"> <app-button>Start Shopping</app-button> </div> <app-product-list :products="products"></app-product-list> </div>
</template>
<style>
...
</style>
<script>
import h1 from '@/components/h1';
import banner from '@/components/banner';
import button from '@/components/button';
import productList from '@/components/product-list';
import data from '@/services/data';
export default { asyncData(ctx, callback) { setTimeout(() => { callback(null, { products: data }); }, 2000); }, components: { 'app-h1': h1, 'app-banner': banner, 'app-button': button, 'app-product-list': productList }
};
</script>

Ignore the imported components and focus on the asyncData method for now. I am simulating an async operation with setTimeout and fetching data after two seconds. The callback method is called with the data you want to expose to the component.

Now back to the imported components. You have already seen the <h1> component. I have created few more to serve as UI components for our app. All these components live in the components directory and you can get the code for them from the Github repo. Rest assured that they contain mostly HTML and CSS so you should be fine understanding what they do.

This is what the output should look like:

Guess what? The fetched data is still rendered to the server!

Parameterized (Dynamic) Routes

Sometimes the data you show in your page views are determined by the state of the routes. A common pattern in web apps is to have a dynamic parameter in a URL. This parameter is used to query data or a database for a given resource. The parameters can come in this form:

https://example.com/product/2

The value 2 in the URL can be 3 or 4 or any value. The most important thing is that your app would fetch that value and run a query against a dataset to retrieve relative information.

In Nuxt.js, you have the following structure in the pages folder:

pages/
--| product/
-----| _id.vue

This resolves to:

router: { routes: [ { name: 'product-id', path: '/product/:id?', component: 'pages/product/_id.vue' } ]
}

To see how that works out, create a product folder in the
pages directory and add a _id.vue file to it:

<template> <div class="product-page"> <app-h1>{{product.title}}</app-h1> <div class="product-sale"> <div class="image"> <img :src="product.imgUrl" :alt="product.title"> </div> <div class="description"> <app-h2>${{product.price}}</app-h2> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p> </div> </div> </div>
</template>
<style> </style>
<script>
import h1 from '@/components/h1';
import h2 from '@/components/h2';
import data from '@/services/data';
export default { asyncData({ params }, callback) { setTimeout(() => { callback(null,{product: data.find(v => v.id === parseInt(params.id))}) }, 2000) }, components: { 'app-h1': h1, 'app-h2': h2 },
};
</script>

What’s important is the asyncData again. We are simulating an async request with setTimout. The request uses the id received via the context object’s params to query our dataset for the first matching id. The rest is just the component rendering the product.

Protecting Routes With Middleware

It won’t take too long before you start realizing that you need to secure some of your website’s contents from unauthorized users. Yes, the data source might be secured (which is important) but user experience demands that you prevent users from accessing unauthorized contents. You can do this by showing a friendly walk-away error or redirecting them to a login page.

In Nuxt.js, you can use a middleware to protect your pages (and in turn your contents). A middleware is a piece of logic that is executed before a route is accessed. This logic can prevent the route from being accessed entirely (probably with redirections).

Create a middleware folder in the root of the project and add an auth.js file:

export default function (ctx) { if(!isAuth()) { return ctx.redirect('/login') }
}
function isAuth() { // Check if user session exists somehow return false;
}

The middleware checks if a method, isAuth, returns false. If that is the case, it implies that the user is not authenticated and would redirect the user to a login page. The isAuth method just returns false by default for test purposes. Usually, you would check a session to see if the user is logged in.

Don’t rely on localStorage because the server does not know that it exists.

You can use this middleware to protect pages by adding it as value to the middleware instance property. You can add it to the _id.vue file we just created:

export default { asyncData({ params }, callback) { setTimeout(() => { callback(null,{product: data.find(v => v.id === parseInt(params.id))}) }, 2000) }, components: { //... }, middleware: 'auth'
};

This automatically shuts this page out every single time we access it. This is because the isAuth method is always returning false.

Long Story, Short

I can safely assume that you have learned what Nuxt.js guide for more features and use cases. If you’re working on a React project and need this kind of tool, then I think you should try Next.js.


Routing and Route Protection in Server-Rendered Vue Apps Using Nuxt.js is a post from CSS-Tricks

Creating a Vue.js Serverless Checkout Form: Configure the Checkout Component

This is the fourth post in a four-part series. In Part one, we set up a serverless Stripe function on Azure. Part two covered how we hosted the function on Github. The third part covered Stripe Elements in Vue. This last post shows how to configure the checkout component and make the shopping cart fully functional.

Article Series:

  1. Setup and Testing
  2. Stripe Function and Hosting
  3. Application and Checkout Component
  4. Configure the Checkout Component (This Post)

As a reminder, here’s where we are in our application at this point:

cart and checkout

Configuring the Checkout Component

We have to do a few things to adjust the component in order for it to meet our needs:

  • Make sure the form is only displaying if we haven’t submitted it—we’ll deal with the logic for this in our pay method in a moment
  • Allow the form to take a customer’s email address in case something is wrong with the order.
  • Disable the submit button until the required email address is provided
  • Finally and most importantly, change to our testing key

Here’s our updated checkout component with the changes to the original code highlighted:

<div v-if="!submitted" class="payment"> <h3>Please enter your payment details:</h3> <label for="email">Email</label> <input id="email" type="email" v-model="stripeEmail" placeholder="name@example.com"/> <label for="card">Credit Card</label> <p>Test using this credit card: <span class="cc-number">4242 4242 4242 4242</span>, and enter any 5 digits for the zip code</p> <card class='stripe-card' id="card" :class='{ complete }' stripe='pk_test_5ThYi0UvX3xwoNdgxxxTxxrG' :options='stripeOptions' @change='complete = $event.complete' /> <button class='pay-with-stripe' @click='pay' :disabled='!complete || !stripeEmail'>Pay with credit card</button>
</div>

There are a number of things we need to store and use for this component, so let’s add them to data or bring them in as props. The props that we need from our parent component will be total and success. We’ll need the total amount of the purchase so we can send it to Stripe, and the success will be something we need to coordinate between this component and the parent, because both components need to know if the payment was successful. I write out the datatypes as well as a default for my props.

props: { total: { type: [Number, String], default: '50.00' }, success: { type: Boolean, default: false }
},

Next, the data we need to store will be the stripeEmail we collected from the form, stripeOptions that I left in to show you can configure some options for your form, as well as status and response that we’ll get from communicating with the server and Stripe. We also want to hold whether or not the form was submitted, and whether the form was completed for enabling and disabling the submit button, which can both be booleans.

data() { return { submitted: false, complete: false, status: '', response: '', stripeOptions: { // you can configure that cc element. I liked the default, but you can // see https://stripe.com/docs/stripe.js#element-options for details }, stripeEmail: '' };
},

Now for the magic! We have everything we need—we just need to alter our pay() method, which will do all the heavy lifting for us. I’m going to use Axios for this, which will receive and transform the data:

npm i axios --save

…or using Yarn:

yarn add axios

If you’re not familiar with Axios and what it does, check out this article for some background information.

pay() { createToken().then(data => { this.submitted = true; // we'll change the flag to let ourselves know it was submitted console.log(data.token); // this is a token we would use for the stripeToken below axios .post( 'https://sdras-stripe.azurewebsites.net/api/charge?code=zWwbn6LLqMxuyvwbWpTFXdRxFd7a27KCRCEseL7zEqbM9ijAgj1c1w==', { stripeEmail: this.stripeEmail, // send the email stripeToken: data.token.id, // testing token stripeAmt: this.total // send the amount }, { headers: { 'Content-Type': 'application/json' } } ) .then(response => { this.status = 'success'; this.$emit('successSubmit'); this.$store.commit('clearCartCount'); // console logs for you 🙂 this.response = JSON.stringify(response, null, 2); console.log(this.response); }) .catch(error => { this.status = 'failure'; // console logs for you 🙂 this.response = 'Error: ' + JSON.stringify(error, null, 2); console.log(this.response); }); });
},

The code above does a number of things:

  • It allows us to track whether we’ve submitted the form or not, with this.submitted
  • It uses Axios to post to our function. We got this URL from going to where the function lives in the portal, and clicking “Get Function URL” on the right side of the screen.
    get function url
  • It sends the email, token, and total to the serverless function
  • If it’s successful, it changes the status to success, commits to our Vuex store, uses a mutation to clear our cart, and emits to the parent cart component that the payment was successful. It also logs the response to the console, though this is for educational purposes and should be deleted in production.
  • If it errors, it changes the status to failure, and logs the error response for help with debugging

If the payment fails, which we’ll know from our status, we need to let the user know something went wrong, clear our cart, and allow them to try again. In our template:

<div v-if="status === 'failure'"> <h3>Oh No!</h3> <p>Something went wrong!</p> <button @click="clearCheckout">Please try again</button>
</div>

The button executes the following clearCheckout method that clears a number of the fields and allow the customer to try again:

clearCheckout() { this.submitted = false; this.status = ''; this.complete = false; this.response = '';
}

If the payment succeeds, we will show a loading component, that will play an SVG animation until we hear back from the server. Sometimes this can take a couple of seconds, so it’s important that our animation make sense if it is seen for a short or long amount of time, and can loop as necessary.

<div v-else class="loadcontain"> <h4>Please hold, we're filling up your cart with goodies</h4> <app-loader />
</div>

Here’s what that looks like:

See the Pen shop loader by Sarah Drasner (@sdras) on CodePen.

Now if we revisit the first cart component we looked at in pages/cart.vue, we can fill that page based on the logic we set up before because it’s been completed:

<div v-if="cartTotal > 0"> <h1>Cart</h1> ... <app-checkout :total="total" @successSubmit="success = true"></app-checkout>
</div> <div v-else-if="cartTotal === 0 && success === false" class="empty"> <h1>Cart</h1> <h3>Your cart is empty.</h3> <nuxt-link exact to="/"><button>Fill 'er up!</button></nuxt-link>
</div> <div v-else> <app-success @restartCart="success = false"/> <h2>Success!</h2> <p>Your order has been processed, it will be delivered shortly.</p>
</div>

If we have items in our cart, we show the cart. If the cart is empty and the success is false, we’ll let them know that their cart is empty. Otherwise, if the checkout has just been processed, we’ll let them know that everything has been executed successfully!

We are now here:

success.vue in the application

In the AppSuccess.vue component, we have a small SVG animation designed to make them feel good about the purchase:

See the Pen success by Sarah Drasner (@sdras) on CodePen.

(You may have to hit “Rerun” to replay the animation.)

We also put a small timer in the mounted() lifecycle hook:

window.setTimeout(() => this.$emit('restartCart'), 3000);

This will show the success for three seconds while they read it then kick off the restartCart that was shown in the component above. This allows us to reset the cart in case they would like to continue shopping.

Conclusion

You learned how to make a serverless function, host it on Github, add required dependencies, communicate with Stripe, set up a Shopping Cart in a Vue application, establish a connection with the serverless function and Stripe, and handle the logic for all of the cart states. Whew, way to go!

It’s worth mentioning that the demo app we looked at is a sample application built for specifically for this purpose of this tutorial. There are a number of steps you’d want to go through for a production site, including testing, building the app’s dist folder, and using real Stripe keys. There are also so many ways to set this up, Serverless functions can be so flexible in tandem with something like Vue. Hopefully this gets you on track and saves you time as you try it out yourself.


Creating a Vue.js Serverless Checkout Form: Configure the Checkout Component is a post from CSS-Tricks

Creating a Vue.js Serverless Checkout Form: Application and Checkout Component

This is the third post in a four-part series. In part one, we set up a serverless Stripe function on Azure. Part two covered how we hosted the function on Github. This post will focus on wiring everything up as a Vue.js application.

Article Series:

  1. Setup and Testing
  2. Stripe Function and Hosting
  3. Application and Checkout Component (This Post)
  4. Configure the Checkout Component

Stripe has a number of ways to build out a checkout form, the most basic being a single button on the page that you trigger to pull up their custom modal. There’s a repo and component for this, but as easy as that is to implement (it’s probably the most simple way to do it), I wanted a little more customization and wanted the checkout flow to be part of the page and application. This approach wouldn’t work for my needs.

Stripe Elements

Stripe also offers a thing called Elements. Elements allow you to integrate Stripe’s payment system into your own checkout form and style it like your own site for a cohesive experience. It won’t feel like you’re using a third party plugin. They do have some pre-styled examples if you prefer something you can use right out of the box.

Luckily for us, there’s a really nice repo with a Vue version of Stripe Elements called vue-stripe-elements. The repo’s documentation is really nice, so you could check that out. Here’s how I put it to use:

npm i vue-stripe-elements-plus --save

…or using Yarn:

yarn add vue-stripe-elements-plus

Now let’s talk about our cart and integrate it.

The Cart

Here’s what everything looks like as a birds eye view of the application. We’ve already addressed the function and stripe pieces, now let’s dig into the application itself.

birds eye view of the application structure

We’re not going to go through setting up the entire application in these posts, rather just the Cart and Checkout. I’d suggest checking out the following links before continuing if you need to catch up on the basics of Vue, Vuex, and Nuxt:

  • CSS-Tricks Vue Guide
  • Simple Server Side Rendering, Routing, and Page Transitions with Nuxt.js

In our general store set up with Vuex, we hold a manifest of all of our product data used to populate the pages with items. We’ll also use that information to populate a (currently empty) cart object where items can be added for purchase. We’ll use that data on a page called `Cart.vue` in the pages directory. If you’re unfamiliar with Nuxt.js, it allows us to use .vue components as pages by creating them in this pages directory. We can still populate these pages with components from the components directory to create a more modular application. Here are the parts we’re discussing now:

Showing we're discussing cart.vue and vuex in the application

We’ll need two pieces of information from that store in Vuex: the contents of the cart and the cartTotal.

We’ll use computed properties in pages/Cart.vue to fetch that information so that we can cache and use them in the cart.

computed: { cart() { return this.$store.state.cart; }, cartTotal() { return this.$store.state.cartTotal; }, ...
}

…and we’ll create a new computed property that will store the monetary total of the items in the cart as well:

computed: { ... total() { return Object.values(this.cart) .reduce((acc, el) => acc + (el.count * el.price), 0) .toFixed(2); }
}

The first thing that we’ll do is see if the cart has items in it. If it does, then we need to check that the payment hasn’t already been processed. We need to do this because there’s no need to display a checkout form if there are no items in the cart or if payment has already been processed for the items that were added.

<div v-if="cartTotal > 0"> <!--we'll add our checkout here-->
</div> <!--If the cart is empty, give them the ability to get back to the main page to add items-->
<div v-else-if="cartTotal === 0 && success === false" class="empty"> <!--we'll add our empty state here-->
</div> <!--If there's a success, let's let people know it's being processed, we'll add a success component later on-->
<div v-else> <!--we'll add success here-->
</div>

We’ll also create a success property in our data that we’ll initially set to false and use later to record whether or not a payment was successfully submitted.

data() { return { success: false };
},

We want to show cart items if they exist, their individual totals (as we can have multiple counts of the same item) and the final total.

<div v-if="cartTotal > 0"> <h1>Cart</h1> <div class="cartitems" v-for="item in cart" key="item"> <div class="carttext"> <h4>{{ item.name }}</h4> <p>{{ item.price | usdollar }} x {{ item.count }}</p> <p>Total for this item: <strong>{{ item.price * item.count }}</strong></p> </div> <img class="cartimg" :src="`/${item.img}`" :alt="`Image of ${item.name}`"> </div> <div class="total"> <h3>Total: {{ total | usdollar }}</h3> </div> <!--we're going to add our checkout here-->
</div>

We’re using a filter to format the prices in US dollars. I format them this way instead of hardcoding them in case I need to support other currencies in the future.

filters: { usdollar: function(value) { return `$${value}`; }
}

Setting up the Checkout Component

Now we’re going to create our checkout component, which will hold all of the Stripe checkout logic and connect to the serverless function we set up in Part Two. We’ll register the component in the Cart.vue file:

import AppCheckout from './../components/AppCheckout.vue'; export default { components: { AppCheckout }, ...
}

Here’s where we’re at now:

Showing the Cart.vue in pages, as well as the checkout component

And, in the checkout component itself, we’ll bring over the base for the file that we saw in the vue-stripe-elements repo documentation:

<template> <div id='app'> <h1>Please give us your payment details:</h1> <card class='stripe-card' :class='{ complete }' stripe='pk_test_XXXXXXXXXXXXXXXXXXXXXXXX' :options='stripeOptions' @change='complete = $event.complete' /> <button class='pay-with-stripe' @click='pay' :disabled='!complete'>Pay with credit card</button> </div>
</template>
<script>
import { stripeKey, stripeOptions } from './stripeConfig.json'
import { Card, createToken } from 'vue-stripe-elements-plus' export default { data () { return { complete: false, stripeOptions: { // see https://stripe.com/docs/stripe.js#element-options for details } } }, components: { Card }, methods: { pay () { // createToken returns a Promise which resolves in a result object with // either a token or an error key. // See https://stripe.com/docs/api#tokens for the token object. // See https://stripe.com/docs/api#errors for the error object. // More general https://stripe.com/docs/stripe.js#stripe-create-token. createToken().then(data => console.log(data.token)) } }
}
</script>

Next Up…

So far, this is what the component looks like out of the box. We’re going to have to update this component a bit to fit our needs, but not too much. Stay tuned tomorrow for the final installment when we connect our component to our serverless function and finish up the checkout!

Article Series:

  1. Setup and Testing
  2. Stripe Function and Hosting
  3. Application and Checkout Component (This Post)
  4. Configure the Checkout Component

Creating a Vue.js Serverless Checkout Form: Application and Checkout Component is a post from CSS-Tricks

Creating a Vue.js Serverless Checkout Form: Stripe Function and Hosting

We’re now in the second post of a four-part series where we’re creating a checkout form application in Vue.js that can accept payments via the Stripe API. In part one, we looked at the concept of serverless functions, set one up in Azure, and connected it to a Stripe account. In this post, we’ll focus on setting up Stripe as a serverless function and hosting it all on Github.

Article Series:

  1. Setup and Testing
  2. Stripe Function and Hosting (This Post)
  3. Application and Checkout Component
  4. Configure the Checkout Component

First, we’re going write our function and test it out in the portal, but eventually we’re going to move it over to Github and have Azure pull in the code. I’ll explain why we do this in a moment.

For now, in order to get it working and testable, we’re going to write it in the portal and fill in the request body to perform the test. But we need to know what Stripe will expect from us first.

Dun dun dun…

Working With Stripe as a Serverless Function

If you check out Stripe’s documentation, you can see that we’ll need to grab the Stripe token in the dashboard. This will eventually mirror the POST parameters submitted by our form. Stripe makes it easy, so it’s fairly straightforward to use their library for the server-side function with Express:

app.get('/', (req, res) => res.render('index.pug', { keyPublishable })); app.post('/charge', (req, res) => { let amount = 500; stripe.customers .create({ email: req.body.stripeEmail, source: req.body.stripeToken }) .then(customer => stripe.charges.create({ amount, description: 'Sample Charge', currency: 'usd', customer: customer.id }) ) .then(charge => res.render('charge.pug'));
}); app.listen(4567);

We won’t need to set up all of Node and Express for this, though, as what we really need is the amount, the currency, the description, and the token, which we can integrate with the testing code we were provided earlier in the portal’s view of our function. So, let’s head over to the Azure portal where our function lives and update that default testing code to accept the parameters we need for Stripe, and also populate the request.body in the test panel.

We’ll add our Stripe testing key and kick everything off. To be totally sure, we’re going to log what we’ve gotten started:

var stripe = require('stripe')('sk_test_whateveryourtestingkeyisgoeshere');
// ^ this is a stripe testing key module.exports = function(context, req) { context.log('starting to get down');

If we have a request body, an email, and a token, then let’s get started. We’ll create a customer from the email and then use that customer to create the Stripe charges, passing in the amount of the charge as we do so.

if ( req.body && req.body.stripeEmail && req.body.stripeToken && req.body.stripeAmt
){ stripe.customers .create({ email: req.body.stripeEmail, source: req.body.stripeToken }) .then(customer => { context.log('starting the stripe charges'); stripe.charges.create({ amount: req.body.stripeAmt, description: 'Sample Charge', currency: 'usd', customer: customer.id }); }) ...

We also want to test if this all completed successfully, or if it errored out. If it did error, we need to log what that error is. We’ll also see if the whole thing errored entirely, making sure we’re logging everything appropriately along the way.

You’ll note that I log a lot. I think it’s not enough to know that something has errored. I want to know when the error happened and why so that I can track it down. This makes it much easier to debug if something were to go wrong.

 ... .then(charge => { context.log('finished the stripe charges'); context.res = { // status: 200 body: 'This has been completed' }; context.done(); }) .catch(err => { context.log(err); context.done(); }); } else { context.log(req.body); context.res = { status: 400, body: "We're missing something" }; context.done(); }
};

In the testing area on the right side of the portal, we’ll fill the request.body with the stripeEmail, stripeToken (a testing token in this case), and some random amount for the charge. When we run this, we can see that it works! We get a 200 OK Status, and we’ve logged This has been completed in the output.

actual function with testing request body params
Testing the request body parameters with the actual function in Azure.

Github-Hosted Serverless Function

Let’s put everything in Github now that it’s working. One big reason we want to do this is because our function will have a dependency on Stripe’s library. If you head over to the sample-stripe-handler repo I’ve created for this tutorial, you’ll see a package.json file. The most important lines in that file are these:

"dependencies": { "stripe": "^5.3.0"
}

This tells the function to pull in the correct version of the Stripe API that we need to use in order for our app to properly function. As a note, you could also use this method to write other kinds of functions using other libraries. This means the possibilities for what to create are endless!

We’ll pull everything from our function into this repo. This includes the function itself, the package.json file, as well as the contents of the function.json file that you’ll see in the “View Files” tab on the right in the Azure portal.

Once we have that all in ready to go in a Github repo, we’ll head back over to the Azure portal, because now we have to let Azure know that we’d like to use this repo to host our function instead of our test. We can still test our function inside the portal—we just won’t be able to edit it via the GUI anymore.

Click on the “Platform Features” tab and select the “Deployment Options” item.

Azure Portal Deployment Options

From here, click “Settings” then “Choose source” and a number of options will be provided. I’m going to choose Github because that’s where I want to host mine, but you can see that there are a lot of other ways we could have done this.

Choose github
Deployment settings source options, including Github.

Once Github has been selected, you will be able to configure which repo you would like to use as your deployment source. I chose the sample-stripe-handler repo that we created earlier.

Choose github repo for deployment option
Configuring Github as the deployment source.

After we’ve done this and it’s loaded, you’ll be taken to a “Deployments” screen that shows the last commit that you made to the repo. That means everything’s working correctly!

first deploy

Let’s test this a little further. My function didn’t work properly the first time because I was using ES6. I could have added in Babel, but I just converted it back to ES5 and pushed to the master branch. You can see the function.json becomes inactive as the last deployment, and my latest commit message—which is mostly me grumbling—is now the latest deploy! Awesome.

New deployment working

We can’t be too careful so, to check that these tests did indeed work, I’m going to head over to the Stripe dashboard. Sure enough, there are testing charges showing up in our dashboard 😀

Stripe dashboard with a little activity

One last thing!

We would be remiss to exclude our good friend CORS, which we need to properly enable for everything to communicate as it should. Let’s go to our function in the dashboard, and select CORS:

select cors

In the prompt that appears, we’ll whitelist our localhost dev server, as well as our final URL for the site. Voila! We’re all set.

whitelist localhost

Next Up…

We got a lot done in this post! Next, we’ll want to learn how to move away from testing only within the function and get this sucker communicating freely with a checkout experience that we’ll build within a Vue.js application. Stay tuned!

Article Series:

  1. Setup and Testing
  2. Stripe Function and Hosting (This Post)
  3. Application and Checkout Component
  4. Configure the Checkout Component

Creating a Vue.js Serverless Checkout Form: Stripe Function and Hosting is a post from CSS-Tricks