2026๋ Nuxt 4 ์๋ฒฝ ๊ฐ์ด๋: ์๋ก์ด ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ์ Nuxt 3 ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต
Nuxt 4์์ ๋์ ๋ app/ ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ, ์ฑ๊ธํค ๋ฐ์ดํฐ ํจ์นญ ๋ ์ด์ด, shallow reactivity, TypeScript ์ปจํ ์คํธ ๋ถ๋ฆฌ๋ฅผ ์ฝ๋ ์์ ์ ํจ๊ป ์์ธํ ๋ถ์ํฉ๋๋ค.

Nuxt 4๋ ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ ์ค์ ํ์ผ์ ๋ช ํํ๊ฒ ๋ถ๋ฆฌํ๋ ์๋ก์ด ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋์ ํ์ต๋๋ค. 2025๋ 7์์ ์ถ์๋์ด 2026๋ 4์ ๊ธฐ์ค ๋ฒ์ 4.4์ ๋๋ฌํ ์ด ๋ฉ์ด์ ์ ๋ฐ์ดํธ๋, ์ฑ๊ธํค ๋ฐ์ดํฐ ํจ์นญ ๋ ์ด์ด, shallow reactivity ๊ธฐ๋ณธ ์ ์ฉ, TypeScript ์ปจํ ์คํธ ๋ถํ ๋ฑ ๊ฐ๋ฐ ๊ฒฝํ์ ํฌ๊ฒ ๊ฐ์ ํ๋ ๊ธฐ๋ฅ๋ค์ ํฌํจํ๊ณ ์์ต๋๋ค. Nuxt 2์์ Nuxt 3์ผ๋ก์ ์ ํ๊ณผ ๋น๊ตํ๋ฉด, ์ด๋ฒ ์ ๊ทธ๋ ์ด๋ ๊ฒฝ๋ก๋ ํจ์ฌ ๋งค๋๋ฝ์ต๋๋ค.
Nuxt ํ์ Codemod์ ํ๋ ฅํ์ฌ ๋๋ถ๋ถ์ ๋ง์ด๊ทธ๋ ์ด์
๋จ๊ณ๋ฅผ ์๋ํํ์ต๋๋ค. npx codemod@latest nuxt/4/migration-recipe๋ฅผ ์คํํ๋ฉด ๋๋ ํฐ๋ฆฌ ์ฌ๊ตฌ์ฑ, ๋ฐ์ดํฐ ํจ์นญ ์
๋ฐ์ดํธ, ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋ API ๊ต์ฒด๊ฐ ์๋์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
Nuxt 4์ app/ ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ
Nuxt 4์์๋ ๋ชจ๋ ์ ํ๋ฆฌ์ผ์ด์
์์ค ์ฝ๋๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก app/ ๋๋ ํฐ๋ฆฌ์ ๋ฐฐ์น๋ฉ๋๋ค. ์ด ๋ณ๊ฒฝ์ ์ค์ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๊ฒ์
๋๋ค. Linux์ Windows์ ํ์ผ ๊ฐ์์(file watcher)๋ ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋๊ฐ node_modules/, .git/, ์ค์ ํ์ผ๊ณผ ํผ์ฌ๋์ง ์๊ณ ์ ์ฉ ํ์ ๋๋ ํฐ๋ฆฌ์ ์ ์ฅ๋ ๋ ์ฑ๋ฅ์ด ํฌ๊ฒ ํฅ์๋ฉ๋๋ค.
์๋ก์ด ๋๋ ํฐ๋ฆฌ ๋ ์ด์์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
my-nuxt-app/
โโ app/
โ โโ assets/
โ โโ components/
โ โโ composables/
โ โโ layouts/
โ โโ middleware/
โ โโ pages/
โ โโ plugins/
โ โโ utils/
โ โโ app.vue
โ โโ app.config.ts
โ โโ error.vue
โโ content/
โโ public/
โโ shared/ # ์ ๊ท: app๊ณผ server ๊ฐ ๊ณต์ ์ฝ๋
โโ server/
โโ nuxt.config.tsshared/ ๋๋ ํฐ๋ฆฌ๋ ์ฃผ๋ชฉํ ๋งํ ์ถ๊ฐ ์ฌํญ์
๋๋ค. shared/์ ๋ฐฐ์น๋ composable์ด๋ ์ ํธ๋ฆฌํฐ๋ Vue ์ฑ๊ณผ Nitro ์๋ฒ ์์ชฝ์์ ์๋ ์ํฌํธ๋ฉ๋๋ค. ์ ํจ์ฑ ๊ฒ์ฌ ์คํค๋ง, ํ์
์ ์, ์ ํธ๋ฆฌํฐ ํจ์๋ฅผ ์ปจํ
์คํธ ๊ฐ์ ๊ณต์ ํ ๋ ์๋์ผ๋ก import ๋ฌธ์ ์์ฑํ ํ์๊ฐ ์์ด์ง๋๋ค.
Nuxt 3์์ Nuxt 4๋ก์ ๋จ๊ณ๋ณ ๋ง์ด๊ทธ๋ ์ด์
์ ๊ทธ๋ ์ด๋ ๊ณผ์ ์ ํ๋์ ๋ช ๋ น์ด์์ ์์ํฉ๋๋ค. Nuxt๋ ๊ธฐ์กด์ ํ๋ซ ๊ตฌ์กฐ๋ฅผ ๊ฐ์งํ๊ณ ๋ณ๊ฒฝ ์์ด ๊ณ์ ๋์ํ๋ฏ๋ก, ์ ์ง์ ์ธ ๋ง์ด๊ทธ๋ ์ด์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
# Nuxt ์
๊ทธ๋ ์ด๋ ๋ฐ ์์กด์ฑ ์ค๋ณต ์ ๊ฑฐ
npx nuxt upgrade --dedupeํจํค์ง ์
๊ทธ๋ ์ด๋ ํ, ์ ํ๋ฆฌ์ผ์ด์
ํ์ผ์ app/ ๋๋ ํฐ๋ฆฌ๋ก ์ด๋ํฉ๋๋ค.
# ๋๋ ํฐ๋ฆฌ ์ฌ๊ตฌ์ฑ ์๋ํ
npx codemod@latest nuxt/4/file-structure์ด codemod๋ assets/, components/, composables/, layouts/, middleware/, pages/, plugins/, utils/, app.vue, error.vue, app.config.ts๋ฅผ app/์ผ๋ก ์ด๋ํฉ๋๋ค. ๋ฃจํธ์ ๋จ์์ผ ํ๋ ํ์ผ๋ค(nuxt.config.ts, server/, public/, content/)์ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค.
๋๋ ํฐ๋ฆฌ ์ฌ๊ตฌ์ฑ์ ์ฆ์ ์งํํ์ง ์์ผ๋ ค๋ ๊ฒฝ์ฐ, ์์ค ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ช ์์ ์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค.
export default defineNuxtConfig({
srcDir: '.',
dir: { app: 'app' },
})์ด ์ค์ ์ ํตํด Nuxt 4๊ฐ ํ๋ก์ ํธ ๋ฃจํธ์์ ํ์ผ์ ํ์ธํ๊ฒ ๋์ด, Nuxt 3๊ณผ ๋์ผํ ๋์์ ์ ์งํฉ๋๋ค.
์ฑ๊ธํค ๋ฐ์ดํฐ ํจ์นญ ๋ ์ด์ด์ ๋ฆฌ์กํฐ๋ธ ํค
Nuxt 4์์๋ useAsyncData์ useFetch์ ๋ฐ์ดํฐ ๊ด๋ฆฌ ๋ฐฉ์์ด ๊ทผ๋ณธ์ ์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. ๋์ผํ ํค๋ฅผ ์ฌ์ฉํ๋ ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ ๋
๋ฆฝ์ ์ธ ๋ณต์ฌ๋ณธ์ ์ ์งํ๋ ๋์ , ํ๋์ ๋ฆฌ์กํฐ๋ธ ์ฐธ์กฐ๋ฅผ ๊ณต์ ํ๊ฒ ๋ฉ๋๋ค.
export function useProductData(productId: string) {
return useAsyncData(
`product-${productId}`,
() => $fetch(`/api/products/${productId}`),
{
getCachedData: (key, nuxtApp, ctx) => {
// ctx.cause๋ก ํจ์นญ ์ด์ ๋ฅผ ํ๋ณ ๊ฐ๋ฅ
if (ctx.cause === 'refresh:manual') return undefined
return nuxtApp.payload.data[key]
},
},
)
}์ด ์๋ก์ด ๋ฐ์ดํฐ ๋ ์ด์ด์๋ ์ธ ๊ฐ์ง ํต์ฌ ๋ณ๊ฒฝ ์ฌํญ์ด ์์ต๋๋ค.
- ๊ณต์ ref: ๋ ์ปดํฌ๋ํธ์์
useProductData('abc')๋ฅผ ํธ์ถํ๋ฉด ๋์ผํdata,error,statusref๊ฐ ๋ฐํ๋ฉ๋๋ค. ํ์ชฝ์ ์ ๋ฐ์ดํธํ๋ฉด ๋ค๋ฅธ ์ชฝ์๋ ์ฆ์ ๋ฐ์๋ฉ๋๋ค. - ์๋ ์ ๋ฆฌ: ํน์ ํค๋ฅผ ์ฌ์ฉํ๋ ๋ง์ง๋ง ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋๋ฉด, ํด๋น ๋ฐ์ดํฐ๊ฐ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ๋ฉ๋๋ค.
- ๋ฆฌ์กํฐ๋ธ ํค: ํค๋ฅผ computed๋ ref๋ก ๋ํํ๋ฉด, ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋ ์๋์ผ๋ก ๋ฐ์ดํฐ๊ฐ ๋ค์ ํจ์นญ๋ฉ๋๋ค.
getCachedData ์ฝ๋ฐฑ์ ์ด์ cause ์์ฑ('initial', 'refresh:hook', 'refresh:manual', 'watch')์ ๊ฐ์ง ์ปจํ
์คํธ ๊ฐ์ฒด๋ฅผ ๋ฐ์ต๋๋ค. ์ด๋ฅผ ํตํด ์บ์ ๋ฐ์ดํฐ ์ ๊ณต๊ณผ ์๋ก์ด ํจ์นญ ๊ฐ์ ์ ํ์ ์ธ๋ฐํ๊ฒ ์ ์ดํ ์ ์์ต๋๋ค.
useAsyncData/useFetch์ data์ error ๊ธฐ๋ณธ๊ฐ์ด null์์ undefined๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. === null ๊ฒ์ฌ๋ฅผ === undefined๋ก ์
๋ฐ์ดํธํ๊ฑฐ๋ ๋์จํ ๋๋ฑ ๋น๊ต๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
Shallow Reactivity ๊ธฐ๋ณธ ์ ์ฉ์ผ๋ก ์ฑ๋ฅ ํฅ์
Nuxt 4์์๋ useAsyncData์ useFetch์ data๊ฐ ref ๋์ shallowRef๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํฉ๋๋ค. Vue๊ฐ ๋ ์ด์ ์ค์ฒฉ๋ ๋ชจ๋ ์์ฑ์ ์ฌ๊ท์ ์ผ๋ก ์ถ์ ํ์ง ์์ผ๋ฏ๋ก, ๊น์ด ์ค์ฒฉ๋ ๊ฐ์ฒด๋ ๋๊ท๋ชจ ๋ฐฐ์ด์ ํฌํจํ๋ API ์๋ต์ ๋ํด ์ธก์ ๊ฐ๋ฅํ ์ฑ๋ฅ ๊ฐ์ ์ ์ ๊ณตํฉ๋๋ค.
<script setup lang="ts">
// data๋ ๊ธฐ๋ณธ์ ์ผ๋ก shallowRef๋ก ๋์
const { data: metrics } = await useFetch('/api/dashboard/metrics')
// ์ง์ ์ ์ธ ์์ฑ ๋ณ๊ฒฝ์ ๋ฆฌ์กํฐ๋นํฐ๋ฅผ ํธ๋ฆฌ๊ฑฐํ์ง ์์
// metrics.value.visits = 100 // ๋ฆฌ๋ ๋๋ง์ด ๋ฐ์ํ์ง ์์
// ์ ์ฒด ๊ฐ์ ๊ต์ฒดํ๋ฉด ์
๋ฐ์ดํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋จ
metrics.value = { ...metrics.value, visits: 100 }
// ํน์ ํธ์ถ์์ ๋ฅ ๋ฆฌ์กํฐ๋นํฐ๋ฅผ ํ์ฑํ
const { data: settings } = await useFetch('/api/settings', {
deep: true,
})
</script>๋์๋ณด๋, ์ํ ๋ชฉ๋ก, ๊ธฐ์ฌ ํ์ด์ง ๋ฑ ๋๋ถ๋ถ์ ์ฝ๊ธฐ ์ ์ฉ ๋ฐ์ดํฐ ํ์์์๋ shallow reactivity๊ฐ ์ฝ๋ ๋ณ๊ฒฝ ์์ด ์ ์์ ์ผ๋ก ๋์ํฉ๋๋ค. ํผ์ด๋ ์ค์ฒฉ๋ ์์ฑ์ ์ง์ ๋ณ๊ฒฝํ๋ ์ธํฐ๋ํฐ๋ธ UI์๋ deep: true ์ต์
์ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Vue.js / Nuxt.js ๋ฉด์ ์ค๋น๊ฐ ๋์ จ๋์?
์ธํฐ๋ํฐ๋ธ ์๋ฎฌ๋ ์ดํฐ, flashcards, ๊ธฐ์ ํ ์คํธ๋ก ์ฐ์ตํ์ธ์.
TypeScript ์ปจํ ์คํธ ๋ถํ ๊ณผ ํ์ ์์ ์ฑ ๊ฐํ
Nuxt 4์์๋ ํ๋ก์ ํธ ๋ด ๊ฐ ์ปจํ ์คํธ์ ๋ํด ๋ณ๋์ TypeScript ์ค์ ์ด ์์ฑ๋ฉ๋๋ค.
.nuxt/tsconfig.app.jsonโ Vue ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ฉ.nuxt/tsconfig.server.jsonโ Nitro ์๋ฒ ์ฝ๋์ฉ.nuxt/tsconfig.shared.jsonโ ๊ณต์ ์ ํธ๋ฆฌํฐ์ฉ.nuxt/tsconfig.node.jsonโ ๋น๋ ์์ ์ค์ ์ฉ
์ด ๋ถ๋ฆฌ ๋๋ถ์ IDE๊ฐ ํด๋ผ์ด์ธํธ ์ฝ๋์์ ์๋ฒ ์ ์ฉ API๋ฅผ ์ ์ํ๊ฑฐ๋ ๊ทธ ๋ฐ๋์ ์ํฉ์ด ๋ฐ์ํ์ง ์์ต๋๋ค. ํ๋ก์ ํธ ๋ฃจํธ์ tsconfig.json์ ๋ค ๊ฐ์ง ์ค์ ์ ๋ชจ๋ ์ฐธ์กฐํ๋ ๊ตฌ์กฐ๊ฐ ๋ฉ๋๋ค.
{
"files": [],
"references": [
{ "path": "./.nuxt/tsconfig.app.json" },
{ "path": "./.nuxt/tsconfig.server.json" },
{ "path": "./.nuxt/tsconfig.shared.json" },
{ "path": "./.nuxt/tsconfig.node.json" }
]
}CI์์์ ํ์
๊ฒ์ฌ๋ ๋ณ๊ฒฝ๋ฉ๋๋ค. vue-tsc ๋ช
๋ น์ด๋ ํ๋ก์ ํธ ์ฐธ์กฐ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๊ธฐ ์ํด -b ํ๋๊ทธ(๋น๋ ๋ชจ๋)๊ฐ ํ์ํฉ๋๋ค.
# ๋ณ๊ฒฝ ์ (Nuxt 3)
nuxt prepare && vue-tsc --noEmit
# ๋ณ๊ฒฝ ํ (Nuxt 4)
nuxt prepare && vue-tsc -b --noEmit๋ ๋ค๋ฅธ TypeScript ๋ณ๊ฒฝ ์ฌํญ์ผ๋ก, compilerOptions.noUncheckedIndexedAccess๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก true๋ก ์ค์ ๋ฉ๋๋ค. ๋ฐฐ์ด ์์๋ ๊ฐ์ฒด ์์ฑ์ ์ธ๋ฑ์ค๋ก ์ ๊ทผํ๋ฉด T | undefined๋ฅผ ๋ฐํํ๊ฒ ๋์ด, ์ปดํ์ผ ์์ ์ ์ ์ฌ์ ์ธ ๋ฐํ์ ์ค๋ฅ๋ฅผ ๊ฐ์งํ ์ ์์ต๋๋ค.
์ปดํฌ๋ํธ ์ด๋ฆ ์ ๊ทํ์ Vue Router v5
Nuxt 4.3์์๋ Vue Router v5๋ก ์
๊ทธ๋ ์ด๋๋์์ผ๋ฉฐ, unplugin-vue-router์ ๋ํ ์์กด์ฑ์ด ์ ๊ฑฐ๋์์ต๋๋ค. ๋๋ถ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์
์์ ์ด ์
๊ทธ๋ ์ด๋๋ ํฌ๋ช
ํ๊ฒ ์งํ๋ฉ๋๋ค.
์ปดํฌ๋ํธ ๋ช
๋ช
๊ท์น์ด ํ์คํ๋์์ต๋๋ค. components/dashboard/MetricsCard.vue์ ์์นํ ์ปดํฌ๋ํธ๋ <KeepAlive>, Vue DevTools, ํ
์คํธ ์ ํธ๋ฆฌํฐ๋ฅผ ํฌํจํ ๋ชจ๋ ์ปจํ
์คํธ์์ ์ผ๊ด๋๊ฒ DashboardMetricsCard๋ผ๋ ์ด๋ฆ์ ๊ฐ์ต๋๋ค.
<!-- app/pages/dashboard.vue -->
<template>
<NuxtPage :keepalive="{
include: ['DashboardMetricsCard', 'DashboardRecentActivity'],
}" />
</template>์ปดํฌ๋ํธ ์ด๋ฆ ํํฐ๋ฅผ ์ฌ์ฉํ๋ <KeepAlive>๊ฐ ์๋ ํ๋ก์ ํธ๋ ์ด ์๋ก์ด ๋ช
๋ช
๊ท์น์ ๋ง๊ฒ ์
๋ฐ์ดํธํด์ผ ํฉ๋๋ค. ์ปจํ
์คํธ์ ๋ฐ๋ผ ์ด๋ฆ์ด ๋ฌ๋ผ์ง๋ ์ด์ ๋์์ ๋ ์ด์ ์ ์ฉ๋์ง ์์ต๋๋ค.
Head ๊ด๋ฆฌ์ ์ฃผ์ ๋ณ๊ฒฝ ์ฌํญ ๋์
Nuxt 4์๋ Unhead v2๊ฐ ํฌํจ๋์ด ์์ผ๋ฉฐ, useHead์ useSeoMeta์์ ์ฌ๋ฌ ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋ ์์ฑ์ด ์ ๊ฑฐ๋์์ต๋๋ค.
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// Unhead v2: vmid, hid, children, body ์์ฑ ์ ๊ฑฐ
useSeoMeta({
title: () => product.value?.name ?? 'Product',
ogTitle: () => product.value?.name ?? 'Product',
description: () => product.value?.description ?? '',
ogImage: () => product.value?.imageUrl ?? '',
})
</script>ํ ํ๋ฆฟ ํ๋ผ๋ฏธํฐ๋ ๋ณ์นญ ์ ๋ ฌ์ ์์กดํ๋ ํ๋ก์ ํธ์์๋ ์ด๋ฅผ ๋ช ์์ ํ๋ฌ๊ทธ์ธ์ผ๋ก ์ค์นํด์ผ ํฉ๋๋ค.
import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins'
export default defineNuxtPlugin({
setup() {
const unhead = injectHead()
unhead.use(TemplateParamsPlugin)
unhead.use(AliasSortingPlugin)
},
})Nuxt 3์ 2026๋ 7์ 31์ผ๊น์ง ๋ณด์ ์ ๋ฐ์ดํธ์ ์ค์ํ ๋ฒ๊ทธ ์์ ์ ๊ณ์ ๋ฐ์ต๋๋ค. ํด๋น ๋ ์ง ์ดํ Nuxt 3์ ์ง์ ๋์์์ ์ ์ธ๋ฉ๋๋ค. EOL ํ๋ ์์ํฌ์์ ํ๋ก๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด์ํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ง๊ธ๋ถํฐ ๋ง์ด๊ทธ๋ ์ด์ ๊ณํ์ ์ธ์ฐ๋ ๊ฒ์ด ๊ถ์ฅ๋ฉ๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ ์ฒดํฌ๋ฆฌ์คํธ์ ์ฃผ์ ์ฌํญ
์๋ codemod๊ฐ ๋๋ถ๋ถ์ ๋ณ๊ฒฝ ์ฌํญ์ ์ฒ๋ฆฌํ์ง๋ง, ์๋ ๋์์ด ํ์ํ ํญ๋ชฉ๋ ์์ต๋๋ค.
window.__NUXT__์ ๊ฑฐ:useNuxtApp().payload๋ก ๊ต์ฒดํด์ผ ํฉ๋๋ค. ์ด ์ ์ญ ๊ฐ์ฒด๋ Nuxt 4์์ ํ์ด๋๋ ์ด์ ํ ์ญ์ ๋ฉ๋๋ค.pages:extendํ : ํ์ด์ง ๋ฉํ ์ค์บ ํ์ ์คํ๋๋ ์๋ก์ดpages:resolvedํ ์ผ๋ก ์ ํํด์ผ ํฉ๋๋ค.dedupe๋ถ๋ฆฌ์ธ:refresh({ dedupe: true })๋ฅผrefresh({ dedupe: 'cancel' })๋ก,false๋ฅผ'defer'๋ก ๊ต์ฒดํฉ๋๋ค.- ์ธ๋ผ์ธ ์คํ์ผ: ๊ธฐ๋ณธ์ ์ผ๋ก Vue ์ปดํฌ๋ํธ ์คํ์ผ๋ง ์ธ๋ผ์ธํ๋๋ฉฐ, ๊ธ๋ก๋ฒ CSS๋ ๋ณ๋ ํ์ผ๋ก ๋ก๋๋ฉ๋๋ค. Nuxt 3 ๋์์ ๋ณต์ํ๋ ค๋ฉด
features: { inlineStyles: true }๋ฅผ ์ถ๊ฐํฉ๋๋ค. clearNuxtState:undefined๋์ ์ด๊ธฐ๊ฐ์ผ๋ก ๋ฆฌ์ ๋ฉ๋๋ค. ์ด์ ๋์์ด ํ์ํ ๊ฒฝ์ฐclearNuxtState('key', { reset: false })๋ฅผ ์ฌ์ฉํฉ๋๋ค.
ํ๋ก๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ์ค์ฉ์ ์ธ ๋ง์ด๊ทธ๋ ์ด์ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
npx nuxt upgrade --dedupe๋ฅผ ์คํํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ๋น๋๊ฐ ์ ์์ธ์ง ํ์ธ- codemod ์คํ:
npx codemod@latest nuxt/4/migration-recipe - ํ์ผ์
app/์ผ๋ก ์ด๋ (file-structure codemod๋ก ์๋ํ) - ๋ฐ์ดํฐ ํจ์นญ ๋ก์ง์์
null๊ฒ์ฌ๋ฅผundefined๋ก ์ ๋ฐ์ดํธ - ์ ๊ทํ๋ ์ด๋ฆ์ผ๋ก
<KeepAlive>์ปดํฌ๋ํธ ํ ์คํธ - CI ํ์
๊ฒ์ฌ๋ฅผ
vue-tsc -b --noEmit์ผ๋ก ์ ๋ฐ์ดํธ - ์ ์ฒด ํ
์คํธ ์ค์ํธ๋ฅผ ์คํํ๊ณ
noUncheckedIndexedAccess๋ก ์ธํด ๋ฐ๊ฒฌ๋ TypeScript ์ค๋ฅ ์์
Vue์ Nuxt ๊ฐ๋ ์ ๋ ๊น์ด ์ดํดํ๋ ค๋ฉด SharpSkill์ Vue/Nuxt ๋ฉด์ ์ง๋ฌธ์ ์ฐธ๊ณ ํ๊ฑฐ๋, Nuxt 4์๋ ์ด์ด์ง๋ ๋ ๋๋ง ์ ๋ต์ ๋ฐฐ๊ฒฝ์ผ๋ก SSR ๋ฐ ์ ์ ์์ฑ ๊ฐ์ด๋๋ฅผ ํ์ธํด ๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
๊ฒฐ๋ก
- Nuxt 4.4(2026๋
4์ ๊ธฐ์ค ์ต์ ๋ฒ์ )๋
app/๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ, ์ฑ๊ธํค ๋ฐ์ดํฐ ํจ์นญ, ๋ถํ TypeScript ์ปจํ ์คํธ๋ฅผ ํ๋ก๋์ ์ค๋น ์๋ฃ๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ํ๋ฆฝํ์ต๋๋ค npx codemod@latest nuxt/4/migration-recipe๋ช ๋ น์ด๋ก ๋๋ ํฐ๋ฆฌ ์ฌ๊ตฌ์ฑ, ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋ API ๊ต์ฒด, ๋ฐ์ดํฐ ํจ์นญ ์ ๋ฐ์ดํธ๊ฐ ์๋ํ๋ฉ๋๋คshallowRef๊ธฐ๋ฐ์ shallow reactivity๋ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ฝ๋ ๋ณ๊ฒฝ ์์ด ์ฝ๊ธฐ ์ค์ฌ ํ์ด์ง์ ์ฑ๋ฅ์ ๊ฐ์ ํฉ๋๋ค- ์ปจํ ์คํธ๋ณ ๊ฐ๋ณ TypeScript ์ค์ (app, server, shared, node)์ ์ปจํ ์คํธ ๊ฐ ํ์ ๋์ถ์ ์ ๊ฑฐํ๊ณ IDE ์๋ ์์ฑ ์ ํ๋๋ฅผ ํฅ์์ํต๋๋ค
- Nuxt 3์ 2026๋ 7์ 31์ผ์ ์ง์์ด ์ข ๋ฃ๋๋ฏ๋ก, ๊ทธ ์ด์ ์ ๋ง์ด๊ทธ๋ ์ด์ ์ ์๋ฃํด์ผ ์ง์๋๋ ๋ฒ์ ์ ์ ์งํ ์ ์์ต๋๋ค
- Vue Router v5์ Unhead v2๋ ๋ ์ ๋๋ API๋ฅผ ์ ๊ณตํ์ง๋ง, ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋ ์์ฑ์ ์ ๊ฑฐ๋ก ์ธํด ๋ง์ด๊ทธ๋ ์ด์ ์ ์ ๊ฒ์ด ํ์ํฉ๋๋ค
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
ํ๊ทธ
๊ณต์
๊ด๋ จ ๊ธฐ์ฌ

2026๋ Vue 3์ TypeScript: ํ์ ์์ ํ Props, Emits, ์ปดํฌ์ ๋ธ
TypeScript๋ก ํ์ ์์ ํ Vue 3 ์ปดํฌ๋ํธ ๋ง์คํฐํ๊ธฐ: ์ ๋ค๋ฆญ defineProps, ํํ defineEmits, ํ์ ์ง์ ์ปดํฌ์ ๋ธ, defineModel, InjectionKey์ ๋ฉด์ ์ง๋ฌธ๊น์ง.

2026๋ Vue 3 ํ ์คํ : Vitest, Vue Test Utils ๊ทธ๋ฆฌ๊ณ ๋ฉด์ ์ง๋ฌธ
2026๋ Vue ํ ์คํ ์ค์ ๊ฐ์ด๋. Vitest ์ค์ , Vue Test Utils๋ก ์ปดํฌ๋ํธ ๋ง์ดํธ, ์ปดํฌ์ ๋ธ๊ณผ Pinia ์คํ ์ด ํ ์คํธ, API ๋ชจํน, ์ปค๋ฒ๋ฆฌ์ง ์ธก์ , ๊ทธ๋ฆฌ๊ณ ์ฑ์ฉ ํ์ด ์ค์ ๋ก ๋์ง๋ ๋ฉด์ ์ง๋ฌธ๊น์ง ๋ค๋ฃน๋๋ค.

Vue 3 ์ปดํฌ์ ๋ธ ์ฌํ ๊ฐ์ด๋: ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํจํด๊ณผ ๊ธฐ์ ๋ฉด์ ์ง๋ฌธ 2026
Vue 3 ๊ณ ๊ธ ์ปดํฌ์ ๋ธ ํจํด์ ์ฒด๊ณ์ ์ผ๋ก ๋ถ์ํฉ๋๋ค. ๋น๋๊ธฐ ์ฒ๋ฆฌ, ์์กด์ฑ ์ฃผ์ , ํผ ์ ํจ์ฑ ๊ฒ์ฌ, ํ ์คํธ ์ ๋ต, ๊ทธ๋ฆฌ๊ณ 2026๋ ๊ธฐ์ ๋ฉด์ ์์ ์์ฃผ ์ถ์ ๋๋ ์ง๋ฌธ๊ณผ ๋ต๋ณ์ ๋ค๋ฃน๋๋ค.