Top-level directories
After cloning the Vuemail repository you will see a few root-level directories. Here’s a brief overview of each:| Directory | Description |
|---|---|
| apps | Here you can find all of the apps related to our online presence, like:
|
| benchmarks | We make benchmarks from version-to-version to demonstrate data-observable performance gains with metrics like p99 and p75.For example, see the Tailwind benchmark, which measures the cost of rendering an email with the Tailwind component. |
| packages | Most contributions will be made to the packages in this directory.This directory contains all our published NPM packages: the components, the CLI, the render utility, the preview app, the editor and the Nuxt module, alongside shared configuration. |
Feel free to open a discussion if you have suggestions on how to better structure these packages to make them more manageable and approachable.
Multiple packages
The Vuemail repository is a pnpm monorepo, which means it contains multiple packages. Because we use pnpm, you will need to use pnpm to install and run each package. If you do not have pnpm installed, follow the pnpm installation guide:- @vuemaildev/vuemail
- The package for our email CLI, and for all of our components
- @vuemaildev/render
- The render utility. Can also be imported from
@vuemaildev/vuemail.
- The render utility. Can also be imported from
- @vuemaildev/ui
- The preview app the CLI runs
- @vuemaildev/editor
- The embeddable visual editor for composing emails
- @vuemaildev/nuxt
- The Nuxt module that lets server routes render emails
- create-vuemail
- Used for our automatic setup
Turborepo
We encourage using turborepo to manage the packages. It’s often helpful to install Turborepo globally to make it easier to run commands in any of the repositories. With a global installation, runningturbo build in any of the packages will build both the package
you are on as well as the dependent packages. The global installation handles version mismatching as well.
The Vuemail CLI
The CLI is built using commander, a CLI builder for node. It handles parsing of command line arguments and ensuring that the syntax for the command is as expected. Thedev, build, start and export commands all depend on the user first installing @vuemaildev/ui,
in the same version as @vuemaildev/vuemail. The CLI loads it from the user’s project, and when it’s missing or its
version doesn’t match, it asks to install it, using nypm to add it
with the user’s package manager.
The Preview Server
The Preview Server,@vuemaildev/ui, has two sides:
src/nodeis the server the CLI starts. It compiles the user’s emails with Vite and@vitejs/plugin-vue, loading them with Vite’s server-side module loader, and renders them with the render utility from the user’s own@vuemaildev/vuemail. Vite’s file watcher detects changes to the files the emails depend on, which the server sends to the browser as server-sent events.src/clientis the preview app itself, a Vue 3 single page app built with Vite, vue-router, reka-ui and Tailwind CSS 4.
email build renders every
email ahead of time instead, into a static website.
Testing
For testing, we use vitest. We prefer to define globals, and run tests under thehappy-dom
environment for the code that runs in the browser, like the preview app and the editor, and under node for the rest.
We do not strictly enforce testing coverage, but encourage it.
For help testing, see our Development workflow guide.
The tests of
@vuemaildev/nuxt build and start real Nuxt apps, so they take longer than the others.Linting
We use biomejs for linting and formatting. Both the linting and formatting are ensured by our GitHub CI so make sure you lint and format your code (pnpm lint:fix) before opening a PR or asking for a review on it.
For help linting and formatting, see our Development workflow guide on linting.
Building
We use tsdown to build the packages. The preview app of@vuemaildev/ui is built with
Vite. For help building packages, see our Development workflow guide.
Building each package runs
tsdown with the settings in its tsdown.config.ts. @vuemaildev/vuemail and @vuemaildev/render are built as both ESM and CJS,
along with the type definitions exported from the entry point, src/index.ts, without bundling vue, which can cause issues.Why build before publishing?
We build the packages before publishing for a few reasons:- All the exported types can be imported from the same place the JavaScript is imported
- We have proper CommonJS and ES Modules support
- Code that isn’t exported is not published or downloaded