Skip to content

Commit

Permalink
feat: add sentry & use vite env & add kakao oauth
Browse files Browse the repository at this point in the history
  • Loading branch information
aube-dev committed Sep 18, 2024
1 parent 6068e0a commit bedf770
Show file tree
Hide file tree
Showing 27 changed files with 1,644 additions and 294 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ module.exports = {
importNames: ['useFetcher'],
message: '`@/hooks/useTypedFetcher`를 사용해 주세요.',
},
{
group: ['@remix-run/cloudflare'],
importNames: ['redirect'],
message:
'`@/utils/server`의 `redirectWithAuthCookie`를 사용해 주세요.',
},
],
},
],
Expand Down
11 changes: 5 additions & 6 deletions app/apis/auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Api } from '@/models/api';

export const api_loginWithKakao = new Api<
{ code: string; state: string },
export const api_loginWithOauth = new Api<
{ oauthKey: string },
{
userId: number;
accessToken: string;
Expand All @@ -10,13 +10,12 @@ export const api_loginWithKakao = new Api<
refreshTokenExpiresAt: string;
}
>({
method: 'POST',
endpoint: '/login/oauth2/code/kakao',
method: 'GET',
endpoint: '/oauth2/token',
needToLogin: false,
request: (variables) => ({
queryParams: {
code: variables.code,
state: variables.state,
oauthKey: variables.oauthKey,
},
}),
});
27 changes: 5 additions & 22 deletions app/components/KakaoLoginButton/KakaoLoginButton.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
import React, { useEffect, useState } from 'react';
import useEnv from '@/hooks/useEnv';

const KakaoLoginButton: React.FC = () => {
const env = useEnv();
const [kakaoAuthUrl, setKakaoAuthUrl] = useState('');

useEffect(() => {
const redirectUri =
window.location.origin.replace('localhost', '127.0.0.1') + '/oauth/kakao';
setKakaoAuthUrl(
`${env.API_URL}/oauth2/authorization/kakao?redirect_to=${redirectUri}`,
);
// setKakaoAuthUrl('http://146.56.161.252:8080/oauth2/authorization/kakao');
}, [env.API_URL]);

return (
<a href={kakaoAuthUrl}>
<button>카카오로 로그인</button>
</a>
);
};
const KakaoLoginButton: React.FC = () => (
<a href="/oauth/kakao">
<button>카카오로 로그인</button>
</a>
);

export default KakaoLoginButton;
11 changes: 11 additions & 0 deletions app/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createContext } from 'react';

export interface AuthStore {
isLoggedIn: boolean;
}

const AuthContext = createContext<AuthStore>({
isLoggedIn: false,
});

export default AuthContext;
4 changes: 0 additions & 4 deletions app/contexts/EnvContext.tsx

This file was deleted.

36 changes: 36 additions & 0 deletions app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { RemixBrowser, useLocation, useMatches } from '@remix-run/react';
import * as Sentry from '@sentry/remix';
import { startTransition, StrictMode, useEffect } from 'react';
import { hydrateRoot } from 'react-dom/client';

Sentry.init({
dsn: import.meta.env.SHARED_SENTRY_DSN,
tracesSampleRate: 1,

integrations: [
Sentry.browserTracingIntegration({
useEffect,
useLocation,
useMatches,
}),
// https://github.com/import-js/eslint-plugin-import/issues/2969#issuecomment-1967510143
// eslint-disable-next-line import/namespace
Sentry.replayIntegration({
maskAllText: true,
blockAllMedia: true,
}),
],

replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1,
environment: import.meta.env.SHARED_APP_MODE,
});

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>,
);
});
88 changes: 88 additions & 0 deletions app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type {
AppLoadContext,
EntryContext,
HandleDataRequestFunction,
} from '@remix-run/cloudflare';
import { RemixServer } from '@remix-run/react';
import * as Sentry from '@sentry/remix';
import * as isbotModule from 'isbot';
import { renderToReadableStream } from 'react-dom/server';

Sentry.init({
dsn: import.meta.env.SHARED_SENTRY_DSN,
tracesSampleRate: 1,
autoInstrumentRemix: true,
environment: import.meta.env.SHARED_APP_MODE,
});

export const handleError = Sentry.sentryHandleError;

export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
loadContext: AppLoadContext,
) {
const body = await renderToReadableStream(
<RemixServer context={remixContext} url={request.url} />,
{
signal: request.signal,
onError(error: unknown) {
// Log streaming rendering errors from inside the shell
console.error(error);
responseStatusCode = 500;
},
},
);

if (isBotRequest(request.headers.get('user-agent'))) {
await body.allReady;
}

responseHeaders.set('Content-Type', 'text/html');

const cookieHeader = await loadContext.authSessionService.commitSession();
if (cookieHeader) {
responseHeaders.append('Set-Cookie', cookieHeader);
}

const response = new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
});

return response;
}

export const handleDataRequest: HandleDataRequestFunction = async (
response,
{ context },
) => {
const cookieHeader = await context.authSessionService.commitSession();
if (cookieHeader) {
response.headers.append('Set-Cookie', cookieHeader);
}
return response;
};

// We have some Remix apps in the wild already running with isbot@3 so we need
// to maintain backwards compatibility even though we want new apps to use
// isbot@4. That way, we can ship this as a minor Semver update to @remix-run/dev.
function isBotRequest(userAgent: string | null) {
if (!userAgent) {
return false;
}

// isbot >= 3.8.0, >4
if ('isbot' in isbotModule && typeof isbotModule.isbot === 'function') {
return isbotModule.isbot(userAgent);
}

// isbot < 3.8.0
if ('default' in isbotModule && typeof isbotModule.default === 'function') {
return isbotModule.default(userAgent);
}

return false;
}
10 changes: 10 additions & 0 deletions app/hooks/useAuth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useContext } from 'react';
import AuthContext from '@/contexts/AuthContext';

const useAuth = () => {
const authStore = useContext(AuthContext);

return authStore;
};

export default useAuth;
21 changes: 0 additions & 21 deletions app/hooks/useEnv.tsx

This file was deleted.

1 change: 0 additions & 1 deletion app/hooks/useTypedFetcher.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { type TypedResponse } from '@remix-run/cloudflare';
// `useTypedFetcher`를 사용하라는 규칙인데 이 파일이 바로 그 구현체이므로 무시
// eslint-disable-next-line no-restricted-imports
import { useFetcher } from '@remix-run/react';
import { useEffect } from 'react';
Expand Down
4 changes: 2 additions & 2 deletions app/models/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ export class Api<Variables, Result> {
options?: ApiOptions,
): Promise<ApiReturn<Result>> {
try {
const baseUrl = this.baseUrl ?? context.API_URL;
const baseUrl: string = this.baseUrl ?? import.meta.env.SERVER_API_URL;

const token = context.authSession
? await context.authSessionService.getAuthToken(context)
? await context.authSessionService.getAuthToken()
: null;

const fetchInfo = this.getFetchInfo(variables, token?.accessToken);
Expand Down
40 changes: 21 additions & 19 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,35 @@ import {
ScrollRestoration,
useFetchers,
useLoaderData,
useRouteError,
} from '@remix-run/react';
import { useEffect, useRef } from 'react';
import useErrorToast from './hooks/useErrorToast';
import { withSentry } from '@sentry/remix';
import { useEffect, useMemo, useRef } from 'react';
import * as styles from './root.css';
import { EnvContext } from '@/contexts/EnvContext';
import AuthContext, { type AuthStore } from '@/contexts/AuthContext';
import useErrorToast from '@/hooks/useErrorToast';

import '@/styles/theme.css';

export const loader = async (args: LoaderFunctionArgs) =>
json({
env: args.context.clientEnv,
});
export const loader = async ({ context }: LoaderFunctionArgs) => {
const authToken = await context.authSessionService.getAuthToken();
const isLoggedIn = authToken !== null;
return json({ isLoggedIn });
};

const App = () => {
const data = useLoaderData<typeof loader>();
const loaderData = useLoaderData<typeof loader>();

const fetchers = useFetchers();
const { error, clearError } = useErrorToast();
const errorToastRemovalTimeoutIdRef = useRef<NodeJS.Timeout | null>(null);

const authStoreValue = useMemo<AuthStore>(
() => ({
isLoggedIn: loaderData.isLoggedIn,
}),
[loaderData.isLoggedIn],
);

useEffect(() => {
if (error) {
if (errorToastRemovalTimeoutIdRef.current) {
Expand All @@ -52,7 +61,7 @@ const App = () => {
<Links />
</head>
<body>
<EnvContext.Provider value={data.env}>
<AuthContext.Provider value={authStoreValue}>
<Outlet />
{fetchers.length > 0 && (
<div className={styles.loadingToast}>
Expand All @@ -69,19 +78,12 @@ const App = () => {
</div>
</div>
)}
</EnvContext.Provider>
</AuthContext.Provider>
<ScrollRestoration />
<Scripts />
</body>
</html>
);
};

export const ErrorBoundary = () => {
const error = useRouteError();
console.log('ErrorBoundary', error);

return <p>Error</p>;
};

export default App;
export default withSentry(App);
20 changes: 13 additions & 7 deletions app/routes/_index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { MetaFunction } from '@remix-run/cloudflare';
import KakaoLoginButton from '@/components/KakaoLoginButton';
import useAuth from '@/hooks/useAuth';
// import Test from '@/components/Test';

export const meta: MetaFunction = () => [
Expand All @@ -11,12 +12,17 @@ export const meta: MetaFunction = () => [
},
];

const Index = () => (
<div>
<h1>Ort</h1>
{/* <Test /> */}
<KakaoLoginButton />
</div>
);
const Index = () => {
const { isLoggedIn } = useAuth();

return (
<div>
<h1>Ort</h1>
isLoggedIn: {isLoggedIn ? 'true' : 'false'}
{/* <Test /> */}
<KakaoLoginButton />
</div>
);
};

export default Index;
20 changes: 10 additions & 10 deletions app/routes/oauth.kakao.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export const loader = async () => null;
import { type LoaderFunctionArgs } from '@remix-run/cloudflare';
import { redirectWithAuthCookie } from '@/utils/server';

const KakaoRedirect = () => (
<div>
{/* <p className={textStyle.headline1B}>{fetcher.state}</p>
<fetcher.Form method="POST">
<button type="submit">test submit</button>
</fetcher.Form> */}
</div>
);
export const loader = async ({ request, context }: LoaderFunctionArgs) => {
const url = new URL(request.url);
const { origin } = url;

export default KakaoRedirect;
return redirectWithAuthCookie(
`${import.meta.env.SERVER_API_URL}/oauth2/authorization/kakao?redirect_to=${origin}/oauth`,
context.authSessionService,
);
};
Loading

0 comments on commit bedf770

Please sign in to comment.