Vue render error

Весь прошлый год я работал с моим любимым фреймворком, Vue.js, описывал и представлял его. И я понял, что ещё не разобрался с обработкой ошибок во Vue. Мне бы хотелось объяснить это тем, что я пишу идеальный код, но мы все знаем, как обстоит дело в действительности. В течение нескольких последних дней я экспериментировал с различными методами обработки ошибок, которые предоставляет Vue, и решил поделиться своими открытиями. Очевидно, что этот обзор не охватит все возможные сценарии, но я надеюсь, что он вам поможет!

Весь прошлый год я работал с моим любимым фреймворком, Vue.js, описывал и представлял его. И я понял, что ещё не разобрался с обработкой ошибок во Vue. Мне бы хотелось объяснить это тем, что я пишу идеальный код, но мы все знаем, как обстоит дело в действительности. В течение нескольких последних дней я экспериментировал с различными методами обработки ошибок, которые предоставляет Vue, и решил поделиться своими открытиями. Очевидно, что этот обзор не охватит все возможные сценарии, но я надеюсь, что он вам поможет!

Ошибки

Чтобы протестировать различные методы обработки, я решил взять три разных типа ошибок (по крайней мере, для начала). В первом случае это было просто обращение к несуществующей переменной:

<div id="app" v-cloak>
  Hello, {{name}}
</div>

В этом примере пользователю не выдаётся сообщение об ошибке, но в консоль выводится предупреждение [Vue warn].


Вот как выглядит выполнение этого примера:

Во втором примере я попытался связать переменную с вычисляемым свойством, которое должно генерировать ошибку:

<div id="app" v-cloak>
  Hello, {{name2}}
</div>
const app = new Vue({
  el:'#app',
  computed:{
	name2() {
  	return x;
	}
  }
})

В этом случае в консоль выводится как предупреждение [Vue warn], так и обычное сообщение об ошибке, но пользователю не выдаётся ничего.

Вот так выполняется код для этого примера:

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

<div id="app" v-cloak>
   	<button @click="doIt">Do It</button>
</div>
const app = new Vue({
  el:'#app',
  methods:{
   	  doIt() {
          	  return x;
   	  }
  }
})

Как и в предыдущем случае, сообщение об этой ошибке в консоли будет выводиться дважды: одно предупреждение и одно сообщение о данной ошибке. Но, в отличие от него, ошибка возникает только при реальном нажатии на кнопку.

И вот демонстрация для этого примера:

Прежде чем мы продолжим, я хочу пояснить, что в этих примерах представлены не все типы ошибок, которые вы можете сделать. Это всего лишь несколько основных, которые, по моему мнению, могут часто встречаться в приложениях на базе Vue.js.

Итак, как же вы можете обрабатывать ошибки в приложениях Vue? Надо сказать, я был немного удивлен, что в основном руководстве по фреймворку Vue нет раздела, посвящённого обработке ошибок.

Да, подобный раздел в руководстве есть, но весьма короткий, и весь его смысл умещается в следующую цитату:

«Если при отрисовке компонента произойдёт ошибка выполнения, она будет передана в глобальную функцию конфигурации Vue.config.errorHandler, если таковая была указана. Наверное, полезно было бы использовать этот хук совместно с сервисом отслеживания ошибок, таким как Sentry, тем более что его интеграция с Vue официально поддерживается».

На мой взгляд, эта тема должна чуть больше раскрываться в документации (и я думаю, что мог бы помочь в её дополнении). В общем, обработка ошибок во Vue сводится к следующим средствам:

  • errorHandler;
  • warnHandler;
  • renderError;
  • errorCaptured;
  • window.onerror (это средство не является специфическим для Vue).

Давайте подробно рассмотрим эти приёмы.

Средство обработки ошибок номер один: errorHandler

Первое средство — это errorHandler. Как вы, вероятно, догадались, это стандартный обработчик ошибок для приложений Vue.js. Вы можете назначить его следующим образом:

Vue.config.errorHandler = function(err, vm, info) {

}

В приведённом выше объявлении функции err — это описание текущей ошибки, info — строка информации об ошибке, специфичная для Vue, а vm — текущее приложение Vue. Помните, что на одной веб-странице могут одновременно выполняться несколько приложений Vue. Этот обработчик ошибок будет относиться к ним всем. Рассмотрим следующий простой пример:

Vue.config.errorHandler = function(err, vm, info) {
  console.log(`Error: ${err.toString()}nInfo: ${info}`);
}

В случае первой ошибки этот код не выполняет никаких действий. Если вы помните, при этом генерируется предупреждение, а не сообщение об ошибке.

Во втором случае ошибка обрабатывается и выводится следующий текст:

Error: ReferenceError: x is not defined
Info: render

Наконец, третий пример даёт следующий результат:

Error: ReferenceError: x is not defined
Info: v-on handler

Обратите внимание, насколько «полезна» информация под заголовком Info в двух предыдущих примерах. Теперь проверим, как работает следующее средство.

Средство обработки ошибок номер два: warnHandler

warnHandler обрабатывает — что бы вы думали? — предупреждения Vue. Заметьте, что в продакшене этот обработчик игнорируется. Обработчик для этого метода также слегка отличается от предыдущего:

Vue.config.warnHandler = function(msg, vm, trace) {

}

Два первых аргумента — msg и vm — не требуют дополнительных пояснений, а аргумент trace должен быть деревом компонентов. Рассмотрим пример:

Vue.config.warnHandler = function(msg, vm, trace) {
  console.log(`Warn: ${msg}nTrace: ${trace}`);
}

В первом примере теперь есть обработчик для генерируемого им предупреждения, и он возвращает следующее:

Второй и третий примеры не изменяются. Живые примеры для всех трёх случаев представлены ниже.

Средство обработки ошибок номер три: renderError

Теперь я продемонстрирую третий метод обработки ошибок: renderError. В отличие от предыдущих двух, это средство зависит от компонента и не является универсальным. Так же, как и в случае с warnHandler, этот обработчик в продакшене отключается.

Чтобы его использовать, вставьте его в свой компонент/приложение. Ниже приведён изменённый пример из документации.

const app = new Vue({
  el:'#app',
  renderError (h, err) {
	return h('pre', { style: { color: 'red' }}, err.stack)
  }
})

Если этот обработчик ошибок используется в первом примере, то он ничего не делает, что, если подумать, вроде бы логично, так как первый пример выдаёт предупреждение, а не ошибку. Если вы проверите этот обработчик во втором примере, где ошибку выдаёт вычисляемое свойство, то увидите, что его результат на экране отображается. Вы можете это увидеть в приведённой ниже демонстрации на CodePen.

Честно говоря, мне не совсем понятно, зачем использовать это средство, когда консоль гораздо удобнее, однако если отдел контроля качества или другие тестировщики не знакомы с консолью браузера, то более простое сообщение об ошибке на экране может им помочь.

Средство обработки ошибок номер четыре: errorCaptured

Наконец, есть средство errorCaptured (специфично для Vue), которое привело меня в замешательство и, честно говоря, до сих пор немного смущает. В документации говорится следующее:

«Вызывается, если фиксируется ошибка в любом дочернем компоненте. Этот хук получает три аргумента: ошибку, экземпляр компонента, который вызвал ошибку, и строку, содержащую информацию о том, где была зафиксирована ошибка. Хук может возвращать значение false, чтобы предотвратить дальнейшее распространение ошибки».

Согласно моим исследованиям (опять-таки, я сильно сомневаюсь в этом), этот обработчик ошибок должен использоваться только родительским компонентом, обрабатывающим ошибку дочернего компонента. Насколько я знаю, его нельзя использовать в основном экземпляре Vue, а можно только в компоненте, имеющем потомков.

Чтобы проверить это, я создал вот такой набор из родительского и дочернего компонентов:

Vue.component('cat', {
  template:`
<div><h1>Cat: </h1>
  <slot></slot>
</div>`,
  props:{
    name:{
      required:true,
      type:String
    }
  },
   errorCaptured(err,vm,info) {
    console.log(`cat EC: ${err.toString()}ninfo: ${info}`);
     return false;
  }

});

Vue.component('kitten', {
  template:'<div><h1>Kitten: {{ dontexist() }}</h1></div>',
  props:{
    name:{
      required:true,
      type:String
    }
  }
});

Обратите внимание, что компонент kitten содержит ошибку. Теперь, если я попытаюсь использовать этот компонент следующим образом,

<div id="app" v-cloak>
  <cat name="my cat">
      <kitten></kitten>
  </cat>
</div>

я получу от обработчика сообщение:

cat EC: TypeError: dontexist is not a function
info: render

Вы можете это увидеть в приведённом ниже примере.

Так что да, интересное средство. Я полагаю, что оно будет в основном использоваться теми, кто создаёт библиотеки компонентов с отношениями типа родитель/потомок. Это средство скорее подходит для разработчика библиотеки, чем для обычного разработчика, если такое деление имеет смысл. Но опять-таки, это только моё первое впечатление от данного средства.

Единое средство для управления всем на свете: window.onerror

Последний (и самый мощный) вариант — использовать window.onerror, глобальный обработчик ошибок для всего, что только может случиться при выполнении вашего JavaScript-кода. Этот обработчик имеет следующий формат:

window.onerror = function(message, source, line, column, error) {

}

Вероятно, единственное, о чём вы не можете догадаться в приведённом выше коде, это смысл аргумента source, который представляет собой URL-адрес скрипта.

Вот здесь-то и начинается самое интересное. Если вы определите эту функцию, но при этом не используете Vue.config.errorHandler, то она вам не поможет. Vue ожидает, что вы определите Vue.config.errorHandler, и, если вы этого не сделаете, не распространит ошибку за свои пределы. Наверное, в этом есть какой-то смысл… Даже не знаю, для меня особого смысла в этом нет. Ещё более странная вещь: допустим, в самом вашем обработчике ошибок Vue есть ошибка. Она также не дойдёт до обработчика window.onerror.

Вот демонстрация на CodePen с соответствующим примером. Я закомментировал ошибку в errorHandler, но если вы уберёте комментарий, то увидите, что глобальный обработчик ошибок не сработает. Он сработает только в одном случае: если вы нажмёте вторую кнопку.

Заключение

Надеюсь, материал этой статьи будет полезен читателям. Как уже написано в самом начале, этой темой я только начал заниматься, поэтому, разумеется, жду комментариев, замечаний и предложений. Я с удовольствием прочитаю, как другие разработчики используют эти средства в своих приложениях!

Фото в начале статьи: автор — Дэвид Коваленко, сайт Unsplash

В этой статье я хотел бы описать встроенные методы обработки ошибок существующие во Vue.js. Очевидно, что я не опишу каждый возможный сценарий, но я надеюсь, что эта статья поможет познакомиться с работой с ошибками во Vue.js!

Ошибки!

Чтобы протестировать различные методы обработки ошибок, я решил использовать три разных типа ошибок. Первый просто ссылка на переменную, которой не существует:

<div id="app" v-cloak>
  Hello, {{name}}
</div>

Этот пример не будет отображать ошибку для пользователя, он должен выводить предупреждение [Vue warn] в консоль.

Error messages

Вы можете просмотреть этот пример здесь:

Для второго примера я попытался связать переменную с вычисляемым свойством, которая выводит ошибку:

<div id="app" v-cloak>
  Hello, {{name2}}
</div>

<script>
const app = new Vue({
  el:'#app',
  computed:{
    name2() {
      return x;
    }
  }
})
</script>

Этот код так же выдает [Vue warn] и обычную ошибку в консоли но при этом ничего не показывает пользователю в окне браузера.

Error messages

Вот код для него.

Для третьей ошибки я использовал метод, который выдает ошибку при выполнении.

<div id="app" v-cloak>
 <button @click="doIt">Do It</button>
</div>

<script>
const app = new Vue({
  el:'#app',
  methods:{
    doIt() {
      return x;
    }
  }
})
</script>

Как и предыдущая, эта ошибка будет выводится дважды в консоли, одно предупреждение и одна ошибка. В отличие от прошлого раза, ошибка появляется только тогда, когда вы нажмете на кнопку.

Error with the click handler

И вот код для него:

Хорошо, прежде чем мы продолжим, я просто хочу прояснить, что эта выборка не репрезентативно для каждого типа ошибок, которые можно создать, это всего лишь базовый показатель из нескольких вариантов, который, я думаю, достаточно распространены в приложениях Vue.js.

Итак, как вы обрабатываете ошибки в приложениях Vue? Я должен сказать, что был немного удивлен, что в главном Vue Guide не было четко определенного раздела по обработке ошибок.

Results for Error

Да, есть общее описание в руководстве, но текст достаточно короткий, и весь может поместиться в одну цитату:

Если во время рендеринга компонента возникает ошибка выполнения, она будет передана в глобальную конфигурационную функцию Vue.config.errorHandler(если она была задействована). Возможно, было бы неплохо использовать этот хук вместе с сервисом отслеживания ошибок, таким как Sentry, который обеспечивает официальную интеграцию для Vue.

На мой взгляд, эта тема должна быть описана более подробно в документации. В общем, обработка ошибок в Vue сводится к следующим методам:

  • errorHandler
  • warnHandler
  • renderError
  • errorCaptured
  • window.onerror (не Vue-специфическая техника)

Первый метод обработки ошибок: errorHandler

Первый метод, который мы рассмотрим, это errorHandler. Как вы можете догадаться, это общий обработчик ошибок для приложений Vue.js. Его использование выглядит так:

Vue.config.errorHandler = function(err, vm, info) {

}

В приведенном выше объявлении переменная err — это фактический объект ошибки, info — это строка ошибки, специфичная для Vue, а vm — фактическое приложение Vue. Помните, что одновременно на одной веб-странице может работать несколько приложений Vue. Этот обработчик ошибок будет применяться ко всем из них. Рассмотрим этот простой пример:

Vue.config.errorHandler = function(err, vm, info) {
  console.log(`Error: ${err.toString()}nInfo: ${info}`);
}

Для первого примера кода эта обработка ошибки ничего не делает. Если вы помните, оно выдает предупреждение, а не ошибку.

Для второго примера кода, она обработает ошибку и выдаст сообщение:

Error: ReferenceError: x is not defined
Info: render

Наконец, для третьего примера она выдаст такой сообщение:

Error: ReferenceError: x is not defined
Info: v-on handler

Теперь давайте проверим следующий метод.

Второй метод обработки ошибок: warnHandler

warnHandler Vue предупреждения. Обратите внимание, что этот обработчик игнорируется во время режима продакт. Обработчик метода также немного отличается:

Vue.config.warnHandler = function(msg, vm, trace) {

}

Переменные msg, и vm самоочевидны, а trace содержит дерево компонентов. Рассмотрим этот пример:

Vue.config.warnHandler = function(msg, vm, trace) {
  console.log(`Warn: ${msg}nTrace: ${trace}`);
}

Первый пример кода теперь обрабатывается и выдает предупреждения:

Warn: Property or method 'name' is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
Trace: 

(found in <Root>)

Второй и третий примеры не меняются. Вы можете просмотреть работу примером ниже:

Третий метод обработки ошибок: renderError

Третий метод, который я продемонстрирую, это renderError. В отличие от предыдущих двух, этот метод используется только внутри компонентов, а не глобально. Также, как warnHandler, он отключен в режиме продакт.

Чтобы его использовать, нужно описать его в компоненте или приложение. Пример использования:

const app = new Vue({
  el:'#app',
  renderError (h, err) {
    return h('pre', { style: { color: 'red' }}, err.stack)
  }
})

Если он использовать в первом примере с ошибкой, он ничего не делает, так как первый выдает предупреждение, а не ошибку. Если вы задействуете его во втором, c вычисляемым свойством то будет вывод ошибки на экрана браузера. Вы можете увидеть это в коде ниже.

Честно говоря, я не уверен, для каких целей я бы использовал этот метод. На мой взгляд консоль более подходящее место для вывода ошибок, но если ваша команда QA или другие тестировщики не знакомы с консолью браузера, этот метод может помочь вывести сообщение об ошибке на экране.

Четвертый метод обработки ошибок: errorCaptured

Финальный (специфичной для Vue) метод errorCaptured. В документации о нем сказано:

Вызывается, когда фиксируется ошибка любого потомка компонента. Хук получает три аргумента: ошибку, экземпляр компонента, который вызвал ошибку, и строку, содержащую информацию о том, где была зафиксирована ошибка. Хук может вернуть false, чтобы предотвратить дальнейшее распространение ошибки.

Основываясь на моих исследованиях (я определенно шокирован этим), этот обработчик ошибок должен использоваться только «родительским» компонентом, обрабатывающим ошибку «дочернего» компонента. Насколько я знаю, его нельзя использовать в основном экземпляре Vue, только в компоненте с дочерними элементами.

Чтобы проверить этот метод, я создал родительский / дочерний набор компонентов, например:

Vue.component('cat', {
  template:`
<div><h1>Cat: </h1>
  <slot></slot>
</div>`,
  props:{
    name:{
      required:true,
      type:String
    }
  },
   errorCaptured(err,vm,info) {
    console.log(`cat EC: ${err.toString()}ninfo: ${info}`); 
     return false;
  }

});

Vue.component('kitten', {
  template:'<div><h1>Kitten: </h1></div>',
  props:{
    name:{
      required:true,
      type:String
    }
  }
});

Обратите внимание, что в компоненте kitten есть ошибка. Теперь, если я попытаюсь использовать:

<div id="app" v-cloak>
  <cat name="my cat">
      <kitten></kitten>
  </cat>
</div>

Я получу сообщение от обработчика:

cat EC: TypeError: dontexist is not a function
info: render

Вы можете просмотреть это в коде ниже.

Так что да … интересный метод. Я предполагаю, что он будет в основном использоваться людьми, создающими библиотеки компонентов с отношениями типа родительский / дочерний. Это скорее метод «разработчика библиотеки», чем метод «обычного разработчика». Но опять же — это только мое первоначальное впечатление от этого метода.

Единый метод, чтобы управлять ими всеми: window.onerror

Obligatory LOTR reference ring

Последний (и самый мощный) вариант — использование window.onerror, глобальный обработчик ошибок для всего, что может пойти не так с вашим JavaScript. Обработчик имеет форму:

window.onerror = function(message, source, line, column, error) {

}

Вероятно, единственное,о чем вы не можете догадаться, это что такое переменная source. В ней содержится URL скрипта. Здесь все становится интереснее. Если вы определите этот метод и не используете Vue.config.errorHandler, то он не будет работать. Vue ожидает, что вы определите errorHandler а, если вы этого не сделаете, не распространит ошибку за пределы себя.

Вот пример использование этого метода. Я закомментировал ошибку в errorHandler, но если вы удалите комментарий, вы увидите, что глобальный обработчик ошибок не запускается. Единственное, что вы можете увидеть — запуск глобального обработчика, при нажатие на вторую кнопку.

Заключение

Я надеюсь, что эта статья была для вас полезна. Мне бы очень хотелось услышать, как люди используют эти методы в своих приложениях!

Перевод статьи: Handling Errors in Vue.js

Была ли вам полезна эта статья?

« Back to home

Posted on 2018.12.09

· Tagged in

vue

How to handle errors in Vue.js in a generic way and how to highlight the component that triggered the error.

This article describes a solution to handle all unexpected errors centrally in a Vue.js application, to process and visualize them in an uniform way. Here’s how the end result looks like:

Specifically for this purpose, Vue.js has a very handy errorCaptured hook. This is how it works:

Vue.component('bad-component', {
    template: `&lt;div&gt;The bad guy&lt;/div&gt;`,
    created: function() { throw new Error('oops!') }
});

var vm = new Vue({
    template: `&lt;div&gt;
        &lt;h2&gt;My application&lt;/h2&gt;
        &lt;bad-component&gt;&lt;/bad-component&gt;
    &lt;/div&gt;`,
    errorCaptured: function(err, component, details) {
        alert(err);
    }
});

show(vm);

By the way: code examples are editable.

The hook can be added not only to the Vue instance, but also to any Vue component. Errors are bubbling up through the components to the Vue instance, triggering all errorCaptured hooks on the way. In order to stop propagation, errorCaptured should return false.

Update: Initially, Vue.js was not catching errors in methods, but this was fixed back in December 2018, so I removed a big part of this article that was explaining how to workaround that methods problem.

And this also works if the error happens in a method:

Vue.component('bad-component', {
    template: `&lt;button @click="badOne"&gt;Click me&lt;/button&gt;`,
    methods: {
        badOne: function() { throw new Error('from method') }
    }
});

var vm = new Vue({
    template: `&lt;div&gt;
        &lt;h2&gt;My application&lt;/h2&gt;
        &lt;bad-component&gt;&lt;/bad-component&gt;
    &lt;/div&gt;`,
    errorCaptured: function(err, component, details) {
        alert(err);
    }
})

show(vm)

That’s it! Easy, isn’t it?

Displaying the error

Now we only need to implement some UI for displaying the error message and highlighting the component where it occured.

Because we’re using errorCaptured (as opposed to the global config.errorHandler), we have the context where we can easily display some error message.

So if we add to template something like:

<div v-if="error" class="app-error">{{ error }}</div>

Then we can display it like this:

var vm = new Vue({
    // ....
    data: {
        error: ""
    },
    errorCaptured: function(err, component, details) {
        error = err.toString();
    }
}

Notice we also have component as one of the parameters. And Vue components have $el property that points to the DOM element. Even though it’s a bad practice to do something directly with DOM elements when you are using Vue.js, but we’re now talking about exceptional situations which shouldn’t happen at all (in best case scenario).

So to highlight the component, we can use $el. Here’s the naïve code implementing this idea:

errorCaptured: function(err, component, details) {
    this.error = err.toString() || "Unexpected error has occured!";
    component.$el.classList.add("error-frame");
}

By testing this in practice, I was able to discover some cases when $el is not yet available when errorCaptured is fired (e.g. when error happens in render function), so you need to defer it with setTimeout. Also, if render fails, $el will be empty comment element, so we need to detect that as well and probably highlight the parent component instead.

Finally, we also need to have a close button so that user can clear the error message.

Ok, so here’s the final version:

Vue.component('bad-component', {
    template: `&lt;button @click="badOne"&gt;Click me&lt;/button&gt;`,
    methods: {
        badOne: async function() {
            var response = await fetch("https://non-existent-url");
            var data = await response.json();
            console.log(data);
        }
    }
});

var vm = new Vue({
    template: `&lt;div&gt;
        &lt;h2&gt;My application&lt;/h2&gt;
        &lt;bad-component&gt;&lt;/bad-component&gt;
        &lt;div v-if="error" class="app-error"&gt;
            {{ error }}
            &lt;span class="close-button" v-on:click="removeError"&gt;&amp;#10005;&lt;/span&gt;
        &lt;/div&gt;
    &lt;/div&gt;`,
    data: {
        error: "",
        errorEl: null
    },
    errorCaptured: function(err, component, details) {
        var _self = this;
        _self.error = err.toString() || "Unexpected error has occured!";
        setTimeout(function() {
            _self.errorEl = component.$el;
            if (!_self.errorEl || _self.errorEl.nodeName=="#comment")
                _self.errorEl = component.$parent.$el;
            _self.errorEl.classList.add("error-frame");
        }, 0)
    },
    methods: {
        removeError: function() {
            if (!this.error)
                return;
            this.error = "";
            this.errorEl.classList.remove("error-frame");
            this.errorEl = null;
        }
    }
});

show(vm)

By the way, if you’re using vue-router, it might be also useful to remove error automatically if user leaves current view:

router.afterEach((to, from) => {
    vm.removeError();
});

Conclusion

Vue has a powerful mechanism for catching errors on multiple levels. You can create error boundaries, or catch the errors centrally,
and it is possible to visually highlight the component where error has happened.

Наличие  в приложении эффективного механизма обработки ошибок дает много преимуществ:

  • Предотвращение остановки приложения при возникновении необработанного исключения.
  • Возможность отслеживания и оперативного исправления ошибок.
  • Информирование пользователей о произошедшем сбое и предоставление альтернативного варианта интерфейса.

Это четвертая часть серии статей о разработке приложения на Vue.js. Исходники созданного приложения доступны здесь.

В этой статье мы научимся работать с ошибками и исключениями в приложении, созданном на основе Vue.js. В этом фреймворке доступно два способа обработки:

  • С помощью глобальной конфигурации Vue.js.
  • С помощью хуков ErrorBoundaries или errorCaptured .
  • Применение глобальной конфигурации в Vue.js:
  • Использование хуков errorBoundaries и errorCaptured:
  • Заключение

В фреймворке Vue.js есть объект Vue.config. Он содержит глобальные конфигурации приложения: журналов ошибок и предупрежденийсредства разработкиобработчика ошибок  и т.д.

Мы можем переопределить конфигурацию обработки ошибок с помощью функции Vue.config.errorHandler. Она вызывается для всех не перехваченных исключений, которые возникли в любом компоненте приложения.

Пример регистрации обработчика ошибок:

import Vue from 'vue';

Vue.config.errorHandler = (err, vm, info) => {
  

};

Обработчик принимает три параметра:

  1. err: трассировка ошибок, содержит message и error stack;
  2. vm: компонент Vue/экземпляр, в котором произошла ошибка;
  3. info: специфическая информация Vue: хуки жизненного цикла, события и т.д.

Обработчик Vue.config.errorHandler фиксирует ошибки, характерные для экземпляров Vue. Он не сможет зафиксировать ошибки, которые произошли вне экземпляра.

Для перехвата сторонних ошибок, которые возникают вне экземпляра Vue, можно обработать событие окна onerror. Для этого нужно зарегистрировать хэндлер, который будет перехватывать все необработанные исключения вне экземпляра Vue. Например:

window.onerror = function(message, source, lineno, colno, error) {
  //код для обработки ошибок
};

В Vue.js 2.5.0 появился новый хук errorCaptured. Он позволяет обрабатывать специфические ошибки компонента внутри самого компонента. Хук errorCaptured имеет такой же синтаксис и принимает те же параметры, что и errorHandler:

	export default {
	  name: "app-user-list",
	
	  created() {
	    this.$store.dispatch(actionsTypes.FETCH_USER_DATA);
	  },
	
	  errorCaptured(err, vm, info) {
	    // err: трассировка ошибки
	    // vm: компонент, в котором произошла ошибка
	    // info: специфическая информация об ошибке.
	    // TODO: Perform any custom logic or log to server
	    // возвращаем false, чтобы остановить распространение ошибок. Затем переходим к родительскому или глобальному обработчику ошибок.
	  }
	};

Хук errorCaptured в компоненте Vue

Ограничение диапазона перехватываемых ошибок являются еще одной формой использования хука errorCaptured. Для этого создается компонент, который отвечает за перехват необработанных ошибок и исключений в дереве дочерних компонентов. Он регистрируют эти ошибки или отображают резервный пользовательский интерфейс. Пример реализации:

error-boundary.vue

	<template>
	  <div>
	    <slot
	      v-if="err"
	      name="error"
	      v-bind:err="err"
	      v-bind:vm="vm"
	      v-bind:info="info"
	    >Something went wrong</slot>
	    <slot v-else></slot>
	  </div>
	</template>
	
	<script>
	export default {
	  name: "error-boundary",
	  props: {
	    stopPropagation: Boolean
	  },
	  data() {
	    return {
	      err: false,
	      vm: null,
	      info: null
	    };
	  },
	  errorCaptured(err, vm, info) {
	    this.err = err;
	    this.vm = vm;
	    this.info = info;
	
	    return !this.stopPropagation;
	  }
	};
	</script>
	
	<style lang="scss" scoped>
	</style>

Пример использования:

<template>
	  <div class="user-list">
	    <error-boundary>
	      <app-user-item/>
	    </error-boundary>
	  </div>
	</template>

Любая не перехваченная ошибка или исключение в компоненте app-user-item будет обработана компонентом error-boundary.

Если приложение работает в пределах error-boundary , тогда оно будет вести себя как глобальный обработчик ошибок errorHandler.

По умолчанию ошибка, перехваченная хуками errorCaptured , будет распространяться на его родительский компонент и затем на глобальный обработчик ошибок (config.errorHandler). Такое  распространение можно остановить, вернув false из метода errorCaptured.

Я подготовил шаблон этой архитектуры. Вы можете найти его здесь.

В этой статье мы рассмотрели реализацию глобальной обработки ошибок с помощью объекта config.errorHandler. А также локальный обработчик на основе хука errorCaptured.

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement. We’ll occasionally send you account related emails.

Already on GitHub?
Sign in
to your account

Comments

@lovetingyuan

Version

3.0.0-rc.11

Reproduction link

https://codesandbox.io/s/github/lovetingyuan/vue3-comment-render-bug

Steps to reproduce

github: https://github.com/lovetingyuan/vue3-comment-render-bug
1 use vite to serve the website
2 click button: show list
3 click first item

What is expected?

There should no errors.

What is actually happening?

vue.js:1166 [Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue-next 
  at <KeepAlive> 
  at <App>
warn @ vue.js:1166
logError @ vue.js:1339
handleError @ vue.js:1331
callWithErrorHandling @ vue.js:1285
flushJobs @ vue.js:1487
flushJobs @ vue.js:1500
Promise.then (async)
queueFlush @ vue.js:1387
queueCb @ vue.js:1409
queuePostFlushCb @ vue.js:1415
queueEffectWithSuspense @ vue.js:2458
scheduler @ vue.js:6425
run @ vue.js:479
trigger @ vue.js:485
set @ vue.js:578
showContent @ C:Usersvue3-comment-render-bugcomponentsListComp.vue:22
_createBlock.onClick._cache.<computed>._cache.<computed> @ C:Usersvue3-comment-render-bugcomponentsListComp.vue:3
callWithErrorHandling @ vue.js:1282
callWithAsyncErrorHandling @ vue.js:1291
invoker @ vue.js:8003
vue.js:7722 Uncaught (in promise) TypeError: Failed to execute 'insertBefore' on 'Node': parameter 1 is not of type 'Node'.
    at insert (vue.js:7722)
    at move (vue.js:6014)
    at move (vue.js:5976)
    at move (vue.js:5962)
    at Object.sharedContext.deactivate (vue.js:4034)
    at unmount (vue.js:6024)
    at patch (vue.js:5070)
    at componentEffect (vue.js:5665)
    at Object.reactiveEffect [as update] (vue.js:343)
    at updateComponent (vue.js:5549)

@lovetingyuan
lovetingyuan

changed the title
vue render error when there is comment node

vue render error when there is comment node and keep-alive and dynamic component

Sep 16, 2020

@lovetingyuan

I am not sure about the reason. But if I remove keep-alive or remove the comment node in ListComp.vue, there is no render error.

@lovetingyuan

Excuse me, but I found the bug still occurs when built in production mode.

Run yarn build and use dist as http server root dir. The issue mentioned above is still there.

index.5a30f16e.js:1 TypeError: Failed to execute 'insertBefore' on 'Node': parameter 1 is not of type 'Node'.
    at insert (index.5a30f16e.js:1)
    at Z (index.5a30f16e.js:1)
    at Z (index.5a30f16e.js:1)
    at Z (index.5a30f16e.js:1)
    at Object.i.deactivate (index.5a30f16e.js:1)
    at Q (index.5a30f16e.js:1)
    at w (index.5a30f16e.js:1)
    at index.5a30f16e.js:1
    at Object.n [as update] (index.5a30f16e.js:1)
    at L (index.5a30f16e.js:1)
{
  "dependencies": {
    "vue": "3.0.0"
  },
  "devDependencies": {
    "@vue/compiler-sfc": "3.0.0",
    "vite": "1.0.0-rc.4"
  }
}

@yyx990803 Could you check it? Thanks a lot.

@underfin

@lovetingyuan

Yep, I use cross-env NODE_ENV=production vite build, and it works well. So it is not a vue’s bug, right? If so, please feel free to close this issue. Thanks!

Понравилась статья? Поделить с друзьями:
  • Vts ошибка а57
  • Vts ошибка a50 motsup
  • Vts ошибка a225
  • Vtosters не работает музыка ошибка
  • Vtm 4 honda pilot ошибка