2019年9月2日 星期一

[Vue] Error handling


 Vue.js   Error handling   Typescript 



Introduction


We are going to learn how to do global error handling in Vue.js, including of:




Type: (err: Error, vm: Component, info: string)

The global error handler for uncaught errors during component render function and watchers.
Notice that it can also catch the error from asynchronous function, but the call stacks must be all async.



Type: (err: Error, vm: Component, info: string) => ?boolean

This hook (method) is put on a parent component and will be called when an error from sub-component(s) is captured.
We can return false on this hook to stop propagating further.



The sample codes in based on Typescript.
However, the concept and codes can be applied to Javascript.


Related articles

2.  [Vue] Error Handling





Environment


vue.js 2.6.6
Vue CLI 3.5.1
typescript 3.2.1


Implement

               
Global error handler

Lets create a custom error handler and assign it to Vue.config.errorHandler later.

error-handler.ts

import toastr from 'toastr';

/**
 * Format component's name
 *
 * @param {*} vm {Compoent}
 */
const formatComponentName = (vm: any) => {
  if (vm.$root === vm) {
    return 'root';
  }
  const name = vm._isVue
    ? (vm.$options && vm.$options.name) ||
      (vm.$options && vm.$options._componentTag)
    : vm.name;
  const errComponent = name ? 'Component "' + name + '"' : 'unknown component';
  const errFile =
    vm._isVue && vm.$options && vm.$options.__file ? vm.$options && vm.$options.__file : '';
  return `${errComponent} at ${errFile}`;
};

/**
 * Global error handler
 *
 * @param {*} err {Error message}
 * @param {*} vm {Compoent}
 * @param {*} info {Error information}
 */
const errorHandler = (err: any, vm: any, info: any) => {
  // err: error trace
  // vm: component in which error occured
  // info: Vue specific error information such as lifecycle hooks, events etc

  // Do something here…
  // For example, use toastr to show the error
  toastrCustom.error(err);

};

export { errorHandler };



Then we can configure the global error handler,

main.ts (for Vue CLI)

import { errorHandler as customErrorHandler } from '@/modules/error-handler';

/* Global Vue config */
Vue.config.errorHandler = customErrorHandler;


It’s done!
Here are some captured samples.

Normal error

const err = 'Shit happens';
throw err;

Result:





Error from Async function

When using async-await on function, make sure the call stacks are all async-await.
If you call an async function in another non-async function, the error from the async function will NOT BE CAPTURED by the global error handler!

async mounted() {
  
    await new Promise((resolve, reject) => {
        reject('Shit happens in Asyc function')
      });
},






errorCaptured hook

We can put an errorCaptured hook on a parent component to capture the error(s) from sub-components.
Take the following routes for example, the Main component is supposed to has the errorCaptured hook.

const routes = [
  {
    name: 'main',
    component: Main,
    children: [
      { path: 'home', name: 'home', component: Home },
      { path: 'about', name: 'about', component: About }
    ],
  },
];



Main.vue

<script lang="ts">
export default Vue.extend({
  name: 'Main',
  data() {
    return {
    };
  },
  errorCaptured (err: any, vm: any, info: any) {
    // Do something here…
    toastr.error(err);
  }
});
</script>


Now we can capture error(s) from sub-component. For example, we get an error when mounting the sub-component, and results in:





Wait a minute! Why we got 2 error messages on one error?
Because the errorCaptured hook in default propagated the error on upper level, so the global error handler also captured the error.
To stop the errorCaptured hook propagate further, return false inside it.

errorCaptured (err: any, vm: any, info: any) {
    toastrCustom.error(err);
    return false;
},


More..

Though we can capture most errors, however it’s hard and costly trying to catch all errors on client-side.
It is recommend to use Sentry for advanced usage.



Reference









沒有留言:

張貼留言