Nuxt error handler

Learn how to catch errors in different lifecycle.

Learn how to catch errors in different lifecycle.

Handling Errors

Nuxt 3 is a full-stack framework, which means there are several sources of unpreventable user runtime errors that can happen in different contexts:

  1. Errors during the Vue rendering lifecycle (SSR + SPA)
  2. Errors during API or Nitro server lifecycle
  3. Server and client startup errors (SSR + SPA)

Errors During the Vue Rendering Lifecycle (SSR + SPA)

You can hook into Vue errors using onErrorCaptured.

In addition, Nuxt provides a vue:error hook that will be called if any errors propagate up to the top level.

If you are using an error reporting framework, you can provide a global handler through vueApp.config.errorHandler. It will receive all Vue errors, even if they are handled.

Example With Global Error Reporting Framework

export default defineNuxtPlugin((nuxtApp) => {  nuxtApp.vueApp.config.errorHandler = (error, context) => {    // ...  }})

Server and Client Startup Errors (SSR + SPA)

Nuxt will call the app:error hook if there are any errors in starting your Nuxt application.

This includes:

  • running Nuxt plugins
  • processing app:created and app:beforeMount hooks
  • mounting the app (on client-side), though you should handle this case with onErrorCaptured or with vue:error
  • processing the app:mounted hook

Errors During API or Nitro Server Lifecycle

You cannot currently define a server-side handler for these errors, but can render an error page (see the next section).

Rendering an Error Page

When Nuxt encounters a fatal error, whether during the server lifecycle, or when rendering your Vue application (both SSR and SPA), it will either render a JSON response (if requested with Accept: application/json header) or an HTML error page.

You can customize this error page by adding ~/error.vue in the source directory of your application, alongside app.vue. This page has a single prop — error which contains an error for you to handle.

When you are ready to remove the error page, you can call the clearError helper function, which takes an optional path to redirect to (for example, if you want to navigate to a ‘safe’ page).

Make sure to check before using anything dependent on Nuxt plugins, such as $route or useRouter, as if a plugin threw an error, then it won’t be re-run until you clear the error.

Example

error.vue

<template>  <button @click="handleError">Clear errors</button></template><script setup>const props = defineProps({  error: Object})const handleError = () => clearError({ redirect: '/' })</script>

Error Helper Methods

useError

  • function useError (): Ref<Error | { url, statusCode, statusMessage, message, description, data }>

This function will return the global Nuxt error that is being handled.

createError

  • function createError (err: { cause, data, message, name, stack, statusCode, statusMessage, fatal }): Error

You can use this function to create an error object with additional metadata. It is usable in both the Vue and Nitro portions of your app, and is meant to be thrown.

If you throw an error created with createError:

  • on server-side, it will trigger a full-screen error page which you can clear with clearError.
  • on client-side, it will throw a non-fatal error for you to handle. If you need to trigger a full-screen error page, then you can do this by setting fatal: true.

Example

pages/movies/[slug].vue

<script setup>const route = useRoute()const { data } = await useFetch(`/api/movies/${route.params.slug}`)if (!data.value) {  throw createError({ statusCode: 404, statusMessage: 'Page Not Found' })}</script>

showError

  • function showError (err: string | Error | { statusCode, statusMessage }): Error

You can call this function at any point on client-side, or (on server side) directly within middleware, plugins or setup() functions. It will trigger a full-screen error page which you can clear with clearError.

It is recommended instead to use throw createError().

clearError

  • function clearError (options?: { redirect?: string }): Promise<void>

This function will clear the currently handled Nuxt error. It also takes an optional path to redirect to (for example, if you want to navigate to a ‘safe’ page).

Rendering Errors Within Your App

Nuxt also provides a <NuxtErrorBoundary> component that allows you to handle client-side errors within your app, without replacing your entire site with an error page.

This component is responsible for handling errors that occur within its default slot. On client-side, it will prevent the error from bubbling up to the top level, and will render the #error slot instead.

The #error slot will receive error as a prop. (If you set error = null it will trigger re-rendering the default slot; you’ll need to ensure that the error is fully resolved first or the error slot will just be rendered a second time.)

If you navigate to another route, the error will be cleared automatically.

Example

pages/index.vue

<template>  <!-- some content -->  <NuxtErrorBoundary @error="someErrorLogger">    <!-- You use the default slot to render your content -->    <template #error="{ error }">      You can display the error locally here.      <button @click="error = null">        This will clear the error.      </button>    </template>  </NuxtErrorBoundary></template>

If you’ve ever worked with Nuxt, you know that errors can be handled in a variety of ways, particularly when those errors result from HTTP requests made with Axios. There are 3 typical places in a Nuxt app where error handling logic can be written — the Vuex action, the page middleware, and the component. While it’s acceptable to use all 3 locations, wouldn’t it be nice to have a standardized way of dealing with the errors that are received, regardless of their structure? That’s the crux of the problem — your error handler has to be flexible enough to deal with different responses so that it doesn’t cause errors of its own.

In this post, we’ll discuss how we previously handled Axios errors in our Nuxt apps, why this approach was problematic, and how we fixed it by creating a package for consolidated error handling. We’ll then run through some examples of using the new approach.

The Old Approach

Our old error handling approach involved doing the following 2 things:

  1. Destructuring the Axios error response in a Vuex action
  2. Using the destructured response in a component

Let’s look at some example code.

Destructuring the Error Response

// Vuex action
async someAction() {
  try {
    const response = await this.$axios.$get('/some/endpoint')

    // Do something with the response (e.g., call a mutation on it)

  } catch ({ response }) {
    throw response
  }
}

In this action, we’re destructuring response from the Axios error so that we can use it directly in the component, as opposed to having to use error.response.

Using the Destructured Response in a Component

// A method in a component
async handleSubmit() {
  try {
    await this.$store.dispatch('someAction')
  } catch (errors) {
    // Set validation errors on a form
    this.form.setErrors(errors.data.errors)
  }
}

errors is equal to the response destructured from the Axios error, since that’s what we’re throwing in the Vuex action above. If you’ve written something similar to this, then you can probably see what the potential problems are with this approach. Let’s move on and discuss those.

The Problem with the Old Approach

There are 2 main problems with the error handling approach taken in the previous section:

  1. There’s no guarantee that there will be a response to destructure from the Axios error.
  2. We were expecting to have errors.data.errors in the component, but the error object that we get may not have that structure.

Having a Response to Destructure Isn’t Guaranteed

We can’t assume that we’ll have response on the error that we get back, since that may not always be the case. For example, if a network error occurs during an HTTP request, then error.response will be undefined. If that’s the case, the Vuex action will be throwing undefined, not an object, and our component will be trying to access properties on an object that isn’t defined. Our catch block will then result in an error of its own.

The Response Structure May Be Different from What Was Expected

We also can’t assume that the error response will have a specific structure. In the example above, we’re assuming that the error was a 422 validation error, which would have a structure like this:

response: {
  data: {
    message: 'The given data was invalid.',
    errors: {
      name: ['The name field is required.'],
    },
  },
}

Behind the scenes, our this.form.setErrors() method would perform some specific logic on the properties of response.data.errors. However, something else could go wrong, and we could get a 404, a 500, or some other error instead, which would not necessarily have response.data.errors. If this were the case, then our component method’s catch block would fail because response.data.errors would be undefined.

So how can we fix these issues? The purpose of our error handlers is what the name implies — to handle errors. We don’t want to potentially create other errors in trying to handle the ones we already have. Luckily, there’s a solution, and it’s simpler than you might think.

Fixing the Problem

In order to fix the issues discussed above, we have to do the following:

  • Handle network errors at the highest level possible
  • Create a class that will generate specific error messages for specific response statuses (e.g., 401, 404)
  • Create a class that will handle any error response

Using an Axios Interceptor to Handle Network Errors

It’s important to handle network errors at the highest level possible so that the error handlers within components don’t have to handle them. This is where an Axios interceptor comes in. You can read more about Axios interceptors in the docs, but here’s the gist of what we have to do:

  • Make an axios.js file in the plugins directory and register the plugin in the Nuxt config
  • Add an onError handler
  • Add an if block to the onError handler that checks for error.response and performs some logic if error.response is undefined

Let’s look at some example code.

// nuxt.config.js

plugins: [
  { src: '@/plugins/axios.js' }
]

// plugins/axios.js

export default ({ $axios, redirect, app }, inject) => {
  $axios.onError((error) => {
    if (error.response === undefined) {
      // Display a flash notification
      app.notify({
        title: 'Network Error: Please refresh and try again.',
        type: 'error',
        duration: -1,
      })

      throw error
    }

    // Handle other types of errors (e.g., redirect to login on 401 errors)

    throw error
  })
}

In this example, each time an Axios error occurs, the error is intercepted and checked to see if it has a response property. If it doesn’t, this indicates that a network error occurred. If that’s the case, we’re displaying a flash notification to the user and requesting that they refresh their browser.

Creating a Class to Generate Error Messages

A crucial part of good frontend error handling is displaying a message that is not only useful to the user, but that will also provide some helpful information to the support team and developers. This is where an ErrorMessages class comes in. This class will be used in conjunction with an Errors class, which is what will be responsible for parsing errors and returning the error message.

Let’s take a look at the ErrorMessages class.

// ErrorMessages.js

export const defaultErrorMessages = {
  401: `Not Authenticated: Sorry, you have to be logged in to access this!`,
  403: `Not Authorized: Sorry, you can't access this!`,
  404: `Not Found: We couldn't find what you're looking for. Please refresh and try again, or contact the support team.`,
  422: 'Validation Error',
  500: 'Server Error: Please contact the support team.',
}

export const defaultGeneralErrorMessage = 'Error: Please refresh and try again, or contact the support team.'

export default class ErrorMessages {
  /**
   * @param {object | null} errorMessages
   * @param {string | null} generalErrorMessage 
   */
  constructor(errorMessages, generalErrorMessage) {
    this.errorMessages = errorMessages || defaultErrorMessages
    this.generalErrorMessage = generalErrorMessage || defaultGeneralErrorMessage
  }

  /**
   * Retrieve the error message for a particular status code.
   *
   * @param {number} errorStatus
   * @return {string} errorMessage
   */
  getErrorMessage(errorStatus) {
    if (errorStatus && this.errorMessages[errorStatus]) {
      return this.errorMessages[errorStatus]
    }

    return this.generalErrorMessage
  }
}

In this file, we create some default error messages to use in case custom messages aren’t provided. We then simply use the getErrorMessage method to get the error message for the particular error status (e.g., 401), if there’s a status that matches. If not, we return the general error message. The getErrorMessage method will be used by the Errors class, which we’ll look at next.

Creating a Class to Handle Any Error Response

The purpose of the Errors class is to receive Axios errors and parse them, regardless of their structure, so that components can have a consistent error response to use when handling errors. We’ll only touch on a couple of the most relevant class methods here, but you can view the full class on GitHub if you’re interested.

First, we need to initialize the class in the constructor. This is where the ErrorMessages class is used.

/**
 * @param {object | null} customMessages
 * @param {string | null} customDefaultMessage 
 */
constructor(customMessages = null, customDefaultMessage = '') {
  this.errors = {}
  this.errorMessages = new ErrorMessages(customMessages, customDefaultMessage)
}

The first thing we’ll do when we use an instance of this class is set all errors, regardless of the error response structure.

/**
 * Set all errors, regardless of type.
 *
 * @param {*} errors
 * @return {self}
 */
setAll(errors) {
  this.errors = errors

  return this
}

setAll returns this so that it’s possible to chain other methods onto it. One such method is parse, which will parse the errors and return a consistent payload based upon the error status.

/**
 * Parse errors and return a payload based on error status.
 *
 * @return {object} errorResponse
 */
parse() {
  const status = this.errors.response ? this.errors.response.status : this.errors.status
  const errors = this.errors.response ? this.errors.response.data : this.errors.data

  if (status === 422) {
    this.setValidation(errors)
  }

  return {
    status,
    message: this.errorMessages.getErrorMessage(status),
  }
}

The setValidation method will destructure errors, which is the object that will contain validation errors, from the error response and set those as the class instance’s errors. This makes it easier to work with validation errors.

Now let’s take a look at how we can actually use this new approach.

Using the New Approach

We’ve turned this approach into a package, @zaengle/error-handler, which you can view on npm. You can also view the package code and documentation on GitHub. In Nuxt, third-party packages are commonly used as plugins, so we’ll walk through how to make one for the error handler package. We’ll then examine how to use that plugin at both the page level, within anonymous middleware, and at the component level, within a custom method.

Creating a Nuxt Plugin

Creating a Nuxt plugin will prevent us from having to import the Error class in every component in which we need to use it.

// plugins/error-handler.js

import ErrorHandler from '@zaengle/error-handler'

export default (context, inject) => {
  inject('errorHandler', new ErrorHandler())
}

// nuxt.config.js

plugins: [
  { src: '@/plugins/error-handler.js' }
]

Using the Plugin in a Page

It’s common in a Nuxt app to use the middleware function to request data on page load. The potential errors from such requests can be handled in the following manner.

// pages/somePage.vue

async middleware({ store, error, $errorHandler }) {
  try {
    // This could also be an Axios request
    await store.dispatch('someAction')
  } catch (errors) {
    const errorResponse = $errorHandler.setAndParse(errors)

    error({
      statusCode: errorResponse.status,
      message: errorResponse.message
    })
  }
}

Since we added the error handler to the app’s context in the plugin, it can be destructured as the $errorHandler argument in the middleware function.

Notice that we do not do any destructuring of the errors argument passed to the catch block — this is to avoid one of the issues we discussed above, which is destructuring something that may not be present. Instead, we simply pass whatever errors we receive to the error handler’s setAndParse method, which is a method that simply calls the setAll and parse methods that we saw in the previous section. We then pass the status and the message, which we know we’ll be getting because they’re from an object of our own construction, to Nuxt’s error method so that the error message can be displayed on the error page.

Using the Plugin in a Component

There are also instances in which we’ll need to handle errors in the methods in our components. Let’s take a look at an example.

// components/someComponent.vue

export default {
  methods: {
    handleSomething() {
      try {
        // This could also be an Axios request
        await this.$store.dispatch('someAction')
      } catch (errors) {
        const errorResponse = this.$errorHandler.setAndParse(errors)

        // Do something with errorResponse (e.g., display a flash notification)
        this.notify({
	  status: errorResponse.status,
	  message: errorResponse.message
	})
      }
    }
  }
}

As we saw in the page example, we do not do any destructuring of the errors argument passed to the catch block. Instead, we simply pass whatever errors we get to our error handler and let the class take care of parsing them.

Wrapping Up

Error handling is one of the most important aspects of a frontend JavaScript application, but it can also be something that’s difficult to do gracefully. This is largely due to the fact that we may not always get the error structure that we’re expecting, or we may not even get an error response at all. To circumvent these potential issues, we can do the following:

  • Deal with network errors at the highest level (i.e., in an Axios interceptor) so that our components aren’t trying to handle errors that don’t have a response
  • Avoid destructuring error arguments in components and instead pass whatever errors we get to a class that will parse them and give us a consistent, predictable response that can be used in our error handlers

If you’d like to implement this approach in your apps, feel free to give our package a try. If you have alternate methods of dealing with the error handling issues mentioned in this post, please let us know @zaengle.

  1. Hero image

@AvailCat

I’m using nuxt.js in our production environment, but i can’t find any document about how to capture and analyze exceptions during running asyncData or nuxtServerInit.

I suggest to add options like Vue.config.errorHandler to nuxt.config.js, this will allow us capture exception, inject request id into response

This question is available on Nuxt.js community (#c1512)

@piyushchauhan2011

Why not pull out the exception handling code in Vuex store. You can use try, catch block to capture and trigger error handling from store. As for routing, vue-router provides changing route from store which you can trigger after receiving exception. @Meeeeow

@AvailCat

@piyushchauhan2011 Huge try...catch is not a good solution. Change route? I don’t need jump to another page after exception, but i need a hook to receive exceptions from asyncData, which not control by Vue.config.errorHandle.
Nuxt print exception to console rather than throw it, so there is not way to send exceptions to third part service such as Sentry

@piyushchauhan2011

ahh like a middleware than can send the thrown exception to bugsnag or sentry. I like the idea 👍 @Meeeeow . There has to be a way to capture after request completed exceptions and send them to sentry as well as handle them at same time to show nice error page etc. using middleware

@DiederikvandenB

@DiederikvandenB

I dove a bit deeper in the code and found the problem. Nuxt allows us to register custom server middleware, but this gets loaded before Nuxt’s own middleware. See: https://github.com/nuxt/nuxt.js/blob/75350cdd78d17e565b6c58d6c1aaa00c5146cbae/lib/core/renderer.js#L277-L288

The Connect docs explain:

When a middleware passes an error to next, the app will proceed to look for the error middleware that was declared after that middleware and invoke it, skipping any error middleware above that middleware and any non-error middleware below.

Meaning that if we define an error middleware (by requesting the err object in addition to the req, res, next) this middleware is injected before the error actually appears, rendering the function useless.

@DiederikvandenB

Using the Nuxt Modules I was able to get Sentry working. Check this gist.

You will want to add the sentry.js and sentry-client.js files to the modules directory, and then add the module to your nuxt.config.js using the correct settings.

A quick explanation what this code does. As I explained in the comment above, the problem is that we cannot add our own error handling because it’s loaded before Nuxt’s own middleware. What I did is ‘backup’ the original nuxtErrorMiddleware, then I overwrite it with the middleware that actually loads Sentry, and then I execute the original nuxtErrorMiddleware again, so we see the nicely printed error.

@Atinux

@hackuun

I don’t understand why this issue is closed? I don’t want to use Sentry. How to handle errors in Nuxt? This is so confusing. I have error that Error template is not catching. You guys can explain how to handle it, please?

@DiederikvandenB

While I agree with the fact that it would be great to have a more straightforward way to handle errors, or maybe better documentation regarding this subject, but the answer to your question is already posted above, @iamdubx.

You could either check out my gist, or my module, which you can find here: https://github.com/nuxt-community/sentry-module. If you do not want to use Sentry that is of course perfectly fine. You can just modify the code, specifically this file. Just remove all the references to Sentry/Raven and add your own error handler on what is now rule number 53. Good luck.

@DualWield

I don’t understand why this issue is closed? I also want to know how to handle global errors in Nuxt .

@DiederikvandenB

@DualWield

@DiederikvandenB Thank you. Yes, it seems that can solve this problem.But I dont’ know how to (where to) hook the errorMiddleware. Is there something in the document ?

@DiederikvandenB

Check these two lines and this example.

Basically what you need to do is create a plugin which hooks on to the render:errorMiddleware. Good luck =).

@Atinux, would you appreciate a PR for the docs in which I explain the errorMiddleware hook?

@Atinux

@DiederikvandenB

In that case I’ll have a look at it tonight!

@nicroto

Nuxt.js is great.

A single «check how this project does it» line within the API docs, though, is not a good documentation.
Please, consider an example within the docs of the (supposedly) simple issue of Handling Errors in SSR, which doesn’t have the inherent distraction (and over-complication) of trying to distil it from a whole project.

Thanks for working on this issue.

@ChrisRobston

You guys are rock!!! Just letting you know, sorry for flood.

@lock

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock
lock
bot

locked as resolved and limited conversation to collaborators

Nov 1, 2018

Server-side rendering (SSR) is an application’s ability to preload a website in the server before sending it to the client to be hydrated by your JavaScript bundle. Hydration refers to the process in which JS takes over the static HTML sent by the server and turns it into a dynamic DOM, which can then react to client-side data changes.

SSR adds a whole new layer to web apps, and despite its many benefits, it may cause problems for developers. SSR means that some work is done on the server, which can be a source for bugs; therefore, these errors need to be handled appropriately as they would be in any normal web application.

Because multiple tools exist to help developers build SSR web apps, in this article we are going to focus on the best practices for gracefully handling errors. I’ll also present some examples showcasing how it may be done in Next.js or Nuxt.js.

Best practices for handling errors in SSR apps

An app that handles errors gracefully will enable the flow of known or unknown errors in a controlled manner, which will help the user and developers know that something went wrong without completely blocking the app’s process.

SSR applications have both a client and server side, so we need to know what to do on both in order to have a complete end-to-end error handling system.

Handing SSR errors on the client side

Our client side will deal mostly with the frontend as we know it. The following is a list of ways in which you can handle errors gracefully on your SSR app’s frontend.

Try…catch blocks

Try…catch blocks help catch errors in asynchronous calls. These errors are output in the catch block, and my be used to notify the user of a potential error and even send it up via an error service:

const handleSignUp = async (email) => {
  try {
    await backend.emailVerificationLink(email)
  } catch(error) {
    console.error(error) // you may also 
    setHasErrors(true)
  }
}

Interceptors for network errors

If you are using an HTTP client like Axios, you can easily handle errors in your app using an interceptor, which will perform a particular action based on the error received from a request or during a response:

axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  });

More tools for handling client-side errors

Client-side error handling is easy with help of tools like react-error-boundary in React. It helps by providing a wrapper that you can use around your components to gracefully handle any errors that occur in that context:

function ErrorFallback({error, resetErrorBoundary}) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre>{error.message}</pre>
    </div>
  )
}

const ui = (
  <ErrorBoundary
    FallbackComponent={ErrorFallback}
    onReset={() => // reset the state of your app so the error doesn't happen again }}
  >
    <ComponentThatMayError />
  </ErrorBoundary>
)

Vue.js also provides an errorCaptured hook that will work like a charm whenever any component in its hierarchy catches an error. These errors will be channeled to a global error handler, onto which you may attach a logger:

// in component.vue
errorCaptured(err, instance, info) {
  // handle inside component (/! caution component state still editable)
}

// in main.ts
Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` is a Vue-specific error info, e.g. which lifecycle hook
  // the error was found in. Only available in 2.2.0+
}

LogRocket: The ultimate solution for handling client-side errors

While using an option like react-error-boundary will surface an error, it won’t give you any insight into why the issue occurred. If you’re interested in automatically surfacing client-side errors, monitoring and tracking Redux state, and tracking slow network requests and component load time, try LogRocket. LogRocket Dashboard Free Trial Banner

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — start monitoring for free.

Handling SSR errors on the server side

Catching errors in data fetchers

The early return pattern refers to returning values as early as possible to help end a function and get a result.

For example, in Next, you would write your getInitialProps function this way:

import Error from "next/error"

function Page({ stars, statusCode}) {  
  if (statusCode !== 200) {
    <Error statusCode={statusCode} />
  } 
  return <div>Next stars: {stars}</div>
}

Page.getInitialProps = async (ctx) => {
  try{
    const res = await fetch('https://api.github.com/repos/vercel/next.js')
    const json = await res.json()

    if (res.status >= 400) {
      return { stars: json.stargazers_count, statusCode: res.status }
    }
    return { stars: json.stargazers_count, statusCode: 200 }    
  } catch(error) {
    return {stars: null, statusCode: 503}
  }
}

This will ensure that you are able to render Page correctly if the result is correct. If there’s an error during the request, it will be gracefully handled and shown to the user using Next’s Error component.

In Nuxt, there are the fetch and asyncData hooks, which are able to handle errors by themselves. These hooks are all used to fetch data, however, they do not handle the process in a similar manner.

Diagram showing lifecycle of Nuxt hook

Source: Nuxt docs

Handling the errors at the fetching point of the app is definitely one of the most important error management tasks in an SSR application.

Error status codes

There are many recognizable HTTP error codes. Usually, the codes you may want to display to the user are client errors (400-500). Otherwise, every error code should still be caught and logged.

In case your SSR app uses server or API middleware, you need to return the appropriate errors too, because they operate exactly as a backend to your app.

Redirect to error pages

In case an error causes your page to get messy (loading or not found), you always want to have a fallback page or component that will help describe the error to the user and hide any unnecessary technical details that may not help the user fix it.

Next already provides a static 404 page that will pop up anytime a user tries to access a nonexistent page. However, you may need a custom 404 page in case you need to add information, or to suit your branding needs.

This is done by creating a pages/404.js file, which is able to fetch data at build time if required. Note that you can do the same with the status code 500 referring to server errors:

// pages/404.js
export default function Custom404() {
  return <h1>404 - Page Not Found</h1>
}

// pages/500.js
export default function Custom500() {
  return <h1>500 - Server-side error occurred</h1>
}

If ever you need to have a different error description page based on the the error caught, you can resort to more advanced error page customizations, which work using Next’s error component. You can override it by customizing pages/_error.js

In Nuxt, you are gifted with a special layout defined in a layouts/error.vue file. This layout is basically a Vue component with the ability to catch errors along with their status codes. This gives developers a great amount of flexibility:

<!-- layouts/error.vue -->
<template>
  <div>
    <h1 v-if="error.statusCode === 404">Page not found</h1>
    <h1 v-else>An error occurred</h1>
    <NuxtLink to="/">Home page</NuxtLink>
  </div>
</template>

<script>
  export default {
    props: ['error'],
    layout: 'error' // you can set a custom layout for the error page
  }
</script>

Handle and log everything

Because you are in an SSR environment, there’s much more involved than just the user interfaces. Sometimes you deal with middleware and serverMiddlewares in Nuxt or Next.js, which may perform some work on your pages before, during, or after render. These should return appropriate errors, because they act as part of your code.

In certain SSR websites, the server or API middleware act as a full-fledged backend. They may handle API calls like an Express server would. These can easily connect to your logging engine and handle API request errors as they would in Node.

Having your errors handled from end to end will grant you the ability to drill through errors, and find their origin and root cause.

Reporting and logging tips

Once your application gets into a user’s hands, it will be beneficial for you start handling and extracting logs via a log engine. These logs will come with information on almost every interaction on your app, provided you have the correct setup.

Because you can analyze them in real time, you are also able to pull out errors, anomalies, or any other issue that may come from your applications usage.

Today, there are a plethora of log analysis and management tools. For example, you can see here how Next is used with Sentry to catch and handle errors.

Most of these existing log management tools integrate seamlessly with LogRocket to provide you with well-detailed session information during error reporting.

Wrapping up

Error handling is one of the most important parts of development. Doing it gracefully requires developers to have a good planning and a solid understanding of how errors flow in their web apps.

SSR apps are no less than web apps with a further server step. These server additions increase the work required to have an elegant end-to-end error handling process in your app. However, modern frameworks give us the ability to handle errors following simple steps that scale effortlessly.

Generally, on the client side, you’d wrap your asynchronous calls in try…catch blocks to stop the browser from trying to handle the error itself. This way, you’ll transform it to something understandable and let it flow to the user and to your log engine. On the server side, you can catch and return errors using conventional codes so your client side has no problem trying to understand what went wrong.

LogRocket: Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket. LogRocket Dashboard Free Trial Banner

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your Next.js apps — start monitoring for free.

Nuxt.js — это фреймворк для приложений, основанный на Vue.js.

Мы можем использовать его для создания приложений с рендерингом на стороне сервера и статических сайтов.

В этой статье мы рассмотрим, как обрабатывать ошибки асинхронных данных и плагины с Nuxt.js.

Обработка ошибок

Мы можем обрабатывать ошибки на наших страницах, когда получаем асинхронные данные.

Для этого мы пишем:

<template>
  <div>{{ title }}</div>
</template>
<script>
import axios from "axios";
export default {
  async asyncData({ params, error }) {
    try {
      const { data } = await axios.get(
        `https://jsonplaceholder.typicode.com/posts/${params.id}`
      );
      return { title: data.title };
    } catch {
      error({ statusCode: 404, message: "Post not found" });
    }
  },
};
</script>

У нас есть метод asyncData с объектом, имеющим свойство error.

error — это функция, с помощью которой мы можем отобразить ошибку.

Ресурсы

Nuxt использует загрузчики веб-пакетов vue-loader, file-loader и url-loader для обслуживания ресурсов.

Также мы можем использовать папку static для статических ресурсов.

Чтобы добавить активы, мы можем написать:

<template>
  <div class="container">
    <img src="~/assets/kitten.jpg" />
  </div>
</template>
<script>
export default {};
</script>

~ — это сокращение от корневой папки Nuxt.

Статический

Мы также можем обслуживать ресурсы из папки static.

Например, мы можем переместить наш файл в папку static и написать:

<template>
  <div class="container">
    <img src="/kitten.jpg" />
  </div>
</template>
<script>
export default {};
</script>

/ — это сокращение для static folder.

Плагины

Мы можем добавлять плагины в наше приложение.

Они могут поставляться как внешние пакеты, такие как Axios.

Или мы можем использовать плагины Vue.

Чтобы использовать плагины Vue, мы должны добавить их вручную.

Например, если мы хотим добавить всплывающую подсказку к нашему приложению, мы устанавливаем пакет v-tooltip, запустив:

npm install --save v-tooltip

Затем мы создаем plugins/vue-tooltip.js и добавляем:

import Vue from 'vue'
import VTooltip from 'v-tooltip'
Vue.use(VTooltip)

Затем в nuxt.config.js мы добавляем:

plugins: [
  '@/plugins/vue-tooltip.js'
],

Затем мы можем использовать его как обычно, написав:

<template>
  <div class="container">
    <button v-tooltip="'hello world'">hello</button>
  </div>
</template>
<script>
export default {};
</script>

Вставить в $ root & context

Мы также можем сделать функции доступными во всем нашем приложении.

Для этого мы можем вызвать функцию inject.

Мы можем создать наш собственный плагин, добавив plugins/hello.js:

export default (context, inject) => {
  const hello = msg => console.log(`hello ${msg}!`)
  inject('hello', hello)
}

Затем мы можем добавить наш плагин в nuxt.config.js:

plugins: [
  '@/plugins/hello.js'
],

Затем мы можем вызвать нашу hello функцию, написав:

<template>
  <div class="container"></div>
</template>
<script>
export default {
  mounted() {
    this.$hello("james");
  },
};
</script>

Также нам понадобятся:

context.$hello = hello

в функции, которую мы экспортировали, если мы используем Nuxt 2.12 или более раннюю версию.

Мы также можем использовать функцию $hello с функцией asyncData, написав:

<template>
  <div class="container"></div>
</template>
<script>
export default {
  mounted() {
    this.$hello("james");
  },
  asyncData({ $hello }) {
    $hello("asyncData");
  },
};
</script>

$hello является частью параметра контекста asyncData.

Заключение

Мы можем обрабатывать ошибки, когда получаем данные.

Кроме того, мы можем создавать собственные плагины и функции и внедрять их в наше приложение.

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Numplate light ошибка bmw
  • Numeric overflow occurred during computation teradata ошибка
  • Numeric or value error oracle
  • Numeric or value error number precision too large
  • Numeric or value error invalid lob locator specified ora 22275

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии