모듈 작성자 가이드

Nuxt 애플리케이션을 통합, 향상 또는 확장하기 위한 Nuxt 모듈을 만드는 방법을 배워보세요.

Nuxt의 설정 시스템을 사용하면 Nuxt의 모든 측면을 사용자 정의하고 필요한 모든 통합(Vue 플러그인, CMS, 서버 라우트, 컴포넌트, 로깅 등)을 추가할 수 있습니다.

Nuxt 모듈nuxt dev로 개발 모드에서 Nuxt를 시작하거나 nuxt build로 프로덕션 빌드를 할 때 순차적으로 실행되는 함수입니다. 모듈을 사용하면 불필요한 보일러플레이트를 프로젝트에 추가하거나 Nuxt 자체를 변경할 필요 없이, 맞춤형 솔루션을 npm 패키지로 캡슐화하고, 적절히 테스트하며, 공유할 수 있습니다.

빠른 시작

스타터 템플릿을 사용하여 Nuxt 모듈을 시작하는 것을 권장합니다.

npm create nuxt -- -t module my-module

이렇게 하면 모듈 개발 및 배포에 필요한 모든 보일러플레이트가 포함된 my-module 프로젝트가 생성됩니다.

다음 단계:

  1. 원하는 IDE에서 my-module을 엽니다
  2. 선호하는 패키지 매니저로 의존성을 설치합니다
  3. npm run dev:prepare로 개발을 위한 로컬 파일을 준비합니다
  4. 이 문서를 따라 Nuxt 모듈에 대해 더 알아보세요

스타터 사용하기

모듈 스타터로 기본 작업을 수행하는 방법을 배워보세요.

Nuxt 모듈 스타터 템플릿에 대한 Vue School 영상을 시청하세요.

개발 방법

모듈 소스 코드는 대부분 src 디렉토리 내에 있지만, 모듈을 개발하려면 Nuxt 애플리케이션이 필요합니다. 이를 위해 playground 디렉토리가 있습니다. 이 디렉토리는 이미 모듈과 함께 실행되도록 설정된 Nuxt 애플리케이션으로, 자유롭게 실험할 수 있습니다.

playground는 일반 Nuxt 애플리케이션처럼 사용할 수 있습니다.

  • npm run dev로 개발 서버를 실행하면, src 디렉토리의 모듈을 변경할 때마다 자동으로 리로드됩니다
  • npm run dev:build로 빌드할 수 있습니다
다른 모든 nuxt 명령어는 playground 디렉토리에 대해 사용할 수 있습니다(예: nuxt <COMMAND> playground). 편의를 위해 package.json에 추가적인 dev:* 스크립트를 선언해도 됩니다.

테스트 방법

모듈 스타터에는 기본 테스트 스위트가 포함되어 있습니다:

  • ESLint로 구동되는 린터, npm run lint로 실행
  • Vitest로 구동되는 테스트 러너, npm run test 또는 npm run test:watch로 실행
필요에 따라 이 기본 테스트 전략을 확장해도 됩니다.

빌드 방법

Nuxt 모듈은 @nuxt/module-builder가 제공하는 자체 빌더를 사용합니다. 이 빌더는 별도의 설정 없이 TypeScript를 지원하며, 자산이 올바르게 번들되어 다른 Nuxt 애플리케이션에 배포될 수 있도록 보장합니다.

npm run prepack 명령어로 모듈을 빌드할 수 있습니다.

일부 경우에 모듈을 빌드하는 것이 유용할 수 있지만, 대부분의 경우 직접 빌드할 필요가 없습니다: 개발 중에는 playground가 이를 처리하고, 배포 스크립트도 배포 시 자동으로 처리합니다.

배포 방법

모듈을 npm에 배포하기 전에 npmjs.com 계정이 있고, 로컬에서 npm login으로 인증되어 있는지 확인하세요.

모듈의 버전을 올리고 npm publish 명령어를 사용해 배포할 수도 있지만, 모듈 스타터에는 모듈이 정상적으로 동작하는 버전이 npm에 배포되도록 도와주는 릴리즈 스크립트가 포함되어 있습니다.

릴리즈 스크립트를 사용하려면 먼저 모든 변경사항을 커밋하세요(자동 버전 업 및 변경 로그 업데이트를 위해 Conventional Commits 방식을 따르는 것을 권장합니다). 그런 다음 npm run release로 릴리즈 스크립트를 실행하세요.

릴리즈 스크립트 실행 시 다음이 진행됩니다:

  • 먼저 테스트 스위트를 실행합니다:
    • 린터 실행(npm run lint)
    • 단위, 통합, e2e 테스트 실행(npm run test)
    • 모듈 빌드(npm run prepack)
  • 테스트 스위트가 통과하면, 모듈 배포를 진행합니다:
    • Conventional Commits에 따라 모듈 버전을 올리고 변경 로그를 생성
    • 모듈을 npm에 배포(이때, 배포 아티팩트에 최신 버전 번호가 반영되도록 모듈을 다시 빌드)
    • 새로 배포된 버전을 나타내는 git 태그를 원격 저장소에 푸시
다른 스크립트와 마찬가지로, 필요에 따라 package.json의 기본 release 스크립트를 조정해도 됩니다.

모듈 개발

Nuxt 모듈은 Nuxt 애플리케이션을 거의 모든 방식으로 변경할 수 있는 다양한 강력한 API와 패턴을 제공합니다. 이 섹션에서는 이를 활용하는 방법을 배웁니다.

모듈 구조

Nuxt 모듈에는 두 가지 유형이 있습니다:

어느 경우든 구조는 유사합니다.

모듈 정의

스타터를 사용할 경우, 모듈 정의는 src/module.ts에 있습니다.

모듈 정의는 모듈의 진입점입니다. Nuxt 설정에서 모듈이 참조될 때 Nuxt가 로드하는 부분입니다.

저수준에서는, Nuxt 모듈 정의는 인라인 사용자 옵션과 Nuxt와 상호작용할 수 있는 nuxt 객체를 받는 간단한(비동기일 수도 있는) 함수입니다.

export default function (inlineOptions, nuxt) {
  // 여기서 원하는 작업을 할 수 있습니다..
  console.log(inlineOptions.token) // `123`
  console.log(nuxt.options.dev) // `true` 또는 `false`
  nuxt.hook('ready', async nuxt => {
    console.log('Nuxt가 준비되었습니다')
  })
}

이 함수에 타입 힌트 지원을 받으려면 Nuxt Kit에서 제공하는 상위 수준의 defineNuxtModule 헬퍼를 사용할 수 있습니다.

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule((options, nuxt) => {
  nuxt.hook('pages:extend', pages => {
    console.log(`발견된 페이지 수: ${pages.length}`)
  })
})

하지만, 이 저수준 함수 정의 방식은 권장하지 않습니다. 대신, 모듈을 정의할 때는 특히 npm에 배포할 경우, meta 속성이 포함된 객체 문법을 사용하는 것을 권장합니다.

이 헬퍼는 모듈에 필요한 많은 일반 패턴을 구현하여 Nuxt 모듈 작성이 더 간단해지며, 향후 호환성을 보장하고 모듈 작성자와 사용자 모두의 경험을 향상시킵니다.

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  meta: {
    // 보통 모듈의 npm 패키지 이름
    name: '@nuxtjs/example',
    // `nuxt.config`에서 모듈 옵션을 담는 키
    configKey: 'sample',
    // 호환성 제약
    compatibility: {
      // 지원하는 nuxt 버전의 semver
      nuxt: '>=3.0.0'
    }
  },
  // 모듈의 기본 설정 옵션, 함수로 반환할 수도 있음
  defaults: {},
  // Nuxt 훅을 등록하는 단축 문법
  hooks: {},
  // 모듈 로직을 담는 함수, 비동기일 수 있음
  setup(moduleOptions, nuxt) {
    // ...
  }
})

결국 defineNuxtModule은 저수준의 (inlineOptions, nuxt) 모듈 시그니처를 가진 래퍼 함수를 반환합니다. 이 래퍼 함수는 setup 함수 호출 전에 기본값 및 기타 필요한 단계를 적용합니다:

  • 모듈 옵션 자동 병합을 위한 defaultsmeta.configKey 지원
  • 타입 힌트 및 자동 타입 추론
  • Nuxt 2 기본 호환성용 shim 추가
  • meta.name 또는 meta.configKey에서 계산된 고유 키를 사용해 모듈이 한 번만 설치되도록 보장
  • Nuxt 훅 자동 등록
  • 모듈 메타 기반 호환성 문제 자동 확인
  • Nuxt 내부 사용을 위한 getOptionsgetMeta 노출
  • 최신 버전의 @nuxt/kit에서 defineNuxtModule을 사용하는 한, 하위 및 상위 호환성 보장
  • 모듈 빌더 툴링과의 통합

런타임 디렉토리

스타터를 사용할 경우, 런타임 디렉토리는 src/runtime에 있습니다.

모듈은 Nuxt 설정의 모든 것과 마찬가지로 애플리케이션 런타임에 포함되지 않습니다. 하지만, 모듈이 설치된 애플리케이션에 런타임 코드를 제공하거나 주입하고 싶을 수 있습니다. 런타임 디렉토리는 이를 가능하게 해줍니다.

런타임 디렉토리 내에는 Nuxt 앱과 관련된 모든 종류의 자산을 제공할 수 있습니다:

서버 엔진 Nitro에는:

  • API 라우트
  • 미들웨어
  • Nitro 플러그인

또는 사용자의 Nuxt 애플리케이션에 주입하고 싶은 기타 자산:

  • 스타일시트
  • 3D 모델
  • 이미지
  • 등등

이후 모듈 정의에서 이러한 자산을 애플리케이션에 주입할 수 있습니다.

레시피 섹션에서 자산 주입에 대해 더 알아보세요.
배포된 모듈은 런타임 디렉토리 내 자산에 대해 자동 임포트를 사용할 수 없습니다. 대신, #imports 등에서 명시적으로 임포트해야 합니다.

실제로, 자동 임포트는 성능상의 이유로 node_modules(배포된 모듈이 최종적으로 위치하는 곳) 내 파일에 대해 활성화되어 있지 않습니다.

툴링

모듈 개발을 돕기 위한 공식 툴 세트가 제공됩니다.

@nuxt/module-builder

Nuxt Module Builder는 별도의 설정 없이 모듈 빌드 및 배포의 모든 복잡한 작업을 처리하는 빌드 도구입니다. Nuxt 애플리케이션과의 빌드 아티팩트 호환성을 보장합니다.

@nuxt/kit

Nuxt Kit는 모듈이 Nuxt 애플리케이션과 상호작용할 수 있도록 돕는 조합형 유틸리티를 제공합니다. 가능한 한 수동 대안보다 Nuxt Kit 유틸리티를 사용하는 것이 모듈의 호환성과 코드 가독성을 높이는 데 권장됩니다.

Read more in Docs > Guide > Going Further > Kit.

@nuxt/test-utils

Nuxt Test Utils는 모듈 테스트 내에서 Nuxt 애플리케이션을 설정하고 실행하는 데 도움이 되는 유틸리티 모음입니다.

레시피

여기에서 모듈 작성에 자주 사용되는 패턴을 확인할 수 있습니다.

Nuxt 설정 변경

Nuxt 설정은 모듈에서 읽고 변경할 수 있습니다. 다음은 실험적 기능을 활성화하는 모듈 예시입니다.

import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    // 아직 `experimental` 객체가 없으면 생성합니다
    nuxt.options.experimental ||= {}
    nuxt.options.experimental.componentIslands = true
  }
})

더 복잡한 설정 변경이 필요하다면 defu 사용을 고려하세요.

Nuxt 설정 변경에 관한 Vue School 영상을 시청하세요.

런타임에 옵션 노출하기

모듈은 애플리케이션 런타임의 일부가 아니므로, 모듈 옵션도 런타임에 포함되지 않습니다. 하지만 많은 경우 런타임 코드에서 일부 모듈 옵션에 접근해야 할 수 있습니다. 이럴 때는 Nuxt의 runtimeConfig를 사용해 필요한 설정을 노출하는 것을 권장합니다.

import { defineNuxtModule } from '@nuxt/kit'
import { defu } from 'defu'

export default defineNuxtModule({
  setup (options, nuxt) {
    nuxt.options.runtimeConfig.public.myModule = defu(nuxt.options.runtimeConfig.public.myModule, {
      foo: options.foo
    })
  }
})

사용자가 제공한 public 런타임 설정을 덮어쓰지 않고 defu를 사용해 확장합니다.

이후 플러그인, 컴포넌트, 애플리케이션 등에서 다른 런타임 설정처럼 모듈 옵션에 접근할 수 있습니다:

const options = useRuntimeConfig().public.myModule
공개 런타임 설정에 민감한 모듈 설정(예: 비공개 API 키 등)을 노출하지 않도록 주의하세요. 공개 번들에 포함됩니다.
Read more in Docs > Guide > Going Further > Runtime Config.
Nuxt 모듈 옵션 전달 및 노출에 관한 Vue School 영상을 시청하세요.

addPlugin으로 플러그인 주입하기

플러그인은 모듈이 런타임 로직을 추가하는 일반적인 방법입니다. addPlugin 유틸리티를 사용해 모듈에서 플러그인을 등록할 수 있습니다.

import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    // 상대 경로 해석을 위한 리졸버 생성
    const resolver = createResolver(import.meta.url)

    addPlugin(resolver.resolve('./runtime/plugin'))
  }
})
Read more in Docs > Guide > Going Further > Kit.

addComponent로 Vue 컴포넌트 주입하기

모듈이 Vue 컴포넌트를 제공해야 한다면, addComponent 유틸리티를 사용해 Nuxt가 자동 임포트할 수 있도록 추가할 수 있습니다.

import { defineNuxtModule, addComponent } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    // 런타임 디렉토리에서
    addComponent({
      name: 'MySuperComponent', // vue 템플릿에서 사용할 컴포넌트 이름
      export: 'MySuperComponent', // (선택) 컴포넌트가 named export일 경우
      filePath: resolver.resolve('runtime/components/MySuperComponent.vue')
    })

    // 라이브러리에서
    addComponent({
      name: 'MyAwesomeComponent', // vue 템플릿에서 사용할 컴포넌트 이름
      export: 'MyAwesomeComponent', // (선택) 컴포넌트가 named export일 경우
      filePath: '@vue/awesome-components'
    })
  }
})

또는 addComponentsDir을 사용해 전체 디렉토리를 추가할 수도 있습니다.

import { defineNuxtModule, addComponentsDir } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addComponentsDir({
      path: resolver.resolve('runtime/components')
    })
  }
})

addImportsaddImportsDir로 Composable 주입하기

모듈이 composable을 제공해야 한다면, addImports 유틸리티를 사용해 Nuxt가 자동 임포트할 수 있도록 추가할 수 있습니다.

import { defineNuxtModule, addImports, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addImports({
      name: 'useComposable', // 사용할 composable 이름
      as: 'useComposable',
      from: resolver.resolve('runtime/composables/useComposable') // composable 경로
    })
  }
})

또는 addImportsDir을 사용해 전체 디렉토리를 추가할 수도 있습니다.

import { defineNuxtModule, addImportsDir, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addImportsDir(resolver.resolve('runtime/composables'))
  }
})

addServerHandler로 서버 라우트 주입하기

import { defineNuxtModule, addServerHandler, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addServerHandler({
      route: '/api/hello',
      handler: resolver.resolve('./runtime/server/api/hello/index.get')
    })
  }
})

동적 서버 라우트도 추가할 수 있습니다:

import { defineNuxtModule, addServerHandler, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url)

    addServerHandler({
      route: '/api/hello/:name',
      handler: resolver.resolve('./runtime/server/api/hello/[name].get')
    })
  }
})

기타 자산 주입하기

모듈이 다른 종류의 자산을 제공해야 한다면, 역시 주입할 수 있습니다. 다음은 Nuxt의 css 배열을 통해 스타일시트를 주입하는 간단한 예시입니다.

import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    const resolver = createResolver(import.meta.url)

    nuxt.options.css.push(resolver.resolve('./runtime/style.css'))
  }
})

그리고 NitropublicAssets 옵션을 통해 자산 폴더를 노출하는 좀 더 고급 예시입니다:

import { defineNuxtModule, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    const resolver = createResolver(import.meta.url)

    nuxt.hook('nitro:config', async (nitroConfig) => {
      nitroConfig.publicAssets ||= []
      nitroConfig.publicAssets.push({
        dir: resolver.resolve('./runtime/public'),
        maxAge: 60 * 60 * 24 * 365 // 1년
      })
    })
  }
})

모듈 내에서 다른 모듈 사용하기

모듈이 다른 모듈에 의존한다면, Nuxt Kit의 installModule 유틸리티를 사용해 추가할 수 있습니다. 예를 들어, 모듈 내에서 Nuxt Tailwind를 사용하고 싶다면 다음과 같이 추가할 수 있습니다:

import { defineNuxtModule, createResolver, installModule } from '@nuxt/kit'

export default defineNuxtModule<ModuleOptions>({
  async setup (options, nuxt) {
    const resolver = createResolver(import.meta.url)

    // Tailwind 지시문이 포함된 CSS 파일을 주입할 수 있습니다
    nuxt.options.css.push(resolver.resolve('./runtime/assets/styles.css'))

    await installModule('@nuxtjs/tailwindcss', {
      // 모듈 설정
      exposeConfig: true,
      config: {
        darkMode: 'class',
        content: {
          files: [
            resolver.resolve('./runtime/components/**/*.{vue,mjs,ts}'),
            resolver.resolve('./runtime/*.{mjs,js,ts}')
          ]
        }
      }
    })
  }
})

훅 사용하기

라이프사이클 훅을 사용하면 Nuxt의 거의 모든 측면을 확장할 수 있습니다. 모듈은 프로그래밍 방식 또는 정의 내 hooks 맵을 통해 훅에 연결할 수 있습니다.

import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  // `hooks` 맵을 통해 `app:error` 훅에 연결
  hooks: {
    'app:error': (err) => {
      console.info(`이 오류가 발생했습니다: ${err}`);
    }
  },
  setup (options, nuxt) {
    // 프로그래밍 방식으로 `pages:extend` 훅에 연결
    nuxt.hook('pages:extend', (pages) => {
      console.info(`발견된 페이지 수: ${pages.length}`);
    })
  }
})
Read more in Docs > API > Advanced > Hooks.
모듈에서 Nuxt 라이프사이클 훅을 사용하는 방법에 대한 Vue School 영상을 시청하세요.
모듈 정리

모듈이 watcher를 열거나 처리하거나 시작한다면, Nuxt 라이프사이클이 끝날 때 이를 닫아야 합니다. 이를 위해 close 훅을 사용할 수 있습니다.
import { defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    nuxt.hook('close', async nuxt => {
      // 여기에 사용자 정의 코드를 작성하세요
    })
  }
})

템플릿/가상 파일 추가하기

사용자 앱에서 임포트할 수 있는 가상 파일을 추가해야 한다면, addTemplate 유틸리티를 사용할 수 있습니다.

import { defineNuxtModule, addTemplate } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    // 파일이 Nuxt의 내부 가상 파일 시스템에 추가되며, '#build/my-module-feature.mjs'에서 임포트할 수 있습니다
    addTemplate({
      filename: 'my-module-feature.mjs',
      getContents: () => 'export const myModuleFeature = () => "hello world !"'
    })
  }
})

서버용으로는 대신 addServerTemplate 유틸리티를 사용해야 합니다.

import { defineNuxtModule, addServerTemplate } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    // 파일이 Nitro의 가상 파일 시스템에 추가되며, 서버 코드에서 'my-server-module.mjs'로 임포트할 수 있습니다
    addServerTemplate({
      filename: 'my-server-module.mjs',
      getContents: () => 'export const myServerModule = () => "hello world !"'
    })
  }
})

타입 선언 추가하기

Nuxt 인터페이스를 확장하거나 자체 글로벌 타입을 제공하기 위해, 사용자 프로젝트에 타입 선언을 추가하고 싶을 수 있습니다. 이를 위해 Nuxt는 addTypeTemplate 유틸리티를 제공하며, 이 유틸리티는 템플릿을 디스크에 작성하고 생성된 nuxt.d.ts 파일에 참조를 추가합니다.

모듈이 Nuxt에서 처리하는 타입을 확장해야 한다면, addTypeTemplate을 사용할 수 있습니다:

import { defineNuxtModule, addTemplate, addTypeTemplate } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    addTypeTemplate({
      filename: 'types/my-module.d.ts',
      getContents: () => `// my-module에 의해 생성됨
        interface MyModuleNitroRules {
          myModule?: { foo: 'bar' }
        }
        declare module 'nitropack' {
          interface NitroRouteRules extends MyModuleNitroRules {}
          interface NitroRouteConfig extends MyModuleNitroRules {}
        }
        export {}`
    })
  }
})

더 세밀한 제어가 필요하다면, prepare:types 훅을 사용해 타입을 주입할 콜백을 등록할 수 있습니다.

const template = addTemplate({ /* 템플릿 옵션 */ })
nuxt.hook('prepare:types', ({ references }) => {
  references.push({ path: template.dst })
})
템플릿 업데이트하기

템플릿/가상 파일을 업데이트해야 한다면, 다음과 같이 updateTemplates 유틸리티를 활용할 수 있습니다:

nuxt.hook('builder:watch', async (event, path) => {
  if (path.includes('my-module-feature.config')) {
    // 등록한 템플릿을 다시 로드합니다
    updateTemplates({ filter: t => t.filename === 'my-module-feature.mjs' })
  }
})

테스트

테스트는 다양한 설정에서 모듈이 예상대로 동작하는지 보장하는 데 도움이 됩니다. 이 섹션에서는 모듈에 대해 다양한 종류의 테스트를 수행하는 방법을 안내합니다.

단위 및 통합 테스트

Nuxt 모듈의 단위 및 통합 테스트를 쉽게 할 수 있는 방법을 논의 및 탐색 중입니다.

이 RFC를 확인하고 논의에 참여하세요.

엔드 투 엔드 테스트

Nuxt Test Utils는 모듈을 엔드 투 엔드 방식으로 테스트하는 데 도움이 되는 대표적인 라이브러리입니다. 다음은 이를 활용하는 워크플로우입니다:

  1. test/fixtures/* 내에 "fixture"로 사용할 Nuxt 애플리케이션을 만듭니다
  2. 테스트 파일 내에서 이 fixture로 Nuxt를 설정합니다
  3. @nuxt/test-utils의 유틸리티(예: 페이지 fetch 등)로 fixture와 상호작용합니다
  4. 이 fixture와 관련된 검증을 수행합니다(예: "HTML에 ...이 포함되어 있다")
  5. 반복

실제로, fixture는 다음과 같습니다:

test/fixtures/ssr/nuxt.config.ts
// 1. "fixture"로 사용할 Nuxt 애플리케이션 생성
import MyModule from '../../../src/module'

export default defineNuxtConfig({
  ssr: true,
  modules: [
    MyModule
  ]
})

그리고 그 테스트는:

test/rendering.ts
import { describe, it, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, $fetch } from '@nuxt/test-utils/e2e'

describe('ssr', async () => {
  // 2. 테스트 파일 내에서 이 fixture로 Nuxt 설정
  await setup({
    rootDir: fileURLToPath(new URL('./fixtures/ssr', import.meta.url)),
  })

  it('index 페이지를 렌더링한다', async () => {
    // 3. `@nuxt/test-utils`의 유틸리티로 fixture와 상호작용
    const html = await $fetch('/')

    // 4. 이 fixture와 관련된 검증 수행
    expect(html).toContain('<div>ssr</div>')
  })
})

// 5. 반복
describe('csr', async () => { /* ... */ })
이런 워크플로우의 예시는 모듈 스타터에서 확인할 수 있습니다.

Playground 및 외부에서 수동 QA

모듈을 개발할 때 테스트할 수 있는 playground Nuxt 애플리케이션이 있으면 매우 유용합니다. 모듈 스타터에는 이를 위한 playground가 통합되어 있습니다.

모듈 저장소에 포함되지 않은 다른 Nuxt 애플리케이션에서도 로컬에서 모듈을 테스트할 수 있습니다. 이를 위해 npm pack 명령어나 패키지 매니저의 동등한 명령어로 모듈의 tarball을 생성한 뒤, 테스트 프로젝트의 package.json 패키지에 "my-module": "file:/path/to/tarball.tgz"로 추가하면 됩니다.

이후 일반 프로젝트처럼 my-module을 참조할 수 있습니다.

베스트 프랙티스

강력한 기능에는 큰 책임이 따릅니다. 모듈은 강력하지만, 애플리케이션의 성능과 개발자 경험을 유지하기 위해 모듈 작성 시 다음의 베스트 프랙티스를 염두에 두세요.

비동기 모듈

앞서 본 것처럼, Nuxt 모듈은 비동기일 수 있습니다. 예를 들어, API를 호출하거나 비동기 함수를 호출해야 하는 모듈을 개발할 수 있습니다.

하지만, 비동기 동작에 주의해야 합니다. Nuxt는 모듈이 설정될 때까지 기다린 후 다음 모듈로 넘어가고, 개발 서버나 빌드 프로세스를 시작합니다. 시간이 오래 걸리는 로직은 Nuxt 훅으로 미루는 것이 좋습니다.

모듈 설정에 1초 이상 걸리면 Nuxt가 이에 대한 경고를 표시합니다.

노출하는 인터페이스에 항상 접두사 붙이기

Nuxt 모듈은 노출하는 설정, 플러그인, API, composable, 컴포넌트 등에 명확한 접두사를 붙여야 다른 모듈 및 내부와의 충돌을 방지할 수 있습니다.

이상적으로는 모듈 이름을 접두사로 사용해야 합니다(예: 모듈 이름이 nuxt-foo라면 <FooButton>, useFooBar()를 노출하고, 절대 <Button>, useBar()를 노출하지 마세요).

TypeScript 친화적으로 만들기

Nuxt는 최고의 개발자 경험을 위해 TypeScript를 1급으로 지원합니다.

타입을 노출하고 TypeScript로 모듈을 개발하면, 사용자가 TypeScript를 직접 사용하지 않더라도 이점을 얻을 수 있습니다.

CommonJS 문법 피하기

Nuxt는 네이티브 ESM을 기반으로 합니다. 자세한 내용은 네이티브 ES 모듈을 참고하세요.

모듈 사용법 문서화

readme 파일에 모듈 사용법을 문서화하는 것을 고려하세요:

  • 이 모듈을 왜 사용해야 하나요?
  • 이 모듈을 어떻게 사용하나요?
  • 이 모듈이 하는 일은 무엇인가요?

통합 웹사이트 및 문서로 연결하는 것도 좋은 방법입니다.

StackBlitz 데모 또는 보일러플레이트 제공

모듈과 함께 최소 재현 예제를 만들어 StackBlitz에 추가하고, 이를 모듈 readme에 포함하는 것이 좋은 관행입니다.

이렇게 하면 잠재적 사용자에게 모듈을 빠르고 쉽게 실험할 수 있는 방법을 제공할 뿐만 아니라, 이슈 발생 시 최소 재현 예제를 쉽게 만들어 전달할 수 있습니다.

특정 Nuxt 버전으로 광고하지 않기

Nuxt, Nuxt Kit, 기타 새로운 툴링은 모두 전방 및 후방 호환성을 염두에 두고 설계되었습니다.

생태계의 분열을 방지하기 위해 "Nuxt 3용 X" 대신 "Nuxt용 X"를 사용하고, Nuxt 버전 제약은 meta.compatibility를 사용해 설정하세요.

스타터 기본값 유지

모듈 스타터는 기본 도구 및 설정(예: ESLint 설정)을 제공합니다. 모듈을 오픈소스로 공개할 계획이라면, 이러한 기본값을 유지하는 것이 다른 커뮤니티 모듈과 일관된 코딩 스타일을 공유하게 하여, 타인의 기여가 쉬워집니다.

에코시스템

Nuxt 모듈 에코시스템은 월간 1,500만 NPM 다운로드를 기록하며, 다양한 도구와의 확장 기능 및 통합을 제공합니다. 여러분도 이 에코시스템의 일부가 될 수 있습니다!

Nuxt 모듈 유형에 관한 Vue School 영상을 시청하세요.

모듈 유형

공식 모듈@nuxt/(예: @nuxt/content) 접두사(스코프)를 가진 모듈입니다. Nuxt 팀이 직접 제작 및 적극적으로 유지보수합니다. 프레임워크와 마찬가지로, 커뮤니티의 기여도 언제나 환영합니다!

커뮤니티 모듈@nuxtjs/(예: @nuxtjs/tailwindcss) 접두사(스코프)를 가진 모듈입니다. 커뮤니티 구성원이 제작 및 유지보수하는 검증된 모듈입니다. 역시 누구나 기여할 수 있습니다.

서드파티 및 기타 커뮤니티 모듈은 보통 nuxt- 접두사를 가진 모듈입니다. 누구나 만들 수 있으며, 이 접두사를 사용하면 npm에서 쉽게 찾을 수 있습니다. 아이디어를 시도하고 초안을 작성하기에 가장 좋은 출발점입니다!

비공개 또는 개인 모듈은 본인 또는 회사의 특정 용도로 만든 모듈입니다. Nuxt와 함께 동작하는 데 별도의 네이밍 규칙이 필요 없으며, 보통 npm 조직(예: @my-company/nuxt-auth) 아래에 스코프를 둡니다.

커뮤니티 모듈 목록에 등록하기

모든 커뮤니티 모듈은 모듈 목록에 등록될 수 있습니다. 등록하려면 nuxt/modules 저장소에 이슈를 생성하세요. Nuxt 팀이 등록 전 베스트 프랙티스 적용을 도와줄 수 있습니다.

nuxt-modules@nuxtjs/에 참여하기

nuxt-modules로 모듈을 이전하면, 항상 도움을 받을 수 있고, 함께 힘을 합쳐 완벽한 솔루션을 만들 수 있습니다.

이미 배포 및 동작 중인 모듈이 있고, 이를 nuxt-modules로 이전하고 싶다면, nuxt/modules에 이슈를 생성하세요.

nuxt-modules에 참여하면 커뮤니티 모듈을 @nuxtjs/ 스코프로 이름을 변경하고, 문서용 서브도메인(예: my-module.nuxtjs.org)도 제공할 수 있습니다.