Releases: maizzle/framework
v6.0.0-rc.26
- fix(serve): alias culori to its ESM entry for Vite 8 dep optimizer cadc145
- build(deps): bump vite from 7.3.5 to 8.0.16 7014383
- build(deps): sync package-lock with vite 8 devtools transitive deps ecd135e
- fix: resolve TypeScript 6 typecheck errors a420abe
- build(deps): bump oxfmt from 0.35.0 to 0.53.0 4b44efe
- build(deps): bump typescript from 5.9.3 to 6.0.3 2b3034d
- test: cover computeContentBase common ancestor and parallel afterBuild warning d353b10
- fix(build): replace arrays instead of concatenating when merging worker config f1bd4b2
- fix(build): pass effective template config to afterRender and afterTransform hooks 8baa999
- fix(build): preserve directory structure for multi-root content and SFC plaintext destinations 89841de
- feat(build): parallel build across worker threads 69f03ca
- perf: dedup dev-server renders per save, lazy source panels ead901e
- build(deps): bump postcss-merge-longhand from 7.0.7 to 8.0.0 370faf0
- Merge pull request #1708 from maizzle/next f6f5f6c
v6.0.0-rc.25
- fix: normalize code-block wrapper and preserve whitespace !important c00b529
- chore: update tailwindcss 10e7a1c
- chore: update unplugin-vue-markdown 02b1bf9
- fix: drop .ts extension from useConfig import in Markdown e365de1
- chore: update unplugin-vue-components e1114dc
- chore: update markdown-exit dependency dac6269
- chore: update juice to stable v12 058b8ad
- test: cover component sources and config file loading d481ad0
- test: expand WithUrl coverage for srcset, params, and edge cases 8c9f411
- test: expand Row coverage for counting, width, and warnings e990401
- test: cover vnode edge cases in NoWidows dc0f1e5
- test: cover doctype context and boolean attrs in Html 830fcc1
- test: cover build config and static-copy branches cf6f573
- test: cover empty-style and embed paths in purgeCss 0a3d380
- test: cover codeBlockExtract and fill markdownExtract guards e21b29b
- test: cover renderer fonts, markdown, and invalidation paths e63aaa0
- test: cover render() invalid-input guards d8a678d
- test: full branch coverage for runTransformers pipeline 0326bdd
- test: cover juice-failure and codeBlocks paths in inlineCss 750e942
- test: expand coverage for columnWidth transformer 5397760
- test: cover detached link in inlineLink, drop dead guard 92015c4
- test: cover omitted-value rule in removeAttributes d80215e
- test: complete coverage for tailwindcss transformer e8e1eaf
- test: full coverage for cssBox utils f5d529f
- test: add coverage for tailwindComponent transformer 8516ae4
- test: complete coverage for msoPlaceholders 5a7c4d5
- test: cover base transformer edge cases, drop redundant guards 6b829be
- test: cover markdownExtract src and guard paths 530e21d
- feat: auto-derive Img width from nearest sized ancestor 1ec5e96
- test: cover unmapped attribute in attributeToStyle d9f4f5f
- test: complete coverage for addAttributes, drop dead guards 57f1792
- test: complete coverage for resolveProps, drop dead pass-3 loop 29117e1
- test: add full coverage for EventManager 99ce47f
- test: cover text-decoration-line rewrite in tailwindCleanup dc83d33
- test: complete coverage for CodeBlock slot handling 7047124
- test: cover class normalization in Img, drop dead branches d54d781
- test: complete coverage for Markdown component f41efca
- test: cover slots-object branch in Preheader e47d1e0
- test: complete coverage for QrCode component c348c46
- test: cover object-style serialization in Section d7d3cd6
- test: complete branch coverage for Vml component ba3bc57
- test: add coverage for components/utils helpers 86ae024
- fix: ts errors a4d967f
- fix: ts errors in markdown component a3b9f91
- refactor: layout component b5b4574
- refactor: hr component 0b82a39
- refactor: code components 23f78ad
- fix: add mso reset comment to body component 2efd727
- refactor: button component 4aa483d
- fix: inherit text styling on span in Text component 76a53bf
- chore: update skill 3a78824
- chore: update skill 731481f
- chore: add more inter weights to layout component c1f0f51
- fix: prevent duplicate css inlining on img component tag a3827f2
- chore: update dependencies 67d7c98
- chore: update skill 4da4da5
- fix: default Column to vertical-align middle ba42511
- chore: remove overlap component ce35552
- fix: use classes for component base styling fb15e16
v6.0.0-rc.24
- docs: cover slot fallbacks, loop vars, and script props in v5 conversion guide c920e2d
- fix: skip doctype output when config doctype is falsy 4516b0c
- fix: fill preview viewport when email is shorter than it 65bf9b3
- fix: support useConfig and composables in markdown templates 6ebd625
- perf(ui): render sidebar template icons via CSS mask d78298e
- fix: apply config.markdown to the Markdown component 72ac718
- feat: add useOutputPath() composable for per-template output path f7eeef1
v6.0.0-rc.23
- build(deps): use juice@next ad9d931
- chore: update dependencies 886672d
- style: convert multi-line // comments to /** */ blocks 6309bf7
- fix(dev-ui): reflect actual file extension in page title 72fd9bd
- feat(dev-ui): harmonize icon stroke/opacity, add Markdown icon for .md templates d13d345
- fix(dev-ui): drop postcss-safe-parser from browser bundle e994431
- chore: remove unused @types/js-beautify b79e45a
- chore(deps): replace deprecated lucide-vue-next with @lucide/vue a284359
- feat: vml component 6d5c2a4
- fix(useCurrentTemplate): make composable work in serve and across module graphs 3b45f6e
- fix: preserve yahoo: variant CSS and dedupe component class binding 3312648
- feat(img): add href prop with VML rect href and anchor wrapping 89cf98e
- feat: add support for amp4email e86ffd7
- feat(img): add alt to VML rect in cropped mode 0582a48
v6.0.0-rc.22
- docs(skills): document Img cropped mode 640523e
- fix(code-block): apply shiki theme bg to wrapping td 0c21898
- fix(inline-css): stop reformatting inline style attributes 10bc2cd
- feat(img): add aspect prop for cropped images with VML fallback 1d67243
- docs(skills): add v5 → v6 migration reference 35325a2
- docs(skills): tighten references, add missing composables 1418983
- docs(skills): sync usePreheader options with current API 9af9187
- docs(skills): sync COMPONENTS reference with current props 34bf8d5
- fix(serializer): re-encode < and > in text nodes 7c15f46
- fix: usePreheader output df6ce90
- chore: add height css on body component 1f89604
- test: add useCurrentTemplate tests 69be2ca
- feat(codeinline): opt-in shiki highlighting via theme prop 23a15c7
- feat: use shiki for CodeInline a9cd215
- refactor(text): default to mt-4 instead of m-0 my-4 42bd2b2
- refactor(container)!: drop msoWidth prop 68aa14b
- feat(column): sibling-aware width redistribution for auto cols e81561e
- test(container): cover MSO td bg-mirror and border-aware padding skip 8bf3192
- feat(section): auto-hoist padding and bg-color to MSO td f2ee59f
- fix(column): account for own border/padding, mirror to MSO td 2cadaa6
- fix(preheader): add back spaces prop 95ef872
- refactor(preheader): escape slot, auto-pad spaces to 200 chars 7b2a3e1
- refactor: rename safeClassNames transformer 34411d7
- refactor(transformers): string API for addAttributes/safeClassNames f543083
- chore: extract cli skill reference a672c86
- ci: update dependabot config d0818df
v6.0.0-rc.21
- test(vue): cover vue.plugins factory form and render isolation bfe34b5
- test(serve): cover watched-file matcher 9779dd3
- fix(serve): match watched files via project-relative paths 0652292
- feat(vue): support factory form for vue.plugins 06b4112
- feat(events)!: nest template param with path info 3448e96
- fix(tailwind): scope per-block CSS via source(none) 24c32e4
v6.0.0-rc.20
v6.0.0-rc.19
- chore: update skill f03c316
- refactor: spacer component styling 685f06a
- refactor: hr component styling f7e74d9
- chore: update skill a65dc7d
- refactor: minify transformer 3cd4402
- refactor: format transformer 04348ad
- refactor: entities transformer 0b5ad33
- refactor: urlQuery transformer f75143a
- refactor: base url transformer 5466382
- refactor: filters transformer dbbca94
- refactor: inlineLink transformer 19d813b
- refactor: removeAttributes transformer 42b6855
- refactor: attributeToStyle transformer 34a5400
- refactor: sixHex transformer 62b1955
- refactor: shorthandCss transformer 4bd78ec
- refactor: pascal case for inline api 7ca4d93
- refactor: purgeCss api 08aa967
- refactor: rename Vml component to OutlookBg b68e5c3
- refactor: accept html string in inline transformer api da96dcb
- refactor: hr component 953ba48
- fix: html component 4788b40
- fix: using inline CSS on Button 919ce6f
- refactor: button component 7ac66a5
- fix: minify config types 34164b4
- feat: plaintext components 396bc99
- build(deps): update dependencies b41c43a
- test: cover active renderer b69dc43
- feat: qr code component b6ca0c5
- ci: update node versions bc65ed5
- refactor: container component c1c652c
- fix(render): reuse serve()'s renderer in user-land render() calls aace1cc
- fix(render): never autoload host vite.config in SSR pipeline 69af806
- feat: doctype prop for html component e344aa6
- build(deps): update dependencies 6b4c6e6
- fix(serve): accept port option to override config 3461683
- revert: disable isolation in vitest d5715d0
- test: disable isolation to halve summed import cost 0332400
- test: split render.test.ts for parallel execution 4f4e60f
- chore: support passing options in usePlaintext composable 4a3c32a
- refactor: plaintext config a110329
v6.0.0-rc.18
Breaking changes
CSS inlining and purging now on by default
css.inline and css.purge now default to true. Most email projects will need them on anyway.
If your project relies on either being off, set them explicitly:
// maizzle.config.ts
export default defineConfig({
css: {
inline: false,
purge: false,
},
})Shorthand CSS and prettify also on by default
Same story for css.shorthand and html.format. Output is now compact (shorthand) and pretty-printed by default.
build() options flattened
The programmatic build() API used to take a wrapped options object:
// before
await build({ config: { css: { inline: true } } })
await build({ config: './my.config.ts' })Now it takes the config directly:
// after
await build({ css: { inline: true } })
await build('./my.config.ts')
await build() // loads maizzle.config.ts from cwd<Divider> renamed to <Hr>
Even if it's a <div> for compatibility reasons, it basically does what an <hr> does. Plus, API parity with React Email.
New features
Per-template transformer toggles
New useTransformers() composable lets you control the transformer pipeline from inside a single template, no need to touch maizzle.config.ts:
<script setup>
useTransformers(false)
</script>Or pass an object for granular control:
<script setup>
// Skip specific transformers for this template
useTransformers({ inlineCSS: false, prettify: false })
// Force-enable transformers that are off globally
useTransformers({ minify: true })
</script>The same shape is now accepted on the global config too:
export default defineConfig({
useTransformers: {
inlineCSS: false,
minify: true,
},
})Force-enable (true) only applies to boolean-driven transformers (inlineCSS, purgeCSS, prettify, minify, shorthandCSS, sixHex, safeClassNames, entities).
useBaseUrl() and useUrlQuery() composables
Set url.base and url.query from inside a single template:
<script setup>
useBaseUrl('https://cdn.example.com/emails/')
useUrlQuery({ utm_source: 'maizzle', utm_campaign: 'newsletter' })
</script>Layouts for Markdown templates
.md templates are now wrapped in a built-in MarkdownLayout automatically — you get a complete email document (<html>, <head>, MSO/VML fallback, body shell, plus a centered <Container class="max-w-xl">) without writing any boilerplate.
Choose a different layout via frontmatter:
---
layout: Layout
title: Welcome
---
# Hello!Set layout: false to opt out entirely. The whole frontmatter object is passed to the wrapping component as the :frontmatter prop, so custom layouts can read whatever you put in.
<Button> icon alt + Outlook spacing
<Button> got three new props:
iconAlt— alt text for the icon imagemsoPx— controls horizontal padding in old Outlook (asmso-font-widthpercentage on the spacer<i>elements)outlookFallback— toggle MSO/VML fallback markup off for this button
<Button href="#" icon="https://example.com/arrow.png" icon-alt="Arrow" :mso-px="200">
Continue
</Button><Container> MSO styling
<Container> got two new props:
msoStyle— inline CSS applied only to the MSO<td>(handy for Outlook-only padding)outlookFallback— same toggle as above
<Container mso-style="padding: 10px 20px">
...
</Container><Preheader> simplified
fillerCount and shyCount props were merged into a single spaces prop, and the filler character sequence was unified to  ͏ per repetition:
<Preheader :spaces="200">Short preview.</Preheader>Command palette improvements
- Email search now matches parent directory names too —
app/welcomematchesap w - Token search is order-independent —
welcome appfinds the same file asapp welcome - Result count shown in the footer
Fixed
useEvent()registered in.vueand.mdtemplates didn't actually fire — handlers are now collected during render and run alongside config-level handlersuseTransformers()composable was clobbering global config defaults instead of mergingMarkdownLayoutfailed when the user's project had nocomponents/directory — components are now imported explicitly<Layout>body's MSO XML block (<o:OfficeDocumentSettings>,<w:WordDocument>) is now preserved verbatim instead of being mangled by Vue's template parser.jsdist files are now emitted alongside.d.tsfiles
Changed
- Prettify is automatically skipped when
minifyis enabled — they cancel each other out, no point running both - MSO placeholder transformers (column widths, container widths, td styles) unified under a single pass
Full commits list:
- chore: update skill 2c7a78f
- perf: skip prettify when minify is enabled 4437560
- feat: useBaseUrl and useUrlQuery composables b3b44e7
- feat!: shorthand CSS and prettify on by default 853600b
- feat: useTransformers true keys force-enable transformers 1350acb
- fix: useTransformers composable dropping config defaults a6e086b
- feat!: inline CSS and purge by default 7d39219
- fix: emit .js dist files paired with .d.ts e7ee410
- feat: granular useTransformers toggle 48774f5
- refactor!: flatten build() options d019416
- chore: move @vitest/coverage-v8 to devDependencies d5cb610
- fix: explicit component imports in MarkdownLayout 8996aca
- refactor: unify mso placeholders transformers d4b9ae7
- refactor: container component bd5f57b
- fix: useEvent composable in templates a43edc8
- feat: add layout support for markdown templates 6a57364
- refactor: rename Divider component to Hr 4bf6a8c
- feat: useTransformers composable to disable pipeline per template d6e42c7
- refactor: Button component 5cbcf64
- feat: order-independent token search in command palette c47b538
- refactor: unify Preheader filler entities under
spacesprop 92d6fe0 - feat: show result count in command palette footer 5c67ad2
- fix: preserve Outlook XML markup verbatim in Layout body ab3ec36
- feat: match parent dirs in command palette email search 0fbc2ac
- fix: preserve Outlook XML block in Layout body 25aebf8
- chore: add jsdoc for outlookFallback prop ff842ec
v6.0.0-rc.17
New features
QR code in dev
Running maizzle serve --host or npm run dev -- --host with the official starter will show a QR code for the network URL, so you don't have to type it on your phone:
<Tailwind> component
Added this component to make it easier to migrate from React Email.
You just wrap it around anything inside the emaill body content and it outputs the <style> tag automatically in the <head>:
<template>
<Html>
<Head />
<Body>
<Tailwind>
<Container class="max-w-xl font-inter">
...
</Container>
</Tailwind>
</Body>
</Html>
</template>You need to include the <Head /> component when using it, and nesting <Tailwind> components ignores the nested ones, only the top-most will take effect.
By default, it uses import "@maizzle/tailwindcss"; to compile Tailwind, but you can provide your own via the config slot:
<template>
<Html>
<Head />
<Body>
<Tailwind>
+ <template #config>
+ import "@maizzle/tailwindcss";
+
+ /* ... add custom CSS? */
+ </template>
<Container class="max-w-xl font-inter">
...
</Container>
</Tailwind>
</Body>
</Html>
</template>Bundled @maizzle/tailwindcss
The framework now bundles our Tailwind CSS v4 config for HTML email, so you don't need to install it explicitly in your projects anymore.
Fixed
- fixed some
pnpmissues with component auto-imports - fixed the source code previews jumping when you saved a template
- fixed an issue where
<style embedwas not surviving css purging
Changed
- switching from HTML preview to source code previews is now instant, as they are prefetched in the background
Full commits list:
- fix: resolve component types in IDEs under pnpm 04293f7
- fix: resolve culori and postcss-safe-parser under pnpm 4a01c0f
- feat: add <Tailwind> component 08a8b6d
- feat: bundle @maizzle/tailwindcss 59fe17d
- fix: prevent jump in source views 5504878
- fix: prefetch source previews in background d52c86b
- refactor: render qr code before server info 725ed6f
- fix: preserving embedded style tags 6f9d22b
- chore: update row warning for missing columns afb1b1b
- feat: network url qr code bd51ecc
- chore: declare *.vue module shim for tsc b9a045c
- refactor: don't expose renderer bbd956a
- fix: using safeParser in purgecss transformer d64032a