[{"data":1,"prerenderedAt":1076},["ShallowReactive",2],{"navigation_docs_ko":3,"-ko-note-nuxt4-nuxt-use-async-data":195,"-ko-note-nuxt4-nuxt-use-async-data-surround":1071},[4,124,181],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":27},"Note (개발 지식)","emojione-v1:note-pad","\u002Fko\u002Fnote","ko\u002F1.note",[10,28,42,68,78,88,104,114],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":27},"Spring","logos:spring-icon","\u002Fko\u002Fnote\u002Fspring","ko\u002F1.note\u002F0.spring",[16],{"title":17,"icon":18,"path":19,"stem":20,"children":21,"page":27},"Spring Ai","custom:ai","\u002Fko\u002Fnote\u002Fspring\u002Fspring-ai","ko\u002F1.note\u002F0.spring\u002F1.spring-ai",[22],{"title":23,"path":24,"stem":25,"icon":26},"Spring AI 핵심 개념과 LLM 애플리케이션 구조 이해","\u002Fko\u002Fnote\u002Fspring\u002Fspring-ai\u002Fspring-ai","ko\u002F1.note\u002F0.spring\u002F1.spring-ai\u002F1.spring-ai","lucide:file-text",false,{"title":29,"icon":30,"path":31,"stem":32,"children":33,"page":27},"Javascript","skill-icons:javascript","\u002Fko\u002Fnote\u002Fjavascript","ko\u002F1.note\u002F1.javascript",[34,38],{"title":35,"path":36,"stem":37,"icon":26},"Promise.all과 구조 분해 할당을 활용한 데이터 처리 패턴","\u002Fko\u002Fnote\u002Fjavascript\u002Fdestructuring","ko\u002F1.note\u002F1.javascript\u002F1.destructuring",{"title":39,"path":40,"stem":41,"icon":26},"JavaScript 배열 고차 함수와 데이터 처리 패턴 이해","\u002Fko\u002Fnote\u002Fjavascript\u002Ffilter","ko\u002F1.note\u002F1.javascript\u002F2.filter",{"title":43,"icon":44,"path":45,"stem":46,"children":47,"page":27},"Nuxt4","logos:nuxt-icon","\u002Fko\u002Fnote\u002Fnuxt4","ko\u002F1.note\u002F2.nuxt4",[48,52,56,60,64],{"title":49,"path":50,"stem":51,"icon":26},"Nuxt 4를 선택한 이유와 아키텍처 및 실무 가이드","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-info","ko\u002F1.note\u002F2.nuxt4\u002F1.nuxt-info",{"title":53,"path":54,"stem":55,"icon":26},"Nuxt useAsyncData 동작 원리와 SSR 데이터 페칭 최적화","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-use_async_data","ko\u002F1.note\u002F2.nuxt4\u002F2.nuxt-use_async_data",{"title":57,"path":58,"stem":59,"icon":26},"Nuxt Content v3 데이터 모델과 Query 시스템 이해","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-content-v3","ko\u002F1.note\u002F2.nuxt4\u002F3.nuxt-content-v3",{"title":61,"path":62,"stem":63,"icon":26},"Nuxt Auto-imports 내부 동작과 컴파일 과정 분석","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-auto-import","ko\u002F1.note\u002F2.nuxt4\u002F4.nuxt-auto-import",{"title":65,"path":66,"stem":67,"icon":26},"Nuxt 렌더링 방식 이해: SSR, SSG, ISR, CSR 구현 방법","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-rendering-strategy","ko\u002F1.note\u002F2.nuxt4\u002F5.nuxt-rendering-strategy",{"title":69,"icon":70,"path":71,"stem":72,"children":73,"page":27},"Nitro","unjs:nitro","\u002Fko\u002Fnote\u002Fnitro","ko\u002F1.note\u002F3.nitro",[74],{"title":75,"path":76,"stem":77,"icon":26},"Nitro 아키텍처와 서버 엔진 구조","\u002Fko\u002Fnote\u002Fnitro\u002Fnitro","ko\u002F1.note\u002F3.nitro\u002Fnitro",{"title":79,"icon":80,"path":81,"stem":82,"children":83,"page":27},"Devops","vscode-icons:file-type-pipeline","\u002Fko\u002Fnote\u002Fdevops","ko\u002F1.note\u002F4.devops",[84],{"title":85,"path":86,"stem":87,"icon":26},"서버사이드 WebAssembly(Wasm)와 차세대 실행 환경","\u002Fko\u002Fnote\u002Fdevops\u002Fwebassembly","ko\u002F1.note\u002F4.devops\u002F1.webAssembly",{"title":89,"icon":90,"path":91,"stem":92,"children":93,"page":27},"Tooling","lucide:wrench","\u002Fko\u002Fnote\u002Ftooling","ko\u002F1.note\u002F4.tooling",[94],{"title":95,"icon":96,"path":97,"stem":98,"children":99,"page":27},"Package Manager","devicon:npm","\u002Fko\u002Fnote\u002Ftooling\u002Fpackage-manager","ko\u002F1.note\u002F4.tooling\u002F1.package-manager",[100],{"title":101,"path":102,"stem":103,"icon":26},"Package Lock 파일의 역할과 의존성 관리 원리","\u002Fko\u002Fnote\u002Ftooling\u002Fpackage-manager\u002Fpackage-lock","ko\u002F1.note\u002F4.tooling\u002F1.package-manager\u002F1.package-lock",{"title":105,"icon":106,"path":107,"stem":108,"children":109,"page":27},"Web","streamline-plump:web","\u002Fko\u002Fnote\u002Fweb","ko\u002F1.note\u002F4.web",[110],{"title":111,"path":112,"stem":113,"icon":26},"웹 애플리케이션 렌더링 아키텍처 이해","\u002Fko\u002Fnote\u002Fweb\u002Frendering-modes","ko\u002F1.note\u002F4.web\u002F2.rendering-modes",{"title":115,"icon":116,"path":117,"stem":118,"children":119,"page":27},"SEO","icon-park-solid:seo","\u002Fko\u002Fnote\u002Fseo","ko\u002F1.note\u002F6.seo",[120],{"title":121,"path":122,"stem":123,"icon":26},"[SEO] 개발 블로그 검색 노출을 위한 robots.txt와 SEO 설정 가이드","\u002Fko\u002Fnote\u002Fseo\u002Fseo","ko\u002F1.note\u002F6.seo\u002F1.seo",{"title":125,"icon":126,"path":127,"stem":128,"children":129,"page":27},"Project (개발일지)","icon-park-solid:branch-two","\u002Fko\u002Fproject","ko\u002F2.project",[130],{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":27},"Brolog","custom:symbol","\u002Fko\u002Fproject\u002Fbrolog","ko\u002F2.project\u002F1.brolog",[136,140,144,148,152,156,160,164,168,173,177],{"title":137,"path":138,"stem":139,"icon":26},"Brolog 프로젝트 개요","\u002Fko\u002Fproject\u002Fbrolog\u002Foutline","ko\u002F2.project\u002F1.brolog\u002F1.outline",{"title":141,"path":142,"stem":143,"icon":26},"[Brolog] Nuxt Multi Layer 프로젝트 Vercel 배포 (3) - Runtime 기능 문제 분석과 AI Assistant 전환","\u002Fko\u002Fproject\u002Fbrolog\u002Fvercel-deploy3-ai-integration","ko\u002F2.project\u002F1.brolog\u002F10.vercel-deploy3-ai-integration",{"title":145,"path":146,"stem":147,"icon":26},"[Brolog] AI Assistant 적용 과정 - Agent 구조와 API 사용량 관리 시 고려사항","\u002Fko\u002Fproject\u002Fbrolog\u002Fai-assistant-application-process","ko\u002F2.project\u002F1.brolog\u002F11.ai-assistant-application-process",{"title":149,"path":150,"stem":151,"icon":26},"[Brolog] 검색 엔진 노출을 위한 SEO 적용 과정","\u002Fko\u002Fproject\u002Fbrolog\u002Fbrolog-seo","ko\u002F2.project\u002F1.brolog\u002F12.brolog-seo",{"title":153,"path":154,"stem":155,"icon":26},"Brolog 프로젝트 구조","\u002Fko\u002Fproject\u002Fbrolog\u002Fstructure","ko\u002F2.project\u002F1.brolog\u002F2.structure",{"title":157,"path":158,"stem":159,"icon":26},"[Nuxt Content] 네비게이션 아이콘 커스텀 빌드","\u002Fko\u002Fproject\u002Fbrolog\u002Fcustom-icon","ko\u002F2.project\u002F1.brolog\u002F3.custom-icon",{"title":161,"path":162,"stem":163,"icon":26},"[Nuxt 4] Auto-imports 동작 원리와 자동 import 시스템 이해","\u002Fko\u002Fproject\u002Fbrolog\u002Fnuxt-auto-import","ko\u002F2.project\u002F1.brolog\u002F4.nuxt-auto-import",{"title":165,"path":166,"stem":167,"icon":26},"[Brolog] 개발 블로그 메인 페이지 구현","\u002Fko\u002Fproject\u002Fbrolog\u002Fdevelop-main","ko\u002F2.project\u002F1.brolog\u002F5.develop-main",{"title":169,"path":170,"stem":171,"icon":172},"[Brolog] 브랜드 아이덴티티 적용 - Custom 404 페이지와 Default No Image 구현","\u002Fko\u002Fproject\u002Fbrolog\u002Fcustom-error-and-default-thumbnail","ko\u002F2.project\u002F1.brolog\u002F6.custom-error-and-default-thumbnail","lucide:image",{"title":174,"path":175,"stem":176,"icon":26},"[Brolog] Nuxt Multi Layer 프로젝트 Vercel 배포 (1)","\u002Fko\u002Fproject\u002Fbrolog\u002Fvercel-deploy1","ko\u002F2.project\u002F1.brolog\u002F8.vercel-deploy1",{"title":178,"path":179,"stem":180,"icon":26},"[Brolog] Nuxt Multi Layer 프로젝트 Vercel 배포 (2) - Build Pipeline 오류 분석과 Nuxt 실행 구조 이해","\u002Fko\u002Fproject\u002Fbrolog\u002Fvercel-deploy2-error-analyze","ko\u002F2.project\u002F1.brolog\u002F9.vercel-deploy2-error-analyze",{"title":182,"icon":183,"path":184,"stem":185,"children":186,"page":27},"Error (트러블슈팅)","emojione:stop-sign","\u002Fko\u002Ftrouble-shooting","ko\u002F3.trouble-shooting",[187],{"title":131,"icon":132,"path":188,"stem":189,"children":190,"page":27},"\u002Fko\u002Ftrouble-shooting\u002Fbrolog","ko\u002F3.trouble-shooting\u002F1.brolog",[191],{"title":192,"path":193,"stem":194,"icon":26},"[Nuxt Content] Nuxt Icon 오류 해결과 Custom Collection 기반 오프라인 아이콘 구성","\u002Fko\u002Ftrouble-shooting\u002Fbrolog\u002Fnuxt-icon-restricted-network-troubleshooting","ko\u002F3.trouble-shooting\u002F1.brolog\u002F1.nuxt-icon-restricted-network-troubleshooting",{"id":196,"title":53,"body":197,"date":1056,"description":1057,"extension":1058,"links":1059,"meta":1060,"navigation":1066,"path":54,"seo":1067,"stem":55,"__hash__":1070},"docs_ko\u002Fko\u002F1.note\u002F2.nuxt4\u002F2.nuxt-use_async_data.md",{"type":198,"value":199,"toc":1044},"minimark",[200,1040],[201,202,204,209,218,221,226,238,268,270,274,279,412,455,457,461,470,479,497,512,520,530,706,708,712,726,994,996,1000,1006],"u-page-card",{":spotlight":203},"true",[205,206,208],"h1",{"id":207},"서버에서-한-번만-useasyncdata-데이터-페칭의-본질","서버에서 한 번만, useAsyncData 데이터 페칭의 본질",[210,211,212,213,217],"p",{},"Nuxt 4 환경에서 블로그 포스트나 API 데이터를 가져올 때 가장 핵심이 되는 컴포저블은 단연 ",[214,215,216],"code",{},"useAsyncData","다. 일반적인 Vue 3 Single Page Application(SPA)의 데이터 페칭 방식을 Nuxt(SSR)에 그대로 대입하면 중복 호출과 화면 깜빡임이라는 치명적인 성능 저하를 마주하게 된다. 이를 우회하고 우아한 데이터 파이프라인을 구축하는 아키텍처적 방법을 알아보자.",[219,220],"hr",{},[222,223,225],"h2",{"id":224},"_1-ssr의-고질적-문제-중복-호출double-fetching과-하이드레이션","1. SSR의 고질적 문제: 중복 호출(Double Fetching)과 하이드레이션",[210,227,228,229,232,233,237],{},"기존 Vue 3 + Vite(SPA) 환경에서는 컴포넌트가 마운트된 후(",[214,230,231],{},"onMounted",") 브라우저가 직접 API를 호출하는 것이 정석이었다. 그러나 서버 사이드 렌더링(SSR) 환경인 Nuxt에서는 코드가 ",[234,235,236],"strong",{},"서버에서 한 번, 브라우저에서 한 번, 총 두 번 실행","되는 특성을 가진다.",[239,240,241,252],"ul",{},[242,243,244,251],"li",{},[234,245,246,247,250],{},"일반 ",[214,248,249],{},"$fetch()","의 한계:"," 서버가 페이지를 빌드할 때 API를 호출하고, 브라우저가 HTML을 넘겨받은 뒤 똑같은 API를 또 호출한다. 불필요한 네트워크 오버헤드가 발생할 뿐만 아니라, 서버 데이터와 클라이언트 데이터의 동기화 타이밍 차이로 인해 하이드레이션 미스매치(Hydration Mismatch) 에러가 발생한다.",[242,253,254,259,260,263,264,267],{},[234,255,256,258],{},[214,257,216],{},"의 해결책:"," 서버에서 데이터를 최초로 가져오면, 그 결과물을 ",[214,261,262],{},"payload","라는 내장 임시 저장소에 공유 상태(State)로 박제하여 브라우저로 함께 토스한다. 브라우저는 네트워킹을 생략하고 이 저장소에서 데이터를 즉시 꺼내 재사용하므로 ",[234,265,266],{},"네트워크 요청을 단 1번으로 최적화","한다.",[219,269],{},[222,271,273],{"id":272},"_2-useasyncdata-구조-및-핵심-반환-객체","2. useAsyncData 구조 및 핵심 반환 객체",[210,275,276,278],{},[214,277,216],{},"는 단순한 데이터 호출 래퍼(Wrapper)를 넘어, 요청의 수명 주기와 로딩 상태를 선언적으로 관리할 수 있는 반응형 객체들을 반환한다.",[280,281,287],"pre",{"className":282,"code":283,"filename":284,"language":285,"meta":286,"style":286},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const { data, status, error, refresh } = await useAsyncData(\n        'main-posts-feed',                      \u002F\u002F 1. 애플리케이션 전역 고유 키 (Unique Key)\n        () => queryCollection('docs_ko').all(), \u002F\u002F 2. 비동기 데이터를 반환하는 콜백 함수\n        options                                 \u002F\u002F 3. 성능 및 동작 제어를 위한 옵션 객체\n)\n","Example","ts","",[214,288,289,339,358,397,406],{"__ignoreMap":286},[290,291,294,298,302,306,309,312,314,317,319,322,325,328,332,336],"span",{"class":292,"line":293},"line",1,[290,295,297],{"class":296},"spNyl","const",[290,299,301],{"class":300},"sMK4o"," {",[290,303,305],{"class":304},"sTEyZ"," data",[290,307,308],{"class":300},",",[290,310,311],{"class":304}," status",[290,313,308],{"class":300},[290,315,316],{"class":304}," error",[290,318,308],{"class":300},[290,320,321],{"class":304}," refresh ",[290,323,324],{"class":300},"}",[290,326,327],{"class":300}," =",[290,329,331],{"class":330},"s7zQu"," await",[290,333,335],{"class":334},"s2Zo4"," useAsyncData",[290,337,338],{"class":304},"(\n",[290,340,342,345,349,352,354],{"class":292,"line":341},2,[290,343,344],{"class":300},"        '",[290,346,348],{"class":347},"sfazB","main-posts-feed",[290,350,351],{"class":300},"'",[290,353,308],{"class":300},[290,355,357],{"class":356},"sHwdD","                      \u002F\u002F 1. 애플리케이션 전역 고유 키 (Unique Key)\n",[290,359,361,364,367,370,373,375,378,380,383,386,389,392,394],{"class":292,"line":360},3,[290,362,363],{"class":300},"        ()",[290,365,366],{"class":296}," =>",[290,368,369],{"class":334}," queryCollection",[290,371,372],{"class":304},"(",[290,374,351],{"class":300},[290,376,377],{"class":347},"docs_ko",[290,379,351],{"class":300},[290,381,382],{"class":304},")",[290,384,385],{"class":300},".",[290,387,388],{"class":334},"all",[290,390,391],{"class":304},"()",[290,393,308],{"class":300},[290,395,396],{"class":356}," \u002F\u002F 2. 비동기 데이터를 반환하는 콜백 함수\n",[290,398,400,403],{"class":292,"line":399},4,[290,401,402],{"class":304},"        options                                 ",[290,404,405],{"class":356},"\u002F\u002F 3. 성능 및 동작 제어를 위한 옵션 객체\n",[290,407,409],{"class":292,"line":408},5,[290,410,411],{"class":304},")\n",[239,413,414,426,447],{},[242,415,416,421,422,425],{},[234,417,418],{},[214,419,420],{},"data",": 비동기 함수가 최종 반환한 데이터가 담긴 Vue 3 ",[214,423,424],{},"Ref"," 객체다.",[242,427,428,433,434,437,438,437,441,437,444,382],{},[234,429,430],{},[214,431,432],{},"status",": 현재 데이터 페칭의 상태를 실시간 문자열로 제공한다. (",[214,435,436],{},"'idle'",", ",[214,439,440],{},"'pending'",[214,442,443],{},"'success'",[214,445,446],{},"'error'",[242,448,449,454],{},[234,450,451],{},[214,452,453],{},"refresh",": 페이지 전체를 새로고침하지 않고, 특정 이벤트(예: 버튼 클릭) 시점에 데이터를 수동으로 다시 불러와서 UI를 갱신하는 고차 함수다.",[219,456],{},[222,458,460],{"id":459},"_3-실무-아키텍처를-위한-고급-옵션-options-파이프라인","3. 실무 아키텍처를 위한 고급 옵션 (Options) 파이프라인",[210,462,463,465,466,469],{},[214,464,216],{},"의 세 번째 인자인 ",[214,467,468],{},"options"," 객체를 활용하면 프론트엔드 레벨에서 서빙되는 데이터 구조를 극적으로 경량화할 수 있다.",[471,472,474,475,478],"h3",{"id":473},"default-패턴을-이용한-초기-런타임-에러-방지","① ",[214,476,477],{},"default"," 패턴을 이용한 초기 런타임 에러 방지",[210,480,481,482,485,486,489,490,493,494,496],{},"비동기 데이터가 도착하기 전, ",[214,483,484],{},"data.value","는 기본적으로 ",[214,487,488],{},"null"," 상태다. 이때 템플릿이나 computed에서 배열 메서드(",[214,491,492],{},".map()",")를 호출하면 에러가 터진다. ",[214,495,477],{}," 옵션으로 초기 상태를 보장하는 것이 안전하다.",[498,499,500],"blockquote",{},[210,501,502,505,507,508,511],{},[234,503,504],{},"💡 데이터 안정성 확보",[214,506,477],{}," 옵션을 배열 구조(",[214,509,510],{},"() => []",")로 정의하면 v-for 루프나 가공 함수가 데이터 로딩 중에도 크래시 없이 안전하게 실행된다.",[471,513,515,516,519],{"id":514},"transform을-통한-네트워크-페이로드-경량화","② ",[214,517,518],{},"transform","을 통한 네트워크 페이로드 경량화",[210,521,522,523,526,527,529],{},"Content 모듈이나 외부 CMS에서 넘겨주는 원본 데이터 중, ",[234,524,525],{},"현재 컴포넌트 렌더링에 꼭 필요한 필드만 필터링하여 보관","할 수 있다. 브라우저가 전달받는 ",[214,528,262],{}," 메모리 크기가 줄어들어 전체적인 성능과 메모리 효율이 극대화된다.",[280,531,533],{"className":282,"code":532,"filename":284,"language":285,"meta":286,"style":286},"\u002F\u002F 본문(body) 내용 등 무거운 필드를 제외하고 목록용 데이터만 슬라이싱하는 예시\nconst { data: postsSummary } = await useAsyncData('posts-summary', () => queryCollection('docs').all(), {\n  transform: (rawPosts) => rawPosts.map(post => ({\n    title: post.title,\n    description: post.description,\n    to: post._path\n  }))\n})\n",[214,534,535,540,603,641,659,675,690,699],{"__ignoreMap":286},[290,536,537],{"class":292,"line":293},[290,538,539],{"class":356},"\u002F\u002F 본문(body) 내용 등 무거운 필드를 제외하고 목록용 데이터만 슬라이싱하는 예시\n",[290,541,542,544,546,549,552,555,557,559,561,563,565,567,570,572,574,577,579,581,583,585,588,590,592,594,596,598,600],{"class":292,"line":341},[290,543,297],{"class":296},[290,545,301],{"class":300},[290,547,305],{"class":548},"swJcz",[290,550,551],{"class":300},":",[290,553,554],{"class":304}," postsSummary ",[290,556,324],{"class":300},[290,558,327],{"class":300},[290,560,331],{"class":330},[290,562,335],{"class":334},[290,564,372],{"class":304},[290,566,351],{"class":300},[290,568,569],{"class":347},"posts-summary",[290,571,351],{"class":300},[290,573,308],{"class":300},[290,575,576],{"class":300}," ()",[290,578,366],{"class":296},[290,580,369],{"class":334},[290,582,372],{"class":304},[290,584,351],{"class":300},[290,586,587],{"class":347},"docs",[290,589,351],{"class":300},[290,591,382],{"class":304},[290,593,385],{"class":300},[290,595,388],{"class":334},[290,597,391],{"class":304},[290,599,308],{"class":300},[290,601,602],{"class":300}," {\n",[290,604,605,608,610,613,617,619,621,624,626,629,631,634,636,638],{"class":292,"line":360},[290,606,607],{"class":334},"  transform",[290,609,551],{"class":300},[290,611,612],{"class":300}," (",[290,614,616],{"class":615},"sHdIc","rawPosts",[290,618,382],{"class":300},[290,620,366],{"class":296},[290,622,623],{"class":304}," rawPosts",[290,625,385],{"class":300},[290,627,628],{"class":334},"map",[290,630,372],{"class":304},[290,632,633],{"class":615},"post",[290,635,366],{"class":296},[290,637,612],{"class":304},[290,639,640],{"class":300},"{\n",[290,642,643,646,648,651,653,656],{"class":292,"line":399},[290,644,645],{"class":548},"    title",[290,647,551],{"class":300},[290,649,650],{"class":304}," post",[290,652,385],{"class":300},[290,654,655],{"class":304},"title",[290,657,658],{"class":300},",\n",[290,660,661,664,666,668,670,673],{"class":292,"line":408},[290,662,663],{"class":548},"    description",[290,665,551],{"class":300},[290,667,650],{"class":304},[290,669,385],{"class":300},[290,671,672],{"class":304},"description",[290,674,658],{"class":300},[290,676,678,681,683,685,687],{"class":292,"line":677},6,[290,679,680],{"class":548},"    to",[290,682,551],{"class":300},[290,684,650],{"class":304},[290,686,385],{"class":300},[290,688,689],{"class":304},"_path\n",[290,691,693,696],{"class":292,"line":692},7,[290,694,695],{"class":300},"  }",[290,697,698],{"class":304},"))\n",[290,700,702,704],{"class":292,"line":701},8,[290,703,324],{"class":300},[290,705,411],{"class":304},[219,707],{},[222,709,711],{"id":710},"_4-nuxt-4-content-모듈-최적화-실무-패턴","4. Nuxt 4 Content 모듈 최적화 실무 패턴",[210,713,714,715,718,719,721,722,725],{},"블로그 메인 피드처럼 정제된 가공 데이터가 필요할 때, 별도의 외부 ",[214,716,717],{},"computed"," 파이프라인으로 결합도를 높이기보다 ",[214,720,216],{}," 콜백 내부에서 ",[214,723,724],{},"await"," 후 인라인으로 최종 형태를 빌드하여 반환하는 패턴이 스코프 관리 측면에서 가장 이상적이다.",[280,727,729],{"className":282,"code":728,"filename":284,"language":285,"meta":286,"style":286},"const { data: formattedPosts } = await useAsyncData('main-posts-feed', async () => {\n  \u002F\u002F 1. 비동기 쿼리를 통해 raw 데이터 배열을 온전히 확보\n  const rawPosts = await queryCollection('docs_ko')\n    .order('date', 'DESC') \u002F\u002F 최신순 정렬\n    .all()\n\n  \u002F\u002F 2. 확보된 순수 배열을 하이드레이션 이전에 즉시 맵핑 및 가공\n  return rawPosts.map(post => ({\n    ...post,\n    image: post.image || '[https:\u002F\u002Fnuxt.com\u002Fassets\u002Fblog\u002Fnuxt-icon\u002Fcover.png](https:\u002F\u002Fnuxt.com\u002Fassets\u002Fblog\u002Fnuxt-icon\u002Fcover.png)',\n    date: formatDate(post.date), \u002F\u002F 날짜 포맷 레이어 적용\n    to: post._path,\n  }))\n}, {\n  default: () => [], \u002F\u002F 초기 렌더링 안정성 확보\n})\n",[214,730,731,771,776,799,832,841,847,852,873,883,910,936,952,959,967,987],{"__ignoreMap":286},[290,732,733,735,737,739,741,744,746,748,750,752,754,756,758,760,762,765,767,769],{"class":292,"line":293},[290,734,297],{"class":296},[290,736,301],{"class":300},[290,738,305],{"class":548},[290,740,551],{"class":300},[290,742,743],{"class":304}," formattedPosts ",[290,745,324],{"class":300},[290,747,327],{"class":300},[290,749,331],{"class":330},[290,751,335],{"class":334},[290,753,372],{"class":304},[290,755,351],{"class":300},[290,757,348],{"class":347},[290,759,351],{"class":300},[290,761,308],{"class":300},[290,763,764],{"class":296}," async",[290,766,576],{"class":300},[290,768,366],{"class":296},[290,770,602],{"class":300},[290,772,773],{"class":292,"line":341},[290,774,775],{"class":356},"  \u002F\u002F 1. 비동기 쿼리를 통해 raw 데이터 배열을 온전히 확보\n",[290,777,778,781,783,785,787,789,791,793,795,797],{"class":292,"line":360},[290,779,780],{"class":296},"  const",[290,782,623],{"class":304},[290,784,327],{"class":300},[290,786,331],{"class":330},[290,788,369],{"class":334},[290,790,372],{"class":548},[290,792,351],{"class":300},[290,794,377],{"class":347},[290,796,351],{"class":300},[290,798,411],{"class":548},[290,800,801,804,807,809,811,814,816,818,821,824,826,829],{"class":292,"line":399},[290,802,803],{"class":300},"    .",[290,805,806],{"class":334},"order",[290,808,372],{"class":548},[290,810,351],{"class":300},[290,812,813],{"class":347},"date",[290,815,351],{"class":300},[290,817,308],{"class":300},[290,819,820],{"class":300}," '",[290,822,823],{"class":347},"DESC",[290,825,351],{"class":300},[290,827,828],{"class":548},") ",[290,830,831],{"class":356},"\u002F\u002F 최신순 정렬\n",[290,833,834,836,838],{"class":292,"line":408},[290,835,803],{"class":300},[290,837,388],{"class":334},[290,839,840],{"class":548},"()\n",[290,842,843],{"class":292,"line":677},[290,844,846],{"emptyLinePlaceholder":845},true,"\n",[290,848,849],{"class":292,"line":692},[290,850,851],{"class":356},"  \u002F\u002F 2. 확보된 순수 배열을 하이드레이션 이전에 즉시 맵핑 및 가공\n",[290,853,854,857,859,861,863,865,867,869,871],{"class":292,"line":701},[290,855,856],{"class":330},"  return",[290,858,623],{"class":304},[290,860,385],{"class":300},[290,862,628],{"class":334},[290,864,372],{"class":548},[290,866,633],{"class":615},[290,868,366],{"class":296},[290,870,612],{"class":548},[290,872,640],{"class":300},[290,874,876,879,881],{"class":292,"line":875},9,[290,877,878],{"class":300},"    ...",[290,880,633],{"class":304},[290,882,658],{"class":300},[290,884,886,889,891,893,895,898,901,903,906,908],{"class":292,"line":885},10,[290,887,888],{"class":548},"    image",[290,890,551],{"class":300},[290,892,650],{"class":304},[290,894,385],{"class":300},[290,896,897],{"class":304},"image",[290,899,900],{"class":300}," ||",[290,902,820],{"class":300},[290,904,905],{"class":347},"[https:\u002F\u002Fnuxt.com\u002Fassets\u002Fblog\u002Fnuxt-icon\u002Fcover.png](https:\u002F\u002Fnuxt.com\u002Fassets\u002Fblog\u002Fnuxt-icon\u002Fcover.png)",[290,907,351],{"class":300},[290,909,658],{"class":300},[290,911,913,916,918,921,923,925,927,929,931,933],{"class":292,"line":912},11,[290,914,915],{"class":548},"    date",[290,917,551],{"class":300},[290,919,920],{"class":334}," formatDate",[290,922,372],{"class":548},[290,924,633],{"class":304},[290,926,385],{"class":300},[290,928,813],{"class":304},[290,930,382],{"class":548},[290,932,308],{"class":300},[290,934,935],{"class":356}," \u002F\u002F 날짜 포맷 레이어 적용\n",[290,937,939,941,943,945,947,950],{"class":292,"line":938},12,[290,940,680],{"class":548},[290,942,551],{"class":300},[290,944,650],{"class":304},[290,946,385],{"class":300},[290,948,949],{"class":304},"_path",[290,951,658],{"class":300},[290,953,955,957],{"class":292,"line":954},13,[290,956,695],{"class":300},[290,958,698],{"class":548},[290,960,962,965],{"class":292,"line":961},14,[290,963,964],{"class":300},"},",[290,966,602],{"class":300},[290,968,970,973,975,977,979,982,984],{"class":292,"line":969},15,[290,971,972],{"class":334},"  default",[290,974,551],{"class":300},[290,976,576],{"class":300},[290,978,366],{"class":296},[290,980,981],{"class":304}," []",[290,983,308],{"class":300},[290,985,986],{"class":356}," \u002F\u002F 초기 렌더링 안정성 확보\n",[290,988,990,992],{"class":292,"line":989},16,[290,991,324],{"class":300},[290,993,411],{"class":304},[219,995],{},[222,997,999],{"id":998},"_5-결론-및-체크리스트","5. 결론 및 체크리스트",[210,1001,1002,1003,1005],{},"Nuxt 4 아키텍처에서 ",[214,1004,216],{},"를 다룰 때는 다음 세 가지 규칙을 항상 준수해야 정교한 하이브리드 웹 애플리케이션을 완성할 수 있다.",[1007,1008,1009,1019,1031],"ol",{},[242,1010,1011,1014,1015,1018],{},[234,1012,1013],{},"고유 ID 규칙:"," 첫 번째 인자인 ",[214,1016,1017],{},"key","는 서비스 전역 컨텍스트 상에서 단 하나만 존재해야 한다. 키가 중복될 경우 서로 다른 컴포넌트 간에 데이터 오버라이트 현상이 발생한다.",[242,1020,1021,1024,1025,1027,1028,1030],{},[234,1022,1023],{},"비동기 타이밍 스코프:"," 콜백 블록 내부에서 맵핑 함수를 쓸 때는 반드시 대상을 ",[214,1026,724],{},"로 명확하게 평가(Evaluation)하여 비동기 프로미스 객체에 직접 ",[214,1029,492],{},"을 요청하는 실수를 방지해야 한다.",[242,1032,1033,1036,1037,1039],{},[234,1034,1035],{},"미니멀 데이터 유지:"," 블로그 목록 화면에서 굳이 들고 있을 필요가 없는 무거운 마크다운 객체 구조는 ",[214,1038,518],{}," 또는 인라인 매퍼를 통해 철저히 걷어내어 가벼운 상태를 유지해야 한다.",[1041,1042,1043],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":286,"searchDepth":341,"depth":341,"links":1045},[1046,1047,1048,1054,1055],{"id":224,"depth":341,"text":225},{"id":272,"depth":341,"text":273},{"id":459,"depth":341,"text":460,"children":1049},[1050,1052],{"id":473,"depth":360,"text":1051},"① default 패턴을 이용한 초기 런타임 에러 방지",{"id":514,"depth":360,"text":1053},"② transform을 통한 네트워크 페이로드 경량화",{"id":710,"depth":341,"text":711},{"id":998,"depth":341,"text":999},"2026-07-08","Nuxt의 useAsyncData가 SSR 환경에서 데이터 중복 요청을 방지하고 Hydration 성능을 개선하는 원리와 활용 방법 정리","md",null,{"tags":1061,"image":1065},[43,1062,1063,1064],"Vue3","SSR","WebDev","images\u002Fnuxt-thumbnail2.png",{"icon":26},{"title":1068,"description":1069},"Nuxt useAsyncData 사용법과 SSR 중복 요청 방지 원리 | SSR 최적화 방법","Nuxt useAsyncData의 데이터 패칭 흐름과 SSR 환경에서 중복 요청을 방지하는 원리, 효율적인 사용 방법을 알아봅니다.","pps4UxvQ-vRfi0izLE2-krePVjDwxrMJdvG5qS_S49I",[1072,1074],{"title":49,"path":50,"stem":51,"description":1073,"icon":26,"children":-1},"Vue 생태계에서 Nuxt가 등장한 배경부터 Nuxt 4의 단일 앱 레이어 구조, Auto-imports, SSR 데이터 페칭, 그리고 실무 주의점 정리",{"title":57,"path":58,"stem":59,"description":1075,"icon":26,"children":-1},"Nuxt Content v3의 SQLite 기반 데이터 구조, Collections 시스템, Schema 정의 방식과 콘텐츠 조회 메커니즘 정리",1785305903769]