Nuxt의 설정과 훅 시스템을 사용하면 Nuxt의 모든 측면을 커스터마이징하고 필요한 모든 통합(뷰 플러그인, CMS, 서버 라우트, 컴포넌트, 로깅 등)을 추가할 수 있습니다.
Nuxt 모듈은 nuxt dev로 개발 모드에서 Nuxt를 시작하거나 nuxt build로 프로덕션용 프로젝트를 빌드할 때 순차적으로 실행되는 함수입니다.
모듈을 사용하면 프로젝트에 불필요한 보일러플레이트를 추가하거나 Nuxt 자체를 변경하지 않고도, 커스텀 솔루션을 npm 패키지로 캡슐화하고, 적절히 테스트하며, 공유할 수 있습니다.
Nuxt 모듈은 우리의 스타터 템플릿을 사용해 시작하는 것을 권장합니다.
npm create nuxt -- -t module my-module
yarn create nuxt -t module my-module
pnpm create nuxt -t module my-module
bun create nuxt -- -t module my-module
이 명령은 모듈을 개발하고 배포하는 데 필요한 모든 보일러플레이트가 포함된 my-module 프로젝트를 생성합니다.
다음 단계:
my-module을 엽니다.npm run dev:prepare로 개발용 로컬 파일을 준비합니다.모듈 스타터로 기본 작업을 수행하는 방법을 알아보세요.
모듈 소스 코드는 src 디렉터리 안에 있지만, 대부분의 경우 모듈을 개발하려면 Nuxt 애플리케이션이 필요합니다. 이를 위해 존재하는 것이 playground 디렉터리입니다. 이 디렉터리는 이미 여러분의 모듈을 사용하도록 설정된, 마음껏 실험할 수 있는 Nuxt 애플리케이션입니다.
플레이그라운드는 다른 Nuxt 애플리케이션과 동일하게 다룰 수 있습니다.
npm run dev로 개발 서버를 실행하면, src 디렉터리의 모듈을 변경할 때마다 자동으로 리로드됩니다.npm run dev:build로 빌드할 수 있습니다.nuxt 명령은 playground 디렉터리를 대상으로 사용할 수 있습니다(예: nuxt <COMMAND> playground). 편의를 위해 package.json 안에 이들을 참조하는 추가적인 dev:* 스크립트를 선언해도 좋습니다.모듈 스타터에는 기본 테스트 스위트가 포함되어 있습니다.
Nuxt 모듈은 @nuxt/module-builder가 제공하는 자체 빌더를 사용합니다. 이 빌더는 별도의 설정이 필요 없으며, TypeScript를 지원하고, 에셋이 다른 Nuxt 애플리케이션에 배포될 수 있도록 올바르게 번들되도록 보장합니다.
npm run prepack을 실행해 모듈을 빌드할 수 있습니다.
playground가 이를 처리하고, 배포 스크립트도 배포 시 빌드를 처리합니다.npm login으로 인증되어 있는지 확인하세요.버전을 올리고 npm publish 명령을 사용해 모듈을 배포할 수도 있지만, 모듈 스타터에는 모듈의 동작하는 버전을 npm에 배포하는지 확인하는 데 도움을 주는 릴리스 스크립트가 포함되어 있습니다.
릴리스 스크립트를 사용하려면 먼저 모든 변경 사항을 커밋하세요(자동 버전 증가와 변경 로그 업데이트를 활용하기 위해 Conventional Commits를 따르는 것을 권장합니다). 그런 다음 npm run release로 릴리스 스크립트를 실행합니다.
릴리스 스크립트를 실행하면 다음이 수행됩니다.
npm run lint)npm run test)npm run prepack)package.json의 기본 release 스크립트를 조정해도 좋습니다.Nuxt 모듈은 Nuxt 애플리케이션을 거의 모든 방식으로 변경할 수 있는 다양한 강력한 API와 패턴을 제공합니다. 이 섹션에서는 이를 활용하는 방법을 설명합니다.
Nuxt 모듈은 두 가지 종류로 나눌 수 있습니다.
modules 디렉터리의 일부로 존재합니다.두 경우 모두 구조는 유사합니다.
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', (nuxt) => {
console.log('Nuxt is ready')
})
}
이 함수에 대해 Nuxt Kit가 제공하는 상위 수준의 defineNuxtModule 헬퍼를 사용하면 타입 힌트를 지원받을 수 있습니다.
import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule((options, nuxt) => {
nuxt.hook('pages:extend', (pages) => {
console.log(`Discovered ${pages.length} pages`)
})
})
하지만, 이와 같은 저수준 함수 정의 방식은 권장하지 않습니다. 대신, 모듈을 정의할 때 특히 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: {},
// 다른 모듈에 대한 설정 - 이것이 해당 모듈이 여러분의 모듈보다 먼저 실행된다는 것을 보장하지는 않지만,
// 실행되기 전에 다른 모듈의 설정을 변경할 수 있게 해줍니다.
moduleDependencies: {
'some-module': {
// 모듈에 대한 버전 제약을 지정할 수 있습니다. 사용자가 다른
// 버전을 설치한 경우, Nuxt는 시작 시 오류를 발생시킵니다.
version: '>=2',
// 기본적으로 moduleDependencies는 Nuxt가 설치할 모듈 목록에
// 추가되지만, `optional`이 설정된 경우는 예외입니다.
optional: true,
// `nuxt.options`를 덮어쓸 설정입니다.
overrides: {},
// 설정해야 할 값입니다. 모듈의 기본값을 덮어쓰지만
// `nuxt.options`에 설정된 값은 덮어쓰지 않습니다.
defaults: {},
},
},
// 모듈 로직을 담는 함수로, 비동기일 수 있습니다.
setup (moduleOptions, nuxt) {
// ...
},
})
궁극적으로 defineNuxtModule은 저수준 (inlineOptions, nuxt) 모듈 시그니처를 가진 래퍼 함수를 반환합니다. 이 래퍼 함수는 setup 함수를 호출하기 전에 기본값과 기타 필요한 단계를 적용합니다.
defaults와 meta.configKey 지원meta.name 또는 meta.configKey에서 계산된 고유 키를 사용해 모듈이 한 번만 설치되도록 보장getOptions와 getMeta 노출@nuxt/kit에서 제공하는 defineNuxtModule을 사용하는 한, 하위 및 상위 호환성 보장src/runtime에 있습니다.모듈은 Nuxt 설정의 다른 모든 것과 마찬가지로 애플리케이션 런타임에 포함되지 않습니다. 하지만, 모듈이 설치된 애플리케이션에 런타임 코드를 제공하거나 주입하고 싶을 수 있습니다. 이를 가능하게 하는 것이 런타임 디렉터리입니다.
런타임 디렉터리 안에서는 Nuxt 앱과 관련된 모든 종류의 에셋을 제공할 수 있습니다.
서버 엔진 Nitro에는 다음을 제공할 수 있습니다.
또는 사용자 Nuxt 애플리케이션에 주입하고 싶은 다른 종류의 에셋:
그런 다음 모듈 정의에서 이 모든 에셋을 애플리케이션에 주입할 수 있습니다.
#imports 등에서 명시적으로 임포트해야 합니다.
node_modules(배포된 모듈이 실제로 위치하게 되는 곳) 내 파일에 대해 활성화되지 않습니다.모듈 개발을 돕기 위한 1st-party 도구 세트가 제공됩니다.
@nuxt/module-builderNuxt Module Builder는 모듈을 빌드하고 배포하는 데 필요한 모든 무거운 작업을 처리하는 제로 설정 빌드 도구입니다. 이는 모듈 빌드 아티팩트가 Nuxt 애플리케이션과 올바르게 호환되도록 보장합니다.
@nuxt/kitNuxt Kit은 모듈이 Nuxt 애플리케이션과 상호작용하는 데 도움이 되는 컴포저블 유틸리티를 제공합니다. 모듈의 호환성과 코드 가독성을 높이기 위해 가능한 한 수동 대안 대신 Nuxt Kit 유틸리티를 사용하는 것이 좋습니다.
@nuxt/test-utilsNuxt Test Utils는 모듈 테스트 내에서 Nuxt 애플리케이션을 설정하고 실행하는 데 도움이 되는 유틸리티 모음입니다.
여기에서는 모듈을 작성할 때 사용되는 일반적인 패턴을 살펴봅니다.
Nuxt 설정은 모듈에 의해 읽고 변경할 수 있습니다. 다음은 실험적 기능을 활성화하는 모듈의 예시입니다.
import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
// 아직 존재하지 않는 경우 `experimental` 객체를 생성합니다.
nuxt.options.experimental ||= {}
nuxt.options.experimental.componentIslands = true
},
})
더 복잡한 설정 변경을 처리해야 하는 경우 defu를 사용하는 것을 고려해야 합니다.
모듈은 애플리케이션 런타임의 일부가 아니므로, 모듈 옵션도 런타임의 일부가 아닙니다. 하지만 많은 경우 런타임 코드 내에서 일부 모듈 옵션에 접근해야 할 수 있습니다. 이를 위해 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를 사용한다는 점에 주의하세요.
그런 다음 플러그인, 컴포넌트, 애플리케이션 어디에서든 다른 런타임 설정과 마찬가지로 모듈 옵션에 접근할 수 있습니다.
import { useRuntimeConfig } from '@nuxt/kit'
const options = useRuntimeConfig().public.myModule
addPlugin으로 플러그인 주입하기플러그인은 모듈이 런타임 로직을 추가하는 일반적인 방법입니다. 모듈에서 addPlugin 유틸리티를 사용해 플러그인을 등록할 수 있습니다.
import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
// 상대 경로를 해석하기 위한 리졸버 생성
const resolver = createResolver(import.meta.url)
addPlugin(resolver.resolve('./runtime/plugin'))
},
})
addComponent로 Vue 컴포넌트 주입하기모듈이 Vue 컴포넌트를 제공해야 하는 경우, addComponent 유틸리티를 사용해 Nuxt가 자동 임포트로 해석할 수 있도록 추가할 수 있습니다.
import { addComponent, createResolver, defineNuxtModule, useRuntimeConfig } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
// 런타임 디렉터리에서
addComponent({
name: 'MySuperComponent', // vue 템플릿에서 사용할 컴포넌트 이름
export: 'MySuperComponent', // (선택 사항) 컴포넌트가 기본이 아닌 이름 있는 export인 경우
filePath: resolver.resolve('runtime/components/MySuperComponent.vue'),
})
// 라이브러리에서
addComponent({
name: 'MyAwesomeComponent', // vue 템플릿에서 사용할 컴포넌트 이름
export: 'MyAwesomeComponent', // (선택 사항) 컴포넌트가 기본이 아닌 이름 있는 export인 경우
filePath: '@vue/awesome-components',
})
},
})
또는 addComponentsDir을 사용해 전체 디렉터리를 추가할 수도 있습니다.
import { addComponentsDir, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addComponentsDir({
path: resolver.resolve('runtime/components'),
})
},
})
addImports와 addImportsDir로 컴포저블 주입하기모듈이 컴포저블을 제공해야 하는 경우, addImports 유틸리티를 사용해 Nuxt가 자동 임포트로 해석할 수 있도록 추가할 수 있습니다.
import { addImports, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addImports({
name: 'useComposable', // 사용할 컴포저블 이름
as: 'useComposable',
from: resolver.resolve('runtime/composables/useComposable'), // 컴포저블 경로
})
},
})
또는 addImportsDir을 사용해 전체 디렉터리를 추가할 수도 있습니다.
import { addImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addImportsDir(resolver.resolve('runtime/composables'))
},
})
addServerHandler로 서버 라우트 주입하기import { addServerHandler, createResolver, defineNuxtModule } 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 { addServerHandler, createResolver, defineNuxtModule } 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 { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
nuxt.options.css.push(resolver.resolve('./runtime/style.css'))
},
})
그리고 Nitro의 publicAssets 옵션을 통해 에셋 폴더를 노출하는 좀 더 고급 예시입니다.
import { createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
nuxt.hook('nitro:config', (nitroConfig) => {
nitroConfig.publicAssets ||= []
nitroConfig.publicAssets.push({
dir: resolver.resolve('./runtime/public'),
maxAge: 60 * 60 * 24 * 365, // 1년
})
})
},
})
모듈이 다른 모듈에 의존하는 경우, moduleDependencies 옵션을 사용해 이를 지정할 수 있습니다. 이는 버전 제약과 설정 병합을 포함해 모듈 의존성을 처리하는 더 견고한 방법을 제공합니다.
import { createResolver, defineNuxtModule } from '@nuxt/kit'
const resolver = createResolver(import.meta.url)
export default defineNuxtModule<ModuleOptions>({
meta: {
name: 'my-module',
},
moduleDependencies: {
'@nuxtjs/tailwindcss': {
// 모듈에 대한 버전 제약을 지정할 수 있습니다.
version: '>=6',
// `nuxt.options`를 덮어쓸 설정
overrides: {
exposeConfig: true,
},
// 설정해야 할 값입니다. 모듈의 기본값을 덮어쓰지만
// `nuxt.options`에 설정된 값은 덮어쓰지 않습니다.
defaults: {
config: {
darkMode: 'class',
content: {
files: [
resolver.resolve('./runtime/components/**/*.{vue,mjs,ts}'),
resolver.resolve('./runtime/*.{mjs,js,ts}'),
],
},
},
},
},
},
setup (options, nuxt) {
// Tailwind 지시문이 포함된 CSS 파일을 주입할 수 있습니다.
nuxt.options.css.push(resolver.resolve('./runtime/assets/styles.css'))
},
})
moduleDependencies 옵션은 더 이상 사용되지 않는 installModule 함수를 대체하며, 올바른 설정 순서와 설정 병합을 보장합니다.라이프사이클 훅을 사용하면 Nuxt의 거의 모든 측면을 확장할 수 있습니다. 모듈은 프로그램적으로 또는 정의 내 hooks 맵을 통해 훅에 연결할 수 있습니다.
import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
// `hooks` 맵을 통해 `app:error` 훅에 연결
hooks: {
'app:error': (err) => {
console.info(`This error happened: ${err}`)
},
},
setup (options, nuxt) {
// 프로그램적으로 `pages:extend` 훅에 연결
nuxt.hook('pages:extend', (pages) => {
console.info(`Discovered ${pages.length} pages`)
})
},
})
close 훅을 사용할 수 있습니다.import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
nuxt.hook('close', async (nuxt) => {
// 여기에 커스텀 코드를 작성하세요
})
},
})
모듈은 자체 훅을 정의하고 호출할 수도 있으며, 이는 모듈을 확장 가능하게 만드는 강력한 패턴입니다.
다른 모듈이 여러분의 모듈 훅에 구독할 수 있기를 기대한다면, modules:done 훅 안에서 이를 호출해야 합니다. 이렇게 하면 다른 모든 모듈이 자신의 setup 함수 동안 여러분의 훅에 리스너를 등록할 기회를 가진 후에 호출되도록 보장할 수 있습니다.
// my-module/module.ts
import { defineNuxtModule } from '@nuxt/kit'
export interface ModuleHooks {
'my-module:custom-hook': (payload: { foo: string }) => void
}
export default defineNuxtModule({
setup (options, nuxt) {
// `modules:done` 안에서 훅을 호출합니다.
nuxt.hook('modules:done', async () => {
const payload = { foo: 'bar' }
await nuxt.callHook('my-module:custom-hook', payload)
})
},
})
사용자 앱에서 임포트할 수 있는 가상 파일을 추가해야 하는 경우, addTemplate 유틸리티를 사용할 수 있습니다.
import { addTemplate, defineNuxtModule } 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 { addServerTemplate, defineNuxtModule } 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 !"',
})
},
})
템플릿/가상 파일을 업데이트해야 하는 경우, 다음과 같이 updateTemplates 유틸리티를 활용할 수 있습니다.
nuxt.hook('builder:watch', (event, path) => {
if (path.includes('my-module-feature.config')) {
// 등록한 템플릿을 다시 로드합니다.
updateTemplates({ filter: t => t.filename === 'my-module-feature.mjs' })
}
})
사용자 프로젝트에 타입 선언을 추가하고 싶을 수도 있습니다
(예: Nuxt 인터페이스를 확장하거나 자체 글로벌 타입을 제공하기 위해).
이를 위해 Nuxt는 템플릿을 디스크에 작성하고 생성된 nuxt.d.ts 파일에 참조를 추가하는 addTypeTemplate 유틸리티를 제공합니다.
모듈이 Nuxt가 처리하는 타입을 확장해야 하는 경우, addTypeTemplate을 사용해 이 작업을 수행할 수 있습니다.
import { addTemplate, addTypeTemplate, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
addTypeTemplate({
filename: 'types/my-module.d.ts',
getContents: () => `// Generated by my-module
interface MyModuleNitroRules {
myModule?: { foo: 'bar' }
}
declare module 'nitropack/types' {
interface NitroRouteRules extends MyModuleNitroRules {}
interface NitroRouteConfig extends MyModuleNitroRules {}
}
export {}`,
})
},
})
더 세밀한 제어가 필요하다면, prepare:types 훅을 사용해 타입을 주입하는 콜백을 등록할 수 있습니다.
const template = addTemplate({ /* template options */ })
nuxt.hook('prepare:types', ({ references }) => {
references.push({ path: template.dst })
})
tsconfig.json 확장하기모듈에서 사용자 프로젝트의 TypeScript 설정을 확장하는 방법은 여러 가지가 있습니다.
가장 간단한 방법은 다음과 같이 Nuxt 설정을 직접 수정하는 것입니다.
// tsconfig.app.json 확장
nuxt.options.typescript.tsConfig.include ??= []
nuxt.options.typescript.tsConfig.include.push(resolve('./augments.d.ts'))
// tsconfig.shared.json 확장
nuxt.options.typescript.sharedTsConfig.include ??= []
nuxt.options.typescript.sharedTsConfig.include.push(resolve('./augments.d.ts'))
// tsconfig.node.json 확장
nuxt.options.typescript.nodeTsConfig.include ??= []
nuxt.options.typescript.nodeTsConfig.include.push(resolve('./augments.d.ts'))
// tsconfig.server.json 확장
nuxt.options.nitro.typescript ??= {}
nuxt.options.nitro.typescript.tsConfig ??= {}
nuxt.options.nitro.typescript.tsConfig.include ??= []
nuxt.options.nitro.typescript.tsConfig.include.push(resolve('./augments.d.ts'))
또는 prepare:types와 nitro:prepare:types 훅을 사용해 특정 타입 컨텍스트에 대한 TypeScript 참조를 확장하거나, 위 예시와 유사하게 TypeScript 설정을 수정할 수 있습니다.
nuxt.hook('prepare:types', ({ references, sharedReferences, nodeReferences }) => {
// 앱 컨텍스트 확장
references.push({ path: resolve('./augments.d.ts') })
// 공유 컨텍스트 확장
sharedReferences.push({ path: resolve('./augments.d.ts') })
// node 컨텍스트 확장
nodeReferences.push({ path: resolve('./augments.d.ts') })
})
nuxt.hook('nitro:prepare:types', ({ references }) => {
// 서버 컨텍스트 확장
references.push({ path: resolve('./augments.d.ts') })
})
tsconfig.json의 exclude 옵션의 영향을 받지 않고 타입 컨텍스트에 파일을 추가합니다.Nuxt는 모듈의 디렉터리를 자동으로 적절한 타입 컨텍스트에 포함합니다. 모듈에서 타입을 확장하려면, 확장하려는 타입 컨텍스트에 따라 타입 선언 파일을 적절한 디렉터리에 배치하기만 하면 됩니다. 또는 TypeScript 설정을 확장해 임의의 위치에서 확장할 수도 있습니다.
my-module/runtime/ - 앱 타입 컨텍스트(runtime/server 디렉터리는 제외)my-module/runtime/server/ - 서버 타입 컨텍스트my-module/ - node 타입 컨텍스트(runtime/ 및 runtime/server 디렉터리는 제외)-| my-module/ # node 타입 컨텍스트
---| runtime/ # 앱 타입 컨텍스트
------| augments.app.d.ts
------| server/ # 서버 타입 컨텍스트
---------| augments.server.d.ts
---| module.ts
---| augments.node.d.ts
테스트는 다양한 설정에서 모듈이 예상대로 동작하는지 확인하는 데 도움이 됩니다. 이 섹션에서는 모듈에 대해 다양한 종류의 테스트를 수행하는 방법을 설명합니다.
Nuxt Test Utils는 모듈을 엔드 투 엔드 방식으로 테스트하는 데 도움이 되는 기본 라이브러리입니다. 다음은 이를 사용할 때의 워크플로입니다.
test/fixtures/* 안에 "fixture"로 사용할 Nuxt 애플리케이션을 생성합니다.@nuxt/test-utils의 유틸리티(예: 페이지 fetch)를 사용해 fixture와 상호작용합니다.실제로, fixture는 다음과 같습니다.
// 1. "fixture"로 사용할 Nuxt 애플리케이션 생성
import MyModule from '../../../src/module'
export default defineNuxtConfig({
ssr: true,
modules: [
MyModule,
],
})
그리고 해당 테스트는 다음과 같습니다.
import { describe, expect, it } from 'vitest'
import { fileURLToPath } from 'node:url'
import { $fetch, setup } from '@nuxt/test-utils/e2e'
describe('ssr', async () => {
// 2. 테스트 파일 안에서 이 fixture로 Nuxt 설정
await setup({
rootDir: fileURLToPath(new URL('./fixtures/ssr', import.meta.url)),
})
it('renders the index page', async () => {
// 3. `@nuxt/test-utils` 유틸리티를 사용해 fixture와 상호작용
const html = await $fetch('/')
// 4. 이 fixture와 관련된 검증 수행
expect(html).toContain('<div>ssr</div>')
})
})
// 5. 반복
describe('csr', async () => { /* ... */ })
모듈을 개발할 때 테스트할 수 있는 플레이그라운드 Nuxt 애플리케이션을 갖는 것은 매우 유용합니다. 모듈 스타터에는 이를 위한 플레이그라운드가 통합되어 있습니다.
모듈을 다른 Nuxt 애플리케이션(모듈 저장소의 일부가 아닌 애플리케이션)과 로컬에서 테스트할 수도 있습니다. 이를 위해 npm pack 명령 또는 사용하는 패키지 매니저의 동등한 명령을 사용해 모듈에서 tarball을 생성할 수 있습니다. 그런 다음 테스트 프로젝트의 package.json 패키지에 "my-module": "file:/path/to/tarball.tgz"와 같이 모듈을 추가합니다.
그 후에는 일반 프로젝트와 마찬가지로 my-module을 참조할 수 있어야 합니다.
큰 힘에는 큰 책임이 따릅니다. 모듈은 강력하지만, 애플리케이션 성능과 개발자 경험을 좋게 유지하기 위해 모듈을 작성할 때 염두에 두어야 할 몇 가지 모범 사례가 있습니다.
앞에서 보았듯이 Nuxt 모듈은 비동기일 수 있습니다. 예를 들어, 어떤 API를 fetch하거나 비동기 함수를 호출해야 하는 모듈을 개발하고 싶을 수 있습니다.
하지만, 비동기 동작에 주의해야 합니다. Nuxt는 다음 모듈로 넘어가고 개발 서버나 빌드 프로세스를 시작하기 전에 모듈 설정이 완료되기를 기다립니다. 시간이 많이 걸리는 로직은 Nuxt 훅으로 미루는 것이 좋습니다.
Nuxt 모듈은 다른 모듈 및 내부와의 충돌을 피하기 위해 노출하는 모든 설정, 플러그인, API, 컴포저블 또는 컴포넌트에 명시적인 접두사를 제공해야 합니다.
이상적으로는 모듈 이름을 접두사로 사용해야 합니다(예: 모듈 이름이 nuxt-foo인 경우 <Button>과 useBar()가 아니라 <FooButton>과 useFooBar()를 노출해야 합니다).
모듈이 설정 파일 생성, 데이터베이스 설정, 의존성 설치와 같은 일회성 설정 작업을 수행해야 하는 경우, 메인 setup 함수에서 로직을 실행하는 대신 라이프사이클 훅을 사용하세요.
import { addServerHandler, defineNuxtModule } from 'nuxt/kit'
import semver from 'semver'
export default defineNuxtModule({
meta: {
name: 'my-database-module',
version: '1.0.0',
},
async onInstall (nuxt) {
// 일회성 설정: 데이터베이스 스키마 생성, 설정 파일 생성 등
await generateDatabaseConfig(nuxt.options.rootDir)
},
async onUpgrade (options, nuxt, previousVersion) {
// 버전별 마이그레이션 처리
if (semver.lt(previousVersion, '1.0.0')) {
await migrateLegacyData()
}
},
setup (options, nuxt) {
// 모든 빌드에서 실행되는 일반 설정 로직
addServerHandler({ /* ... */ })
},
})
이 패턴은 매 빌드마다 불필요한 작업을 방지하고 더 나은 개발자 경험을 제공합니다. 자세한 내용은 라이프사이클 훅 문서를 참고하세요.
Nuxt는 최고의 개발자 경험을 위해 1급 TypeScript 통합을 제공합니다.
타입을 노출하고 TypeScript로 모듈을 개발하면, 사용자가 TypeScript를 직접 사용하지 않더라도 이점이 있습니다.
Nuxt는 네이티브 ESM에 의존합니다. 자세한 내용은 네이티브 ES 모듈을 참고하세요.
README 파일에 모듈 사용법을 문서화하는 것을 고려하세요.
통합 대상 웹사이트와 문서에 대한 링크를 제공하는 것도 항상 좋은 생각입니다.
모듈과 함께 StackBlitz를 사용해 최소 재현 예제를 만들어 모듈 README에 추가하는 것이 좋습니다.
이는 잠재적인 모듈 사용자에게 모듈을 빠르고 쉽게 실험할 수 있는 방법을 제공할 뿐만 아니라, 문제가 발생했을 때 여러분에게 보낼 수 있는 최소 재현 예제를 쉽게 만들 수 있는 방법도 제공합니다.
Nuxt, Nuxt Kit 및 기타 새로운 도구들은 전방 및 후방 호환성을 염두에 두고 설계되었습니다.
에코시스템의 분열을 피하기 위해 "Nuxt 3용 X" 대신 "Nuxt용 X"를 사용하고, Nuxt 버전 제약을 설정하기 위해 meta.compatibility를 사용하는 것을 선호하세요.
모듈 스타터에는 기본 도구 및 설정 세트(예: ESLint 설정)가 포함되어 있습니다. 모듈을 오픈 소스로 공개할 계획이라면, 이러한 기본값을 유지하는 것이 좋습니다. 이렇게 하면 모듈이 다른 커뮤니티 모듈과 일관된 코딩 스타일을 공유하게 되어, 다른 사람들이 기여하기 쉬워집니다.
Nuxt 모듈 에코시스템은 월간 1,500만 회 이상의 NPM 다운로드를 기록하며, 다양한 도구와의 확장 기능 및 통합을 제공합니다. 여러분도 이 에코시스템의 일부가 될 수 있습니다!
공식 모듈은 @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)을 제공할 수 있습니다.