globalbrain / sefirot

Global Brain Design System.
https://sefirot.globalbrains.com
MIT License
151 stars 12 forks source link

feat: unify error handling and add sentry integration #504

Closed brc-dd closed 3 months ago

brc-dd commented 4 months ago

closes #476

Usage

Nuxt

// plugins/2-sentry.client.ts

import { useErrorHandler } from 'sefirot/composables/Error'
import { useAuth } from '@/composables/Auth'

export default defineNuxtPlugin({
  name: 'sentry-plugin',
  setup: (nuxtApp) => {
    const { public: { sentry } } = useRuntimeConfig()
    const { data: user } = useAuth()
    if (!sentry.dsn) { return }

    const handler = useErrorHandler({
      ...sentry,
      user: () => ({
        id: user.value.user?.id,
        username: user.value.user?.name,
        email: user.value.user?.email
      })
    })

    nuxtApp.hook('vue:error', handler)
    nuxtApp.hook('app:error', handler)
  }
})
// nuxt.config.ts

  runtimeConfig: {
    public: {
      sentry: {
        dsn: process.env.SENTRY_DSN,
        environment: process.env.SENTRY_ENVIRONMENT
      }
    }
  },

useError / clearErrror / createError

Use Nuxt's builtins:

throw createError({ statusCode: 403, statusMessage: 'Authorization failed' })
throw createError({ statusCode: 404, statusMessage: 'Page not found' })
throw createError({ statusCode: 500, statusMessage: 'Unexpected error occurred' })

Vite

// main.ts

import { createPinia } from 'pinia'
import { useErrorHandler } from 'sefirot/composables/Error'
import { createApp } from 'vue'
import { useAuth } from '@/stores/Auth'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)
app.use(pinia)

const userStore = useAuth() // should be called after installing pinia

app.config.errorHandler = useErrorHandler({
  dsn: import.meta.env.VITE_SENTRY_DSN,
  environment: import.meta.env.VITE_SENTRY_ENVIRONMENT,
  user: () => ({
    id: userStore.user?.id,
    username: userStore.user?.name,
    email: userStore.user?.email
  })
})

// ...

app.mount('#app')

useError / clearErrror

import { useError } from 'sefirot/stores/Error'

const error = useError()

error.data

await error.clear({ redirect: '/' })

createError

import { AuthorizationError, PageNotFoundError, UnexpectedError } from 'sefirot/errors'

throw new AuthorizationError()
throw new PageNotFoundError()
throw new UnexpectedError()
netlify[bot] commented 4 months ago

Deploy Preview for sefirot-story ready!

Name Link
Latest commit 4ecc14b18a20e6f953a0fa798b1e326f92e57e94
Latest deploy log https://app.netlify.com/sites/sefirot-story/deploys/6603d60ce82a0500082b3fe6
Deploy Preview https://deploy-preview-504--sefirot-story.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

netlify[bot] commented 4 months ago

Deploy Preview for sefirot-docs ready!

Name Link
Latest commit 4ecc14b18a20e6f953a0fa798b1e326f92e57e94
Latest deploy log https://app.netlify.com/sites/sefirot-docs/deploys/6603d60c687cca0008601e55
Deploy Preview https://deploy-preview-504--sefirot-docs.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

kiaking commented 3 months ago

Since this is composable, should we place it under sefirot/lib/composables? Or at least, useErrorHandler function should be πŸ‘€

Another thing I'm curious is that, how would we integrate this with regular error handling?

For example, let's say we want to show global error in layout. I'm currently imagining to do something like this, but maybe there is a better way.

<script setup lang="ts">
// Not sentry, generic error handler.
import { useErrorHandling } from 'sefirot/composables/Error'

const { error } = useErrorHandling()
</script>

<template>
  <div class="Layout">
    <!-- Show error page if error is captured -->
    <ErrorPage v-if="error" :error="error" />
    <RouterView v-else="" />
  </div>
</template>
// In `Error.ts`
function useErrorHandling() {
  const error = ref<Error | null>(null)

  onErrorCaptured((err) => {
    // Not sure how to implement this but something like this?
    if (err.statusCode === 404) {
      error.value = new ErrorType(404)
    }

    // Prevent crushing error. How do we integrate Sentry?
    // Like for some error, do not report to sentry etc. (ignore 404)
    return false
  })

  return {
    error
  }
}
brc-dd commented 3 months ago

Ah, I’ll push useError code. See slack updates πŸ˜