nuxt-generation-emails 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,7 +46,7 @@ export default defineNuxtConfig({
46
46
  Scaffold the emails directory with example templates and reusable components:
47
47
 
48
48
  ```bash
49
- npx nuxt-gen-emails setup
49
+ npx nuxt-generation-emails setup
50
50
  ```
51
51
 
52
52
  This creates:
@@ -82,9 +82,9 @@ Then add this to your `.vscode/settings.json` so `.mjml` files get Handlebars hi
82
82
  ### 3. Add More Templates
83
83
 
84
84
  ```bash
85
- npx nuxt-gen-emails add welcome
86
- npx nuxt-gen-emails add v1/order-confirmation
87
- npx nuxt-gen-emails add marketing/campaigns/summer-sale
85
+ npx nuxt-generation-emails add welcome
86
+ npx nuxt-generation-emails add v1/order-confirmation
87
+ npx nuxt-generation-emails add marketing/campaigns/summer-sale
88
88
  ```
89
89
 
90
90
  Each command creates a `.vue` + `.mjml` pair with a ready-to-customize starter template.
@@ -289,14 +289,14 @@ The `components/` directory is reserved — it is skipped during route generatio
289
289
 
290
290
  ## Sending Emails
291
291
 
292
- The generated `POST` endpoints render email HTML via MJML. To send, register a Nitro plugin that listens for the `nuxt-gen-emails:send` hook.
292
+ The generated `POST` endpoints render email HTML via MJML. To send, register a Nitro plugin that listens for the `nuxt-generation-emails:send` hook.
293
293
 
294
294
  ### Server plugin
295
295
 
296
296
  ```ts
297
297
  // server/plugins/gen-emails.ts
298
298
  export default defineNitroPlugin((nitro) => {
299
- nitro.hooks.hook('nuxt-gen-emails:send', async ({ html, data }) => {
299
+ nitro.hooks.hook('nuxt-generation-emails:send', async ({ html, data }) => {…})
300
300
  // data contains: { to?, from?, subject?, ...anything from sendData }
301
301
  console.log('Sending email to:', data.to)
302
302
  // Your provider logic here (SendGrid, SES, Postmark, etc.)
@@ -317,7 +317,7 @@ import sgMail from '@sendgrid/mail'
317
317
  export default defineNitroPlugin((nitro) => {
318
318
  sgMail.setApiKey(process.env.SENDGRID_API_KEY!)
319
319
 
320
- nitro.hooks.hook('nuxt-gen-emails:send', async ({ html, data }) => {
320
+ nitro.hooks.hook('nuxt-generation-emails:send', async ({ html, data }) => {
321
321
  await sgMail.send({
322
322
  to: data.to as string,
323
323
  from: (data.from as string) || 'noreply@yourdomain.com',
@@ -352,7 +352,7 @@ curl -X POST http://localhost:3000/api/emails/welcome \
352
352
 
353
353
  1. `templateData` from the request body is passed directly to the Handlebars template (no transformations)
354
354
  2. MJML compiles the result into email-safe HTML
355
- 3. The `nuxt-gen-emails:send` hook is called with `{ html, data }` where `data` is `sendData`
355
+ 3. The `nuxt-generation-emails:send` hook is called with `{ html, data }` where `data` is `sendData`
356
356
  4. The response always returns `{ success: true, html: "..." }`
357
357
 
358
358
  If no Nitro plugin is configured, the endpoint still renders and returns the HTML — useful for testing.
@@ -426,8 +426,8 @@ export default defineEventHandler((event) => {
426
426
 
427
427
  | Command | Description |
428
428
  |---------|-------------|
429
- | `npx nuxt-gen-emails setup` | Scaffold the emails directory with components and an example template |
430
- | `npx nuxt-gen-emails add <name>` | Create a new email template (`.vue` + `.mjml` pair) |
429
+ | `npx nuxt-generation-emails setup` | Scaffold the emails directory with components and an example template |
430
+ | `npx nuxt-generation-emails add <name>` | Create a new email template (`.vue` + `.mjml` pair) |
431
431
 
432
432
  ---
433
433
 
@@ -423,8 +423,8 @@ const setupCommand = defineCommand({
423
423
 
424
424
  const main = defineCommand({
425
425
  meta: {
426
- name: "nuxt-gen-emails",
427
- description: "CLI for nuxt-gen-emails module",
426
+ name: "nuxt-generation-emails",
427
+ description: "CLI for nuxt-generation-emails module",
428
428
  version: "1.0.0"
429
429
  },
430
430
  subCommands: {
package/dist/module.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
 
3
- /** Payload passed to the `nuxt-gen-emails:send` Nitro runtime hook. */
3
+ /** Payload passed to the `nuxt-generation-emails:send` Nitro runtime hook. */
4
4
  type NuxtGenEmailsSendData<TAdditional extends Record<string, unknown> = Record<string, unknown>> = {
5
5
  /** Recipient email address. */
6
6
  to?: string;
@@ -9,7 +9,7 @@ type NuxtGenEmailsSendData<TAdditional extends Record<string, unknown> = Record<
9
9
  /** Email subject line. */
10
10
  subject?: string;
11
11
  } & TAdditional;
12
- /** Payload passed to the `nuxt-gen-emails:send` Nitro runtime hook. */
12
+ /** Payload passed to the `nuxt-generation-emails:send` Nitro runtime hook. */
13
13
  interface NuxtGenEmailsSendPayload<TSendData extends Record<string, unknown> = NuxtGenEmailsSendData> {
14
14
  /** The rendered HTML string of the email template. */
15
15
  html: string;
package/dist/module.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
 
3
- /** Payload passed to the `nuxt-gen-emails:send` Nitro runtime hook. */
3
+ /** Payload passed to the `nuxt-generation-emails:send` Nitro runtime hook. */
4
4
  type NuxtGenEmailsSendData<TAdditional extends Record<string, unknown> = Record<string, unknown>> = {
5
5
  /** Recipient email address. */
6
6
  to?: string;
@@ -9,7 +9,7 @@ type NuxtGenEmailsSendData<TAdditional extends Record<string, unknown> = Record<
9
9
  /** Email subject line. */
10
10
  subject?: string;
11
11
  } & TAdditional;
12
- /** Payload passed to the `nuxt-gen-emails:send` Nitro runtime hook. */
12
+ /** Payload passed to the `nuxt-generation-emails:send` Nitro runtime hook. */
13
13
  interface NuxtGenEmailsSendPayload<TSendData extends Record<string, unknown> = NuxtGenEmailsSendData> {
14
14
  /** The rendered HTML string of the email template. */
15
15
  html: string;
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.0.0"
6
6
  },
7
- "version": "1.0.2",
7
+ "version": "1.0.4",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -304,7 +304,7 @@ export default defineEventHandler(async (event) => {
304
304
 
305
305
  const nitro = useNitroApp()
306
306
  // @ts-ignore - custom hook
307
- await nitro.hooks.callHook('nuxt-gen-emails:send', { html, data: sendData })
307
+ await nitro.hooks.callHook('nuxt-generation-emails:send', { html, data: sendData })
308
308
 
309
309
  return { success: true, message: 'Email rendered successfully', html }
310
310
  }
@@ -506,7 +506,7 @@ function generateServerRoutes(emailsDir, buildDir) {
506
506
  const emailPath = `${routePrefix}/${emailName}`.replace(/^\//, "");
507
507
  const mjmlPath = join(dirPath, `${emailName}.mjml`);
508
508
  if (!fs.existsSync(mjmlPath)) {
509
- console.warn(`[nuxt-gen-emails] Missing co-located MJML file for ${emailName}.vue \u2014 skipping API route. Expected: ${mjmlPath}`);
509
+ console.warn(`[nuxt-generation-emails] Missing co-located MJML file for ${emailName}.vue \u2014 skipping API route. Expected: ${mjmlPath}`);
510
510
  continue;
511
511
  }
512
512
  const handlerDir = routePrefix ? join(handlersDir, routePrefix.replace(/^\//, "")) : handlersDir;
@@ -519,7 +519,7 @@ function generateServerRoutes(emailsDir, buildDir) {
519
519
  const handlerFilePath = join(handlerDir, handlerFileName);
520
520
  const handlerContent = generateApiRoute(emailName, emailPath, examplePayload);
521
521
  fs.writeFileSync(handlerFilePath, handlerContent, "utf-8");
522
- console.log(`[nuxt-gen-emails] Generated API handler: ${handlerFilePath}`);
522
+ console.log(`[nuxt-generation-emails] Generated API handler: ${handlerFilePath}`);
523
523
  handlers.push({
524
524
  route: `/api/emails/${emailPath}`,
525
525
  method: "post",
@@ -548,7 +548,7 @@ const module$1 = defineNuxtModule({
548
548
  async setup(options, nuxt) {
549
549
  const resolver = createResolver(import.meta.url);
550
550
  addTypeTemplate({
551
- filename: "types/nuxt-gen-emails-nitro.d.ts",
551
+ filename: "types/nuxt-generation-emails-nitro.d.ts",
552
552
  getContents: () => `
553
553
  export interface NuxtGenEmailsSendPayload {
554
554
  html: string
@@ -571,12 +571,12 @@ export interface NuxtGenEmailsApiBody<
571
571
 
572
572
  declare module 'nitropack' {
573
573
  interface NitroRuntimeHooks {
574
- 'nuxt-gen-emails:send': (payload: NuxtGenEmailsSendPayload) => void | Promise<void>
574
+ 'nuxt-generation-emails:send': (payload: NuxtGenEmailsSendPayload) => void | Promise<void>
575
575
  }
576
576
  }
577
577
  declare module 'nitropack/types' {
578
578
  interface NitroRuntimeHooks {
579
- 'nuxt-gen-emails:send': (payload: NuxtGenEmailsSendPayload) => void | Promise<void>
579
+ 'nuxt-generation-emails:send': (payload: NuxtGenEmailsSendPayload) => void | Promise<void>
580
580
  }
581
581
  }
582
582
  `
@@ -605,10 +605,15 @@ export function registerMjmlComponents(): void {
605
605
  write: true,
606
606
  getContents: () => `import { computed, h, getCurrentInstance } from 'vue'
607
607
  import type { ComputedRef } from 'vue'
608
- import mjml2html from 'mjml-browser'
609
608
  import Handlebars from 'handlebars'
610
609
  import { registerMjmlComponents } from './register-components'
611
610
 
611
+ // Lazy-load mjml-browser only on the client to avoid "window is not defined" during SSR
612
+ let mjml2html: ((mjml: string) => { html: string; errors: unknown[] }) | null = null
613
+ if (import.meta.client) {
614
+ mjml2html = (await import('mjml-browser')).default
615
+ }
616
+
612
617
  const mjmlTemplates: Record<string, string> = import.meta.glob(
613
618
  ['${templateGlobPath}/**/*.mjml', '!${templateGlobPath}/components/**'],
614
619
  { query: '?raw', import: 'default', eager: true }
@@ -644,7 +649,7 @@ export function useNgeTemplate(name: string, props: Record<string, unknown>): Co
644
649
  const source = templateMap[name]
645
650
  if (!source) {
646
651
  const available = Object.keys(templateMap).join(', ')
647
- console.error(\`[nuxt-gen-emails] Template "\${name}" not found. Available: \${available}\`)
652
+ console.error(\`[nuxt-generation-emails] Template "\${name}" not found. Available: \${available}\`)
648
653
  const fallback = computed(() => \`<pre style="color:red;">Template "\${name}" not found</pre>\`)
649
654
  const instance = getCurrentInstance()
650
655
  if (instance) instance.render = () => h('div', { innerHTML: fallback.value })
@@ -654,6 +659,8 @@ export function useNgeTemplate(name: string, props: Record<string, unknown>): Co
654
659
  const compiled = Handlebars.compile(source)
655
660
 
656
661
  const renderedHtml = computed(() => {
662
+ // mjml-browser requires window \u2014 skip rendering during SSR
663
+ if (!mjml2html) return ''
657
664
  try {
658
665
  const mjmlString = compiled({ ...props })
659
666
  const result = mjml2html(mjmlString)
@@ -724,19 +731,19 @@ export function useNgeTemplate(name: string, props: Record<string, unknown>): Co
724
731
  }
725
732
  if (nuxt.options.dev && fs.existsSync(emailsDir)) {
726
733
  const relDir = relative(nuxt.options.rootDir, emailsDir);
727
- consola.info(`[nuxt-gen-emails] Watching for new templates in ${relDir}/`);
734
+ consola.info(`[nuxt-generation-emails] Watching for new templates in ${relDir}/`);
728
735
  nuxt.options.watch.push(emailsDir + "/**/*.vue");
729
736
  nuxt.options.watch.push(emailsDir + "/**/*.mjml");
730
737
  nuxt.hook("builder:watch", (event, relativePath) => {
731
738
  const absolutePath = join(nuxt.options.rootDir, relativePath);
732
739
  const rel = relative(emailsDir, absolutePath);
733
740
  if (event === "add" && (relativePath.endsWith(".vue") || relativePath.endsWith(".mjml"))) {
734
- consola.success(`[nuxt-gen-emails] New template detected: ${rel}`);
735
- consola.info("[nuxt-gen-emails] Restarting to register new routes...");
741
+ consola.success(`[nuxt-generation-emails] New template detected: ${rel}`);
742
+ consola.info("[nuxt-generation-emails] Restarting to register new routes...");
736
743
  nuxt.callHook("restart");
737
744
  } else if (event === "unlink" && (relativePath.endsWith(".vue") || relativePath.endsWith(".mjml"))) {
738
- consola.warn(`[nuxt-gen-emails] Template removed: ${rel}`);
739
- consola.info("[nuxt-gen-emails] Restarting to update routes...");
745
+ consola.warn(`[nuxt-generation-emails] Template removed: ${rel}`);
746
+ consola.info("[nuxt-generation-emails] Restarting to update routes...");
740
747
  nuxt.callHook("restart");
741
748
  }
742
749
  });
@@ -11,7 +11,7 @@ const responseData = ref(null);
11
11
  const error = ref("");
12
12
  const copySuccess = ref(false);
13
13
  const copyHtmlSuccess = ref(false);
14
- const lastUsedEmail = useCookie("nuxt-gen-emails-last-email", {
14
+ const lastUsedEmail = useCookie("nuxt-generation-emails-last-email", {
15
15
  default: () => "",
16
16
  sameSite: "lax"
17
17
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-generation-emails",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A Nuxt module for authoring, previewing, and sending transactional email templates with MJML and Handlebars.",
5
5
  "author": "nullcarry@icloud.com",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  }
32
32
  },
33
33
  "bin": {
34
- "nuxt-gen-emails": "./dist/cli/index.mjs"
34
+ "nuxt-generation-emails": "./dist/cli/index.mjs"
35
35
  },
36
36
  "main": "./dist/module.mjs",
37
37
  "types": "./dist/types.d.mts",