getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
8.01k stars 1.58k forks source link

vue-router: TypeError: Cannot read properties of undefined (reading '__vccOpts') #14080

Open phlegx opened 3 weeks ago

phlegx commented 3 weeks ago

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/node

SDK Version

8.35.0

Framework Version

Vue 8.35.0

Link to Sentry event

No response

Reproduction Example/SDK Setup

I have a Vue 3 (3.5.4) application using vue-router (4.4.3) and with SSR environment. In the Vue app I use @sentry/vue (8.35.0) and for production I use express node server.

Vue package.json

{
  "scripts": {
    ...
    "server:run": "NODE_ENV=production node --import ./server/instrument.js server"
  }
} 

server/instrument.js

import * as Sentry from '@sentry/node'

Sentry.init({
  dsn: process.env.DSN,
  tracesSampleRate: 1.0,
  profilesSampleRate: 1.0,
})

server/index.js

import * as Sentry from '@sentry/node'
...
const { default: renderPage } = await import(path.join(root, 'dist/server/main.js')) /* Vue server client app. */
...
app.use('*', async (request, response) => {
  try {
    ...
    const { html, status, statusText, headers } = await renderPage(url, {
      manifest,
      preload: true,
      request,
      response,
    })
    ...
})
...
Sentry.setupExpressErrorHandler(app)
...
app.listen(port)

After run the server with yarn server:run I get the following error on first server call. The node server crashes completely.

TypeError: Cannot read properties of undefined (reading '__vccOpts')
    at file:///.../node_modules/vue-router/dist/vue-router.mjs:2172:55
TypeError: Cannot read properties of undefined (reading '__vccOpts')
    at file:///.../node_modules/vue-router/dist/vue-router.mjs:2172:55
file:///.../node_modules/vue-router/dist/vue-router.mjs:2172
                    const options = resolvedComponent.__vccOpts || resolvedComponent;

router/index.js

import { RouterView } from 'vue-router'
import { asyncLoadRouter } from '@common/helpers'

export default [
  {
    path: '/',
    component: RouterView,
    children: [
      {
        path: '',
        component: asyncLoadRouter('WrapperHome'),
        children: [
          {
            path: '',
            name: 'home',
            component: asyncLoadRouter('wrapper/Home'),
          },
        ],
      }
    ],
  },
]

Steps to Reproduce

  1. Build Vue app with vite
  2. Run yarn server:run
  3. Open application in browser
  4. Error is thrown. Removing --import ./server/instrument.js from server:run script, the error is not thrown.

Expected Result

The server should run without throwing this error, like before adding @sentry/node code. If I use only @sentry/vue in the Vue app, all works fine. Adding @sentry/node to express server script causes node server crash.

Is there also a way to isolate @sentry/node import on express server from @sentry/vue in Vue app?

Actual Result

After run the server with yarn server:run I get the following error on first server call. The node server crashes completely.

node server log

TypeError: Cannot read properties of undefined (reading '__vccOpts')
    at file:///.../node_modules/vue-router/dist/vue-router.mjs:2172:55
TypeError: Cannot read properties of undefined (reading '__vccOpts')
    at file:///.../node_modules/vue-router/dist/vue-router.mjs:2172:55
file:///.../node_modules/vue-router/dist/vue-router.mjs:2172
                    const options = resolvedComponent.__vccOpts || resolvedComponent;
chargome commented 3 weeks ago

Hey @phlegx I'm not familiar with this ssr setup, but does that mean that you run your init call in your Vue app on the server?

phlegx commented 3 weeks ago

Yes, I’m running the Sentry initialization on server side (SSR) in server/main.js. The configuration handles both server and client error tracking, allowing errors to be captured from the server-side rendering process as well as client-side interactions.

chargome commented 3 weeks ago

Can you make sure to only call Sentry.init (of @sentry/vue) on the client and check if that helps? Otherwise a minimal repro would be nice to debug this issue more efficiently!

phlegx commented 3 weeks ago

But if I remove Sentry.init from server/instrument.js, the instrument.js is "empty" and useless. It only contains:

import * as Sentry from '@sentry/node'

So I can also remove --import ./server/instrument.js from server:run script. Like described above: Removing --import ./server/instrument.js from server:run script, the error is not thrown.

chargome commented 3 weeks ago

No, I was referring to the init call from your @sentry/vue SDK, not from @sentry/node

phlegx commented 3 weeks ago

Can you make sure to only call Sentry.init (of @sentry/vue) on the client and check if that helps?

I have removed the Sentry.init from @sentry/node in server/instrument.js of node server and left the code with Sentry.init as is only on the @sentry/vue client. And it works. But why it don't work like for express like described in the docs?

s1gr1d commented 3 weeks ago

All packages are wrapped with import-in-the-middle under the hood and it could be that any vue packages are wrapped as well (and this should not be the case). You can try disabling this by adding this in your server-side init:

registerEsmLoaderHooks: {
    exclude: [/vue/],
  },

Here are the docs: https://docs.sentry.io/platforms/javascript/guides/express/install/esm/#skipping-instrumentation

phlegx commented 3 weeks ago

Node express server with --import ./server/instrument.js

// server/instrument.js
import * as Sentry from '@sentry/node'

Sentry.init({
  ...
  registerEsmLoaderHooks: {
    exclude: [/vue/],
  },
  ...

Vue app (SSR server/client app):

import * as Sentry from '@sentry/vue'

Sentry.init({
  ...
  1. Start server yarn server:run
  2. Open browser localhost:8000
  3. Server console error output:
TypeError: client._captureRequestSession is not a function
    at Immediate.<anonymous> (file:///.../my-app/server/node_modules/@sentry/node/build/esm/integrations/http/index.js:143:43)
    at process.processImmediate (node:internal/timers:483:21)
    at process.callbackTrampoline (node:internal/async_hooks:130:17)
error Command failed with exit code 1.
chargome commented 3 weeks ago

@phlegx this really looks like you're bundling @sentry/node into your client or the other way around with @sentry/vue running on the server. Please add some checks to initialise these SDKs only in their respective environment or provide a reproduction issue.

phlegx commented 3 weeks ago

I added a check for build and call Sentry.init only for Vue client side app.

Node express server with --import ./server/instrument.js

// server/instrument.js
import * as Sentry from '@sentry/node'

Sentry.init({
  ...
  registerEsmLoaderHooks: {
    exclude: [/vue/],
  },
  ...

Vue app (SSR server/client side app):

Added check for build. It adds Sentry.init only for Vue client app and not for Vue server side app. SSR environment: the build creates two folders in dist. One client folder, with the build code for Vue client app and server folder with the build code for Vue server side app.

import * as Sentry from '@sentry/vue'

if (!import.meta.env.SSR) {
  Sentry.init({...})
}
  1. Build app yarn app:build
  2. Start server yarn server:run
  3. Open browser localhost:8000
  4. Server console error output like described in this issue:
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
TypeError: Cannot read properties of undefined (reading '__vccOpts')
    at file:///.../node_modules/vue-router/dist/vue-router.mjs:2172:55
TypeError: Cannot read properties of undefined (reading '__vccOpts')
    at file:///.../node_modules/vue-router/dist/vue-router.mjs:2172:55
file:///.../node_modules/vue-router/dist/vue-router.mjs:2172
                    const options = resolvedComponent.__vccOpts || resolvedComponent;
chargome commented 3 weeks ago

Ok this is getting a bit hard to debug this way, could you provide a runnable reproduction for this, e.g. a public github repo or a stackblitz maybe?

getsantry[bot] commented 2 days ago

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you remove the label Waiting for: Community, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀