From 0b5e116f7f85c35a5110566d45c731c3de994cf5 Mon Sep 17 00:00:00 2001 From: Edmund Hung Date: Sun, 27 Mar 2022 16:04:10 +0200 Subject: [PATCH] refactor: limit root loader to be session specific --- app/hooks.ts | 6 +-- app/root.tsx | 45 +++---------------- app/routes/__layout.tsx | 45 +++++++++++++++++++ app/routes/{ => __layout}/$guide.$list.tsx | 0 .../{ => __layout}/$guide.$list/index.tsx | 4 +- app/routes/{ => __layout}/$guide.tsx | 0 app/routes/{ => __layout}/$guide/index.tsx | 4 +- app/routes/{ => __layout}/admin.tsx | 0 .../{ => __layout}/admin/pages.statistics.tsx | 0 app/routes/{ => __layout}/admin/pages.tsx | 0 app/routes/{ => __layout}/admin/resources.tsx | 0 .../admin/users.$userId.backup.tsx | 0 app/routes/{ => __layout}/admin/users.tsx | 0 .../{ => __layout}/resources/$resourceId.tsx | 0 app/routes/{ => __layout}/resources/index.tsx | 0 app/routes/{ => __layout}/submit.tsx | 4 +- worker/context/session.ts | 23 +++++----- worker/types.ts | 5 +++ 18 files changed, 78 insertions(+), 58 deletions(-) create mode 100644 app/routes/__layout.tsx rename app/routes/{ => __layout}/$guide.$list.tsx (100%) rename app/routes/{ => __layout}/$guide.$list/index.tsx (98%) rename app/routes/{ => __layout}/$guide.tsx (100%) rename app/routes/{ => __layout}/$guide/index.tsx (98%) rename app/routes/{ => __layout}/admin.tsx (100%) rename app/routes/{ => __layout}/admin/pages.statistics.tsx (100%) rename app/routes/{ => __layout}/admin/pages.tsx (100%) rename app/routes/{ => __layout}/admin/resources.tsx (100%) rename app/routes/{ => __layout}/admin/users.$userId.backup.tsx (100%) rename app/routes/{ => __layout}/admin/users.tsx (100%) rename app/routes/{ => __layout}/resources/$resourceId.tsx (100%) rename app/routes/{ => __layout}/resources/index.tsx (100%) rename app/routes/{ => __layout}/submit.tsx (98%) diff --git a/app/hooks.ts b/app/hooks.ts index 698c0a1..5f74f04 100644 --- a/app/hooks.ts +++ b/app/hooks.ts @@ -1,10 +1,10 @@ import { useMatches } from 'remix'; -import { GuideMetadata } from '~/types'; +import { GuideMetadata, SessionData } from '~/types'; -export function useFlashMessage(): string | null { +export function useSessionData(): SessionData { const [rootMatch] = useMatches(); - return rootMatch?.data.message ?? null; + return (rootMatch?.data as SessionData) ?? null; } export function useLists(): Required['lists'] { diff --git a/app/root.tsx b/app/root.tsx index 78f6d1f..aa1cd3c 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -8,16 +8,11 @@ import { Meta, Links, Scripts, - useLoaderData, - useLocation, LiveReload, useCatch, Outlet, json, } from 'remix'; -import clsx from 'clsx'; -import Progress from '~/components/Progress'; -import SidebarNavigation from '~/components/SidebarNavigation'; import type { Context } from '~/types'; import stylesUrl from '~/styles/tailwind.css'; @@ -36,24 +31,14 @@ export let meta: MetaFunction = () => { }; export let loader: LoaderFunction = async ({ context }) => { - const { session, resourceStore } = context as Context; - const [profile, [message, headers], guide] = await Promise.all([ - session.isAuthenticated(), - session.getFlashMessage(), - resourceStore.getData(), - ]); + const { session } = context as Context; + const [data, setCookieHeader] = await session.getData(); - return json( - { - profile, - message, - lists: guide.metadata.lists, - version: process.env.VERSION, + return json(data, { + headers: { + 'Set-Cookie': setCookieHeader, }, - { - headers, - }, - ); + }); }; export const unstable_shouldReload: ShouldReloadFunction = ({ submission }) => { @@ -85,25 +70,9 @@ function Document({ } export default function App() { - const { profile, lists } = useLoaderData(); - const location = useLocation(); - const isMenuOpened = - new URLSearchParams(location.search).get('open') === 'menu'; - return ( - - -
- -
+
); } diff --git a/app/routes/__layout.tsx b/app/routes/__layout.tsx new file mode 100644 index 0000000..48b8743 --- /dev/null +++ b/app/routes/__layout.tsx @@ -0,0 +1,45 @@ +import type { LoaderFunction, ShouldReloadFunction } from 'remix'; +import { Outlet, json, useLoaderData, useLocation } from 'remix'; +import clsx from 'clsx'; +import Progress from '~/components/Progress'; +import SidebarNavigation from '~/components/SidebarNavigation'; +import { Context } from '~/types'; +import { useSessionData } from '~/hooks'; + +export let loader: LoaderFunction = async ({ context }) => { + const { resourceStore } = context as Context; + const guide = await resourceStore.getData(); + + return json({ + lists: guide.metadata.lists, + }); +}; + +export const unstable_shouldReload: ShouldReloadFunction = ({ submission }) => { + return typeof submission !== 'undefined'; +}; + +export default function Layout() { + const { lists } = useLoaderData(); + const { profile } = useSessionData(); + const location = useLocation(); + const isMenuOpened = + new URLSearchParams(location.search).get('open') === 'menu'; + + return ( + <> + + +
+ +
+ + ); +} diff --git a/app/routes/$guide.$list.tsx b/app/routes/__layout/$guide.$list.tsx similarity index 100% rename from app/routes/$guide.$list.tsx rename to app/routes/__layout/$guide.$list.tsx diff --git a/app/routes/$guide.$list/index.tsx b/app/routes/__layout/$guide.$list/index.tsx similarity index 98% rename from app/routes/$guide.$list/index.tsx rename to app/routes/__layout/$guide.$list/index.tsx index 690d382..00daa7f 100644 --- a/app/routes/$guide.$list/index.tsx +++ b/app/routes/__layout/$guide.$list/index.tsx @@ -15,7 +15,7 @@ import { getSuggestions, patchResource } from '~/resources'; import { getSearchOptions, getTitleBySearchOptions } from '~/search'; import type { Context, Resource, SearchOptions, User } from '~/types'; import BookmarkDetails from '~/components/BookmarkDetails'; -import { useFlashMessage } from '~/hooks'; +import { useSessionData } from '~/hooks'; interface LoaderData { resource: Resource; @@ -171,7 +171,7 @@ export const unstable_shouldReload: ShouldReloadFunction = ({ export default function UserProfile() { const { resource, user, suggestions } = useLoaderData(); - const message = useFlashMessage(); + const { message } = useSessionData(); const location = useLocation(); const [showBookmark, action] = useMemo(() => { const searchParams = new URLSearchParams(location.search); diff --git a/app/routes/$guide.tsx b/app/routes/__layout/$guide.tsx similarity index 100% rename from app/routes/$guide.tsx rename to app/routes/__layout/$guide.tsx diff --git a/app/routes/$guide/index.tsx b/app/routes/__layout/$guide/index.tsx similarity index 98% rename from app/routes/$guide/index.tsx rename to app/routes/__layout/$guide/index.tsx index f37d4ac..21a30ec 100644 --- a/app/routes/$guide/index.tsx +++ b/app/routes/__layout/$guide/index.tsx @@ -15,7 +15,7 @@ import { getSuggestions, patchResource } from '~/resources'; import { getSearchOptions, getTitleBySearchOptions } from '~/search'; import type { Context, Resource, SearchOptions, User } from '~/types'; import BookmarkDetails from '~/components/BookmarkDetails'; -import { useFlashMessage } from '~/hooks'; +import { useSessionData } from '~/hooks'; interface LoaderData { resource: Resource; @@ -171,7 +171,7 @@ export const unstable_shouldReload: ShouldReloadFunction = ({ export default function UserProfile() { const { resource, user, suggestions } = useLoaderData(); - const message = useFlashMessage(); + const { message } = useSessionData(); const location = useLocation(); const [showBookmark, action] = useMemo(() => { const searchParams = new URLSearchParams(location.search); diff --git a/app/routes/admin.tsx b/app/routes/__layout/admin.tsx similarity index 100% rename from app/routes/admin.tsx rename to app/routes/__layout/admin.tsx diff --git a/app/routes/admin/pages.statistics.tsx b/app/routes/__layout/admin/pages.statistics.tsx similarity index 100% rename from app/routes/admin/pages.statistics.tsx rename to app/routes/__layout/admin/pages.statistics.tsx diff --git a/app/routes/admin/pages.tsx b/app/routes/__layout/admin/pages.tsx similarity index 100% rename from app/routes/admin/pages.tsx rename to app/routes/__layout/admin/pages.tsx diff --git a/app/routes/admin/resources.tsx b/app/routes/__layout/admin/resources.tsx similarity index 100% rename from app/routes/admin/resources.tsx rename to app/routes/__layout/admin/resources.tsx diff --git a/app/routes/admin/users.$userId.backup.tsx b/app/routes/__layout/admin/users.$userId.backup.tsx similarity index 100% rename from app/routes/admin/users.$userId.backup.tsx rename to app/routes/__layout/admin/users.$userId.backup.tsx diff --git a/app/routes/admin/users.tsx b/app/routes/__layout/admin/users.tsx similarity index 100% rename from app/routes/admin/users.tsx rename to app/routes/__layout/admin/users.tsx diff --git a/app/routes/resources/$resourceId.tsx b/app/routes/__layout/resources/$resourceId.tsx similarity index 100% rename from app/routes/resources/$resourceId.tsx rename to app/routes/__layout/resources/$resourceId.tsx diff --git a/app/routes/resources/index.tsx b/app/routes/__layout/resources/index.tsx similarity index 100% rename from app/routes/resources/index.tsx rename to app/routes/__layout/resources/index.tsx diff --git a/app/routes/submit.tsx b/app/routes/__layout/submit.tsx similarity index 98% rename from app/routes/submit.tsx rename to app/routes/__layout/submit.tsx index e24e026..8204ae2 100644 --- a/app/routes/submit.tsx +++ b/app/routes/__layout/submit.tsx @@ -8,7 +8,7 @@ import { Context } from '~/types'; import { formatMeta, isMaintainer } from '~/helpers'; import { toggleSearchParams } from '~/search'; import IconLink from '~/components/IconLink'; -import { useFlashMessage } from '~/hooks'; +import { useSessionData } from '~/hooks'; export let meta: MetaFunction = () => { return formatMeta({ @@ -115,7 +115,7 @@ export let action: ActionFunction = async ({ request, context }) => { }; export default function Submit() { - const message = useFlashMessage(); + const { message } = useSessionData(); const location = useLocation(); const toggleMenuURL = useMemo( () => `?${toggleSearchParams(location.search, 'menu')}`, diff --git a/worker/context/session.ts b/worker/context/session.ts index ca41d5d..9a3d698 100644 --- a/worker/context/session.ts +++ b/worker/context/session.ts @@ -1,7 +1,7 @@ import { Authenticator } from 'remix-auth'; import { GitHubStrategy } from 'remix-auth-github'; import { createCookieSessionStorage, redirect } from 'remix'; -import type { Env, MessageType, UserProfile } from '../types'; +import type { Env, MessageType, SessionData, UserProfile } from '../types'; import { getUserStore } from '../store/UserStore'; export type Session = ReturnType; @@ -86,21 +86,22 @@ export function createSession( redirectTo: '/', }); }, - async isAuthenticated(): Promise { - return await authenticator.isAuthenticated(request); - }, - async getFlashMessage(): Promise<[string | null, Record]> { + async getData(): Promise<[SessionData, string]> { const session = await sessionStorage.getSession( request.headers.get('Cookie'), ); + const profile = session.get(authenticator.sessionKey) ?? null; const message = session.get('message') ?? null; - const setCookieHeader = !message - ? null - : { - 'Set-Cookie': await sessionStorage.commitSession(session), - }; + const setCookieHeader = await sessionStorage.commitSession(session); + const data = { + profile, + message, + }; - return [message, setCookieHeader ?? {}]; + return [data, setCookieHeader]; + }, + async isAuthenticated(): Promise { + return await authenticator.isAuthenticated(request); }, async commitWithFlashMessage( message: string, diff --git a/worker/types.ts b/worker/types.ts index a088e93..61b29da 100644 --- a/worker/types.ts +++ b/worker/types.ts @@ -24,6 +24,11 @@ export interface Env { USER_STORE: DurableObjectNamespace; } +export interface SessionData { + profile: UserProfile | null; + message: string | null; +} + export interface UserProfile { id: string; name: string;