Skip to content

Commit f95b08f

Browse files
committed
Implement structural updates and optimizations across multiple modules
1 parent 23c81e3 commit f95b08f

8 files changed

Lines changed: 662 additions & 31 deletions

File tree

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"private": false,
55
"dependencies": {
66
"@amplitude/analytics-browser": "^1.5.5",
7+
"@sentry/react": "^9.38.0",
78
"@tanstack/query-async-storage-persister": "^5.8.3",
89
"@tanstack/react-query": "^4.13.0",
910
"@tanstack/react-query-persist-client": "^5.8.4",
@@ -65,6 +66,7 @@
6566
"react-error-overlay": "6.0.9"
6667
},
6768
"devDependencies": {
69+
"@sentry/vite-plugin": "^3.5.0",
6870
"@types/chrome": "^0.0.241",
6971
"@types/dompurify": "^2.3.4",
7072
"@types/jest": "^29.1.2",

src/config/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const API_ENDPOINT = import.meta.env.VITE_API_URL as string
55
export const LS_ANALYTICS_ID_KEY = 'hackerTabAnalyticsId'
66
export const FIREBASE_API_KEY = import.meta.env.VITE_FIREBASE_API_KEY as string
77
export const BUILD_TARGET = (import.meta.env.VITE_BUILD_TARGET as 'web' | 'extension') || 'web'
8+
export const SENTRY_DSN = import.meta.env.VITE_SENTRY_DSN
89

910
// Meta
1011
export const name = 'Hackertab.dev'

src/index.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as Sentry from '@sentry/react'
12
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'
23
import 'normalize.css'
34
import 'react-simple-toasts/dist/style.css'
@@ -8,17 +9,23 @@ import { AppErrorBoundary } from 'src/providers/AppErrorBoundary'
89
import { AppRoutes } from './routes/AppRoutes'
910

1011
import { createRoot } from 'react-dom/client'
12+
import { initSentry } from './lib/sentry'
1113
const container = document.getElementById('root')
1214
if (!container) {
1315
throw new Error('Failed to find the root element')
1416
}
17+
18+
initSentry()
1519
const root = createRoot(container)
1620
root.render(
17-
<AppErrorBoundary>
21+
<Sentry.ErrorBoundary
22+
fallback={({ error, resetError }) => (
23+
<AppErrorBoundary error={error} resetError={resetError} />
24+
)}>
1825
<PersistQueryClientProvider client={queryClient} persistOptions={{ persister: persister }}>
1926
<ConfigurationWrapper>
2027
<AppRoutes />
2128
</ConfigurationWrapper>
2229
</PersistQueryClientProvider>
23-
</AppErrorBoundary>
30+
</Sentry.ErrorBoundary>
2431
)

src/lib/analytics.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useUserPreferences } from 'src/stores/preferences'
44
import { isDevelopment } from 'src/utils/Environment'
55
import { getAppVersion } from 'src/utils/Os'
66
import AppStorage from './localStorage'
7+
import { identifySentryUser } from './sentry'
78

89
enum Objects {
910
PAGE = 'Page',
@@ -120,6 +121,10 @@ export const setupIdentification = () => {
120121
if (onboardingResult?.title) {
121122
identifyUserOccupation(onboardingResult.title)
122123
}
124+
identifySentryUser({
125+
[Attributes.LANGUAGES]: userSelectedTags.map((tag: any) => tag.value),
126+
[Attributes.DISPLAY_LAYOUT]: layout,
127+
})
123128
}
124129

125130
export const trackPageView = (pageName: string, dndModeActive: boolean = false) => {
@@ -408,10 +413,10 @@ export const trackUserDelete = () => {
408413
})
409414
}
410415

411-
export const trackDisplayTypeChange = (value: "grid" | "cards") => {
416+
export const trackDisplayTypeChange = (value: 'grid' | 'cards') => {
412417
trackEvent({
413418
object: Objects.DISPLAY_LAYOUT,
414-
verb: Verbs.CHANGE,
419+
verb: Verbs.CHANGE,
415420
attributes: {
416421
[Attributes.DISPLAY_LAYOUT]: value,
417422
},
@@ -421,7 +426,7 @@ export const trackDisplayTypeChange = (value: "grid" | "cards") => {
421426
export const trackFeedScroll = () => {
422427
trackEvent({
423428
object: Objects.FEED,
424-
verb: Verbs.SCROLL
429+
verb: Verbs.SCROLL,
425430
})
426431
}
427432
// Identification
@@ -459,7 +464,7 @@ export const identifyAdvBlocked = (blocked: boolean) => {
459464
export const identifyUserStreak = (value: number) => {
460465
identifyUserProperty(Attributes.STREAK, value)
461466
}
462-
export const identifyDisplayLayout = (value: "grid" | "cards") => {
467+
export const identifyDisplayLayout = (value: 'grid' | 'cards') => {
463468
identifyUserProperty(Attributes.DISPLAY_LAYOUT, value)
464469
}
465470
// Private functions

src/lib/sentry.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as Sentry from '@sentry/react'
2+
import { SENTRY_DSN } from 'src/config'
3+
import { isDevelopment } from 'src/utils/Environment'
4+
5+
export const initSentry = () => {
6+
Sentry.init({
7+
dsn: SENTRY_DSN,
8+
sendDefaultPii: true,
9+
enabled: !isDevelopment(),
10+
})
11+
}
12+
13+
export const identifySentryUser = (user: { [key: string]: any }) => {
14+
Sentry.setUser(user)
15+
}

src/providers/AppErrorBoundary.tsx

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
import React from 'react'
2-
import { ErrorBoundary} from 'react-error-boundary'
31
import { AiFillBug } from 'react-icons/ai'
42
import { WiRefresh } from 'react-icons/wi'
53

6-
export const AppErrorBoundary = ({ children }: {children: React.ReactNode}) => {
7-
8-
const ErrorFallback = ({ error, resetErrorBoundary }: {error: Error, resetErrorBoundary: () => void}) => {
9-
return (
10-
<div className="Page appError">
11-
<AiFillBug size={64} />
12-
<p>Sorry there was a problem loading this page.</p>
13-
<p>{error.message}</p>
14-
<button onClick={resetErrorBoundary}>
15-
<WiRefresh size={32} className={'buttonIcon'} /> Try again
16-
</button>
17-
</div>
18-
)
19-
}
20-
21-
return <ErrorBoundary FallbackComponent={ErrorFallback}>{children}</ErrorBoundary>
4+
type AppErrorBoundaryProps = {
5+
error: unknown
6+
resetError: () => void
7+
}
8+
export const AppErrorBoundary = ({ error, resetError }: AppErrorBoundaryProps) => {
9+
return (
10+
<div className="Page appError">
11+
<AiFillBug size={64} />
12+
<p>Sorry there was a problem loading this page.</p>
13+
<p>{String(error)}</p>
14+
<button onClick={resetError}>
15+
<WiRefresh size={32} className={'buttonIcon'} /> Try again
16+
</button>
17+
</div>
18+
)
2219
}

vite.config.mjs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { sentryVitePlugin } from '@sentry/vite-plugin'
12
import react from '@vitejs/plugin-react'
3+
import fs from 'fs'
24
import path from 'path'
35
import { defineConfig, loadEnv } from 'vite'
46
import { ViteEjsPlugin } from 'vite-plugin-ejs'
@@ -9,13 +11,17 @@ export default defineConfig(({ mode }) => {
911
const env = loadEnv(mode, process.cwd(), '')
1012
const buildTarget = env.VITE_BUILD_TARGET || 'web'
1113
const buildPlatform = env.VITE_BUILD_PLATFORM
12-
14+
const manifestPath = path.resolve(__dirname, 'public', 'base.manifest.json')
15+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'))
16+
const appVersion = manifest.version || '0.0.0'
1317
if (!env.VITE_API_URL) {
1418
throw new Error('VITE_API_URL is not defined, create an .env file with this variable')
1519
}
1620

1721
if (buildTarget == 'extension' && !buildPlatform) {
18-
throw new Error('VITE_BUILD_PLATFORM is not defined, create an .env file with this variable')
22+
throw new Error(
23+
'VITE_BUILD_PLATFORM is not defined, create an .env file with this variable with either "firefox" or "chrome"'
24+
)
1925
}
2026

2127
return {
@@ -28,11 +34,24 @@ export default defineConfig(({ mode }) => {
2834
react(),
2935
viteTsconfigPaths(),
3036
svgrPlugin(),
37+
sentryVitePlugin({
38+
org: 'hackertabdev',
39+
project: 'hackertab',
40+
authToken: env.VITE_SENTRY_TOKEN,
41+
disable: mode === 'development',
42+
release: {
43+
name: `${appVersion}-${buildTarget == 'extension' ? buildPlatform : buildTarget}`,
44+
},
45+
sourcemaps: {
46+
filesToDeleteAfterUpload: ['./dist/assets/*.map', './assets/*.map'],
47+
},
48+
}),
3149
],
3250
define: {
3351
'process.env': {},
3452
},
3553
build: {
54+
sourcemap: true,
3655
emptyOutDir: true,
3756
cssCodeSplit: false,
3857
rollupOptions: {

0 commit comments

Comments
 (0)