Skip to main content

Module behavior

What the module registers, its fixed conventions, and the opt-in codeBlock configuration.

Nuxt Email is a standard Nuxt module registered in modules. Discovery, preview routes, and the render API are fixed by convention. Syntax-highlighted blocks are the one opt-in feature.

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@lupinum/nuxt-email'],
})

What the module registers

  • Components. Eighteen built-in E* components are auto-imported for use inside email templates. Configuring codeBlock adds ECodeBlock.
  • renderEmail — a Nitro-only auto-import generated from the discovered templates, typed with each template's name and props.
  • defineEmail entry point — import it from @lupinum/nuxt-email/define-email inside a template to declare subject or authored text metadata.
  • Development preview — the /__email application and its endpoints, registered only when nuxt.options.dev is true.
  • Nuxt DevTools shortcut — a development-only iframe tab pointing to that same baseURL-aware preview.

Package entry points

The published package exposes six entry points. Runtime and type-only exports are listed separately.

ImportRuntime exportsType-only exports
@lupinum/nuxt-emailDefault Nuxt moduleModuleOptions, RenderedEmail, EmailComponentProps
@lupinum/nuxt-email/buildbuildEmailRegistry (Node build only)BuildEmailRegistryOptions
@lupinum/nuxt-email/renderrenderEmailComponent, EmailRenderError, UnknownEmailTemplateErrorRenderedEmail, EmailComponentProps, EmailComponents
@lupinum/nuxt-email/define-emaildefineEmail, DefineEmailOutsideRenderError, DuplicateEmailDefinitionErrorDefineEmailOptions
@lupinum/nuxt-email/testingrenderEmailComponent, EmailRenderErrorRenderedEmail
@lupinum/nuxt-email/errorsEmailRenderError, UnknownEmailTemplateError, DefineEmailOutsideRenderError, DuplicateEmailDefinitionError, TailwindMissingHeadError—

After nuxt prepare, the generated #nuxt-email/testing alias supplies the configured testing renderer. Use it when a template depends on generated component configuration such as ECodeBlock. It follows the same renderEmailComponent and EmailRenderError testing surface.

There is no public renderEmail package export; its type is generated from each application's templates. For a server registry without Nitro, see Render outside Nitro.

Template discovery

  • Templates are .vue files under app/emails/.
  • Nested paths become slash-separated names (app/emails/account/reset-password.vue → account/reset-password).
  • app/emails/components/ is reserved for your own supporting components and is not discovered.
  • Discovery follows the active Nuxt srcDir: a custom srcDir: 'src/' uses src/emails/.
  • Email templates from inherited Nuxt layers are not merged into the active application's registry. Keep the application-owned templates in its active srcDir/emails tree.
  • In a monorepo, register the module in each Nuxt application that sends email. Each application owns one registry from its own active srcDir/emails; package and layer templates are not merged implicitly.
  • Sibling .fixtures.ts files supply deterministic preview props in development and are excluded from production output.

The registry is regenerated when templates are added, renamed, or deleted, which changes the generated server types. Run nuxt prepare after such changes.

Optional syntax highlighting

codeBlock is the only module option. It uses the Shiki syntax highlighter. The option requires one theme and a non-empty, closed language allowlist:

OptionTypeDefaultRequired
codeBlock{ languages: readonly string[], theme: string }—No
codeBlock.languagesNon-empty readonly string[]—Yes when codeBlock is set
codeBlock.themestring—Yes when codeBlock is set
ts
export default defineNuxtConfig({
  modules: ['@lupinum/nuxt-email'],
  nuxtEmail: {
    codeBlock: {
      languages: ['typescript', 'vue'],
      theme: 'github-dark',
    },
  },
})

Only the configured languages and the grammars they import enter the server bundle. Nuxt Email creates the highlighter on first use. Without this option, ECodeBlock is unregistered and Shiki performs no module-setup or production-bundle work. Shiki remains an installation-time dependency. Unsupported top-level options fail during setup.

Production boundary

The production server keeps templates referenced by its registry because Nitro renders them there. The client bundle excludes those templates.

The /__email application, its endpoints, and every discovered .fixtures.ts module are absent from production output. See the preview workflow and security boundary.