nuxt-generation-emails 1.0.7 → 1.1.1
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/dist/cli/index.mjs +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +41 -33
- package/dist/runtime/types/mjml.d.ts +1 -1
- package/package.json +3 -3
package/dist/cli/index.mjs
CHANGED
|
@@ -46,7 +46,7 @@ const props = withDefaults(defineProps<{
|
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* useNgeTemplate auto-loads the sibling .mjml file, compiles it with
|
|
49
|
-
* Handlebars, and
|
|
49
|
+
* Handlebars, and sets the render function \u2014 no <template> block needed.
|
|
50
50
|
* MJML components from components/ are registered automatically.
|
|
51
51
|
*/
|
|
52
52
|
useNgeTemplate('${templatePath}', props)
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -623,7 +623,7 @@ export default defineEventHandler(async (event) => {
|
|
|
623
623
|
const mjmlSource = readFileSync(join(emailsDir, '${emailPath}.mjml'), 'utf-8')
|
|
624
624
|
const compiledTemplate = Handlebars.compile(mjmlSource)
|
|
625
625
|
const mjmlString = compiledTemplate(templateData)
|
|
626
|
-
const { html, errors } = mjml2html(mjmlString)
|
|
626
|
+
const { html, errors } = await mjml2html(mjmlString)
|
|
627
627
|
|
|
628
628
|
if (errors && errors.length > 0) {
|
|
629
629
|
throw new Error('MJML compilation errors: ' + errors.map(e => e.formattedMessage).join('; '))
|
|
@@ -789,15 +789,18 @@ export function registerMjmlComponents(): void {
|
|
|
789
789
|
addTemplate({
|
|
790
790
|
filename: "nge/use-template.ts",
|
|
791
791
|
write: true,
|
|
792
|
-
getContents: () => `import {
|
|
793
|
-
import type {
|
|
792
|
+
getContents: () => `import { h, ref, watch, toRef, getCurrentInstance } from 'vue'
|
|
793
|
+
import type { Ref, VNode } from 'vue'
|
|
794
794
|
import Handlebars from 'handlebars'
|
|
795
795
|
import { registerMjmlComponents } from './register-components'
|
|
796
796
|
|
|
797
|
-
// Lazy-load mjml-browser only on the client to avoid "window is not defined" during SSR
|
|
798
|
-
|
|
797
|
+
// Lazy-load mjml-browser only on the client to avoid "window is not defined" during SSR.
|
|
798
|
+
// mjml-browser v5+ returns a Promise, so we store the convert function in a ref
|
|
799
|
+
// and resolve the HTML asynchronously via watchEffect.
|
|
800
|
+
type Mjml2Html = (mjml: string) => Promise<{ html: string; errors: unknown[] }>
|
|
801
|
+
const mjml2html: Ref<Mjml2Html | null> = ref(null)
|
|
799
802
|
if (import.meta.client) {
|
|
800
|
-
|
|
803
|
+
import('mjml-browser').then(m => { mjml2html.value = m.default })
|
|
801
804
|
}
|
|
802
805
|
|
|
803
806
|
const mjmlTemplates: Record<string, string> = import.meta.glob(
|
|
@@ -820,51 +823,56 @@ let _componentsRegistered = false
|
|
|
820
823
|
/**
|
|
821
824
|
* Load and render an MJML email template by name.
|
|
822
825
|
* Registers MJML components (Handlebars partials) automatically on first call.
|
|
823
|
-
* Sets the component's render function
|
|
826
|
+
* Sets the current component's render function \u2014 no <template> block needed.
|
|
824
827
|
*
|
|
825
828
|
* @param name - Template name relative to the emails directory (e.g. 'example', 'v1/test')
|
|
826
829
|
* @param props - Reactive props object from defineProps
|
|
827
|
-
* @returns ComputedRef<string> containing the rendered HTML
|
|
828
830
|
*/
|
|
829
|
-
export function useNgeTemplate(name: string, props: Record<string, unknown>):
|
|
831
|
+
export function useNgeTemplate(name: string, props: Record<string, unknown>): void {
|
|
830
832
|
if (!_componentsRegistered) {
|
|
831
833
|
registerMjmlComponents()
|
|
832
834
|
_componentsRegistered = true
|
|
833
835
|
}
|
|
834
836
|
|
|
837
|
+
const instance = getCurrentInstance()
|
|
838
|
+
const renderedHtml = ref('')
|
|
839
|
+
|
|
835
840
|
const source = templateMap[name]
|
|
836
841
|
if (!source) {
|
|
837
842
|
const available = Object.keys(templateMap).join(', ')
|
|
838
843
|
console.error(\`[nuxt-generation-emails] Template "\${name}" not found. Available: \${available}\`)
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
return fallback
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
const compiled = Handlebars.compile(source)
|
|
846
|
-
|
|
847
|
-
const renderedHtml = computed(() => {
|
|
848
|
-
// mjml-browser requires window \u2014 skip rendering during SSR
|
|
849
|
-
if (!mjml2html) return ''
|
|
850
|
-
try {
|
|
851
|
-
const mjmlString = compiled({ ...props })
|
|
852
|
-
const result = mjml2html(mjmlString)
|
|
853
|
-
return result.html
|
|
854
|
-
}
|
|
855
|
-
catch (e: unknown) {
|
|
856
|
-
console.error(\`[\${name}] Error rendering MJML:\`, e)
|
|
857
|
-
return \`<pre style="color:red;">\${e instanceof Error ? e.message : String(e)}\\n\${e instanceof Error ? e.stack : ''}</pre>\`
|
|
844
|
+
renderedHtml.value = \`<pre style="color:red;">Template "\${name}" not found</pre>\`
|
|
845
|
+
if (instance) {
|
|
846
|
+
instance.render = (): VNode => h('div', { innerHTML: renderedHtml.value })
|
|
858
847
|
}
|
|
859
|
-
|
|
848
|
+
return
|
|
849
|
+
}
|
|
860
850
|
|
|
861
|
-
// Set render function on the component instance so
|
|
862
|
-
const instance = getCurrentInstance()
|
|
851
|
+
// Set the render function on the component instance so Vue renders the HTML directly.
|
|
863
852
|
if (instance) {
|
|
864
|
-
instance.render = () => h('div', { innerHTML: renderedHtml.value })
|
|
853
|
+
instance.render = (): VNode => h('div', { innerHTML: renderedHtml.value })
|
|
865
854
|
}
|
|
866
855
|
|
|
867
|
-
|
|
856
|
+
const compiled = Handlebars.compile(source)
|
|
857
|
+
|
|
858
|
+
// mjml-browser v5 returns a Promise \u2014 use watch to resolve async results reactively.
|
|
859
|
+
// Tracks both the mjml2html loader ref AND all accessed props (via the Handlebars compile spread).
|
|
860
|
+
watch(
|
|
861
|
+
[mjml2html, toRef(() => ({ ...props }))],
|
|
862
|
+
async ([convert]) => {
|
|
863
|
+
if (!convert) { renderedHtml.value = ''; return }
|
|
864
|
+
try {
|
|
865
|
+
const mjmlString = compiled({ ...props })
|
|
866
|
+
const result = await convert(mjmlString)
|
|
867
|
+
renderedHtml.value = result.html
|
|
868
|
+
}
|
|
869
|
+
catch (e: unknown) {
|
|
870
|
+
console.error(\`[\${name}] Error rendering MJML:\`, e)
|
|
871
|
+
renderedHtml.value = \`<pre style="color:red;">\${e instanceof Error ? e.message : String(e)}\\n\${e instanceof Error ? e.stack : ''}</pre>\`
|
|
872
|
+
}
|
|
873
|
+
},
|
|
874
|
+
{ immediate: true, deep: true },
|
|
875
|
+
)
|
|
868
876
|
}
|
|
869
877
|
`
|
|
870
878
|
});
|
|
@@ -21,7 +21,7 @@ declare module 'mjml-browser' {
|
|
|
21
21
|
preprocessors?: Array<(xml: string) => string>
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function mjml2html(mjml: string, options?: MjmlOptions): MjmlResult
|
|
24
|
+
function mjml2html(mjml: string, options?: MjmlOptions): Promise<MjmlResult>
|
|
25
25
|
export default mjml2html
|
|
26
26
|
}
|
|
27
27
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-generation-emails",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
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": {
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"citty": "^0.2.1",
|
|
67
67
|
"consola": "^3.4.2",
|
|
68
68
|
"handlebars": "^4.7.8",
|
|
69
|
-
"mjml": "^
|
|
70
|
-
"mjml-browser": "^
|
|
69
|
+
"mjml": "^5.0.0-alpha.11",
|
|
70
|
+
"mjml-browser": "^5.0.0-alpha.11",
|
|
71
71
|
"pathe": "^2.0.3"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|