agent-rules-kit
Version:
Bootstrap of **Cursor** rules (`.mdc`) and mirror documentation (`.md`) for AI agent-guided projects.
379 lines (313 loc) • 7.86 kB
Markdown
---
title: Nuxt 3 Modules and Plugins Guide
description: Comprehensive guide for working with Nuxt 3 modules and plugins
tags: [Nuxt, Modules, Plugins, Configuration]
globs: ./**/*
always: true
---
# Nuxt 3 Modules and Plugins Guide
## Module Development
### 1. Basic Module Structure
```typescript
// modules/my-module/module.ts
import { defineNuxtModule } from '@nuxt/kit';
export interface ModuleOptions {
enabled?: boolean;
configuration?: Record<string, any>;
}
export default defineNuxtModule<ModuleOptions>({
meta: {
name: 'my-module',
configKey: 'myModule',
compatibility: {
nuxt: '^3.0.0',
},
},
defaults: {
enabled: true,
configuration: {},
},
setup(options, nuxt) {
// Module implementation
if (!options.enabled) return;
// Add runtime directory
const { resolve } = createResolver(import.meta.url);
nuxt.options.build.transpile.push(resolve('./runtime'));
// Add composables
addImportsDir(resolve('./runtime/composables'));
// Add components
addComponent({
name: 'MyComponent',
filePath: resolve('./runtime/components/MyComponent.vue'),
});
// Add plugins
addPlugin(resolve('./runtime/plugin'));
// Add runtime config
nuxt.options.runtimeConfig.myModule = options.configuration;
},
});
```
### 2. Module with Hooks
```typescript
// modules/analytics/module.ts
export default defineNuxtModule({
meta: {
name: 'analytics',
},
setup(_, nuxt) {
nuxt.hook('app:created', (app) => {
// Initialize analytics
});
nuxt.hook('pages:generated', () => {
// Track page generation
});
nuxt.hook('build:done', () => {
// Cleanup after build
});
},
});
```
## Plugin Development
### 1. Type-Safe Plugins
```typescript
// plugins/api.ts
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig();
const api = {
async get<T>(endpoint: string): Promise<T> {
return $fetch<T>(`${config.public.apiBase}${endpoint}`);
},
async post<T>(endpoint: string, data: any): Promise<T> {
return $fetch<T>(`${config.public.apiBase}${endpoint}`, {
method: 'POST',
body: data,
});
},
};
return {
provide: {
api,
},
};
});
// Types extension
declare module '#app' {
interface NuxtApp {
$api: typeof api;
}
}
```
### 2. Plugin with Vue Integration
```typescript
// plugins/notifications.ts
export default defineNuxtPlugin((nuxtApp) => {
const notifications = reactive({
items: [] as Notification[],
add(notification: Notification) {
this.items.push(notification);
setTimeout(() => this.remove(notification.id), 5000);
},
remove(id: string) {
const index = this.items.findIndex((item) => item.id === id);
if (index !== -1) this.items.splice(index, 1);
},
});
nuxtApp.vueApp.provide('notifications', notifications);
return {
provide: {
notify: notifications.add.bind(notifications),
},
};
});
```
## Module Configuration Patterns
### 1. Environment-aware Configuration
```typescript
// nuxt.config.ts
export default defineNuxtConfig({
myModule: {
enabled: true,
configuration: {
apiKey: process.env.API_KEY,
environment: process.env.NODE_ENV,
features: {
analytics: process.env.ENABLE_ANALYTICS === 'true',
monitoring: process.env.ENABLE_MONITORING === 'true',
},
},
},
});
```
### 2. Dynamic Module Loading
```typescript
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
// Conditional module loading
process.env.NODE_ENV === 'development' && '@nuxt/devtools',
[
'@nuxtjs/sentry',
{
dsn: process.env.SENTRY_DSN,
enabled: process.env.NODE_ENV === 'production',
},
],
].filter(Boolean),
});
```
## Advanced Module Patterns
### 1. Module Composition
```typescript
// modules/full-stack/module.ts
import { defineNuxtModule } from '@nuxt/kit';
export default defineNuxtModule({
meta: {
name: 'full-stack',
dependencies: {
'@nuxtjs/supabase': '^1.0.0',
'@pinia/nuxt': '^0.5.0',
},
},
setup(_, nuxt) {
// Ensure required modules are installed
const modules = ['@nuxtjs/supabase', '@pinia/nuxt', '@nuxt/image'];
modules.forEach((module) => {
if (!nuxt.options.modules.includes(module)) {
nuxt.options.modules.push(module);
}
});
// Add custom configuration
nuxt.options.runtimeConfig.public.apiBase =
process.env.API_BASE || '/api';
// Add composables
addImportsDir('./runtime/composables');
},
});
```
### 2. Module with TypeScript Integration
```typescript
// modules/api-client/module.ts
import { defineNuxtModule, addTemplate } from '@nuxt/kit';
import { generateApi } from './generator';
export default defineNuxtModule({
meta: {
name: 'api-client',
},
setup(_, nuxt) {
// Generate API client from OpenAPI spec
const apiClient = generateApi();
// Add generated types
addTemplate({
filename: 'api-client.d.ts',
getContents: () => apiClient.types,
});
// Add runtime code
addTemplate({
filename: 'api-client.ts',
getContents: () => apiClient.code,
});
// Extend TypeScript config
nuxt.hook('prepare:types', ({ references }) => {
references.push({
path: resolve(nuxt.options.buildDir, 'api-client.d.ts'),
});
});
},
});
```
## Plugin Best Practices
### 1. Plugin Organization
```typescript
// plugins/index.ts
export default defineNuxtPlugin((nuxtApp) => {
// Register lifecycle hooks
nuxtApp.hook('app:mounted', () => {
// Initialize client-side features
});
// Register error handlers
nuxtApp.hook('vue:error', (error) => {
// Handle Vue errors
});
// Register global properties
nuxtApp.vueApp.config.globalProperties.$format = {
date: (date: Date) => date.toLocaleDateString(),
};
});
```
### 2. Plugin with SSR Considerations
```typescript
// plugins/analytics.ts
export default defineNuxtPlugin((nuxtApp) => {
const router = useRouter();
if (process.client) {
// Client-side initialization
router.afterEach((to) => {
trackPageView(to.fullPath);
});
}
if (process.server) {
// Server-side initialization
nuxtApp.hooks.hook('render:html', (html) => {
// Add analytics script to head
html.head.push(`<script src="analytics.js"></script>`);
});
}
});
```
## Testing Modules and Plugins
### 1. Module Testing
```typescript
// tests/my-module.test.ts
import { describe, test, expect } from 'vitest';
import { setupTest, createResolver } from '@nuxt/test-utils';
import myModule from '../modules/my-module';
describe('my-module', async () => {
await setupTest({
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
server: true,
browser: true,
});
test('module configuration', async () => {
const { nuxt } = useTestContext();
expect(nuxt.options.runtimeConfig.myModule).toBeDefined();
});
test('adds components', () => {
const resolver = createResolver(import.meta.url);
const components = nuxt.options.components;
expect(components).toContainEqual({
name: 'MyComponent',
filePath: resolver.resolve('./runtime/components/MyComponent.vue'),
});
});
});
```
### 2. Plugin Testing
```typescript
// tests/plugins/api.test.ts
import { describe, test, expect, vi } from 'vitest';
import { createApp, definePlugin } from '#app';
describe('api plugin', () => {
test('provides api client', async () => {
const plugin = definePlugin(async (nuxtApp) => {
const { $api } = useNuxtApp();
expect($api).toBeDefined();
expect(typeof $api.get).toBe('function');
expect(typeof $api.post).toBe('function');
});
const app = createApp();
await app.use(plugin);
});
test('handles api calls', async () => {
const { $api } = useNuxtApp();
const mockData = { id: 1 };
vi.spyOn(global, 'fetch').mockImplementationOnce(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve(mockData),
})
);
const result = await $api.get('/test');
expect(result).toEqual(mockData);
});
});
```