Development

Dynamic Imports using Nitro virtual modules

How the Vue SFC email templates are dynamically imported and rendered using Nitro virtual modules.

This modules provides a robust approach to rendering full Vue Single File Components (SFC) as email templates by leveraging Nuxt's build system and virtual modules.

How It Works

1. Build-Time Template Discovery

  • During the Nuxt build process, the module scans the configured emails directory
  • It discovers all .vue files and generates metadata for each template
  • Creates a virtual Nitro module that imports all discovered templates

2. Virtual Module Generation

The virtual module (#email-templates) contains:

import AwsVerifyEmail from "/path/to/emails/AwsVerifyEmail.vue";
import Newsletter from "/path/to/emails/Newsletter.vue";
// ... other templates

export const emailTemplates = {
  AwsVerifyEmail: AwsVerifyEmail,
  Newsletter: Newsletter,
  // ...
};

export const emailTemplateMapping = {
  AwsVerifyEmail: {
    name: "AwsVerifyEmail",
    filename: "AwsVerifyEmail.vue",
    displayName: "Aws Verify Email",
    importPath: "#email-templates/AwsVerifyEmail",
    filePath: "/path/to/emails/AwsVerifyEmail.vue",
  },
  // ...
};

3. Runtime Template Resolution

  • Server endpoints use the template resolver utility
  • Templates are accessed by name through the virtual module
  • Full SFC compilation is handled by Nuxt/Nitro automatically

4. Development API Endpoints

API endpoints are only available in development mode and are used exclusively by Nuxt DevTools. They are automatically disabled in production to prevent exposing email templates publicly.
  • GET /api/emails - Returns template metadata (dev-only, for DevTools)
  • POST /api/emails/render - Renders templates using compiled Vue components (dev-only, for DevTools)
  • POST /api/emails/source - Returns template source code (dev-only, for DevTools)

For production use, use the renderEmailComponent function in your server-side code instead.

Benefits

✅ Complete SFC Support

  • Script Setup: All reactive data, computed properties, and composition API features work
  • Styles: Scoped styles and CSS modules are properly handled
  • TypeScript: Full TypeScript support with proper type checking
  • Props: Component props are properly typed and validated

✅ Performance

  • Templates are compiled at build time, not runtime
  • No need to parse Vue SFC syntax on every request
  • Virtual modules are cached and optimized by Nitro

✅ Developer Experience

  • Hot reloading works in development
  • Full IDE support with proper imports and type checking
  • No need to duplicate template logic

✅ Maintainability

  • Clean separation between build-time discovery and runtime rendering
  • Easy to extend with additional metadata or features
  • Robust error handling for missing templates

Architecture Flow

  1. Build Time:
    emails/
    ├── WelcomeEmail.vue
    ├── PasswordReset.vue
    └── Newsletter.vue
    
    ↓ Module scans directory
    
    Virtual Module (#email-templates)
    ├── imports all .vue files
    ├── creates component mapping
    └── exports template utilities
    
  2. Runtime:
    API Request → Template Resolver → Virtual Module → Full Vue Component → SSR Render → HTML Output
    

This approach provides the best balance of functionality, performance, and maintainability while leveraging Nuxt's existing infrastructure.