> ## Documentation Index
> Fetch the complete documentation index at: https://vuemail.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Vite plugins

> Run your own Vite plugins when Vuemail compiles your templates

To preview, build, and export your emails, Vuemail compiles each template with [Vite](https://vite.dev/) and its
[Vue plugin](https://github.com/vitejs/vite-plugin-vue). The `--vite-plugins` option adds your own
[Vite plugins](https://vite.dev/guide/api-plugin) to that compilation step.

Use it when a template depends on something only a plugin can provide, such as:

* A compile-time transform
* Imports that need a custom resolver, like virtual modules or data fetched at build time
* File types Vite doesn't load on its own

## 1. Create a plugins module

Create a module whose default export is an array of Vite plugins.
It can also export a function that returns the array, sync or async, for plugins that need setup.
The module can be written in JavaScript or TypeScript.

This example lets templates import the latest releases of any GitHub repository, fetched while the template is compiled:

```js vite-plugins.mjs theme={null}
const prefix = 'github-releases:';

export default [
  {
    name: 'github-releases',
    resolveId(id) {
      // The `\0` keeps other plugins from handling the virtual module
      if (id.startsWith(prefix)) return `\0${id}`;
    },
    async load(id) {
      if (!id.startsWith(`\0${prefix}`)) return;

      const repo = id.slice(`\0${prefix}`.length);
      const response = await fetch(
        `https://api.github.com/repos/${repo}/releases?per_page=3`,
      );
      if (!response.ok) {
        throw new Error(`Could not fetch releases for ${repo}`);
      }
      const releases = await response.json();

      return `export default ${JSON.stringify(
        releases.map((release) => ({
          name: release.name || release.tag_name,
          url: release.html_url,
          body: release.body ?? '',
        })),
      )};`;
    },
  },
];
```

> [!NOTE]
>
> Vite keeps a module it compiled until the files it comes from change, so the
> preview server fetches the releases once, when it first renders a template
> that imports them. Restart `email dev` to fetch them again.

## 2. Use it in a template

With the plugin in place, a template can import the releases like any other module:

```vue emails/whats-new.vue theme={null}
<script setup lang="ts">
import releases from 'github-releases:vuejs/core';
import { Button, Heading, Html, Markdown, Section } from '@vuemaildev/vuemail';
</script>

<template>
  <Html>
    <Section v-for="release in releases" :key="release.url">
      <Heading as="h2">{{ release.name }}</Heading>
      <Markdown :source="release.body" />
      <Button :href="release.url">View on GitHub</Button>
    </Section>
  </Html>
</template>
```

For TypeScript to know the type of the virtual module, declare it in a `.d.ts` file of your project:

```ts github-releases.d.ts theme={null}
declare module 'github-releases:*' {
  const releases: { name: string; url: string; body: string }[];
  export default releases;
}
```

## 3. Pass the plugins module to the CLI

Pass the module's path to every command that compiles your templates. The path is relative to the directory you run the command from.

```json package.json theme={null}
{
  "scripts": {
    "dev": "email dev --vite-plugins ./vite-plugins.mjs",
    "build": "email build --vite-plugins ./vite-plugins.mjs",
    "export": "email export --vite-plugins ./vite-plugins.mjs"
  }
}
```

`email start` doesn't take the option, since it serves the website `email build` already built with your plugins.

## Things to know

* **Plugins are loaded once per process.** After editing a working plugins module, restart `email dev` for the changes to apply.
* **Loading errors stop the command.** If the plugins module fails to load, `email dev`, `email build` and `email export` stop and print the error.
* **Vuemail's Vue plugin runs first.** Your plugins get the compiled output of `.vue` files. Give a plugin [`enforce: 'pre'`](https://vite.dev/guide/api-plugin#plugin-ordering) to run it before the Vue plugin.
* **Your Vite configuration isn't loaded.** Plugins in `vite.config.ts` don't apply to your emails, only the ones you pass with `--vite-plugins`. See [how Vuemail compiles your emails](https://vuemail.dev/docs/guides/vite.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.