Hey!
April has been a quieter month for me, which is nice after the busyness of the first part of this year.
I'm going to be giving a talk at Vue.JS Live on April 25th, so make sure you don't miss it!
You can check it out here: https://vuejslive.com/
Also, don't forget to check out the latest Deja Vue podcast episode here.
As always, here are your tips.
— Michael
null
Proper error handling is a crucial part of any production app, even if it isn’t the most exciting thing.
Nuxt 3 comes with the NuxtErrorBoundary
component which makes handling client-side errors a breeze:
<NuxtErrorBoundary><!-- Put components in here --></NuxtErrorBoundary>
Use the error
named slot and the error
object to show an error message to the user:
<template #error="{ error }"><div><p>Oops, it looks like the video player broke :/</p><p>{{ error.message }}</p></div></template>
If we pass the error
object to another method, we can more easily manipulate it in order to resolve our error:
<NuxtErrorBoundary><ImageViewer /><template #error="{ error }"><div><p>Oops, the image viewer isn't working properly!</p><p>{{ error.message }}</p><!-- Pass the error to another method to recover --><p><button @click="recoverFromError(error)">Try again</button></p></div></template></NuxtErrorBoundary>
Use a recoverFromError
function to set the value of the error
ref to null
and re-render the default slot:
const recoverFromError = (error) => {// Try to resolve the error hereerror.value = null;}
In some cases, a more drastic action might be needed, like navigating to a safe page using the navigateTo
utility:
const recoverFromError = async (error) => {// Navigate away first, otherwise we'll get stuck in a loopawait navigateTo('/');error.value = null;};
You can place NuxtErrorBoundary
components around distinct chunks of functionality, like each widget in an admin dashboard, to contain and handle errors in specific ways.
This is better than simply having a generic error message that’s shown no matter what the error is. By isolating errors with NuxtErrorBoundary
we can show more useful error messages and provide better ways of recovering!
Learn more from the docs: https://nuxt.com/docs/api/components/nuxt-error-boundary
If you've got large chunks of static or mostly static content, you can tell Vue to (mostly) ignore it using the v-once
directive:
<template><!-- These elements never change --><div v-once><h1 class="text-center">Bananas for sale</h1><p>Come get this wonderful fruit!</p><p>Our bananas are always the same price — ${{ banana.price }} each!</p><div class="rounded p-4 bg-yellow-200 text-black"><h2>Number of bananas in stock: as many as you need</h2><p>That's right, we never run out of bananas!</p></div><p>Some people might say that we're... bananas about bananas!</p></div></template>
This can be a helpful performance optimization if you need it.
The v-once
directive tells Vue to evaluate it once and never update it again. After the initial update it's treated as fully static content.
Here are the docs for v-once.
It's possible to add global properties to your Vue app in both Vue 2 and Vue 3:
// Vue 3const app = createApp({});app.config.globalProperties.$myGlobal = 'globalpropertiesftw';// Vue 2Vue.prototype.$myGlobal = 'globalpropertiesftw';
I would recommend prefixing any global properties with a $
.
This helps prevent naming conflicts with other variables, and it's a standard convention that makes it easy to spot when a value is global.
This global property can be accessed directly off of any component when using the Options API:
computed: {getGlobalProperty() {return this.$myGlobal;},},
Why can't this be used with the composition API?
Because the composition API is designed to be context-free and has no access to this
.
Instead, you can create a simple composable to access your globals:
<script setup>import useGlobals from './useGlobals';const { $myGlobal } = useGlobals();</script>
// useGlobals.jsexport default () => ({$myGlobal: 'globalpropertiesftw',});
Composables are great, except that it seems we always need to create a new file for them.
In this article I explore some ways we can create inline composables — no need to create new files all over the place!
Check it out here: 3 Ways to Create Inline Composables
"What one programmer can do in one month, two programmers can do in two months." — Fred Brooks
The best way to commit something to long-term memory is to periodically review it, gradually increasing the time between reviews 👨‍🔬
Actually remembering these tips is much more useful than just a quick distraction, so here's a tip from a couple weeks ago to jog your memory.
If you need to run a piece of code only once, there’s a Nuxt composable for that (since 3.9):
<script setup>await callOnce(async () => {// This will only be run one time, even with SSR});</script>
Using callOnce
ensures that your code is only executed one time — either on the server during SSR or on the client when the user navigates to a new page.
It also has a key similar to useFetch
or useAsyncData
, to make sure that it can keep track of what’s been executed and what hasn’t:
<script setup>['one', 'two', 'three'].forEach(item => {// Run once for each itemcallOnce(item, async () => {// Do something with the item});});</script>
By default Nuxt will use the file and line number to automatically generate a unique key, but this won’t work in all cases.
p.s. I also have four products/courses: Clean Components Toolkit, Vue Tips Collection 2, Mastering Nuxt 3, and Reusable Components