Repository: vuejs/vue
Pull request: fix(#8567): handle errors on immediate watchers

As stated in the [related issue](https://github.com/vuejs/vue/issues/8567), the handle callback call should be wrapped in a try/catch that explicitly calls handleError.

fix #8567

<!--
Please make sure to read the Pull Request Guidelines:
https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#pull-request-guidelines
-->

<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->

**What kind of change does this PR introduce?** (check at least one)

- [x] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:

**Does this PR introduce a breaking change?** (check one)

- [ ] Yes
- [x] No

If yes, please describe the impact and migration path for existing applications:

**The PR fulfills these requirements:**

- [x] It's submitted to the `dev` branch for v2.x (or to a previous version branch), _not_ the `master` branch
- [x] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [x] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [x] New/updated tests are included

If adding a **new feature**, the PR's description includes:
- [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

**Other information:**
This is my first PR so feel free to provide feedback or request modifications both in the code and the PR itself! 😄 

Changed files:
filename: src/core/instance/state.js
patch: @@ -351,7 +351,11 @@ export function stateMixin (Vue: Class<Component>) {
     options.user = true
     const watcher = new Watcher(vm, expOrFn, cb, options)
     if (options.immediate) {
-      cb.call(vm, watcher.value)
+      try {
+        cb.call(vm, watcher.value)
+      } catch (error) {
+        handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`)
+      }
     }
     return function unwatchFn () {
       watcher.teardown()

filename: test/unit/features/error-handling.spec.js
patch: @@ -92,6 +92,16 @@ describe('Error handling', () => {
     }).then(done)
   })
 
+  it('should recover from errors in user immediate watcher callback', done => {
+    const vm = createTestInstance(components.userImmediateWatcherCallback)
+    waitForUpdate(() => {
+      expect(`Error in callback for immediate watcher "n"`).toHaveBeenWarned()
+      expect(`Error: userImmediateWatcherCallback error`).toHaveBeenWarned()
+    }).thenWaitFor(next => {
+      assertBothInstancesActive(vm).end(next)
+    }).then(done)
+  })
+
   it('config.errorHandler should capture render errors', done => {
     const spy = Vue.config.errorHandler = jasmine.createSpy('errorHandler')
     const vm = createTestInstance(components.render)
@@ -234,6 +244,21 @@ function createErrorTestComponents () {
     }
   }
 
+  components.userImmediateWatcherCallback = {
+    props: ['n'],
+    watch: {
+      n: {
+        immediate: true,
+        handler () {
+          throw new Error('userImmediateWatcherCallback error')
+        }
+      }
+    },
+    render (h) {
+      return h('div', this.n)
+    }
+  }
+
   // event errors
   components.event = {
     beforeCreate () {