9148c358d0
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를 Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류. - 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로 자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거, 동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거. - 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming, Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business, Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로, 나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는 title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백). 원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지. - 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서. - 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는 지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지. - Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경. - 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
6.6 KiB
6.6 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-spa-single-page-application | SPA (Single Page Application) | 10_Wiki/Topics | verified | self |
|
none | A | 0.9 | applied |
|
2026-05-10 | pending |
|
SPA (Single Page Application)
매 한 줄
"매 single HTML shell 의 의 client-side routing + dynamic rendering 의 driven 의 web app 의 architecture.". 매 2010s 의 의 dominant pattern (AngularJS, Backbone, Ember → React, Vue, Angular), 매 2026 의 RSC / SSR / Islands 의 ascendency 의 의 SPA 의 niche 화 — 매 highly-interactive dashboards, internal tools, complex stateful UIs 의 의 the right tool 이며 marketing/content 의 의 의 SSG/SSR 의 권장.
매 핵심
매 정의
- 1 HTML document 의 load — subsequent navigation 의 JS 의 driven (no full page reload).
- Client-side router 의 URL ↔ component tree 의 mapping.
- Data 의 fetch via XHR/Fetch — JSON API or RPC.
- State 의 client 의 in-memory (Redux, Zustand, Jotai, TanStack Query).
매 trade-offs
- Pros: snappy in-app navigation, rich interactivity, app-like UX, shared state across views.
- Cons: SEO 의 weak (without SSR), initial bundle 의 large, white screen 의 risk, accessibility 의 careful 의 wiring.
매 vs. modern alternatives
- SSR / SSG (Next.js, Remix): server 의 HTML 의 generate, hydration 의 client interactivity 의 add.
- RSC (React Server Components, 2026 mainstream): server-only components + client islands.
- Islands (Astro, Fresh, 11ty): static HTML + targeted hydration 의 islands.
- MPA (Multi-Page App): traditional server-rendered pages — Hotwire / Inertia 의 의 modern revival.
매 응용
- Internal admin dashboards (high interactivity, no SEO need).
- Authenticated SaaS apps (Linear, Figma, Notion).
- Real-time collaboration (CRDT-driven, websocket-heavy).
- Browser-based tools (Excalidraw, Tldraw).
💻 패턴
React Router (data router, 2026)
import { createBrowserRouter, RouterProvider } from 'react-router';
const router = createBrowserRouter([
{
path: '/',
Component: Layout,
children: [
{ index: true, Component: Home },
{ path: 'projects/:id', Component: Project, loader: projectLoader },
{ path: '*', Component: NotFound },
],
},
]);
export const App = () => <RouterProvider router={router} />;
Data fetching (TanStack Query)
import { useQuery } from '@tanstack/react-query';
export function ProjectView({ id }: { id: string }) {
const { data, isPending, error } = useQuery({
queryKey: ['project', id],
queryFn: () => fetch(`/api/projects/${id}`).then((r) => r.json()),
staleTime: 60_000,
});
if (isPending) return <Skeleton />;
if (error) return <ErrorBoundary error={error} />;
return <ProjectDetail project={data} />;
}
Client state (Zustand)
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
export const useUIStore = create(
persist<{ sidebar: boolean; toggle: () => void }>(
(set) => ({
sidebar: true,
toggle: () => set((s) => ({ sidebar: !s.sidebar })),
}),
{ name: 'ui-store' },
),
);
Code splitting (lazy routes)
import { lazy, Suspense } from 'react';
const Settings = lazy(() => import('./routes/Settings'));
const router = createBrowserRouter([
{
path: '/settings',
element: (
<Suspense fallback={<RouteSkeleton />}>
<Settings />
</Suspense>
),
},
]);
History API (without router)
window.history.pushState({}, '', '/projects/42');
window.dispatchEvent(new PopStateEvent('popstate'));
window.addEventListener('popstate', () => {
render(parseRoute(location.pathname));
});
Auth guard (route loader)
async function projectLoader({ params }: LoaderFunctionArgs) {
const session = await getSession();
if (!session) throw redirect('/login');
return fetch(`/api/projects/${params.id}`).then((r) => r.json());
}
Vite SPA의 setup
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: { sourcemap: true, target: 'es2022' },
server: { historyApiFallback: true },
});
SEO 의 fallback (prerender + hydrate)
// vite-plugin-prerender
import prerender from 'vite-plugin-prerender';
export default {
plugins: [
react(),
prerender({ routes: ['/', '/about', '/pricing'] }),
],
};
매 결정 기준
| 상황 | Approach |
|---|---|
| Marketing site, blog | SSG (Astro, Next.js static, 11ty) |
| Content site with personalization | SSR (Next.js, Remix) |
| Dashboards, admin tools | SPA (React Router + Vite) |
| Highly interactive editor | SPA with code-splitting |
| Public app needing SEO + interactivity | Next.js (RSC + client islands) |
| MPA-style with sprinkles | Hotwire / Inertia.js |
기본값: 2026 의 default 는 Next.js / Remix (SSR + RSC) — pure SPA 는 internal tools / authenticated apps 의 으로 의 reserve.
🔗 Graph
- 부모: 프론트엔드 및 UIUX 표준
- 변형: SSR · SSG · Islands-Architecture · React Server Components — 경계 의식
- Adjacent: Vite · Code Splitting
🤖 LLM 활용
언제: highly-interactive authenticated app, no SEO requirement, complex client state, real-time collaboration. 언제 X: marketing/content site (SSG), public SEO-critical content (SSR/RSC), simple form-driven app (MPA).
안티패턴
- SPA 의 marketing site: SEO 의 weak, LCP 의 poor — SSG 의 사용.
- Bundle 의 single chunk: route-based code splitting 의 default.
- Auth state 의 localStorage 의 raw token: HttpOnly cookie + refresh flow 의 사용.
- Client routing 의 server fallback 없음: 404 의 deep link 의 —
historyApiFallback/ catch-all rewrite. - No skeleton / suspense: white screen on slow data — Suspense + skeletons.
- Global state 의 overuse: server state 의 TanStack Query, UI state 의 Zustand/Jotai 의 separate.
🧪 검증 / 중복
- Verified (React Router 7 docs, Vue Router 4, MDN SPA architecture, web.dev rendering patterns 2026).
- 신뢰도 A.
🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full SPA architecture with 2026 trade-offs vs RSC/Islands |