Subscribe on changes!

fix: support throw render error when ssr in production

avatar
Oct 10th 2023

Vue version

3.3.4

Link to minimal reproduction

https://play.vuejs.org/#eNp9U8tu3DAM/BVWF2sBx0aRW7Ab9IEAbYE+0ATtRRfD5tpKbcml5N0tDP97KQn7SBvkZnGG5HBIz+LtOBa7CcWNWLua9OjBoZ/GW2X0MFryMAPhFhbYkh0gY2qmjDK1Nc7D4FrYBFxmH7DvLfy01DevspUy6zKV40L88DiMfeWRXwDr7vXtPMfkZVmX/IpRbcbJw+5qsA32GyUYV4KhdXnKFrnwjltvdVs8OmtY9RxylajtMOoe6evoNUtT4gYiErCKle0/xZinCfNjvO6w/vVM/NEdQkyJb4QOaYdKnDBfUYs+wXf3X/DA3yeQlU89s18Av6Oz/RQ0Jtq7yTQs+4IX1X6M3mvTPri7g0fjjkMFoYG5RL4SvI/3L4x+lntdXMc8ZRZ2UTs3IVvIBqZNztDl0OBWm1jPGjQ+h5qQbecT4f2HPf+eNKGMR8ArPl5BuBDTID3Ye0+s+Sn5DbPLaCNdJR7SZfbnP6eGnPaPBBknSTIauToOFjJtj0VvW9nYehqYyiWPtqQ2ZzrxRZOBTmaN3mU5pGPN4ceE8VaTLReaKp54c55eXmiMrKfzSqavCt+hkbLzQ7+CzW1qfakzIqFNUVe+7qREIkv/c2NYZs4RxE/Wm5iBVJbQWHB2QN8Fp/fadxzZm5aqBsFbqDkv/EFpILH8BWncUH8=

Steps to reproduce

I want to catch some errors during vue server-side rendering in node.js instead of defining error handlers inside vue such as app.config.errorHandler. When I use the following code to catch an error, in the development environment vue will throw the error, but in the production environment vue swallows the error, which makes it impossible to catch the error with a catch

const { h, defineComponent, createApp } = require('vue')

const { renderToString } = require('@vue/server-renderer')

const MyComponent = defineComponent({
  created() {
    console.log(document)
  },
  render() {
    return h('div', 'Hello, Vue!')
  }
})

const app = createApp(MyComponent)

renderToString(app).then((html) => {
  console.log(html)
}).catch((error) => {
  console.error('ssr error', error)
  // do something with downgrade to csr mode
})

How to test

$ node issue.js // error can be caught
$ NODE_ENV=production node issue.js // error cannot be caught

The reason for the error is that vue handles error objects differently in development and production environments.

// vue/runtime-core.cjs.js
    if (appErrorHandler) {
      callWithErrorHandling(
        appErrorHandler,
        null,
        10,
        [err, exposedInstance, errorInfo]
      );
      return;
    }
  }
  logError(err, type, contextVNode, throwInDev);
}
function logError(err, type, contextVNode, throwInDev = true) {
  {
    const info = ErrorTypeStrings[type];
    if (contextVNode) {
      pushWarningContext(contextVNode);
    }
    warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`);
    if (contextVNode) {
      popWarningContext();
    }
    if (throwInDev) {
      throw err;
    } else {
      console.error(err);
    }
  }
}

In production environments vue will not throw error

// vue/runtime-core.cjs.prod.js

    const appErrorHandler = instance.appContext.config.errorHandler;
    if (appErrorHandler) {
      callWithErrorHandling(
        appErrorHandler,
        null,
        10,
        [err, exposedInstance, errorInfo]
      );
      return;
    }
  }
  logError(err, type, contextVNode, throwInDev);
}
function logError(err, type, contextVNode, throwInDev = true) {
  {
    console.error(err);
  }
}

What is expected?

We can use try catch some error during vue rendering process

What is actually happening?

try catch cannot catch some error during vue rendering process

System Info

No response

Any additional comments?

For the reasons mentioned aboveļ¼ŒPerhaps a configuration could be added here to decide whether or not to throw an error in the production environment

avatar
Oct 10th 2023

similar to #7876

avatar
Oct 20th 2023

I'm not even using SSR, but I just ran into this same issue when trying to add in a global unhandledrejection listener to show errors in my app. Bizarre behavior to have this functionality change between dev and prod!

avatar
Nov 10th 2023

Just to chime in: I was bitten by this as well, trying to handle unhandledrejection globally. Everything worked right up until I did a production build.