SEO & metas with Nuxt 3 — Course part 16

https://www.youtube.com/watch?v=PpyXtoM5HWQ&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=16

 

유튜브 강의를 참고하고 있습니다.

 


공통 메타태그 설정하기

  • nuxt.config.ts

모든 페이지에서 동일한 title과 description이 적용된다.

export default defineNuxtConfig({
  app: {
    head: {
      title: 'Nuxt course on Youtube',
      meta: [
        { name: 'description', content: 'This is a repository for a course about Nuxt 3 for youtube.' }
      ]
    }
  },
  ...
})

 

페이지 별 메타태그 설정하기

1. useHead()

useHead() 컴포져블을 사용하면 unhead에서 제공하는 프로그래밍 방식 및 반응형 방식으로 <head> 태그를 관리할 수 있다.

'~~' 따음표를 이용한 텍스트 또는 변수로 SEO 설정이 가능하다.

 

  • pages/index.vue
<script setup lang="ts">
const route = useRoute()

useHead({
  title: `타이틀: ${route.name}`,
  meta: [
    { name: 'description', content: 'This is an index page.' }
  ],
  bodyAttrs: {
    class: 'test'
  },
  script: [ { innerHTML: 'console.log(\'Hello world\')' } ]
})
</script>

<template>
  <h1>인덱스 페이지</h1>
</template>

 

2. useSeoMeta()

useSeoMeta() 컴포져블을 사용하면 타입스크립트가 완전히 지원하는 SEO 메타 태그 객체를 정의할 수 있다.

'~~' 따음표를 이용한 텍스트 또는 변수로 SEO 설정이 가능하다.

 

  • pages/auth/index.vue
<script setup lang="ts">
const route = useRoute()

useSeoMeta({
  title: route.name,
  ogTitle: 'Login Page',
  description: 'This is a login page.',
  ogDescription: 'This is a login page.',
  ogImage: 'https://example.com/image.png',
  twitterCard: 'summary_large_image',
})
</script>

<template>
  <div>로그인 페이지</div>
</template>

 

3. <Head> 태그

Nuxt는 <Head>, <Title>, <Style>, <Meta>, <Link> 등의 태그를 제공하기 때문에 HTML 영역에 직접적으로 메타태그를 설정할 수 있다.

 

  • pages/auth/index.vue
<script setup lang="ts">
const description = ref('This is dynamic description.')
</script>

<template>
  <Head>
    <Title>Login Page</Title>
    <Meta name="description" :content="description"/>
    <Style type="text/css" children="body { background-color: gray !important; }" />
  </Head>

  <div>{{ description }}</div>
</template>

useAsyncData with Nuxt 3 — Course part 15

https://www.youtube.com/watch?v=3xeAElHzMe4&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=15

 

유튜브 강의를 참고하고 있습니다.

 


1. useAsyncData

useAsyncData()는 비동기 로직의 resolve 동작을 반환한다.

useFetch('url')과 useAsyncData('url', () => $fetch('url')) 와 거의 동일하게 동작한다.

 

  • server/api/products.ts

async, await를 사용해 비동기 함수를 만든다.

함수가 동작하면 1초 뒤에 productCount가 1씩 증가한다.

let productCount = 0

export default async() => {
  await new Promise((resolve) => {
    setTimeout(() => {
      resolve(productCount++)
    }, 1000)
  })

  return { productCount }
}

 

  • pages/index.vue

useAsyncData()를 사용해 data를 가지고 온다.

클릭 이벤트를 만들어 버튼을 클릭하면 data가 새로고침 된다.

<script setup lang="ts">
const { data: productCount, pending } = await useAsyncData('count', () => $fetch('/api/products'))

const refresh = () => refreshNuxtData('count')

</script>

<template>
  <div v-if="pending">
    <p>pending</p>
    {{ productCount }}
  </div>

  <div v-else>
    <p>resolve</p>
    {{ productCount }}
  </div>

  <button @click="refresh">Refresh</button>
</template>

 

2. useLazyAsyncData

  • pages/index.vue

useLazyAsyncData()를 사용하는 것만 제외하면 나머지는 동일한 코드이다.

얼핏 보면 차이점이 없는 것처럼 보이지만, 페이지 처음 진입 시 useLazyAsyncData()를 사용하면 v-if="pending" 부분이 나타나는 것을 볼 수 있다.

pending 상태의 화면 로직을 보여주고 싶을 때 사용한다.

<script setup lang="ts">
const { data: productCount, pending } = await useLazyAsyncData('count', () => $fetch('/api/products'))

const refresh = () => refreshNuxtData('count')

</script>

<template>
  <div v-if="pending">
    <p>pending</p>
    {{ productCount }}
  </div>

  <div v-else>
    <p>resolve</p>
    {{ productCount }}
  </div>

  <button @click="refresh">Refresh</button>
</template>

 


$fetch

$fetch는 Nuxt3에서 제공하는 전역 메서드이고, HTTP request를 만들 수 있다.

$fetch는 서버와 클라이언트 환경에서의 중복 호출 문제가 있기 때문에 클라이언트 사이드에서만 사용해야 한다.

서버 사이트 렌더링을 위해서는 useFetch나 useAsyncData를 사용해야 한다.

 

useFetch() vs useAsyncData()

2가지 메서드는 동일한 기능을 하는 것처럼 보이지만, 사용법에서 몇 가지 차이가 있다. 

그중 가능 큰 차이는 실행 context의 차이이다.

 

useAsyncData()는 page 값이 바뀌면 url의 params도 변경되지만, useFetch()는 page 값이 바뀌어도 params가 바뀌지 않는다.

 

확실히 이해한 부분이 아니기 때문에 실제로 사용해 보면서 공부가 더 필요하다..

 

 

 

참고자료

https://nuxt.com/docs/api/composables/use-fetch

https://nuxt.com/docs/api/composables/use-async-data

https://jongmin4943.tistory.com/entry/Nuxt3-fetch-useAsyncData-useFetch-%EC%9D%98-%EC%B0%A8%EC%9D%B4

useFetch, useLazyfetch with Nuxt 3 — Course part 14

https://www.youtube.com/watch?v=rU92oLYjTGY&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=14

 

유튜브 강의를 참고하고 있습니다.

 


Data Fetching

Nuxt는 서버 또는 브라우저에서 데이터를 가져와 처리하는 컴포저블을 제공한다.

  • useFetch()
  • useAsyncData
  • $fetch

 


1. useFetch()

useFetch()는 컴포넌트 설정 기능 중에서 데이터 패칭을 수행하는 가장 간단한 방법이다.

 

  • server/api/products.json

data를 json 파일로 만든다.

[
  {
    "name": "책상",
    "price": "$50.99",
    "description": "책상입니다."
  },
  {
    "name": "의자",
    "price": "$30.99",
    "description": "의자입니다."
  },
  {
    "name": "컴퓨터",
    "price": "$999.99",
    "description": "컴퓨터입니다."
  }
]

 

  • server/api/products.ts

json 파일을 import 해 return 한다.

import data from './products.json'

export default defineEventHandler((event) => {
  return {
    data
  }
})

 

  • pages/index.vue

useFetch()를 사용해 data를 가지고 온다.

<script setup lang="ts">
const { data } = await useFetch('/api/products')

console.log(data)
</script>

<template>
  {{ data }}
</template>

 

{ data: products } 라고 변수 이름을 설정할 수도 있다.

결과는 동일하다.

<script setup lang="ts">
const { data: products } = await useFetch('/api/products')

console.log(toRaw(products.value))
</script>

<template>
  {{ products }}
</template>

 

2. useLazyFetch()

useLazyFetch()는 데이터 패칭을 하기 전(EventHandler가 resolve 되기 전)의 과정을 제공한다.

 

  • server/api/products.ts

asycn()과 setTimeout()을 사용해 data를 2초 뒤에 return 한다.

import data from './products.json'

export default defineEventHandler(async()=> {
  return new Promise<any>((resolve) => {
    setTimeout(() => {
      resolve(data)
    }, 2000)
  })
})

 

  • pages/index.vue

useLazyFetch()를 사용해 data를 가지고 온다.

이때 pending(보류: 초기 상태로 이행되기 전이나 거절되기 전의 상태)을 사용해 data를 가지고 오기 전에 화면 로직을 보여준다.

data가 화면에 보이기 전에 Loading 텍스트가 나오고, console.log도 그전에 실행되기 때문에 null 값이 찍힌다.

<script setup lang="ts">
const { data: products, pending } = await useLazyFetch('/api/products')

console.log(toRaw(products.value))
</script>

<template>
  {{ pending ? 'Loading' : products }}
</template>

 

  • nuxt.config.ts

만약 useLazyFetch()와 pending을 사용했는데도 새로고침 즉시 data가 나온다면 SSR 설정이 false인지 확인한다.

SSR은 서버에서 렌더링이 완료된 다음에 브라우저에 보여지기 때문에 useLazyFetch()가 동작하지 않는다.

export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: [],
  ...
  ssr: false
})

Rendering modes with Nuxt 3 — Course part 13

https://www.youtube.com/watch?v=TmgIylXsLuE&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=13

 

유튜브 강의를 참고하고 있습니다.

 


Nuxt 모드

Nuxt 프로젝트를 설치할 때 2가지의 렌더링 모드를 선택할 수 있다.

  1. Universal (SSR/SSG)
  2. Single Page App

 

Universal 모드를 설명하기 전에 웹 페이지 렌더링 방식에 대해 설명한다.

 


1. Client Side Rendering (CSR, 클라이언트 사이드 렌더링)

클라이언트(브라우저)에서 웹 페이지를 렌더링 한다.

사용가가 웹 페이지를 방문하면(서버 요청을 받으면) 서버는 클라이언트에게 HTML과 JS를 보내고, 클라이언트가 그것을 렌더링 한다.

 

ex) React, Vue

 

CSR 장점

  • 페이지 이동시 전체 HTML을 로드할 필요가 없기 때문에 SSR에 비해 속도가 빠르다.
  • 필요한 부분만 변경되기 때문에 새로고침이 발생하지 않아 사용성이 뛰어나다.
  • API 호출이 필요 없기 때문에 지연 로딩 모듈이 필요하지 않다.

 

CSR 단점

  • 초기 페이지 로드 시간이 SSR에 비해 느리다.
  • SEO(Search Engine Optimization, 검색 엔진 최적화)가 어렵다.

 

2. Server Side Rendering (SSR, 서버 사이드 렌더링)

서버에서 웹 페이지를 렌더링 한다.

사용자가 웹 페이지를 방문하면 서버는 리소스를 확인해 렌더링이 끝난 상태로 클라이언트에게 전송한다.

 

ex) Next, Nuxt

 

SSR 장점

  • 초기 페이지 로드 시간이 CSR에 비해 빠르다.
  • SEO가 유리하다.

 

SSR 단점

  • 페이지 이동시 서버에서 새로운 html을 불러와야 하기 때문에 CSR보다 속도가 느리고, 새로고침이 발생해 사용성이 떨어진다.
  • 렌더링을 서버에서 하기 때문에 서버에 부담이 크다.

 

3. Static Site Generation (SSG)

클라이언트에서 필요한 페이지들을 사전에 미리 준비하고, 서버 요청을 받으면 이미 완성된 파일을 브라우저에 렌더링 한다.

SSR과 비슷하지만 서버에서 요청을 할 때 즉시 만드는지 미리 만들어 놓는지의 차이가 있다.

 

SSG 장점

  • 캐싱이 가능하다.
  • SEO가 유리하다.

 

SSG 단점

  • 모든 URL에 대해 개별 HTML 파일을 생성해야 한다. URL을 예측할 수 없다면 적용하기 어렵다.

 

검색 엔진 노출보다 서버의 부담이나 데이터 보호가 중요하다 -> CSR
검색 엔진이 중요하고, 업데이트가 자주 일어난다 -> SSR
검색 엔진이 중요하고, 업데이트가 거의 없다. -> SSG

 

만약 검색 엔진과 새로고침 없는 인터렉션이 모두 중요하다면 CSR + SST인 Universal 렌더링을 고려해야 한다.

 


1. Single Page Application (SPA, 단일 페이지 애플리케이션)

SPA는 말 그대로 하나의 페이지를 사용하는 애플리케이션이다.

서버에서 새로운 페이지를 요청하는 것이 아니라 하나의 페이지에서 내용만 동적으로 변경한다. (CSR 방식으로 렌더링 한다.)

 

SPA 장점

  • 페이지 이동 시 변경된 부분만 갱신되기 때문에 앱과 같은 자연스러운 사용자 경험을 제공한다.
  • 서버가 해야 하는 화면 구성을 클라이언트가 수행하기 때문에 서버 부담이 경감된다.
  • 모듈화 또는 컴포넌트 개발이 용이해 효율성이 증가한다.
  • 프론트앤드와 백앤드 구분이 확실하다.

 

SPA 단점

  • 처음 사이트 접속 시 모든 리소스를 한 번에 받기 때문에 초기 로딩 속도가 느리다.
  • 비즈니스 로직(화면이 변하는 모습)이 사용자에게 노출될 수 있다.
  • SEO가 어렵다.

 

2. Multiple Page Application (MPA, 다중 페이지 애플리케이션)

MPA는 말 그대로 여러 개의 싱글 페이지를 사용하는 애플리케이션이고, 전통적인 웹 방식이라고도 한다.

새로운 페이지를 요청할 때마다 서버에서 리소스가 다운되며 전체 페이지를 다시 렌더링(새로고침)해 내용을 변경한다. (SSR 방식으로 렌더링한다.)

 

MPA 장점

  • 처음 사이트 접속 시 초기 로딩 속도가 빠르다.
  • SEO가 유리하다.

 

MPA 단점

  • 페이지 이동 시 새로고침이 발생해 깜빡임이 발생한다.
  • 서버 요청이 있을 때마다 서버에서 렌더링을 하기 때문에 서버 부담이 증가한다.

 

CSR과 SPA, SSR과 MAP는 개념이 비슷해서 같은 것이라고 착각할 수 있지만,
렌더링을 어떻게 하는지와 페이지를 몇 개 사용하는지의 차이이기 때문에 단어 사용에 주의해야 한다.

 


Universal Mode (유니버셜 모드)

Nuxt는 CSR과 SSR의 장점을 모두 합친 Universal Mode 렌더링을 선택했다.

쉽게 말해 Nuxt 페이지를 처음 접속하면 서버에서 렌더링 하고, 이후 페이지 간 이동은 클라이언트에서 렌더링 한다.

이를 위해서 Nuxt는 클라이언트 사이드 하이드레이션(Client Side Hydration)과 코드 분할(Code Splitting), 프리패칭(Prefetching)을 활용하고 있다.

 

  • 클라이언트 사이드 하이드레이션

서버로부터 받은 정적 HTML을 사용자와 상호작용할 수 있는 다이나믹 DOM으로 바꾸는 방법이다.

 

  • 코드 분할

코드 전체를 로드하지 않고 분할해서 필요에 맞는 번들로 나눠 가져오는 것을 의미한다.

필요한 번들만 가져오기 때문에 로딩 속도가 빠르다.

 

  • 프리패칭

Nuxt는 화면에 보이는 <NuxtLink> 컴포넌트에 한해서 해당 페이지들을 렌더링 하는데 필요한 파일들을 미리 서버에 요청한다.

따라서 사용자가 클릭하기도 전에 이미 CSR에 준비가 되어있고, 사용자가 패칭을 요구하기 전에 미리 패칭 되어 있는 것을 프리패칭이라고 한다.

 

 

  • nuxt.config.ts

클라이언트 측 전용 렌더링을 활성화할 수 있다.

export default defineNuxtConfig({
  ssr: false
})

 

경로 규칙을 사용해 경로별로 다른 캐싱 규칙을 허용하고 서버가 지정된 URL의 요청을 응답하는 방법을 결정한다.

export default defineNuxtConfig({
  routeRules: {
    // Homepage pre-rendered at build time
    '/': { prerender: true },
    
    // Product page generated on-demand, revalidates in background
    '/products/**': { swr: 3600 },
    
    // Blog post generated on-demand once until next deploy
    '/blog/**': { isr: true },
    
    // Admin dashboard renders only on client-side
    '/admin/**': { ssr: false },
    
    // Add cors headers on API routes
    '/api/**': { cors: true },
    
    // Redirects legacy urls
    '/old-page': { redirect: '/new-page' }
  }
})

 

 

 

참고자료

https://nuxt.com/docs/guide/concepts/rendering
https://joshua1988.github.io/vue-camp/nuxt/universal-mode.html

https://hanamon.kr/spa-mpa-ssr-csr-%EC%9E%A5%EB%8B%A8%EC%A0%90-%EB%9C%BB%EC%A0%95%EB%A6%AC/

https://velog.io/@ka0son/%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%82%BC%ED%98%95%EC%A0%9C-CSR-SSR-SSG-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

 

Nitro with Nuxt 3 — Course part 12

https://www.youtube.com/watch?v=1J-ywLgs--s&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=12

 

유튜브 강의를 참고하고 있습니다.

 


Nitro란

Nitro는 초고속 웹 서버를 구축하기 위한 오픈 소스 타입스크립트 프레임워크이다.

Nuxt3는 Nitro를 서버 엔진으로 사용한다.

 

  • Node.js, 브라우저, service-workers 등을 위한 크로스 플랫폼 지원
  • 즉시 사용 가능한 서버리스(serverless, 개발자가 서버를 관리할 필요 없이 빌드하고 실행할 수 있도록 하는 클라우드 네이티브 개발 모델) 지원
  • API 경로 지원
  • 자동 코드 분할 및 비동기 로드 
  • 정적 + 서버리스 사이트를 위한 하이브리드 모드
  • 핫 모듈을 다시 로드하는 개발 서버

 

  • useNitro : Nitro 인스턴스를 반환한다.
  • addServerHandler : 서버 핸들러를 추가한다. 서버 미들웨어나 커스텀 라우터를 생성하고 싶을 때 사용한다.
  • addDevServerHandler : 개발 모드에서만 사용할 서버 핸들러를 추가한다. 프로덕션 빌드에서 제외된다.
  • addServerPlugin : Nitro의 런타임 동작을 확장하기 위한 플러그인을 추가한다.
  • addPrerenderRoutes : Nitro에서 사전 렌더링할 경로를 추가한다.

 

https://nuxt.com/docs/api/kit/nitro

Nitro 메서드에 대한 자세한 설명은 공식 문서를 참고한다.

 

API 레이어

서버 API 엔드포인트와 미들웨어는 Nitro에 의해 추가된다.

  • 핸들러는 자동으로 처리되는 JSON 응답에 대해 객체/베열을 직접 반환할 수 있다.
  • 핸들러는 Promise를 반환할 수 있다. (res.end(), next() 지원 가능)
  • 본문 구문 분석, 쿠키 처리, 리디렉션, 헤더 등을 위한 기능이 있다.

Server with Nuxt 3 — Course part 11

https://www.youtube.com/watch?v=RQhWvHz3I5I&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=11

 

유튜브 강의를 참고하고 있습니다.

 


Server란

Nuxt Server 디렉토리는 데이터베이스나 다른 서버에서 데이터를 가져오고, API를 생성하고, 사이트맵이나 RSS 피드와 같은 정적 서버 측 컨텐츠를 생성하는 작업까지 모두 단일 코드베이스에서 수행할 수 있다. 또한 디렉토리 내의 파일을 자동으로 스캔하여 HMR(Hot Module Replacement) 지원으로 API 및 서버 핸들러를 등록할 수 있다.

 


1. /server/api

  • server/api/hello.ts
export default defineEventHandler((event) => {
  return {
    api: 'hello world'
  }
})

 

  • pages/index.vue

useFetch를 통해서 API를 호출할 수 있다.

<script setup lang="ts">
const { data } = await useFetch('/api/hello')
console.log(data)
</script>

<template>
  <h1>{{ data }}</h1>
</template>

2. /server/routes

  • server/routes/hello.ts

/api 접두사 없이 서버 경로를 추가하려면 /server/routes/ 디렉터리를 사용한다.

export default defineEventHandler(() => 'Hello World!')

 

3. HTTP 메서드

server/api 디렉터리의 파일에는 HTTP 메서드를 붙일 수 있다.

 

  • GET /api/users - 등록된 모든 사용자를 가져온다.
  • POST /api/users - 새로운 사용자를 생성한다.
  • PUT /api/users/{id} - 사용자의 상태를 변경한다.
  • DELETE /api/users/{id} - 사용자를 삭제한다.

 

  • server/api/test.get.ts
export default defineEventHandler(() => 'Test get handler')

 

  • server/api/test.post.ts
export default defineEventHandler(() => 'Test post handler')

State management with Nuxt 3 — Course part 10

https://www.youtube.com/watch?v=IkpoAKS1s-k&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=10

 

유튜브 강의를 참고하고 있습니다.

 


State Management란

상태 관리(State Management)에서 상태(State)란, 앱 구동에 필요한 기본 데이터 소스이다.

이 상태를 변경시킬 때 사용하는 것이 상태 관리이다. 

쉽게 말해 컴포넌트 간의 데이터 전달이나 데이터 변경을 효율적으로 하는 방법이다.

 


1. 일반 변수

  • pages/index.vue

일반 변수를 선언하듯이 counter 변수를 만들면 클릭 이벤트를 만들어도 화면에는 반영되지 않는다.

콘솔창에서만 counter 변수가 증가, 감소한다.

<script setup lang="ts">
let counter = 0

function increment() {
  counter++
  console.log('증가', counter)
}

function decrease() {
  counter--
  console.log('감소', counter)
}
</script>

<template>
  <section>
    <h2>counter 변수</h2>

    <p>{{ counter }}</p>

    <button @click="increment">+</button>
    <button @click="decrease">-</button>
  </section>
</template>

 

2. useState 변수

  • composables/state.ts

useState에 counter 변수를 만든다.

export const useCounter = () => useState<number>('counter', () => 0)

 

  • pages/index.vue

useState를 통해 변수를 만들면 데이터가 변하는 즉시, 화면에서도 변경된다.

<script setup lang="ts">
import { useCounter } from '@/composables/state';

const stateCounter = useCounter()
</script>

<template>
  <section>
    <h2>useState 변수</h2>

    <p>{{ stateCounter }}</p>

    <button @click="stateCounter++">+</button>
    <button @click="stateCounter--">-</button>
  </section>
</template>

 

3. Pinia store 라이브러리

https://pinia.vuejs.org/

Pinia store에 대한 자세한 설명은 위의 링크를 참고한다.

 

  • stores/counter.ts
  1. 터미널에서 yarn add pinia 또는 npm install pinia 명령어를 입력해 pinia 패키기를 설치한다.
  2. pinia를 import 한다.
  3. useCounterStore를 만들고, state에 초기값을 선언한다.
  4. actions에 이벤트를 만든다.
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => {
    return { count: 0 }
  },

  actions: {
    increment() {
      this.count++
    },

    decrement() {
      this.count--
    }
  }
})

 

  • pages/index.vue

pinia를 통해 변수를 만들면 데이터가 변하는 즉시, 화면에서도 변경된다.

<script setup lang="ts">
import { useCounterStore } from '@/stores/counter';

const piniaCounter = useCounterStore()
</script>

<template>
  <section>
    <h2>Pinia 변수</h2>

    <p>{{ piniaCounter.counter }}</p>

    <button @click="piniaCounter.increment">+</button>
    <button @click="piniaCounter.decrement">-</button>
  </section>
</template>

 


useState vs Pinia

Nuxt을 사용해 개발을 하기 위해서는 상태 관리를 어떻게 할지 정해야 한다.

간단한 앱에서는 useState를 사용하고, 복잡한 앱에서는 Pinia를 사용한다는 의견이 많다.

 

Pinia는 Vue.js용 스토어 라이브러리 및 상태 관리 프레임워크이다. 

Pinia에서 제공하는 많은 기능들이 있고, 개발자는 그 기능들을 직접 만들 필요가 없다.

DevTools를 통합할 수 있고, getter와 actions 기능을 통해 상태를 변경할 수 있는 구체적인 방법을 정의할 수 있다.

 

따라서 앱의 얼마나 복잡한지 파악한 다음에 어떤 수준의 도구를 선택할지 결정하면 된다.

 

Modules with Nuxt 3 — Course part 9

https://www.youtube.com/watch?v=JQLH9MDtRQk&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=9

 

유튜브 강의를 참고하고 있습니다.

 


Modules이란

Nuxt를 사용하여 프로덕션급 애플리케이션을 개발할 때 프레임워크의 핵심 기능이 충분하지 않다는 것을 알 수 있다.

이때 Nuxt 모듈을 이용해서 프레임워크 코어를 확장하고 통합을 단순화할 수 있다.

 

Nuxt 모듈 공식문서에서 다양한 모듈 리스트들을 확인할 수 있다.

https://nuxt.com/modules

 


Nuxt Content

Nuxt Content는 프로젝트의 content 디렉터리를 읽고 .md, .yml, .csv 또는 .json 파일을 구문 분석하고 애플리케이션을 위한 강력한 데이터 계층을 생성한다.

 

Nuxt Content에 자세한 설명은 아래 공식 문서를 참고한다.

https://content.nuxt.com/

 

1. Nuxt Content 설치하기

터미널에서 아래 명령어를 실행한다.

package.json 파일에서 설치된 버전을 확인할 수 있다.

yarn add @nuxt/content

또는

npm install @nuxt/content

 

2. nuxt.config.ts에 모듈 추가하기

modules 배열 부분에 사용할 모듈 리스트들을 추가한다.

export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: [
    '@vueuse/nuxt',
    '@nuxt/content'
  ],
  css: ['@/assets/scss/main.scss'],
  postcss: {
    plugins: {
      tailwindcss: {},
      autoprefixer: {}
    }
  }
})

 

3. content 폴더 만들기

  • content/index.md
# content에서 작성한 hello world

 

4. ContentDoc 컴포넌트 사용하기

  • pages/index.vue
<template>
  <ContentDoc/>
</template>

 

결과 화면

 


Auto Animate

Auto Animate는 웹 앱에 부드러운 전환을 추가하는 드롭인 애니메이션 유틸리티이다.

Vue, Nuxt 뿐만 아니라 React, Solid, Svelte 또는 자바스크립트 애플리케이션에서도 사용 가능하다.

 

Auto Animate에 자세한 설명은 아래 공식 문서를 참고한다.

https://auto-animate.formkit.com/

 

1. auto-animate 설치하기

터미널에서 아래 명령어를 실행한다.

package.json 파일에서 설치된 버전을 확인할 수 있다.

yarn add @formkit/auto-animate

또는

npm install @formkit/auto-animate

 

2. 정렬 애니메이션 만들기

  • pages/index.vue
  1. auto-aminate를 import 한다.
  2. [sortList] 변수를 만든다.
  3. <ul> 태그에 ref를 이용해 [sortList] 변수를 참조한다.
  4. 정렬 버튼을 누를 때 마다 <li> 태그들이 animation이 추가되어 움직이는 것을 확인할 수 있다.
<script setup>
import { ref } from 'vue'
import { useAutoAnimate } from '@formkit/auto-animate/vue'

const [sortList] = useAutoAnimate()
const items = ref(["React", "Vue", "Svelte", "Angular"])

function sortAsc() {
  items.value.sort()
}
function sortDesc() {
  items.value.sort().reverse()
}
</script>

<template>
  <div class="mb-5">
    <button
        class="me-5 px-4 py-2 bg-slate-500 rounded"
        @click="sortAsc">
      Sort A-Z ↑
    </button>
    <button
        class="px-4 py-2 bg-slate-500 rounded"
        @click="sortDesc">
      Sort Z-A ↓
    </button>
  </div>

  <ul ref="sortList">
    <li
        v-for="item in items"
        :key="item">
      {{ item }}
    </li>
  </ul>
</template>

 

결과 화면

Middlewares with Nuxt 3 — Course part 8

https://www.youtube.com/watch?v=PhuJE0ayD6A&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=8

 

유튜브 강의를 참고하고 있습니다.

 


Middleware란

Nuxt에서 미들웨어(Middleware)는 페이지나 레이아웃이 렌더링 되기 전에 호출되는 커스텀 훅(Hook)이다.

store, route, params, query, redirect 등에 접근할 수 있기 때문에 내비게이션 가드 형태로 미들웨어 제작이 가능하다.

쉽게 말해 특정 경로로 이동하기 전에 실행하려는 코드를 만들 때 이상적이다.

 

1. middleware 폴더 만들기

  • middleware/auth.global.ts

middleware 폴더 안에 파일을 만들 때 파일명 뒤에 .global을 붙이면 별도의 import 없이 전역에서 사용할 수 있는 미들웨어가 된다.

export default defineNuxtRouteMiddleware((to, from) => {
  console.log(to)
  console.log(from)
})

 

2. auth.global.ts (글로벌 미들웨어)

  • middleware/auth.global.ts

글로벌로 만든 미들웨어에서 navigateTo를 이용해 리다이렉트를 할 경우, isLoggedIn이 계속 false이기 때문에 무한 리다이렉트에 빠져 주의해야 한다.

export default defineNuxtRouteMiddleware((to, from) => {
  let isLoggedIn = false

  if(isLoggedIn) {
    return navigateTo(to.fullPath)
  } else {
    return navigateTo('/auth')
  }
})

 

3. auth.ts (페이지 정의 미들웨어)

  • pages/index.vue
  1. auth.global.ts 미들웨어에서 .global을 지운다.
  2. auth.ts 미들웨어를 사용할 페이지에 import 한다.
  3. / 루트 페이지에 접속하면 바로 /auth 페이지로 이동됨을 볼 수 있다.
<template>
  <h1>Main page</h1>
</template>

<script setup lang="ts">
definePageMeta({
  middleware: 'auth'
})
</script>

Plugins with Nuxt 3 — Course part 7

https://www.youtube.com/watch?v=9MCVjsq35I8&list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&index=7

 

유튜브 강의를 참고하고 있습니다.

 


Plugins이란

Nuxt에는 Vue 애플리케이션 생성 시 Vue 플러그인을 사용할 수 있는 플러그인 시스템이 있다.

Nuxt는 자동으로 plugins 디렉터리 파일을 읽고, Vue 애플리케이션 생성 시 이를 로드한다.

 

1. plugins 폴더 만들기

  • plugins/myPlugins.ts
export default defineNuxtPlugin((nuxtApp) => {
  return {
    provide: {
      hello: (msg: string) => console.log(`Hello ${msg}`)
    }
  }
})

 

2. 플러그인 import 하기

plugins 디렉터리 최상위에 있는 파일(또는 하위 디렉터리 내의 index 파일)은 별로의 import 없이 자동으로 플러그인으로 등록된다.

 

  • pages/index.vue
<script setup lang="ts">
console.log(useNuxtApp())
</script>

 

3. 플러그인 사용하기

  • pages/index.vue
<script setup lang="ts">
const { $hello } = useNuxtApp()

$hello('world')
</script>

 

+ Recent posts