@maizzle/framework 6.0.0-rc.25 → 6.0.0-rc.26

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/serve.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { resolveConfig } from "./config/index.js";
2
- import { runTransformers } from "./transformers/index.js";
3
2
  import { normalizeComponentSources } from "./utils/componentSources.js";
4
3
  import { createRenderer } from "./render/createRenderer.js";
4
+ import { runTransformers } from "./transformers/index.js";
5
5
  import { createPlaintext } from "./plaintext.js";
6
6
  import { stripForHtml, stripForPlaintext } from "./utils/output-markers.js";
7
7
  import { _setCurrentTemplate } from "./composables/useCurrentTemplate.js";
@@ -13,8 +13,8 @@ import { createWatchedFileMatcher } from "./utils/watchPaths.js";
13
13
  import { createRequire } from "node:module";
14
14
  import { readFileSync } from "node:fs";
15
15
  import { basename, dirname, parse, resolve } from "node:path";
16
- import { glob } from "tinyglobby";
17
16
  import { fileURLToPath } from "node:url";
17
+ import { glob } from "tinyglobby";
18
18
  import { createLogger, createServer } from "vite";
19
19
  import vue from "@vitejs/plugin-vue";
20
20
  import { renderUnicodeCompact } from "uqr";
@@ -30,6 +30,19 @@ const pkg = (name) => {
30
30
  return resolved.slice(0, idx + marker.length);
31
31
  };
32
32
  /**
33
+ * Resolve a package's ESM entry via its `exports` map. Aliasing to the
34
+ * package directory bypasses `exports` (it only keys off the bare name),
35
+ * so directory resolution can fall back to a UMD/CJS bundle — which Vite 8
36
+ * flags `needsInterop` and then default-imports, breaking ESM-only deps
37
+ * like culori (named exports, no default). Point the alias at the real
38
+ * ESM entry instead.
39
+ */
40
+ const pkgEsmEntry = (name) => {
41
+ const dir = pkg(name);
42
+ const pj = JSON.parse(readFileSync(resolve(dir, "package.json"), "utf-8"));
43
+ return resolve(dir, pj.exports?.["."]?.import ?? pj.module ?? pj.main);
44
+ };
45
+ /**
33
46
  * Start the Maizzle dev server.
34
47
  *
35
48
  * Creates two things:
@@ -73,6 +86,10 @@ async function serve(options = {}) {
73
86
  find: "vue",
74
87
  replacement: resolve(pkg("vue"), "dist/vue.runtime.esm-bundler.js")
75
88
  },
89
+ {
90
+ find: "culori",
91
+ replacement: pkgEsmEntry("culori")
92
+ },
76
93
  ...[
77
94
  "vue-router",
78
95
  "reka-ui",
@@ -81,8 +98,7 @@ async function serve(options = {}) {
81
98
  "@lucide/vue",
82
99
  "class-variance-authority",
83
100
  "clsx",
84
- "tailwind-merge",
85
- "culori"
101
+ "tailwind-merge"
86
102
  ].map((name) => ({
87
103
  find: name,
88
104
  replacement: pkg(name)
@@ -173,6 +189,7 @@ function maizzleDevPlugin(config, renderer, configInput) {
173
189
  server.watcher.on("add", async (file) => {
174
190
  if (isTemplateFile(file)) {
175
191
  await renderer.invalidateAll();
192
+ bumpGeneration();
176
193
  server.ws.send({
177
194
  type: "custom",
178
195
  event: "maizzle:templates-changed"
@@ -182,6 +199,7 @@ function maizzleDevPlugin(config, renderer, configInput) {
182
199
  server.watcher.on("unlink", async (file) => {
183
200
  if (isTemplateFile(file)) {
184
201
  await renderer.invalidateAll();
202
+ bumpGeneration();
185
203
  server.ws.send({
186
204
  type: "custom",
187
205
  event: "maizzle:templates-changed"
@@ -216,6 +234,7 @@ function maizzleDevPlugin(config, renderer, configInput) {
216
234
  * fresh content).
217
235
  */
218
236
  await renderer.invalidateAll();
237
+ bumpGeneration();
219
238
  if (isTemplateFile(file) || isWatchedFile(file)) server.ws.send({
220
239
  type: "custom",
221
240
  event: "maizzle:template-updated",
@@ -280,6 +299,46 @@ async function serveTemplateList(config, res) {
280
299
  res.end(JSON.stringify(data));
281
300
  }
282
301
  /**
302
+ * Render-result memo for the dev server. A single template save makes the
303
+ * browser fire several endpoint requests in parallel (render, source, stats,
304
+ * plaintext, email) that each need the same SSR render + transformer output.
305
+ * Keying the in-flight Promise by `${generation}:${path}` collapses those into
306
+ * one render and dedupes concurrent requests. The watcher bumps the generation
307
+ * (and clears the cache) on every file/config change, so results never go
308
+ * stale. Each endpoint applies its own tail step (doctype prepend, strip,
309
+ * highlight, …) on top of `rawHtml`, keeping output byte-identical.
310
+ */
311
+ let renderGeneration = 0;
312
+ const renderCache = /* @__PURE__ */ new Map();
313
+ function bumpGeneration() {
314
+ renderGeneration++;
315
+ renderCache.clear();
316
+ }
317
+ function getRendered(absolutePath, config, renderer) {
318
+ const key = `${renderGeneration}:${absolutePath}`;
319
+ let promise = renderCache.get(key);
320
+ if (!promise) {
321
+ promise = (async () => {
322
+ _setCurrentTemplate(parse(absolutePath));
323
+ try {
324
+ const rendered = await renderer.render(absolutePath, config);
325
+ const templateConfig = rendered.templateConfig;
326
+ const doctype = rendered.doctype ?? templateConfig.doctype ?? "<!DOCTYPE html>";
327
+ return {
328
+ rawHtml: await runTransformers(rendered.html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks),
329
+ doctype,
330
+ templateConfig,
331
+ rendered
332
+ };
333
+ } finally {
334
+ _setCurrentTemplate(void 0);
335
+ }
336
+ })();
337
+ renderCache.set(key, promise);
338
+ }
339
+ return promise;
340
+ }
341
+ /**
283
342
  * SSR render a .vue template using the Renderer (not the dev UI server).
284
343
  */
285
344
  async function serveRenderedTemplate(url, config, renderer, res) {
@@ -291,22 +350,15 @@ async function serveRenderedTemplate(url, config, renderer, res) {
291
350
  return;
292
351
  }
293
352
  const absolutePath = resolve(match);
294
- _setCurrentTemplate(parse(absolutePath));
295
353
  try {
296
- await renderer.invalidateAll();
297
- const rendered = await renderer.render(absolutePath, config);
298
- let html = rendered.html;
299
- const templateConfig = rendered.templateConfig;
300
- const doctype = rendered.doctype ?? templateConfig.doctype ?? "<!DOCTYPE html>";
301
- html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks);
354
+ const { rawHtml, doctype } = await getRendered(absolutePath, config, renderer);
355
+ let html = rawHtml;
302
356
  if (doctype) html = `${doctype}\n${html}`;
303
357
  res.setHeader("Content-Type", "text/html");
304
358
  res.end(stripForHtml(html));
305
359
  } catch (error) {
306
360
  res.statusCode = 500;
307
361
  res.end(`<pre>${error.stack || error.message}</pre>`);
308
- } finally {
309
- _setCurrentTemplate(void 0);
310
362
  }
311
363
  }
312
364
  let highlighter = null;
@@ -326,15 +378,9 @@ async function serveHighlightedSource(url, config, renderer, res) {
326
378
  return;
327
379
  }
328
380
  const absolutePath = resolve(match);
329
- _setCurrentTemplate(parse(absolutePath));
330
381
  try {
331
- await renderer.invalidateAll();
332
- const rendered = await renderer.render(absolutePath, config);
333
- let html = rendered.html;
334
- const templateConfig = rendered.templateConfig;
335
- const doctype = rendered.doctype ?? templateConfig.doctype ?? "<!DOCTYPE html>";
336
- html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks);
337
- html = stripForHtml(doctype ? `${doctype}\n${html}` : html);
382
+ const { rawHtml, doctype } = await getRendered(absolutePath, config, renderer);
383
+ const html = stripForHtml(doctype ? `${doctype}\n${rawHtml}` : rawHtml);
338
384
  const highlighted = (await getHighlighter()).codeToHtml(html, {
339
385
  lang: "html",
340
386
  theme: "laserwave",
@@ -347,8 +393,6 @@ async function serveHighlightedSource(url, config, renderer, res) {
347
393
  } catch (error) {
348
394
  res.statusCode = 500;
349
395
  res.end(`<pre>${error.stack || error.message}</pre>`);
350
- } finally {
351
- _setCurrentTemplate(void 0);
352
396
  }
353
397
  }
354
398
  async function serveVueSource(url, config, res) {
@@ -385,22 +429,14 @@ async function servePlaintext(url, config, renderer, res) {
385
429
  return;
386
430
  }
387
431
  const absolutePath = resolve(match);
388
- _setCurrentTemplate(parse(absolutePath));
389
432
  try {
390
- await renderer.invalidateAll();
391
- const rendered = await renderer.render(absolutePath, config);
392
- let html = rendered.html;
393
- const templateConfig = rendered.templateConfig;
394
- const doctype = rendered.doctype ?? templateConfig.doctype ?? "<!DOCTYPE html>";
395
- html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks);
396
- const plaintext = createPlaintext(stripForPlaintext(html));
433
+ const { rawHtml } = await getRendered(absolutePath, config, renderer);
434
+ const plaintext = createPlaintext(stripForPlaintext(rawHtml));
397
435
  res.setHeader("Content-Type", "text/plain");
398
436
  res.end(plaintext);
399
437
  } catch (error) {
400
438
  res.statusCode = 500;
401
439
  res.end(error.message);
402
- } finally {
403
- _setCurrentTemplate(void 0);
404
440
  }
405
441
  }
406
442
  function humanFileSize(bytes, si = false, dp = 2) {
@@ -433,15 +469,9 @@ async function serveStats(url, config, renderer, res) {
433
469
  return;
434
470
  }
435
471
  const absolutePath = resolve(match);
436
- _setCurrentTemplate(parse(absolutePath));
437
472
  try {
438
- await renderer.invalidateAll();
439
- const rendered = await renderer.render(absolutePath, config);
440
- let html = rendered.html;
441
- const templateConfig = rendered.templateConfig;
442
- const doctype = rendered.doctype ?? templateConfig.doctype ?? "<!DOCTYPE html>";
443
- html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks);
444
- html = stripForHtml(html);
473
+ const { rawHtml } = await getRendered(absolutePath, config, renderer);
474
+ const html = stripForHtml(rawHtml);
445
475
  const sizeBytes = Buffer.byteLength(html, "utf-8");
446
476
  const totalImages = (html.match(/<img\b[^>]*>/gi) || []).length + (html.match(/url\s*\([^)]+\)/gi) || []).length;
447
477
  const links = (html.match(/<a\b[^>]*href\s*=/gi) || []).length;
@@ -457,8 +487,6 @@ async function serveStats(url, config, renderer, res) {
457
487
  } catch (error) {
458
488
  res.statusCode = 500;
459
489
  res.end(JSON.stringify({ error: error.message }));
460
- } finally {
461
- _setCurrentTemplate(void 0);
462
490
  }
463
491
  }
464
492
  async function serveEmailEndpoint(url, req, res, config, renderer) {
@@ -494,15 +522,9 @@ async function serveEmailEndpoint(url, req, res, config, renderer) {
494
522
  return;
495
523
  }
496
524
  const absolutePath = resolve(match);
497
- _setCurrentTemplate(parse(absolutePath));
498
525
  try {
499
- await renderer.invalidateAll();
500
- const rendered = await renderer.render(absolutePath, config);
501
- let html = rendered.html;
502
- const templateConfig = rendered.templateConfig;
503
- const doctype = rendered.doctype ?? templateConfig.doctype ?? "<!DOCTYPE html>";
504
- html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks);
505
- if (doctype) html = `${doctype}\n${html}`;
526
+ const { rawHtml, doctype, templateConfig } = await getRendered(absolutePath, config, renderer);
527
+ let html = doctype ? `${doctype}\n${rawHtml}` : rawHtml;
506
528
  const text = createPlaintext(stripForPlaintext(html));
507
529
  html = stripForHtml(html);
508
530
  const result = await sendEmail({
@@ -519,8 +541,6 @@ async function serveEmailEndpoint(url, req, res, config, renderer) {
519
541
  success: false,
520
542
  message: error.message
521
543
  }));
522
- } finally {
523
- _setCurrentTemplate(void 0);
524
544
  }
525
545
  }
526
546
  function serveEmailConfig(config, res) {
package/dist/serve.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"serve.js","names":["parsePath"],"sources":["../src/serve.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { dirname, resolve, basename, parse as parsePath } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { createRequire } from 'node:module'\nimport { createServer, createLogger, type ViteDevServer } from 'vite'\nimport { renderUnicodeCompact } from 'uqr'\nimport vue from '@vitejs/plugin-vue'\nimport tailwindcss from '@tailwindcss/vite'\nimport { glob } from 'tinyglobby'\nimport { createHighlighter, type Highlighter } from 'shiki'\nimport { createPlaintext } from './plaintext.ts'\nimport { stripForHtml, stripForPlaintext } from './utils/output-markers.ts'\nimport { resolveConfig } from './config/index.ts'\nimport { runTransformers } from './transformers/index.ts'\nimport { createRenderer, type Renderer } from './render/createRenderer.ts'\nimport { _setCurrentTemplate } from './composables/useCurrentTemplate.ts'\nimport { setActiveRenderer } from './render/active.ts'\nimport { serveCompatibility } from './server/compatibility.ts'\nimport { serveLint } from './server/linter.ts'\nimport { sendEmail } from './server/email.ts'\nimport { normalizeComponentSources } from './utils/componentSources.ts'\nimport { createWatchedFileMatcher } from './utils/watchPaths.ts'\nimport type { MaizzleConfig } from './types/index.ts'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst devUIDir = resolve(__dirname, 'server/ui')\n\nconst require = createRequire(import.meta.url)\nconst pkg = (name: string) => {\n const resolved = require.resolve(name).replace(/\\\\/g, '/')\n const marker = `node_modules/${name}`\n const idx = resolved.lastIndexOf(marker)\n\n return resolved.slice(0, idx + marker.length)\n}\n\nexport interface ServeOptions {\n config?: Partial<MaizzleConfig> | string\n /** Override the dev server port (takes precedence over config.server.port) */\n port?: number\n /** Expose the server on the network (e.g. --host) */\n host?: boolean | string\n /** When true, suppresses the banner/URL output (used by the Vite plugin, which prints its own) */\n silent?: boolean\n}\n\n/**\n * Start the Maizzle dev server.\n *\n * Creates two things:\n * 1. A Vite dev server for the dev UI (sidebar + preview, with Vue + Tailwind for the UI itself)\n * 2. A Renderer instance for SSR rendering email templates\n *\n * Template rendering goes through the Renderer, not the Vite dev server.\n */\nexport async function serve(options: ServeOptions = {}) {\n const start = performance.now()\n\n let config = await resolveConfig(options.config)\n const port = options.port ?? config.server?.port ?? 3000\n\n // Create a renderer for SSR rendering email templates (with dts for dev)\n let renderer = await createRenderer({ dts: true, markdown: config.markdown, root: config.root, componentDirs: normalizeComponentSources(config.components?.source, process.cwd()), vite: config.vite })\n\n /**\n * Register so user-land render() calls reuse this renderer instead of\n * spinning up another Vite SSR server (which collides when the host\n * app is itself a Vite dev process — e.g. TanStack Start).\n */\n setActiveRenderer(renderer)\n\n const server = await createServer({\n configFile: false,\n plugins: [\n // Vue and Tailwind are only for the dev UI SPA, not for email templates\n vue(),\n tailwindcss(),\n maizzleDevPlugin(config, renderer, options.config),\n ],\n resolve: {\n dedupe: ['vue'],\n alias: [\n { find: '@', replacement: devUIDir },\n { find: 'vue', replacement: resolve(pkg('vue'), 'dist/vue.runtime.esm-bundler.js') },\n ...['vue-router', 'reka-ui', '@vueuse/core', '@vueuse/shared', '@lucide/vue', 'class-variance-authority', 'clsx', 'tailwind-merge', 'culori']\n .map(name => ({ find: name, replacement: pkg(name) })),\n ],\n },\n cacheDir: resolve(devUIDir, '.vite'),\n optimizeDeps: {\n noDiscovery: true,\n include: [\n 'vue',\n 'vue-router',\n '@lucide/vue',\n '@vueuse/core',\n '@vueuse/shared',\n 'reka-ui',\n 'class-variance-authority',\n 'clsx',\n 'tailwind-merge',\n 'culori',\n ],\n },\n server: {\n port,\n host: options.host,\n fs: {\n allow: [process.cwd(), config.root ?? process.cwd(), devUIDir, ...['vue', 'vue-router', 'reka-ui', '@vueuse/core', '@vueuse/shared', '@lucide/vue', 'class-variance-authority', 'clsx', 'tailwind-merge', 'culori'].map(pkg)],\n },\n },\n customLogger: customLogger(),\n })\n\n // Store renderer ref on server for cleanup\n const originalClose = server.close.bind(server)\n server.close = async () => {\n setActiveRenderer(null)\n await renderer.close()\n return originalClose()\n }\n\n await server.listen()\n\n const startupTime = Math.round(performance.now() - start)\n\n if (!options.silent) {\n printBanner(server, startupTime)\n }\n\n // Expose startup time so the plugin can print it later\n ; (server as any)._maizzleStartupTime = startupTime\n\n return server\n}\n\n/**\n * Internal Vite plugin that adds Maizzle middleware and file watching to the dev UI server.\n */\nfunction maizzleDevPlugin(\n config: MaizzleConfig,\n renderer: Renderer,\n configInput: Partial<MaizzleConfig> | string | undefined,\n) {\n return {\n name: 'maizzle:dev',\n enforce: 'pre' as const,\n\n hotUpdate: {\n order: 'pre' as const,\n handler({ file }: { file: string }) {\n /**\n * Prevent Tailwind/Vue from triggering a full reload for email template\n * files. Maizzle handles these via custom HMR events in the\n * watcher below.\n */\n if (isTemplateFile(file)) {\n return []\n }\n },\n },\n\n configureServer(server: ViteDevServer) {\n // File watching\n const defaultWatchPaths = [\n 'maizzle.config.js',\n 'maizzle.config.ts',\n 'tailwind.config.js',\n 'tailwind.config.ts',\n 'locales/**',\n ]\n\n const userWatchPaths = config.server?.watch ?? []\n const watchPaths = [...defaultWatchPaths, ...userWatchPaths]\n const isWatchedFile = createWatchedFileMatcher(watchPaths, config.root ?? process.cwd())\n\n for (const watchPath of watchPaths) {\n server.watcher.add(watchPath)\n }\n\n server.watcher.on('add', async (file) => {\n if (isTemplateFile(file)) {\n await renderer.invalidateAll()\n server.ws.send({ type: 'custom', event: 'maizzle:templates-changed' })\n }\n })\n\n server.watcher.on('unlink', async (file) => {\n if (isTemplateFile(file)) {\n await renderer.invalidateAll()\n server.ws.send({ type: 'custom', event: 'maizzle:templates-changed' })\n }\n })\n\n server.watcher.on('change', async (file) => {\n if (isWatchedFile(file)) {\n config = await resolveConfig(configInput)\n\n // Recreate the renderer so config changes (e.g. markdown.shikiTheme) take effect\n await renderer.close()\n renderer = await createRenderer({ dts: true, markdown: config.markdown, root: config.root, componentDirs: normalizeComponentSources(config.components?.source, process.cwd()), vite: config.vite })\n\n /**\n * Push UI-relevant config bits so the dev UI reacts to live edits\n * without a page reload. Uses the same shape as the initial\n * inject.\n */\n server.ws.send({ type: 'custom', event: 'maizzle:config-updated', data: buildUiConfig(config) })\n }\n\n /**\n * Invalidate all renderer modules so component and config changes\n * are picked up on the next render (Tailwind recompiles with\n * fresh content).\n */\n await renderer.invalidateAll()\n\n if (\n isTemplateFile(file)\n || isWatchedFile(file)\n ) {\n server.ws.send({ type: 'custom', event: 'maizzle:template-updated', data: { file } })\n }\n })\n\n // API middleware (before Vite's middleware)\n server.middlewares.use(async (req: any, res: any, next: any) => {\n const url = req.url || '/'\n\n if (url === '/__maizzle/templates') {\n return serveTemplateList(config, res)\n }\n\n if (url.startsWith('/__maizzle/render/')) {\n return await serveRenderedTemplate(url, config, renderer, res)\n }\n\n if (url.startsWith('/__maizzle/source/')) {\n return await serveHighlightedSource(url, config, renderer, res)\n }\n\n if (url.startsWith('/__maizzle/compatibility/')) {\n return await serveCompatibility(url, res, config, normalizeComponentSources(config.components?.source, process.cwd()))\n }\n\n if (url.startsWith('/__maizzle/lint/')) {\n return await serveLint(url, res, config, normalizeComponentSources(config.components?.source, process.cwd()))\n }\n\n if (url.startsWith('/__maizzle/vue-source/')) {\n return await serveVueSource(url, config, res)\n }\n\n if (url.startsWith('/__maizzle/plaintext/')) {\n return await servePlaintext(url, config, renderer, res)\n }\n\n if (url.startsWith('/__maizzle/stats/')) {\n return await serveStats(url, config, renderer, res)\n }\n\n if (url.startsWith('/__maizzle/email/') && req.method === 'POST') {\n return await serveEmailEndpoint(url, req, res, config, renderer)\n }\n\n if (url === '/__maizzle/email-config') {\n return serveEmailConfig(config, res)\n }\n\n next()\n })\n\n // Dev UI fallback (after Vite's middleware)\n return () => {\n server.middlewares.use(async (req: any, res: any, next: any) => {\n if (isNavigationRequest(req)) {\n return await serveDevUI(server, res, req.url || '/', config)\n }\n\n next()\n })\n }\n },\n }\n}\n\nfunction isTemplateFile(file: string): boolean {\n return (file.endsWith('.vue') || file.endsWith('.md')) && !file.includes('server/ui')\n}\n\nfunction isNavigationRequest(req: any): boolean {\n const accept = req.headers?.accept || ''\n return req.method === 'GET' && accept.includes('text/html')\n}\n\n/**\n * Shape exposed to the dev UI both at initial HTML load (as\n * `window.__MAIZZLE_CONFIG__`) and on the `maizzle:config-updated` HMR event.\n * Add UI-visible config bits here; consumers on both ends pick up automatically.\n */\nfunction buildUiConfig(config: MaizzleConfig) {\n return {\n checks: config.server?.checks ?? true,\n }\n}\n\nasync function serveDevUI(server: ViteDevServer, res: any, url: string, config: MaizzleConfig) {\n let indexHtml = readFileSync(resolve(devUIDir, 'index.html'), 'utf-8')\n\n indexHtml = indexHtml.replace('./main.ts', `/@fs/${resolve(devUIDir, 'main.ts')}`)\n indexHtml = indexHtml.replace('./favicon.svg', `/@fs/${resolve(devUIDir, 'favicon.svg')}`)\n\n const configScript = `<script>window.__MAIZZLE_CONFIG__ = ${JSON.stringify(buildUiConfig(config))};</script>`\n indexHtml = indexHtml.replace('</head>', `${configScript}</head>`)\n\n const transformed = await server.transformIndexHtml(url, indexHtml)\n\n res.setHeader('Content-Type', 'text/html')\n res.end(transformed)\n}\n\nasync function serveTemplateList(config: MaizzleConfig, res: any) {\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n\n const data = templates.map(t => ({\n name: basename(t).replace(/\\.(vue|md)$/, ''),\n path: t,\n href: '/' + t.replace(/\\.(vue|md)$/, ''),\n }))\n\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(data))\n}\n\n/**\n * SSR render a .vue template using the Renderer (not the dev UI server).\n */\nasync function serveRenderedTemplate(url: string, config: MaizzleConfig, renderer: Renderer, res: any) {\n const templateSlug = url.replace('/__maizzle/render/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end('Template not found')\n return\n }\n\n const absolutePath = resolve(match)\n _setCurrentTemplate(parsePath(absolutePath))\n\n try {\n // Invalidate all modules so template + component changes are picked up\n await renderer.invalidateAll()\n\n const rendered = await renderer.render(absolutePath, config)\n let html = rendered.html\n\n const templateConfig = rendered.templateConfig\n const doctype = rendered.doctype ?? templateConfig.doctype ?? '<!DOCTYPE html>'\n\n html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks)\n if (doctype) html = `${doctype}\\n${html}`\n\n res.setHeader('Content-Type', 'text/html')\n res.end(stripForHtml(html))\n } catch (error: any) {\n res.statusCode = 500\n res.end(`<pre>${error.stack || error.message}</pre>`)\n } finally {\n _setCurrentTemplate(undefined)\n }\n}\n\nlet highlighter: Highlighter | null = null\n\nasync function getHighlighter() {\n if (!highlighter) {\n highlighter = await createHighlighter({\n themes: ['laserwave'],\n langs: ['html', 'vue'],\n })\n }\n return highlighter\n}\n\nasync function serveHighlightedSource(url: string, config: MaizzleConfig, renderer: Renderer, res: any) {\n const templateSlug = url.replace('/__maizzle/source/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end('Template not found')\n return\n }\n\n const absolutePath = resolve(match)\n _setCurrentTemplate(parsePath(absolutePath))\n\n try {\n await renderer.invalidateAll()\n\n const rendered = await renderer.render(absolutePath, config)\n let html = rendered.html\n\n const templateConfig = rendered.templateConfig\n const doctype = rendered.doctype ?? templateConfig.doctype ?? '<!DOCTYPE html>'\n html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks)\n\n html = stripForHtml(doctype ? `${doctype}\\n${html}` : html)\n\n const hl = await getHighlighter()\n const highlighted = hl.codeToHtml(html, {\n lang: 'html',\n theme: 'laserwave',\n transformers: [{\n line(node, line) {\n node.properties['data-line'] = line\n },\n }],\n })\n\n res.setHeader('Content-Type', 'text/html')\n res.end(highlighted)\n } catch (error: any) {\n res.statusCode = 500\n res.end(`<pre>${error.stack || error.message}</pre>`)\n } finally {\n _setCurrentTemplate(undefined)\n }\n}\n\nasync function serveVueSource(url: string, config: MaizzleConfig, res: any) {\n const templateSlug = url.replace('/__maizzle/vue-source/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end('Template not found')\n return\n }\n\n try {\n const source = readFileSync(resolve(match), 'utf-8')\n const lang = match.endsWith('.md') ? 'html' : 'vue'\n\n const hl = await getHighlighter()\n const highlighted = hl.codeToHtml(source, {\n lang,\n theme: 'laserwave',\n transformers: [{\n line(node, line) {\n node.properties['data-line'] = line\n },\n }],\n })\n\n res.setHeader('Content-Type', 'text/html')\n res.end(highlighted)\n } catch (error: any) {\n res.statusCode = 500\n res.end(`<pre>${error.stack || error.message}</pre>`)\n }\n}\n\nasync function servePlaintext(url: string, config: MaizzleConfig, renderer: Renderer, res: any) {\n const templateSlug = url.replace('/__maizzle/plaintext/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end('Template not found')\n return\n }\n\n const absolutePath = resolve(match)\n _setCurrentTemplate(parsePath(absolutePath))\n\n try {\n await renderer.invalidateAll()\n\n const rendered = await renderer.render(absolutePath, config)\n let html = rendered.html\n const templateConfig = rendered.templateConfig\n const doctype = rendered.doctype ?? templateConfig.doctype ?? '<!DOCTYPE html>'\n html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks)\n\n const plaintext = createPlaintext(stripForPlaintext(html))\n\n res.setHeader('Content-Type', 'text/plain')\n res.end(plaintext)\n } catch (error: any) {\n res.statusCode = 500\n res.end(error.message)\n } finally {\n _setCurrentTemplate(undefined)\n }\n}\n\nfunction humanFileSize(bytes: number, si = false, dp = 2) {\n const threshold = si ? 1000 : 1024\n\n if (Math.abs(bytes) < threshold) {\n return bytes + ' B'\n }\n\n const units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n let u = -1\n const r = 10 ** dp\n\n do {\n bytes /= threshold\n ++u\n } while (Math.round(Math.abs(bytes) * r) / r >= threshold && u < units.length - 1)\n\n return bytes.toFixed(dp) + ' ' + units[u]\n}\n\nasync function serveStats(url: string, config: MaizzleConfig, renderer: Renderer, res: any) {\n const templateSlug = url.replace('/__maizzle/stats/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end(JSON.stringify({ error: 'Template not found' }))\n return\n }\n\n const absolutePath = resolve(match)\n _setCurrentTemplate(parsePath(absolutePath))\n\n try {\n await renderer.invalidateAll()\n\n const rendered = await renderer.render(absolutePath, config)\n let html = rendered.html\n const templateConfig = rendered.templateConfig\n const doctype = rendered.doctype ?? templateConfig.doctype ?? '<!DOCTYPE html>'\n html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks)\n html = stripForHtml(html)\n\n const sizeBytes = Buffer.byteLength(html, 'utf-8')\n\n // Count images: <img> tags and CSS background images\n const imgTags = (html.match(/<img\\b[^>]*>/gi) || []).length\n const bgImages = (html.match(/url\\s*\\([^)]+\\)/gi) || []).length\n const totalImages = imgTags + bgImages\n\n // Count links\n const links = (html.match(/<a\\b[^>]*href\\s*=/gi) || []).length\n\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({\n size: {\n bytes: sizeBytes,\n formatted: humanFileSize(sizeBytes),\n },\n images: totalImages,\n links,\n }))\n } catch (error: any) {\n res.statusCode = 500\n res.end(JSON.stringify({ error: error.message }))\n } finally {\n _setCurrentTemplate(undefined)\n }\n}\n\nasync function serveEmailEndpoint(url: string, req: any, res: any, config: MaizzleConfig, renderer: Renderer) {\n const templateSlug = url.replace('/__maizzle/email/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end(JSON.stringify({ success: false, message: 'Template not found' }))\n return\n }\n\n let body = ''\n for await (const chunk of req) body += chunk\n\n let payload: { to: string[]; subject: string }\n\n try {\n payload = JSON.parse(body)\n } catch {\n res.statusCode = 400\n res.end(JSON.stringify({ success: false, message: 'Invalid JSON' }))\n return\n }\n\n if (!payload.to?.length) {\n res.statusCode = 400\n res.end(JSON.stringify({ success: false, message: 'Missing recipients' }))\n return\n }\n\n const absolutePath = resolve(match)\n _setCurrentTemplate(parsePath(absolutePath))\n\n try {\n await renderer.invalidateAll()\n\n const rendered = await renderer.render(absolutePath, config)\n let html = rendered.html\n const templateConfig = rendered.templateConfig\n const doctype = rendered.doctype ?? templateConfig.doctype ?? '<!DOCTYPE html>'\n html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks)\n if (doctype) html = `${doctype}\\n${html}`\n\n const text = createPlaintext(stripForPlaintext(html))\n html = stripForHtml(html)\n\n const result = await sendEmail(\n { to: payload.to, subject: payload.subject, html, text },\n config,\n templateConfig,\n )\n\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(result))\n } catch (error: any) {\n res.statusCode = 500\n res.end(JSON.stringify({ success: false, message: error.message }))\n } finally {\n _setCurrentTemplate(undefined)\n }\n}\n\nfunction serveEmailConfig(config: MaizzleConfig, res: any) {\n const emailConfig = config.server?.email\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({\n to: emailConfig?.to ? (Array.isArray(emailConfig.to) ? emailConfig.to : [emailConfig.to]) : [],\n from: emailConfig?.from ?? '',\n subject: emailConfig?.subject ?? '',\n hasTransport: !!emailConfig?.transport,\n }))\n}\n\nexport function printBanner(server: ViteDevServer, startupTime?: number) {\n const info = server.config.logger.info\n const time = startupTime ?? (server as any)._maizzleStartupTime\n\n const networkUrl = server.resolvedUrls?.network[0]\n if (networkUrl) {\n const qr = renderUnicodeCompact(networkUrl, { border: 1 })\n info('')\n info(qr.split('\\n').map(line => ` ${line}`).join('\\n'))\n }\n\n info('')\n info(` \\x1b[32m\\x1b[1mMAIZZLE\\x1b[0m\\x1b[32m v6.0.0\\x1b[0m \\x1b[2mready in\\x1b[0m \\x1b[1m${time}\\x1b[0m ms`)\n info('')\n server.printUrls()\n info('')\n}\n\nfunction customLogger() {\n const logger = createLogger('info')\n const warn = logger.warn\n\n logger.warn = (message, options) => {\n if (typeof message === 'string' && message.includes('<tr> cannot be child of <table>')) {\n return\n }\n\n warn(message, options)\n }\n\n return logger\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"serve.js","names":["parsePath"],"sources":["../src/serve.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { dirname, resolve, basename, parse as parsePath } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { createRequire } from 'node:module'\nimport { createServer, createLogger, type ViteDevServer } from 'vite'\nimport { renderUnicodeCompact } from 'uqr'\nimport vue from '@vitejs/plugin-vue'\nimport tailwindcss from '@tailwindcss/vite'\nimport { glob } from 'tinyglobby'\nimport { createHighlighter, type Highlighter } from 'shiki'\nimport { createPlaintext } from './plaintext.ts'\nimport { stripForHtml, stripForPlaintext } from './utils/output-markers.ts'\nimport { resolveConfig } from './config/index.ts'\nimport { runTransformers } from './transformers/index.ts'\nimport { createRenderer, type Renderer, type RenderedTemplate } from './render/createRenderer.ts'\nimport { _setCurrentTemplate } from './composables/useCurrentTemplate.ts'\nimport { setActiveRenderer } from './render/active.ts'\nimport { serveCompatibility } from './server/compatibility.ts'\nimport { serveLint } from './server/linter.ts'\nimport { sendEmail } from './server/email.ts'\nimport { normalizeComponentSources } from './utils/componentSources.ts'\nimport { createWatchedFileMatcher } from './utils/watchPaths.ts'\nimport type { MaizzleConfig } from './types/index.ts'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst devUIDir = resolve(__dirname, 'server/ui')\n\nconst require = createRequire(import.meta.url)\nconst pkg = (name: string) => {\n const resolved = require.resolve(name).replace(/\\\\/g, '/')\n const marker = `node_modules/${name}`\n const idx = resolved.lastIndexOf(marker)\n\n return resolved.slice(0, idx + marker.length)\n}\n\n/**\n * Resolve a package's ESM entry via its `exports` map. Aliasing to the\n * package directory bypasses `exports` (it only keys off the bare name),\n * so directory resolution can fall back to a UMD/CJS bundle — which Vite 8\n * flags `needsInterop` and then default-imports, breaking ESM-only deps\n * like culori (named exports, no default). Point the alias at the real\n * ESM entry instead.\n */\nconst pkgEsmEntry = (name: string) => {\n const dir = pkg(name)\n const pj = JSON.parse(readFileSync(resolve(dir, 'package.json'), 'utf-8'))\n const entry = pj.exports?.['.']?.import ?? pj.module ?? pj.main\n return resolve(dir, entry)\n}\n\nexport interface ServeOptions {\n config?: Partial<MaizzleConfig> | string\n /** Override the dev server port (takes precedence over config.server.port) */\n port?: number\n /** Expose the server on the network (e.g. --host) */\n host?: boolean | string\n /** When true, suppresses the banner/URL output (used by the Vite plugin, which prints its own) */\n silent?: boolean\n}\n\n/**\n * Start the Maizzle dev server.\n *\n * Creates two things:\n * 1. A Vite dev server for the dev UI (sidebar + preview, with Vue + Tailwind for the UI itself)\n * 2. A Renderer instance for SSR rendering email templates\n *\n * Template rendering goes through the Renderer, not the Vite dev server.\n */\nexport async function serve(options: ServeOptions = {}) {\n const start = performance.now()\n\n let config = await resolveConfig(options.config)\n const port = options.port ?? config.server?.port ?? 3000\n\n // Create a renderer for SSR rendering email templates (with dts for dev)\n let renderer = await createRenderer({ dts: true, markdown: config.markdown, root: config.root, componentDirs: normalizeComponentSources(config.components?.source, process.cwd()), vite: config.vite })\n\n /**\n * Register so user-land render() calls reuse this renderer instead of\n * spinning up another Vite SSR server (which collides when the host\n * app is itself a Vite dev process — e.g. TanStack Start).\n */\n setActiveRenderer(renderer)\n\n const server = await createServer({\n configFile: false,\n plugins: [\n // Vue and Tailwind are only for the dev UI SPA, not for email templates\n vue(),\n tailwindcss(),\n maizzleDevPlugin(config, renderer, options.config),\n ],\n resolve: {\n dedupe: ['vue'],\n alias: [\n { find: '@', replacement: devUIDir },\n { find: 'vue', replacement: resolve(pkg('vue'), 'dist/vue.runtime.esm-bundler.js') },\n // culori is ESM-only — alias to its ESM entry, not the package dir (see pkgEsmEntry)\n { find: 'culori', replacement: pkgEsmEntry('culori') },\n ...['vue-router', 'reka-ui', '@vueuse/core', '@vueuse/shared', '@lucide/vue', 'class-variance-authority', 'clsx', 'tailwind-merge']\n .map(name => ({ find: name, replacement: pkg(name) })),\n ],\n },\n cacheDir: resolve(devUIDir, '.vite'),\n optimizeDeps: {\n noDiscovery: true,\n include: [\n 'vue',\n 'vue-router',\n '@lucide/vue',\n '@vueuse/core',\n '@vueuse/shared',\n 'reka-ui',\n 'class-variance-authority',\n 'clsx',\n 'tailwind-merge',\n 'culori',\n ],\n },\n server: {\n port,\n host: options.host,\n fs: {\n allow: [process.cwd(), config.root ?? process.cwd(), devUIDir, ...['vue', 'vue-router', 'reka-ui', '@vueuse/core', '@vueuse/shared', '@lucide/vue', 'class-variance-authority', 'clsx', 'tailwind-merge', 'culori'].map(pkg)],\n },\n },\n customLogger: customLogger(),\n })\n\n // Store renderer ref on server for cleanup\n const originalClose = server.close.bind(server)\n server.close = async () => {\n setActiveRenderer(null)\n await renderer.close()\n return originalClose()\n }\n\n await server.listen()\n\n const startupTime = Math.round(performance.now() - start)\n\n if (!options.silent) {\n printBanner(server, startupTime)\n }\n\n // Expose startup time so the plugin can print it later\n ; (server as any)._maizzleStartupTime = startupTime\n\n return server\n}\n\n/**\n * Internal Vite plugin that adds Maizzle middleware and file watching to the dev UI server.\n */\nfunction maizzleDevPlugin(\n config: MaizzleConfig,\n renderer: Renderer,\n configInput: Partial<MaizzleConfig> | string | undefined,\n) {\n return {\n name: 'maizzle:dev',\n enforce: 'pre' as const,\n\n hotUpdate: {\n order: 'pre' as const,\n handler({ file }: { file: string }) {\n /**\n * Prevent Tailwind/Vue from triggering a full reload for email template\n * files. Maizzle handles these via custom HMR events in the\n * watcher below.\n */\n if (isTemplateFile(file)) {\n return []\n }\n },\n },\n\n configureServer(server: ViteDevServer) {\n // File watching\n const defaultWatchPaths = [\n 'maizzle.config.js',\n 'maizzle.config.ts',\n 'tailwind.config.js',\n 'tailwind.config.ts',\n 'locales/**',\n ]\n\n const userWatchPaths = config.server?.watch ?? []\n const watchPaths = [...defaultWatchPaths, ...userWatchPaths]\n const isWatchedFile = createWatchedFileMatcher(watchPaths, config.root ?? process.cwd())\n\n for (const watchPath of watchPaths) {\n server.watcher.add(watchPath)\n }\n\n server.watcher.on('add', async (file) => {\n if (isTemplateFile(file)) {\n await renderer.invalidateAll()\n bumpGeneration()\n server.ws.send({ type: 'custom', event: 'maizzle:templates-changed' })\n }\n })\n\n server.watcher.on('unlink', async (file) => {\n if (isTemplateFile(file)) {\n await renderer.invalidateAll()\n bumpGeneration()\n server.ws.send({ type: 'custom', event: 'maizzle:templates-changed' })\n }\n })\n\n server.watcher.on('change', async (file) => {\n if (isWatchedFile(file)) {\n config = await resolveConfig(configInput)\n\n // Recreate the renderer so config changes (e.g. markdown.shikiTheme) take effect\n await renderer.close()\n renderer = await createRenderer({ dts: true, markdown: config.markdown, root: config.root, componentDirs: normalizeComponentSources(config.components?.source, process.cwd()), vite: config.vite })\n\n /**\n * Push UI-relevant config bits so the dev UI reacts to live edits\n * without a page reload. Uses the same shape as the initial\n * inject.\n */\n server.ws.send({ type: 'custom', event: 'maizzle:config-updated', data: buildUiConfig(config) })\n }\n\n /**\n * Invalidate all renderer modules so component and config changes\n * are picked up on the next render (Tailwind recompiles with\n * fresh content).\n */\n await renderer.invalidateAll()\n bumpGeneration()\n\n if (\n isTemplateFile(file)\n || isWatchedFile(file)\n ) {\n server.ws.send({ type: 'custom', event: 'maizzle:template-updated', data: { file } })\n }\n })\n\n // API middleware (before Vite's middleware)\n server.middlewares.use(async (req: any, res: any, next: any) => {\n const url = req.url || '/'\n\n if (url === '/__maizzle/templates') {\n return serveTemplateList(config, res)\n }\n\n if (url.startsWith('/__maizzle/render/')) {\n return await serveRenderedTemplate(url, config, renderer, res)\n }\n\n if (url.startsWith('/__maizzle/source/')) {\n return await serveHighlightedSource(url, config, renderer, res)\n }\n\n if (url.startsWith('/__maizzle/compatibility/')) {\n return await serveCompatibility(url, res, config, normalizeComponentSources(config.components?.source, process.cwd()))\n }\n\n if (url.startsWith('/__maizzle/lint/')) {\n return await serveLint(url, res, config, normalizeComponentSources(config.components?.source, process.cwd()))\n }\n\n if (url.startsWith('/__maizzle/vue-source/')) {\n return await serveVueSource(url, config, res)\n }\n\n if (url.startsWith('/__maizzle/plaintext/')) {\n return await servePlaintext(url, config, renderer, res)\n }\n\n if (url.startsWith('/__maizzle/stats/')) {\n return await serveStats(url, config, renderer, res)\n }\n\n if (url.startsWith('/__maizzle/email/') && req.method === 'POST') {\n return await serveEmailEndpoint(url, req, res, config, renderer)\n }\n\n if (url === '/__maizzle/email-config') {\n return serveEmailConfig(config, res)\n }\n\n next()\n })\n\n // Dev UI fallback (after Vite's middleware)\n return () => {\n server.middlewares.use(async (req: any, res: any, next: any) => {\n if (isNavigationRequest(req)) {\n return await serveDevUI(server, res, req.url || '/', config)\n }\n\n next()\n })\n }\n },\n }\n}\n\nfunction isTemplateFile(file: string): boolean {\n return (file.endsWith('.vue') || file.endsWith('.md')) && !file.includes('server/ui')\n}\n\nfunction isNavigationRequest(req: any): boolean {\n const accept = req.headers?.accept || ''\n return req.method === 'GET' && accept.includes('text/html')\n}\n\n/**\n * Shape exposed to the dev UI both at initial HTML load (as\n * `window.__MAIZZLE_CONFIG__`) and on the `maizzle:config-updated` HMR event.\n * Add UI-visible config bits here; consumers on both ends pick up automatically.\n */\nfunction buildUiConfig(config: MaizzleConfig) {\n return {\n checks: config.server?.checks ?? true,\n }\n}\n\nasync function serveDevUI(server: ViteDevServer, res: any, url: string, config: MaizzleConfig) {\n let indexHtml = readFileSync(resolve(devUIDir, 'index.html'), 'utf-8')\n\n indexHtml = indexHtml.replace('./main.ts', `/@fs/${resolve(devUIDir, 'main.ts')}`)\n indexHtml = indexHtml.replace('./favicon.svg', `/@fs/${resolve(devUIDir, 'favicon.svg')}`)\n\n const configScript = `<script>window.__MAIZZLE_CONFIG__ = ${JSON.stringify(buildUiConfig(config))};</script>`\n indexHtml = indexHtml.replace('</head>', `${configScript}</head>`)\n\n const transformed = await server.transformIndexHtml(url, indexHtml)\n\n res.setHeader('Content-Type', 'text/html')\n res.end(transformed)\n}\n\nasync function serveTemplateList(config: MaizzleConfig, res: any) {\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n\n const data = templates.map(t => ({\n name: basename(t).replace(/\\.(vue|md)$/, ''),\n path: t,\n href: '/' + t.replace(/\\.(vue|md)$/, ''),\n }))\n\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(data))\n}\n\ninterface DedupedRender {\n /** Transformer output — before doctype prepend / stripForHtml / stripForPlaintext. */\n rawHtml: string\n doctype: string\n templateConfig: MaizzleConfig\n rendered: RenderedTemplate\n}\n\n/**\n * Render-result memo for the dev server. A single template save makes the\n * browser fire several endpoint requests in parallel (render, source, stats,\n * plaintext, email) that each need the same SSR render + transformer output.\n * Keying the in-flight Promise by `${generation}:${path}` collapses those into\n * one render and dedupes concurrent requests. The watcher bumps the generation\n * (and clears the cache) on every file/config change, so results never go\n * stale. Each endpoint applies its own tail step (doctype prepend, strip,\n * highlight, …) on top of `rawHtml`, keeping output byte-identical.\n */\nlet renderGeneration = 0\nconst renderCache = new Map<string, Promise<DedupedRender>>()\n\nfunction bumpGeneration() {\n renderGeneration++\n renderCache.clear()\n}\n\nfunction getRendered(absolutePath: string, config: MaizzleConfig, renderer: Renderer): Promise<DedupedRender> {\n const key = `${renderGeneration}:${absolutePath}`\n let promise = renderCache.get(key)\n if (!promise) {\n promise = (async () => {\n _setCurrentTemplate(parsePath(absolutePath))\n try {\n const rendered = await renderer.render(absolutePath, config)\n const templateConfig = rendered.templateConfig\n const doctype = rendered.doctype ?? templateConfig.doctype ?? '<!DOCTYPE html>'\n const rawHtml = await runTransformers(rendered.html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks)\n return { rawHtml, doctype, templateConfig, rendered }\n } finally {\n _setCurrentTemplate(undefined)\n }\n })()\n renderCache.set(key, promise)\n }\n return promise\n}\n\n/**\n * SSR render a .vue template using the Renderer (not the dev UI server).\n */\nasync function serveRenderedTemplate(url: string, config: MaizzleConfig, renderer: Renderer, res: any) {\n const templateSlug = url.replace('/__maizzle/render/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end('Template not found')\n return\n }\n\n const absolutePath = resolve(match)\n\n try {\n const { rawHtml, doctype } = await getRendered(absolutePath, config, renderer)\n let html = rawHtml\n if (doctype) html = `${doctype}\\n${html}`\n\n res.setHeader('Content-Type', 'text/html')\n res.end(stripForHtml(html))\n } catch (error: any) {\n res.statusCode = 500\n res.end(`<pre>${error.stack || error.message}</pre>`)\n }\n}\n\nlet highlighter: Highlighter | null = null\n\nasync function getHighlighter() {\n if (!highlighter) {\n highlighter = await createHighlighter({\n themes: ['laserwave'],\n langs: ['html', 'vue'],\n })\n }\n return highlighter\n}\n\nasync function serveHighlightedSource(url: string, config: MaizzleConfig, renderer: Renderer, res: any) {\n const templateSlug = url.replace('/__maizzle/source/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end('Template not found')\n return\n }\n\n const absolutePath = resolve(match)\n\n try {\n const { rawHtml, doctype } = await getRendered(absolutePath, config, renderer)\n const html = stripForHtml(doctype ? `${doctype}\\n${rawHtml}` : rawHtml)\n\n const hl = await getHighlighter()\n const highlighted = hl.codeToHtml(html, {\n lang: 'html',\n theme: 'laserwave',\n transformers: [{\n line(node, line) {\n node.properties['data-line'] = line\n },\n }],\n })\n\n res.setHeader('Content-Type', 'text/html')\n res.end(highlighted)\n } catch (error: any) {\n res.statusCode = 500\n res.end(`<pre>${error.stack || error.message}</pre>`)\n }\n}\n\nasync function serveVueSource(url: string, config: MaizzleConfig, res: any) {\n const templateSlug = url.replace('/__maizzle/vue-source/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end('Template not found')\n return\n }\n\n try {\n const source = readFileSync(resolve(match), 'utf-8')\n const lang = match.endsWith('.md') ? 'html' : 'vue'\n\n const hl = await getHighlighter()\n const highlighted = hl.codeToHtml(source, {\n lang,\n theme: 'laserwave',\n transformers: [{\n line(node, line) {\n node.properties['data-line'] = line\n },\n }],\n })\n\n res.setHeader('Content-Type', 'text/html')\n res.end(highlighted)\n } catch (error: any) {\n res.statusCode = 500\n res.end(`<pre>${error.stack || error.message}</pre>`)\n }\n}\n\nasync function servePlaintext(url: string, config: MaizzleConfig, renderer: Renderer, res: any) {\n const templateSlug = url.replace('/__maizzle/plaintext/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end('Template not found')\n return\n }\n\n const absolutePath = resolve(match)\n\n try {\n const { rawHtml } = await getRendered(absolutePath, config, renderer)\n const plaintext = createPlaintext(stripForPlaintext(rawHtml))\n\n res.setHeader('Content-Type', 'text/plain')\n res.end(plaintext)\n } catch (error: any) {\n res.statusCode = 500\n res.end(error.message)\n }\n}\n\nfunction humanFileSize(bytes: number, si = false, dp = 2) {\n const threshold = si ? 1000 : 1024\n\n if (Math.abs(bytes) < threshold) {\n return bytes + ' B'\n }\n\n const units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n let u = -1\n const r = 10 ** dp\n\n do {\n bytes /= threshold\n ++u\n } while (Math.round(Math.abs(bytes) * r) / r >= threshold && u < units.length - 1)\n\n return bytes.toFixed(dp) + ' ' + units[u]\n}\n\nasync function serveStats(url: string, config: MaizzleConfig, renderer: Renderer, res: any) {\n const templateSlug = url.replace('/__maizzle/stats/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end(JSON.stringify({ error: 'Template not found' }))\n return\n }\n\n const absolutePath = resolve(match)\n\n try {\n const { rawHtml } = await getRendered(absolutePath, config, renderer)\n const html = stripForHtml(rawHtml)\n\n const sizeBytes = Buffer.byteLength(html, 'utf-8')\n\n // Count images: <img> tags and CSS background images\n const imgTags = (html.match(/<img\\b[^>]*>/gi) || []).length\n const bgImages = (html.match(/url\\s*\\([^)]+\\)/gi) || []).length\n const totalImages = imgTags + bgImages\n\n // Count links\n const links = (html.match(/<a\\b[^>]*href\\s*=/gi) || []).length\n\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({\n size: {\n bytes: sizeBytes,\n formatted: humanFileSize(sizeBytes),\n },\n images: totalImages,\n links,\n }))\n } catch (error: any) {\n res.statusCode = 500\n res.end(JSON.stringify({ error: error.message }))\n }\n}\n\nasync function serveEmailEndpoint(url: string, req: any, res: any, config: MaizzleConfig, renderer: Renderer) {\n const templateSlug = url.replace('/__maizzle/email/', '').replace(/\\?.*$/, '')\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const templates = await glob(contentPatterns)\n const match = templates.find(t => t.replace(/\\.(vue|md)$/, '') === templateSlug)\n\n if (!match) {\n res.statusCode = 404\n res.end(JSON.stringify({ success: false, message: 'Template not found' }))\n return\n }\n\n let body = ''\n for await (const chunk of req) body += chunk\n\n let payload: { to: string[]; subject: string }\n\n try {\n payload = JSON.parse(body)\n } catch {\n res.statusCode = 400\n res.end(JSON.stringify({ success: false, message: 'Invalid JSON' }))\n return\n }\n\n if (!payload.to?.length) {\n res.statusCode = 400\n res.end(JSON.stringify({ success: false, message: 'Missing recipients' }))\n return\n }\n\n const absolutePath = resolve(match)\n\n try {\n const { rawHtml, doctype, templateConfig } = await getRendered(absolutePath, config, renderer)\n let html = doctype ? `${doctype}\\n${rawHtml}` : rawHtml\n\n const text = createPlaintext(stripForPlaintext(html))\n html = stripForHtml(html)\n\n const result = await sendEmail(\n { to: payload.to, subject: payload.subject, html, text },\n config,\n templateConfig,\n )\n\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(result))\n } catch (error: any) {\n res.statusCode = 500\n res.end(JSON.stringify({ success: false, message: error.message }))\n }\n}\n\nfunction serveEmailConfig(config: MaizzleConfig, res: any) {\n const emailConfig = config.server?.email\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({\n to: emailConfig?.to ? (Array.isArray(emailConfig.to) ? emailConfig.to : [emailConfig.to]) : [],\n from: emailConfig?.from ?? '',\n subject: emailConfig?.subject ?? '',\n hasTransport: !!emailConfig?.transport,\n }))\n}\n\nexport function printBanner(server: ViteDevServer, startupTime?: number) {\n const info = server.config.logger.info\n const time = startupTime ?? (server as any)._maizzleStartupTime\n\n const networkUrl = server.resolvedUrls?.network[0]\n if (networkUrl) {\n const qr = renderUnicodeCompact(networkUrl, { border: 1 })\n info('')\n info(qr.split('\\n').map(line => ` ${line}`).join('\\n'))\n }\n\n info('')\n info(` \\x1b[32m\\x1b[1mMAIZZLE\\x1b[0m\\x1b[32m v6.0.0\\x1b[0m \\x1b[2mready in\\x1b[0m \\x1b[1m${time}\\x1b[0m ms`)\n info('')\n server.printUrls()\n info('')\n}\n\nfunction customLogger() {\n const logger = createLogger('info')\n const warn = logger.warn\n\n logger.warn = (message, options) => {\n if (typeof message === 'string' && message.includes('<tr> cannot be child of <table>')) {\n return\n }\n\n warn(message, options)\n }\n\n return logger\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { componentNameFromPath } from "../utils/componentSources.js";
2
2
  import { existsSync } from "node:fs";
3
3
  import { dirname, resolve } from "node:path";
4
- import { glob } from "tinyglobby";
5
4
  import { fileURLToPath } from "node:url";
5
+ import { glob } from "tinyglobby";
6
6
  //#region src/server/sfc-utils.ts
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
8
  /**
@@ -53,6 +53,25 @@ const plaintextContent = ref('')
53
53
  const sourceView = ref<'compiled' | 'vue' | 'plaintext'>('compiled')
54
54
  const copied = ref(false)
55
55
 
56
+ /**
57
+ * Source views (Compiled HTML, Vue source, Plaintext) refresh lazily. On a
58
+ * save we only refetch the view currently on screen and bump
59
+ * `sourcesGeneration` to mark the others stale. Switching to a stale view
60
+ * keeps its previous content visible while a background refetch replaces it
61
+ * in place — so panels never flash empty. Each fetch stamps the generation
62
+ * it was initiated at so a save mid-fetch correctly leaves the view stale.
63
+ */
64
+ const sourcesGeneration = ref(0)
65
+ const compiledGen = ref(-1)
66
+ const vueGen = ref(-1)
67
+ const plaintextGen = ref(-1)
68
+
69
+ function refreshSourceView(view: 'compiled' | 'vue' | 'plaintext') {
70
+ if (view === 'compiled' && (!sourceHtml.value || compiledGen.value < sourcesGeneration.value)) fetchSource()
71
+ if (view === 'vue' && (!vueSourceHtml.value || vueGen.value < sourcesGeneration.value)) fetchVueSource()
72
+ if (view === 'plaintext' && (!plaintextContent.value || plaintextGen.value < sourcesGeneration.value)) fetchPlaintext()
73
+ }
74
+
56
75
  const iframeEl = ref<HTMLIFrameElement>()
57
76
  const compiledSourceEl = ref<HTMLElement>()
58
77
  const vueSourceEl = ref<HTMLElement>()
@@ -300,9 +319,11 @@ const plaintextLoading = ref(false)
300
319
  async function fetchSource() {
301
320
  if (sourceLoading.value) return
302
321
  sourceLoading.value = true
322
+ const gen = sourcesGeneration.value
303
323
  try {
304
324
  const res = await fetch(`/__maizzle/source/${route.params.template}`)
305
325
  sourceHtml.value = await res.text()
326
+ compiledGen.value = gen
306
327
  } finally {
307
328
  sourceLoading.value = false
308
329
  }
@@ -311,9 +332,11 @@ async function fetchSource() {
311
332
  async function fetchVueSource() {
312
333
  if (vueSourceLoading.value) return
313
334
  vueSourceLoading.value = true
335
+ const gen = sourcesGeneration.value
314
336
  try {
315
337
  const res = await fetch(`/__maizzle/vue-source/${route.params.template}`)
316
338
  vueSourceHtml.value = await res.text()
339
+ vueGen.value = gen
317
340
  } finally {
318
341
  vueSourceLoading.value = false
319
342
  }
@@ -322,9 +345,11 @@ async function fetchVueSource() {
322
345
  async function fetchPlaintext() {
323
346
  if (plaintextLoading.value) return
324
347
  plaintextLoading.value = true
348
+ const gen = sourcesGeneration.value
325
349
  try {
326
350
  const res = await fetch(`/__maizzle/plaintext/${route.params.template}`)
327
351
  plaintextContent.value = await res.text()
352
+ plaintextGen.value = gen
328
353
  } finally {
329
354
  plaintextLoading.value = false
330
355
  }
@@ -430,17 +455,11 @@ watch(() => props.templates, (templates) => {
430
455
  })
431
456
 
432
457
  watch(viewMode, (mode) => {
433
- if (mode === 'source') {
434
- if (sourceView.value === 'compiled' && !sourceHtml.value) fetchSource()
435
- if (sourceView.value === 'vue' && !vueSourceHtml.value) fetchVueSource()
436
- if (sourceView.value === 'plaintext' && !plaintextContent.value) fetchPlaintext()
437
- }
458
+ if (mode === 'source') refreshSourceView(sourceView.value)
438
459
  })
439
460
 
440
461
  watch(sourceView, (view) => {
441
- if (view === 'vue' && !vueSourceHtml.value) fetchVueSource()
442
- if (view === 'compiled' && !sourceHtml.value) fetchSource()
443
- if (view === 'plaintext' && !plaintextContent.value) fetchPlaintext()
462
+ refreshSourceView(view)
444
463
  })
445
464
 
446
465
  /**
@@ -482,11 +501,15 @@ if ((import.meta as any).hot) {
482
501
  * long as the new content's height is similar. Plaintext
483
502
  * interpolation updates a single text node, so scroll
484
503
  * is naturally preserved.
504
+ *
505
+ * Only the preview iframe and the currently-visible source view
506
+ * refresh eagerly; hidden source views are marked stale (via the
507
+ * generation bump) and refresh on next switch, keeping their old
508
+ * content on screen until then so panels never flash empty.
485
509
  */
486
510
  fetchTemplate()
487
- fetchSource()
488
- fetchVueSource()
489
- fetchPlaintext()
511
+ sourcesGeneration.value++
512
+ if (viewMode.value === 'source') refreshSourceView(sourceView.value)
490
513
  })
491
514
 
492
515
  /**
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -1,8 +1,8 @@
1
1
  import { RemoveValue } from "../plugins/postcss/removeDeclarations.js";
2
2
  import { TemplateInfo } from "../events/index.js";
3
3
  import { Directive, Plugin } from "vue";
4
- import juice from "juice";
5
4
  import { InlineConfig } from "vite";
5
+ import juice from "juice";
6
6
  import { Options } from "unplugin-vue-markdown/types";
7
7
 
8
8
  //#region src/types/config.d.ts
@@ -519,6 +519,27 @@ interface MaizzleConfig {
519
519
  */
520
520
  extension?: string;
521
521
  };
522
+ /**
523
+ * Build templates in parallel across worker threads.
524
+ *
525
+ * - omitted (default): parallel when there are more than 50 templates
526
+ * - `true`: always parallel, using min(CPU count − 1, 8) workers
527
+ * - `false`: always sequential
528
+ * - `{ workers, threshold }`: parallel when the template count exceeds
529
+ * `threshold` (default 50), using `workers` threads (default
530
+ * min(CPU count − 1, 8)). Set `threshold: 0` to always parallelize.
531
+ *
532
+ * Note: more workers is not faster — each runs a full renderer, so ~8 is the
533
+ * sweet spot and over-provisioning slows builds down.
534
+ *
535
+ * Only applies to file-based configs (the CLI / a config path); an inline
536
+ * config object always builds sequentially. SFC-registered `afterBuild`
537
+ * handlers can't run in a worker — use the config `afterBuild` hook instead.
538
+ */
539
+ parallel?: boolean | {
540
+ workers?: number;
541
+ threshold?: number;
542
+ };
522
543
  /** Static file copying configuration. */
523
544
  static?: {
524
545
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","names":[],"sources":["../../src/types/config.ts"],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","names":[],"sources":["../../src/types/config.ts"],"mappings":";;;;;;;;KAKK,YAAA,GAAe,WAAA,CAAY,UAAA,QAAkB,KAAA;AAAA,UAGjC,eAAA;;AALa;;;;EAW5B,IAAA;EATkB;;;;;EAelB,UAAA;EAfqD;AAAA;AAGvD;;;EAkBE,MAAA;EAZA;;;;;EAkBA,EAAA,GAAK,MAAM;AAAA;AAAA,KAGD,QAAA,GAAW,MAAA;EACrB,QAAA,GAAW,eAAe;AAAA;AAAA,UAGX,SAAA;EAJM;;;;AACK;AAG5B;;;;;;EAYE,KAAA,GAAQ,QAAA;EAiBa;;;;;;;;;;EANrB,IAAA;IAQE,+BANA,GAAA,WAQS;IANT,IAAA,cAAkB,MAAA,SAAe,MAAA,6BAUpB;IARb,UAAA,GAAa,MAAA,kBAQS;IANtB,QAAA,YAkCiB;IAhCjB,SAAA;EAAA;AAAA;AAAA,UAIa,SAAA;EA2JM;;;;;EArJrB,IAAA;EAsBA;;;;;;;EAdA,KAAA,aAAkB,MAAA;EA4DhB;;;;;;;;;;;;;EA9CF,MAAA,aAAmB,YAAA;IA4GnB;;;;;;IArGE,gBAAA;IAqIK;AAAA;AAGT;;;IAlII,oBAAA;IAoJY;;;;;;IA7IZ,QAAA;IA6ImC;;;;;;;AAsB0B;AAGjE;;;IA1JI,gBAAA,GAAmB,MAAA;IA0JsB;AAO7C;;;;AAA2B;IA1JvB,aAAA;IAiKyB;;;;;;IA1JzB,cAAA;IAwKG;AAGP;;;;AAsBe;IA1LX,kBAAA;IA6LuB;;;;;;IAtLvB,UAAA,GAAa,MAAA;MAAiB,KAAA;MAAe,GAAA;IAAA;IAgM9B;;;;IA3Lf,SAAA;EAAA;EA0MkD;AAAA;AAGtD;;;;AAAwD;AACxD;;;;AAAiE;EAhM/D,KAAA;IAkM8B;;;;;IA5L5B,IAAA,wCAA4C,CAAA,UAAW,CAAA;EAAA;EAkMhB;AAG3C;;;;;;EA5LE,cAAA;EAyMmB;;;;;EAnMnB,IAAA,aAAiB,MAAA;EAiMjB;;;;;;AAEyB;EA3LzB,SAAA;IAAwB,IAAA;EAAA;EAgNS;;;;;;;EAxMjC,MAAA;EAgNA;;;;;;;;;AAOM;EA5MN,kBAAA,GAAqB,MAAA,SA3BE,WAAA;EAgPO;;;;;;;;;AAiBoB;AAapD;;EAtOE,OAAA;AAAA;AAAA,UAGe,gBAAA;EA4Ob;;;AASU;AAGd;;;;;;;;;;;;;EAtOE,GAAA,WAAc,MAAA,iBAAuB,MAAA;EAgc/B;;;;;;;;;;;;;;;;;;;;;EA1aN,MAAA,GAAS,KAAA;IAAiB,IAAA;IAAc,KAAA,YAAiB,MAAA;EAAA;AAAA;AAAA,KAG/C,cAAA,aAA2B,MAAM;;;;;;KAOjC,eAAA;AAAA,UAOK,YAAA;EAmSJ;;;;;EA7RX,OAAA,GAAU,eAAe;EAuUrB;;;;;;;EA/TJ,KAAA;AAAA;AAAA,UAGe,aAAA;EAmWO;;;;;;;;;;EAxVtB,eAAA;EA+XA;;;;;;;;;;EApXA,aAAa;AAAA;AAAA,UAGE,UAAA;EAqZmB;EAnZlC,UAAA,GAAa,gBAAA;EAmZ8C;;;;;;;EA3Y3D,cAAA,GAAiB,cAAA;EA6YuD;;;;;EAvYxE,MAAA,6BAAmC,aAAA;EAyYgB;;;;;;;;EAhYnD,MAAA,aAAmB,OAAA,sBAA6B,IAAA;AAAA;AAAA,KAGtC,cAAA,IAAkB,GAAA,UAAa,KAAa;AAAA,KAC5C,aAAA,WAAwB,MAAM,SAAS,cAAA;AAAA,UAElC,cAAA,SAAuB,OAAqB;EA+X/C;;;;;EAzXZ,UAAA,mBAA6B,YAAA;AAAA;AAAA,UAGd,SAAA;;;;;;;;;EASf,OAAA,GAAU,MAAA,YAAkB,MAAA;;EAE5B,UAAA,GAAa,MAAA,SAAe,SAAA;;EAE5B,gBAAA,GAAmB,MAAA;AAAA;;;;;;;;;;;;;;;;;;;UAqBJ,kBAAA;EACf,aAAA;EACA,gBAAA;EACA,SAAA;EACA,gBAAA;EACA,YAAA;EACA,MAAA;EACA,aAAA;EACA,OAAA;EACA,OAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA;EACA,cAAA;EACA,QAAA;EACA,MAAA;AAAA;;;;;;;UASe,eAAA;;;;;EAKf,WAAA;;;;;;EAMA,SAAA;;;;;;EAMA,OAAA,GAAU,OAAO,6BAA6B,IAAA;AAAA;;;;;;;;;;;KAapC,eAAA;uDAIR,IAAA;;;;;EAKA,MAAA;;;;;;;;;EASA,UAAA;AAAA;AAAA,UAGa,aAAA;;;;;;;;;;;;;;;EAef,IAAA;;EAEA,QAAA,GAAW,cAAA;;;;;;;;EAQX,OAAA;;EAEA,MAAA;;;;;;IAME,IAAA;;;;;;;;;;;IAWA,SAAA;EAAA;;;;;;;;;;;;;;;;;;EAmBF,QAAA;IAAuB,OAAA;IAAkB,SAAA;EAAA;;EAEzC,MAAA;;;;;;IAME,MAAA;;;;;;IAMA,WAAA;EAAA;;EAGF,UAAA;;;;;;;;;;;;;;;;;;;;IAoBE,MAAA,GAAS,eAAA,GAAkB,eAAA;EAAA;;EAG7B,MAAA;;;;;;IAME,IAAA;;;;;;;;;;;IAWA,KAAA;;;;;;;;;;;;;;;;;;;;IAoBA,KAAA;kCAEE,EAAA;MAEA,IAAA;MAEA,OAAA;MAEA,SAAA,GAAY,MAAA;IAAA;;;;;;;;;;;;;;IAed,MAAA,WAAiB,YAAA;EAAA;;EAGnB,GAAA,GAAM,SAAA;;;;;;;;;;;;;;;EAeN,SAAA,aAAsB,eAAA;;EAEtB,OAAA,GAAU,aAAA;;;;;;;;;;;;EAYV,eAAA,aAA4B,kBAAA;;;;;;;;;EAS5B,cAAA,GAAiB,MAAA;;;;;;;;;;;;EAYjB,OAAA,GAAU,aAAA;;EAEV,GAAA,GAAM,SAAA;;EAEN,IAAA,GAAO,UAAA;;;;;;;;;;;;;EAaP,IAAA,GAAO,YAAA;;;;;;;;;;;;;;;;EAgBP,GAAA,GAAM,SAAA;;EAKN,YAAA,IAAgB,MAAA;IAAU,MAAA,EAAQ,aAAA;EAAA,aAA2B,OAAA;;EAE7D,YAAA,IAAgB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;EAAA,sBAAmC,OAAA;;EAE9F,WAAA,IAAe,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;IAAc,IAAA;EAAA,sBAAmC,OAAA;;EAE3G,cAAA,IAAkB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;IAAc,IAAA;EAAA,sBAAmC,OAAA;;EAE9G,UAAA,IAAc,MAAA;IAAU,KAAA;IAAiB,MAAA,EAAQ,aAAA;EAAA,aAA2B,OAAA;EAAA,CAG3E,GAAA;AAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maizzle/framework",
3
- "version": "6.0.0-rc.25",
3
+ "version": "6.0.0-rc.26",
4
4
  "description": "Maizzle is a framework that helps you quickly build HTML emails with Tailwind CSS.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -58,10 +58,10 @@
58
58
  "markdown-exit": "^1.1.0-beta.2",
59
59
  "nodemailer": "^8.0.5",
60
60
  "ora": "^9.3.0",
61
- "oxfmt": "^0.35.0",
61
+ "oxfmt": "^0.53.0",
62
62
  "postcss": "^8.5.6",
63
63
  "postcss-calc": "^10.1.1",
64
- "postcss-merge-longhand": "^7.0.5",
64
+ "postcss-merge-longhand": "^8.0.0",
65
65
  "postcss-safe-parser": "^7.0.1",
66
66
  "postcss-sort-media-queries": "^6.5.0",
67
67
  "postcss-value-parser": "^4.2.0",
@@ -69,13 +69,14 @@
69
69
  "reka-ui": "^2.9.3",
70
70
  "string-strip-html": "^13.5.3",
71
71
  "tinyglobby": "^0.2.15",
72
+ "tinypool": "^2.1.0",
72
73
  "tw-animate-css": "^1.4.0",
73
- "typescript": "^5.9.3",
74
+ "typescript": "^6.0.3",
74
75
  "unplugin-auto-import": "^21.0.0",
75
76
  "unplugin-vue-components": "^32.1.0",
76
77
  "unplugin-vue-markdown": "^32.0.0",
77
78
  "uqr": "^0.1.3",
78
- "vite": "^7.3.1",
79
+ "vite": "^8.0.16",
79
80
  "vue-router": "^5.0.2"
80
81
  },
81
82
  "peerDependencies": {