@maizzle/framework 6.1.6 → 6.2.0
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/components/Img.vue +10 -4
- package/dist/components/Section.vue +1 -1
- package/dist/composables/definePreviewProps.d.ts +21 -0
- package/dist/composables/definePreviewProps.d.ts.map +1 -0
- package/dist/composables/definePreviewProps.js +23 -0
- package/dist/composables/definePreviewProps.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/plugins/postcss/resolveMaizzleImports.js +15 -8
- package/dist/plugins/postcss/resolveMaizzleImports.js.map +1 -1
- package/dist/render/createRenderer.d.ts.map +1 -1
- package/dist/render/createRenderer.js +25 -4
- package/dist/render/createRenderer.js.map +1 -1
- package/dist/render/index.d.ts +21 -0
- package/dist/render/index.d.ts.map +1 -1
- package/dist/render/index.js +76 -30
- package/dist/render/index.js.map +1 -1
- package/dist/render/plugins/previewProps.d.ts +13 -0
- package/dist/render/plugins/previewProps.d.ts.map +1 -0
- package/dist/render/plugins/previewProps.js +185 -0
- package/dist/render/plugins/previewProps.js.map +1 -0
- package/dist/render/withPreviewProps.d.ts +15 -0
- package/dist/render/withPreviewProps.d.ts.map +1 -0
- package/dist/render/withPreviewProps.js +40 -0
- package/dist/render/withPreviewProps.js.map +1 -0
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +4 -1
- package/dist/serve.js.map +1 -1
- package/dist/server/ui/.vite/deps/@lucide_vue.js +51812 -41607
- package/dist/server/ui/.vite/deps/@lucide_vue.js.map +1 -1
- package/dist/server/ui/.vite/deps/@vueuse_core.js.map +1 -1
- package/dist/server/ui/.vite/deps/@vueuse_shared.js.map +1 -1
- package/dist/server/ui/.vite/deps/_metadata.json +13 -13
- package/dist/server/ui/.vite/deps/class-variance-authority.js.map +1 -1
- package/dist/server/ui/.vite/deps/clsx.js.map +1 -1
- package/dist/server/ui/.vite/deps/culori.js.map +1 -1
- package/dist/server/ui/.vite/deps/reka-ui.js +240 -73
- package/dist/server/ui/.vite/deps/reka-ui.js.map +1 -1
- package/dist/server/ui/.vite/deps/tailwind-merge.js +102 -22
- package/dist/server/ui/.vite/deps/tailwind-merge.js.map +1 -1
- package/dist/server/ui/.vite/deps/vue-router.js +84 -53
- package/dist/server/ui/.vite/deps/vue-router.js.map +1 -1
- package/dist/server/ui/.vite/deps/vue.runtime.esm-bundler-Dq07uCLt.js.map +1 -1
- package/dist/transformers/format.d.ts.map +1 -1
- package/dist/transformers/minify.d.ts.map +1 -1
- package/dist/transformers/purgeCss.d.ts.map +1 -1
- package/dist/transformers/shorthandCss.js +11 -5
- package/dist/transformers/shorthandCss.js.map +1 -1
- package/dist/transformers/tailwindComponent.js +1 -1
- package/dist/transformers/tailwindComponent.js.map +1 -1
- package/dist/transformers/tailwindcss.js +8 -4
- package/dist/transformers/tailwindcss.js.map +1 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/compileTailwindCss.js +1 -1
- package/dist/utils/compileTailwindCss.js.map +1 -1
- package/package.json +3 -3
package/dist/render/index.js
CHANGED
|
@@ -9,14 +9,66 @@ import { extname, resolve } from "pathe";
|
|
|
9
9
|
import defu from "defu";
|
|
10
10
|
//#region src/render/index.ts
|
|
11
11
|
/**
|
|
12
|
+
* Keys read by rendererOptions() when the instance is created. Passing
|
|
13
|
+
* them per render would silently do nothing, so reject them instead.
|
|
14
|
+
*/
|
|
15
|
+
function assertNoRendererOverrides(config) {
|
|
16
|
+
const overrides = [
|
|
17
|
+
config.root !== void 0 && "root",
|
|
18
|
+
config.markdown !== void 0 && "markdown",
|
|
19
|
+
config.vite !== void 0 && "vite",
|
|
20
|
+
config.components?.source !== void 0 && "components.source",
|
|
21
|
+
config.vue?.customElements !== void 0 && "vue.customElements"
|
|
22
|
+
].filter(Boolean);
|
|
23
|
+
if (overrides.length) throw new Error(`${overrides.join(", ")} can only be set in createMaizzle(), not per render.`);
|
|
24
|
+
}
|
|
25
|
+
function rendererOptions(config) {
|
|
26
|
+
return {
|
|
27
|
+
markdown: config.markdown,
|
|
28
|
+
root: config.root,
|
|
29
|
+
componentDirs: normalizeComponentSources(config.components?.source, process.cwd()),
|
|
30
|
+
vite: config.vite,
|
|
31
|
+
customElements: config.vue?.customElements
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Run a template through a renderer and the post-render pipeline
|
|
36
|
+
* (transformers, doctype, plaintext). Shared by the one-shot render()
|
|
37
|
+
* and instances from createMaizzle().
|
|
38
|
+
*/
|
|
39
|
+
async function renderWith(renderer, template, resolvedConfig) {
|
|
40
|
+
if (template == null) throw new Error(`render() received ${template}. If you used \`import X from './x.vue'\`, Node cannot load .vue files natively — pass the path string instead: render('./x.vue').`);
|
|
41
|
+
if (typeof template !== "string" && typeof template !== "object" && typeof template !== "function") throw new TypeError(`render() expected a file path or SFC source string, got ${typeof template}.`);
|
|
42
|
+
const { props, ...templateConfig } = resolvedConfig;
|
|
43
|
+
const isFile = typeof template === "string" && [".vue", ".md"].includes(extname(template)) && !template.includes("\n");
|
|
44
|
+
const rendered = await renderer.render(isFile ? resolve(template) : template, templateConfig, { props });
|
|
45
|
+
let html = rendered.html;
|
|
46
|
+
const doctype = rendered.doctype ?? rendered.templateConfig.doctype ?? "<!DOCTYPE html>";
|
|
47
|
+
html = await runTransformers(html, rendered.templateConfig, isFile ? resolve(template) : void 0, doctype, rendered.tailwindBlocks);
|
|
48
|
+
if (doctype) html = `${doctype}\n${html}`;
|
|
49
|
+
const globalPlaintext = rendered.templateConfig.plaintext;
|
|
50
|
+
const sfcPlaintext = rendered.plaintext;
|
|
51
|
+
let plaintextResult;
|
|
52
|
+
if (globalPlaintext || sfcPlaintext) {
|
|
53
|
+
const globalCfg = typeof globalPlaintext === "object" ? globalPlaintext : {};
|
|
54
|
+
const stripOptions = defu(sfcPlaintext?.options, globalCfg.options);
|
|
55
|
+
plaintextResult = createPlaintext(stripForPlaintext(html), stripOptions);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
html: stripForHtml(html),
|
|
59
|
+
config: rendered.templateConfig,
|
|
60
|
+
plaintext: plaintextResult
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
12
64
|
* Render a Vue SFC email template to a fully-transformed HTML string.
|
|
13
65
|
* Accepts a file path or a raw SFC source string.
|
|
66
|
+
*
|
|
67
|
+
* Starts and stops a Vite SSR server per call. For repeated renders in a
|
|
68
|
+
* long-running process, use createMaizzle() instead.
|
|
14
69
|
*/
|
|
15
70
|
async function render(template, config) {
|
|
16
|
-
if (template == null) throw new Error(`render() received ${template}. If you used \`import X from './x.vue'\`, Node cannot load .vue files natively — pass the path string instead: render('./x.vue').`);
|
|
17
|
-
if (typeof template !== "string" && typeof template !== "object" && typeof template !== "function") throw new TypeError(`render() expected a file path or SFC source string, got ${typeof template}.`);
|
|
18
71
|
const resolvedConfig = resolveConfigObject(config);
|
|
19
|
-
const { props, ...templateConfig } = resolvedConfig;
|
|
20
72
|
/**
|
|
21
73
|
* Reuse a renderer started by the Vite plugin when one is active.
|
|
22
74
|
* Spinning up a fresh Vite SSR server inside a host Vite dev process
|
|
@@ -24,38 +76,32 @@ async function render(template, config) {
|
|
|
24
76
|
* "outsideEmitter undefined".
|
|
25
77
|
*/
|
|
26
78
|
const active = getActiveRenderer();
|
|
27
|
-
const renderer = active ?? await createRenderer(
|
|
28
|
-
markdown: resolvedConfig.markdown,
|
|
29
|
-
root: resolvedConfig.root,
|
|
30
|
-
componentDirs: normalizeComponentSources(resolvedConfig.components?.source, process.cwd()),
|
|
31
|
-
vite: resolvedConfig.vite,
|
|
32
|
-
customElements: resolvedConfig.vue?.customElements
|
|
33
|
-
});
|
|
79
|
+
const renderer = active ?? await createRenderer(rendererOptions(resolvedConfig));
|
|
34
80
|
try {
|
|
35
|
-
|
|
36
|
-
const rendered = await renderer.render(isFile ? resolve(template) : template, templateConfig, { props });
|
|
37
|
-
let html = rendered.html;
|
|
38
|
-
const doctype = rendered.doctype ?? rendered.templateConfig.doctype ?? "<!DOCTYPE html>";
|
|
39
|
-
html = await runTransformers(html, rendered.templateConfig, isFile ? resolve(template) : void 0, doctype, rendered.tailwindBlocks);
|
|
40
|
-
if (doctype) html = `${doctype}\n${html}`;
|
|
41
|
-
const globalPlaintext = rendered.templateConfig.plaintext;
|
|
42
|
-
const sfcPlaintext = rendered.plaintext;
|
|
43
|
-
let plaintextResult;
|
|
44
|
-
if (globalPlaintext || sfcPlaintext) {
|
|
45
|
-
const globalCfg = typeof globalPlaintext === "object" ? globalPlaintext : {};
|
|
46
|
-
const stripOptions = defu(sfcPlaintext?.options, globalCfg.options);
|
|
47
|
-
plaintextResult = createPlaintext(stripForPlaintext(html), stripOptions);
|
|
48
|
-
}
|
|
49
|
-
return {
|
|
50
|
-
html: stripForHtml(html),
|
|
51
|
-
config: rendered.templateConfig,
|
|
52
|
-
plaintext: plaintextResult
|
|
53
|
-
};
|
|
81
|
+
return await renderWith(renderer, template, resolvedConfig);
|
|
54
82
|
} finally {
|
|
55
83
|
if (!active) await renderer.close();
|
|
56
84
|
}
|
|
57
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Create a Maizzle instance that keeps one Vite SSR server alive across
|
|
88
|
+
* renders. Use this when rendering emails on demand in a long-running
|
|
89
|
+
* process, where the per-call startup cost of render() adds up.
|
|
90
|
+
*/
|
|
91
|
+
async function createMaizzle(config) {
|
|
92
|
+
const baseConfig = config ?? {};
|
|
93
|
+
const renderer = await createRenderer(rendererOptions(resolveConfigObject(baseConfig)));
|
|
94
|
+
return {
|
|
95
|
+
async render(template, renderConfig) {
|
|
96
|
+
if (renderConfig) assertNoRendererOverrides(renderConfig);
|
|
97
|
+
return renderWith(renderer, template, resolveConfigObject(defu(renderConfig, baseConfig)));
|
|
98
|
+
},
|
|
99
|
+
close() {
|
|
100
|
+
return renderer.close();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
58
104
|
//#endregion
|
|
59
|
-
export { createRenderer, render };
|
|
105
|
+
export { createMaizzle, createRenderer, render };
|
|
60
106
|
|
|
61
107
|
//# sourceMappingURL=index.js.map
|
package/dist/render/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/render/index.ts"],"sourcesContent":["import { resolve, extname } from 'pathe'\nimport { resolveConfigObject } from '../config/index.ts'\nimport { runTransformers } from '../transformers/index.ts'\nimport { createPlaintext } from '../plaintext.ts'\nimport { stripForHtml, stripForPlaintext } from '../utils/output-markers.ts'\nimport defu from 'defu'\nimport type { Component } from 'vue'\nimport type { MaizzleConfig } from '../types/index.ts'\nimport { createRenderer } from './createRenderer.ts'\nimport { getActiveRenderer } from './active.ts'\nimport { normalizeComponentSources } from '../utils/componentSources.ts'\n\nexport type { Renderer, RenderedTemplate, CreateRendererOptions } from './createRenderer.ts'\nexport { createRenderer } from './createRenderer.ts'\n\nexport interface RenderResult {\n html: string\n config: MaizzleConfig\n plaintext?: string\n}\n\n/**\n
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/render/index.ts"],"sourcesContent":["import { resolve, extname } from 'pathe'\nimport { resolveConfigObject } from '../config/index.ts'\nimport { runTransformers } from '../transformers/index.ts'\nimport { createPlaintext } from '../plaintext.ts'\nimport { stripForHtml, stripForPlaintext } from '../utils/output-markers.ts'\nimport defu from 'defu'\nimport type { Component } from 'vue'\nimport type { MaizzleConfig } from '../types/index.ts'\nimport { createRenderer, type Renderer } from './createRenderer.ts'\nimport { getActiveRenderer } from './active.ts'\nimport { normalizeComponentSources } from '../utils/componentSources.ts'\n\nexport type { Renderer, RenderedTemplate, CreateRendererOptions } from './createRenderer.ts'\nexport { createRenderer } from './createRenderer.ts'\n\nexport interface RenderResult {\n html: string\n config: MaizzleConfig\n plaintext?: string\n}\n\nexport interface MaizzleInstance {\n /**\n * Render a template through the full pipeline, reusing this instance's\n * renderer. `config` is merged over the config the instance was created\n * with. Keys that shape the renderer (`root`, `markdown`, `vite`,\n * `components.source`, `vue.customElements`) can only be set when\n * creating the instance and throw here. Safe to call concurrently.\n */\n render(template: string | Component, config?: Partial<MaizzleConfig>): Promise<RenderResult>\n /** Shut down the underlying Vite SSR server. */\n close(): Promise<void>\n}\n\n/**\n * Keys read by rendererOptions() when the instance is created. Passing\n * them per render would silently do nothing, so reject them instead.\n */\nfunction assertNoRendererOverrides(config: Partial<MaizzleConfig>): void {\n const overrides = [\n config.root !== undefined && 'root',\n config.markdown !== undefined && 'markdown',\n config.vite !== undefined && 'vite',\n config.components?.source !== undefined && 'components.source',\n config.vue?.customElements !== undefined && 'vue.customElements',\n ].filter(Boolean)\n\n if (overrides.length) {\n throw new Error(\n `${overrides.join(', ')} can only be set in createMaizzle(), not per render.`,\n )\n }\n}\n\nfunction rendererOptions(config: MaizzleConfig) {\n return {\n markdown: config.markdown,\n root: config.root,\n componentDirs: normalizeComponentSources(config.components?.source, process.cwd()),\n vite: config.vite,\n customElements: config.vue?.customElements,\n }\n}\n\n/**\n * Run a template through a renderer and the post-render pipeline\n * (transformers, doctype, plaintext). Shared by the one-shot render()\n * and instances from createMaizzle().\n */\nasync function renderWith(\n renderer: Renderer,\n template: string | Component,\n resolvedConfig: MaizzleConfig,\n): Promise<RenderResult> {\n if (template == null) {\n throw new Error(\n `render() received ${template}. If you used \\`import X from './x.vue'\\`, Node cannot load .vue files natively — pass the path string instead: render('./x.vue').`,\n )\n }\n if (typeof template !== 'string' && typeof template !== 'object' && typeof template !== 'function') {\n throw new TypeError(\n `render() expected a file path or SFC source string, got ${typeof template}.`,\n )\n }\n\n const { props, ...templateConfig } = resolvedConfig\n\n const isFile = typeof template === 'string'\n && ['.vue', '.md'].includes(extname(template))\n && !template.includes('\\n')\n\n const rendered = await renderer.render(isFile ? resolve(template) : template, templateConfig, { props })\n let html = rendered.html\n\n const doctype = rendered.doctype ?? rendered.templateConfig.doctype ?? '<!DOCTYPE html>'\n\n html = await runTransformers(html, rendered.templateConfig, isFile ? resolve(template) : undefined, doctype, rendered.tailwindBlocks)\n if (doctype) html = `${doctype}\\n${html}`\n\n const globalPlaintext = rendered.templateConfig.plaintext\n const sfcPlaintext = rendered.plaintext\n\n let plaintextResult: string | undefined\n\n if (globalPlaintext || sfcPlaintext) {\n const globalCfg = typeof globalPlaintext === 'object' ? globalPlaintext : {}\n const stripOptions = defu(sfcPlaintext?.options, globalCfg.options)\n plaintextResult = createPlaintext(stripForPlaintext(html), stripOptions)\n }\n\n return { html: stripForHtml(html), config: rendered.templateConfig, plaintext: plaintextResult }\n}\n\n/**\n * Render a Vue SFC email template to a fully-transformed HTML string.\n * Accepts a file path or a raw SFC source string.\n *\n * Starts and stops a Vite SSR server per call. For repeated renders in a\n * long-running process, use createMaizzle() instead.\n */\nexport async function render(\n template: string | Component,\n config?: Partial<MaizzleConfig>,\n): Promise<RenderResult> {\n const resolvedConfig = resolveConfigObject(config)\n\n /**\n * Reuse a renderer started by the Vite plugin when one is active.\n * Spinning up a fresh Vite SSR server inside a host Vite dev process\n * (e.g. TanStack Start) collides on env wiring and throws\n * \"outsideEmitter undefined\".\n */\n const active = getActiveRenderer()\n const renderer = active ?? await createRenderer(rendererOptions(resolvedConfig))\n\n try {\n return await renderWith(renderer, template, resolvedConfig)\n } finally {\n if (!active) await renderer.close()\n }\n}\n\n/**\n * Create a Maizzle instance that keeps one Vite SSR server alive across\n * renders. Use this when rendering emails on demand in a long-running\n * process, where the per-call startup cost of render() adds up.\n */\nexport async function createMaizzle(config?: Partial<MaizzleConfig>): Promise<MaizzleInstance> {\n const baseConfig = config ?? {}\n const renderer = await createRenderer(rendererOptions(resolveConfigObject(baseConfig)))\n\n return {\n async render(template, renderConfig) {\n if (renderConfig) assertNoRendererOverrides(renderConfig)\n return renderWith(renderer, template, resolveConfigObject(defu(renderConfig, baseConfig)))\n },\n close() {\n return renderer.close()\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAsCA,SAAS,0BAA0B,QAAsC;CACvE,MAAM,YAAY;EAChB,OAAO,SAAS,KAAA,KAAa;EAC7B,OAAO,aAAa,KAAA,KAAa;EACjC,OAAO,SAAS,KAAA,KAAa;EAC7B,OAAO,YAAY,WAAW,KAAA,KAAa;EAC3C,OAAO,KAAK,mBAAmB,KAAA,KAAa;CAC9C,CAAC,CAAC,OAAO,OAAO;CAEhB,IAAI,UAAU,QACZ,MAAM,IAAI,MACR,GAAG,UAAU,KAAK,IAAI,EAAE,qDAC1B;AAEJ;AAEA,SAAS,gBAAgB,QAAuB;CAC9C,OAAO;EACL,UAAU,OAAO;EACjB,MAAM,OAAO;EACb,eAAe,0BAA0B,OAAO,YAAY,QAAQ,QAAQ,IAAI,CAAC;EACjF,MAAM,OAAO;EACb,gBAAgB,OAAO,KAAK;CAC9B;AACF;;;;;;AAOA,eAAe,WACb,UACA,UACA,gBACuB;CACvB,IAAI,YAAY,MACd,MAAM,IAAI,MACR,qBAAqB,SAAS,mIAChC;CAEF,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,YAAY,OAAO,aAAa,YACtF,MAAM,IAAI,UACR,2DAA2D,OAAO,SAAS,EAC7E;CAGF,MAAM,EAAE,OAAO,GAAG,mBAAmB;CAErC,MAAM,SAAS,OAAO,aAAa,YAC9B,CAAC,QAAQ,KAAK,CAAC,CAAC,SAAS,QAAQ,QAAQ,CAAC,KAC1C,CAAC,SAAS,SAAS,IAAI;CAE5B,MAAM,WAAW,MAAM,SAAS,OAAO,SAAS,QAAQ,QAAQ,IAAI,UAAU,gBAAgB,EAAE,MAAM,CAAC;CACvG,IAAI,OAAO,SAAS;CAEpB,MAAM,UAAU,SAAS,WAAW,SAAS,eAAe,WAAW;CAEvE,OAAO,MAAM,gBAAgB,MAAM,SAAS,gBAAgB,SAAS,QAAQ,QAAQ,IAAI,KAAA,GAAW,SAAS,SAAS,cAAc;CACpI,IAAI,SAAS,OAAO,GAAG,QAAQ,IAAI;CAEnC,MAAM,kBAAkB,SAAS,eAAe;CAChD,MAAM,eAAe,SAAS;CAE9B,IAAI;CAEJ,IAAI,mBAAmB,cAAc;EACnC,MAAM,YAAY,OAAO,oBAAoB,WAAW,kBAAkB,CAAC;EAC3E,MAAM,eAAe,KAAK,cAAc,SAAS,UAAU,OAAO;EAClE,kBAAkB,gBAAgB,kBAAkB,IAAI,GAAG,YAAY;CACzE;CAEA,OAAO;EAAE,MAAM,aAAa,IAAI;EAAG,QAAQ,SAAS;EAAgB,WAAW;CAAgB;AACjG;;;;;;;;AASA,eAAsB,OACpB,UACA,QACuB;CACvB,MAAM,iBAAiB,oBAAoB,MAAM;;;;;;;CAQjD,MAAM,SAAS,kBAAkB;CACjC,MAAM,WAAW,UAAU,MAAM,eAAe,gBAAgB,cAAc,CAAC;CAE/E,IAAI;EACF,OAAO,MAAM,WAAW,UAAU,UAAU,cAAc;CAC5D,UAAU;EACR,IAAI,CAAC,QAAQ,MAAM,SAAS,MAAM;CACpC;AACF;;;;;;AAOA,eAAsB,cAAc,QAA2D;CAC7F,MAAM,aAAa,UAAU,CAAC;CAC9B,MAAM,WAAW,MAAM,eAAe,gBAAgB,oBAAoB,UAAU,CAAC,CAAC;CAEtF,OAAO;EACL,MAAM,OAAO,UAAU,cAAc;GACnC,IAAI,cAAc,0BAA0B,YAAY;GACxD,OAAO,WAAW,UAAU,UAAU,oBAAoB,KAAK,cAAc,UAAU,CAAC,CAAC;EAC3F;EACA,QAAQ;GACN,OAAO,SAAS,MAAM;EACxB;CACF;AACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
//#region src/render/plugins/previewProps.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Vite plugin that compiles the `definePreviewProps()` macro.
|
|
5
|
+
*
|
|
6
|
+
* Runs after plugin-vue (and TS stripping), so it sees plain JS. Blanks
|
|
7
|
+
* out the call inside `setup()`, then re-exports the component wrapped
|
|
8
|
+
* with `withPreviewProps()`, which gets the macro argument as a
|
|
9
|
+
* lazy factory evaluated at module scope.
|
|
10
|
+
*/
|
|
11
|
+
export declare function previewProps(runtimePath: string): Plugin;
|
|
12
|
+
//#endregion
|
|
13
|
+
//# sourceMappingURL=previewProps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewProps.d.ts","names":[],"sources":["../../../src/render/plugins/previewProps.ts"],"mappings":";;;;;;;;;;wBAmIgB,aAAa,sBAAsB"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { parseAst } from "vite";
|
|
2
|
+
//#region src/render/plugins/previewProps.ts
|
|
3
|
+
const MACRO = "definePreviewProps";
|
|
4
|
+
/**
|
|
5
|
+
* Collect binding names from a declaration target: `a`, `{ a, b: c }`,
|
|
6
|
+
* `[a, ...rest]`, `a = 1`.
|
|
7
|
+
*/
|
|
8
|
+
function patternNames(node, out) {
|
|
9
|
+
if (!node) return;
|
|
10
|
+
if (node.type === "Identifier") out.add(node.name);
|
|
11
|
+
else if (node.type === "ObjectPattern") node.properties.forEach((p) => patternNames(p.type === "RestElement" ? p : p.value, out));
|
|
12
|
+
else if (node.type === "ArrayPattern") node.elements.forEach((e) => patternNames(e, out));
|
|
13
|
+
else if (node.type === "AssignmentPattern") patternNames(node.left, out);
|
|
14
|
+
else if (node.type === "RestElement") patternNames(node.argument, out);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Names declared directly in a statement list (not in nested blocks).
|
|
18
|
+
* Imports are left out on purpose: they're allowed in the macro.
|
|
19
|
+
*/
|
|
20
|
+
function declaredNames(statements, out) {
|
|
21
|
+
for (let node of statements) {
|
|
22
|
+
if (node.type === "ExportNamedDeclaration") node = node.declaration;
|
|
23
|
+
if (!node) continue;
|
|
24
|
+
if (node.type === "VariableDeclaration") node.declarations.forEach((d) => patternNames(d.id, out));
|
|
25
|
+
else if ((node.type === "FunctionDeclaration" || node.type === "ClassDeclaration") && node.id) out.add(node.id.name);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Identifiers an expression reads, minus the ones it declares itself
|
|
30
|
+
* (arrow function params, inner variables) and property names.
|
|
31
|
+
*/
|
|
32
|
+
function referencedNames(root) {
|
|
33
|
+
const refs = /* @__PURE__ */ new Set();
|
|
34
|
+
const own = /* @__PURE__ */ new Set();
|
|
35
|
+
const visit = (node, parent, key) => {
|
|
36
|
+
if (!node || typeof node.type !== "string") return;
|
|
37
|
+
if (node.type === "Identifier") {
|
|
38
|
+
if (!(!parent?.computed && (parent?.type === "MemberExpression" && key === "property" || (parent?.type === "Property" || parent?.type === "MethodDefinition") && key === "key"))) refs.add(node.name);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (node.type === "VariableDeclarator") patternNames(node.id, own);
|
|
42
|
+
if (node.params) node.params.forEach((p) => patternNames(p, own));
|
|
43
|
+
if (node.type === "CatchClause") patternNames(node.param, own);
|
|
44
|
+
for (const [k, value] of Object.entries(node)) if (Array.isArray(value)) value.forEach((child) => visit(child, node, k));
|
|
45
|
+
else if (value && typeof value === "object") visit(value, node, k);
|
|
46
|
+
};
|
|
47
|
+
visit(root);
|
|
48
|
+
return [...refs].filter((name) => !own.has(name));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Imports read only by the macro arguments, plus the `__returned__` getters
|
|
52
|
+
* Vue adds for them in non-TS templates. Every other identifier counts
|
|
53
|
+
* as a use (even property names like `$setup.x`), so when in doubt
|
|
54
|
+
* an import stays where it is.
|
|
55
|
+
*/
|
|
56
|
+
function previewOnlyImports(ast, args) {
|
|
57
|
+
const imports = ast.body.filter((n) => n.type === "ImportDeclaration" && n.specifiers.length && !n.attributes?.length);
|
|
58
|
+
const names = new Set(imports.flatMap((n) => n.specifiers.map((s) => s.local.name)));
|
|
59
|
+
let getters = [];
|
|
60
|
+
const used = /* @__PURE__ */ new Set();
|
|
61
|
+
const skip = /* @__PURE__ */ new Set([...args, ...imports]);
|
|
62
|
+
const visit = (node, parent, key) => {
|
|
63
|
+
if (!node || typeof node.type !== "string" || skip.has(node)) return;
|
|
64
|
+
if (node.type === "VariableDeclarator" && node.id.name === "__returned__" && node.init?.type === "ObjectExpression") {
|
|
65
|
+
getters = node.init.properties.filter((p) => p.kind === "get" && names.has(p.key?.name));
|
|
66
|
+
getters.forEach((p) => skip.add(p));
|
|
67
|
+
}
|
|
68
|
+
if (node.type === "Identifier") {
|
|
69
|
+
if (!(parent?.type === "Property" && key === "key" && !parent.computed)) used.add(node.name);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
for (const [k, value] of Object.entries(node)) if (Array.isArray(value)) value.forEach((child) => visit(child, node, k));
|
|
73
|
+
else if (value && typeof value === "object") visit(value, node, k);
|
|
74
|
+
};
|
|
75
|
+
visit(ast);
|
|
76
|
+
const inArg = new Set(args.flatMap(referencedNames));
|
|
77
|
+
const moved = imports.filter((n) => n.specifiers.every((s) => !used.has(s.local.name)) && n.specifiers.some((s) => inArg.has(s.local.name)));
|
|
78
|
+
const movedNames = new Set(moved.flatMap((n) => n.specifiers.map((s) => s.local.name)));
|
|
79
|
+
return {
|
|
80
|
+
imports: moved,
|
|
81
|
+
getters: getters.filter((p) => movedNames.has(p.key.name))
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* `import a, { b as c } from 'x'` -> `const { default: a, b: c } = await import('x')`
|
|
86
|
+
*/
|
|
87
|
+
function dynamicImport(node) {
|
|
88
|
+
const source = JSON.stringify(node.source.value);
|
|
89
|
+
const namespace = node.specifiers.find((s) => s.type === "ImportNamespaceSpecifier");
|
|
90
|
+
const named = node.specifiers.filter((s) => s.type !== "ImportNamespaceSpecifier").map((s) => {
|
|
91
|
+
if (s.type === "ImportDefaultSpecifier") return `default: ${s.local.name}`;
|
|
92
|
+
return `${s.imported.type === "Identifier" ? s.imported.name : JSON.stringify(s.imported.value)}: ${s.local.name}`;
|
|
93
|
+
});
|
|
94
|
+
return [namespace && `const ${namespace.local.name} = await import(${source})`, named.length && `const { ${named.join(", ")} } = await import(${source})`].filter(Boolean).join("; ");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Vite plugin that compiles the `definePreviewProps()` macro.
|
|
98
|
+
*
|
|
99
|
+
* Runs after plugin-vue (and TS stripping), so it sees plain JS. Blanks
|
|
100
|
+
* out the call inside `setup()`, then re-exports the component wrapped
|
|
101
|
+
* with `withPreviewProps()`, which gets the macro argument as a
|
|
102
|
+
* lazy factory evaluated at module scope.
|
|
103
|
+
*/
|
|
104
|
+
function previewProps(runtimePath) {
|
|
105
|
+
return {
|
|
106
|
+
name: "maizzle:preview-props",
|
|
107
|
+
enforce: "post",
|
|
108
|
+
transform(code, id) {
|
|
109
|
+
if (!id.endsWith(".vue") || !code.includes(MACRO)) return;
|
|
110
|
+
const ast = parseAst(code);
|
|
111
|
+
const calls = [];
|
|
112
|
+
const walk = (node, block) => {
|
|
113
|
+
if (!node || typeof node.type !== "string") return;
|
|
114
|
+
if (node.type === "ExpressionStatement" && node.expression.type === "CallExpression" && node.expression.callee.type === "Identifier" && node.expression.callee.name === MACRO) {
|
|
115
|
+
calls.push({
|
|
116
|
+
node,
|
|
117
|
+
block
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const inner = node.type === "BlockStatement" ? node.body : block;
|
|
122
|
+
for (const value of Object.values(node)) if (Array.isArray(value)) value.forEach((child) => walk(child, inner));
|
|
123
|
+
else if (value && typeof value === "object") walk(value, inner);
|
|
124
|
+
};
|
|
125
|
+
walk(ast, ast.body);
|
|
126
|
+
if (calls.length === 0) return;
|
|
127
|
+
const exportDefault = ast.body.find((n) => n.type === "ExportDefaultDeclaration");
|
|
128
|
+
if (!exportDefault) return;
|
|
129
|
+
const [{ node: call, block }] = calls;
|
|
130
|
+
const arg = call.expression.arguments[0];
|
|
131
|
+
/**
|
|
132
|
+
* The argument is moved out of `setup()` to module scope, where
|
|
133
|
+
* template variables don't exist. Vue hoists literal consts there
|
|
134
|
+
* though, so check both scopes and reject either one, keeping
|
|
135
|
+
* the rule simple: inline values and imports only.
|
|
136
|
+
*/
|
|
137
|
+
let error;
|
|
138
|
+
if (calls.length > 1) error = `${MACRO}() can only be called once per template.`;
|
|
139
|
+
else if (arg) {
|
|
140
|
+
const declared = /* @__PURE__ */ new Set();
|
|
141
|
+
declaredNames(ast.body, declared);
|
|
142
|
+
declaredNames(block, declared);
|
|
143
|
+
const local = referencedNames(arg).find((name) => declared.has(name));
|
|
144
|
+
if (local) error = `${MACRO}() cannot use \`${local}\` declared in this template.\nMove it to an import, or write the value inline.`;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Mistakes throw from the factory instead of failing the compile:
|
|
148
|
+
* it only runs in the dev server, so preview data can never
|
|
149
|
+
* break `build` or a production `render()`. Macro-only imports
|
|
150
|
+
* are removed either way, and only loaded by a valid factory.
|
|
151
|
+
*/
|
|
152
|
+
const moved = previewOnlyImports(ast, calls.flatMap(({ node }) => node.expression.arguments));
|
|
153
|
+
let factory = "() => ({})";
|
|
154
|
+
if (error) factory = `() => { throw new Error(${JSON.stringify(`[maizzle] ${error}`)}) }`;
|
|
155
|
+
else if (moved.imports.length) factory = `async () => { ${moved.imports.map(dynamicImport).join("; ")}; return (${code.slice(arg.start, arg.end)}) }`;
|
|
156
|
+
else if (arg) factory = `() => (${code.slice(arg.start, arg.end)})`;
|
|
157
|
+
/**
|
|
158
|
+
* Blank the calls, moved imports and their getters in place (keeping
|
|
159
|
+
* newlines) so line numbers don't shift. A getter takes its comma
|
|
160
|
+
* along, so the `__returned__` object stays valid.
|
|
161
|
+
*/
|
|
162
|
+
const blank = (s) => s.replace(/[^\n]/g, " ");
|
|
163
|
+
const ranges = [
|
|
164
|
+
...calls.map(({ node }) => [node.start, node.end]),
|
|
165
|
+
...moved.imports.map((node) => [node.start, node.end]),
|
|
166
|
+
...moved.getters.map((node) => [node.start, node.end + (/^\s*,/.exec(code.slice(node.end))?.[0].length ?? 0)])
|
|
167
|
+
].sort((a, b) => a[0] - b[0]);
|
|
168
|
+
let out = "";
|
|
169
|
+
let cursor = 0;
|
|
170
|
+
for (const [start, end] of ranges) {
|
|
171
|
+
out += code.slice(cursor, start) + blank(code.slice(start, end));
|
|
172
|
+
cursor = end;
|
|
173
|
+
}
|
|
174
|
+
out += code.slice(cursor, exportDefault.start) + "const __maizzle_sfc = " + code.slice(exportDefault.declaration.start) + `\nimport { withPreviewProps as __maizzle_withPreviewProps } from ${JSON.stringify(runtimePath)}\nexport default __maizzle_withPreviewProps(__maizzle_sfc, ${factory})\n`;
|
|
175
|
+
return {
|
|
176
|
+
code: out,
|
|
177
|
+
map: null
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
export { previewProps };
|
|
184
|
+
|
|
185
|
+
//# sourceMappingURL=previewProps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewProps.js","names":[],"sources":["../../../src/render/plugins/previewProps.ts"],"sourcesContent":["import { parseAst } from 'vite'\nimport type { Plugin } from 'vite'\n\nconst MACRO = 'definePreviewProps'\n\n/**\n * Collect binding names from a declaration target: `a`, `{ a, b: c }`,\n * `[a, ...rest]`, `a = 1`.\n */\nfunction patternNames(node: any, out: Set<string>): void {\n if (!node) return\n if (node.type === 'Identifier') out.add(node.name)\n else if (node.type === 'ObjectPattern') node.properties.forEach((p: any) => patternNames(p.type === 'RestElement' ? p : p.value, out))\n else if (node.type === 'ArrayPattern') node.elements.forEach((e: any) => patternNames(e, out))\n else if (node.type === 'AssignmentPattern') patternNames(node.left, out)\n else if (node.type === 'RestElement') patternNames(node.argument, out)\n}\n\n/**\n * Names declared directly in a statement list (not in nested blocks).\n * Imports are left out on purpose: they're allowed in the macro.\n */\nfunction declaredNames(statements: any[], out: Set<string>): void {\n for (let node of statements) {\n if (node.type === 'ExportNamedDeclaration') node = node.declaration\n if (!node) continue\n if (node.type === 'VariableDeclaration') node.declarations.forEach((d: any) => patternNames(d.id, out))\n else if ((node.type === 'FunctionDeclaration' || node.type === 'ClassDeclaration') && node.id) out.add(node.id.name)\n }\n}\n\n/**\n * Identifiers an expression reads, minus the ones it declares itself\n * (arrow function params, inner variables) and property names.\n */\nfunction referencedNames(root: any): string[] {\n const refs = new Set<string>()\n const own = new Set<string>()\n\n const visit = (node: any, parent?: any, key?: string): void => {\n if (!node || typeof node.type !== 'string') return\n if (node.type === 'Identifier') {\n const isPropertyName = !parent?.computed && (\n (parent?.type === 'MemberExpression' && key === 'property')\n || ((parent?.type === 'Property' || parent?.type === 'MethodDefinition') && key === 'key')\n )\n if (!isPropertyName) refs.add(node.name)\n return\n }\n if (node.type === 'VariableDeclarator') patternNames(node.id, own)\n if (node.params) node.params.forEach((p: any) => patternNames(p, own))\n if (node.type === 'CatchClause') patternNames(node.param, own)\n for (const [k, value] of Object.entries(node)) {\n if (Array.isArray(value)) value.forEach(child => visit(child, node, k))\n else if (value && typeof value === 'object') visit(value, node, k)\n }\n }\n visit(root)\n\n return [...refs].filter(name => !own.has(name))\n}\n\n/**\n * Imports read only by the macro arguments, plus the `__returned__` getters\n * Vue adds for them in non-TS templates. Every other identifier counts\n * as a use (even property names like `$setup.x`), so when in doubt\n * an import stays where it is.\n */\nfunction previewOnlyImports(ast: any, args: any[]): { imports: any[]; getters: any[] } {\n const imports = ast.body.filter((n: any) => n.type === 'ImportDeclaration' && n.specifiers.length && !n.attributes?.length)\n const names = new Set<string>(imports.flatMap((n: any) => n.specifiers.map((s: any) => s.local.name)))\n\n let getters: any[] = []\n const used = new Set<string>()\n const skip = new Set([...args, ...imports])\n\n const visit = (node: any, parent?: any, key?: string): void => {\n if (!node || typeof node.type !== 'string' || skip.has(node)) return\n if (node.type === 'VariableDeclarator' && node.id.name === '__returned__' && node.init?.type === 'ObjectExpression') {\n getters = node.init.properties.filter((p: any) => p.kind === 'get' && names.has(p.key?.name))\n getters.forEach(p => skip.add(p))\n }\n if (node.type === 'Identifier') {\n if (!(parent?.type === 'Property' && key === 'key' && !parent.computed)) used.add(node.name)\n return\n }\n for (const [k, value] of Object.entries(node)) {\n if (Array.isArray(value)) value.forEach(child => visit(child, node, k))\n else if (value && typeof value === 'object') visit(value, node, k)\n }\n }\n visit(ast)\n\n const inArg = new Set(args.flatMap(referencedNames))\n const moved = imports.filter((n: any) =>\n n.specifiers.every((s: any) => !used.has(s.local.name))\n && n.specifiers.some((s: any) => inArg.has(s.local.name)),\n )\n const movedNames = new Set(moved.flatMap((n: any) => n.specifiers.map((s: any) => s.local.name)))\n\n return { imports: moved, getters: getters.filter(p => movedNames.has(p.key.name)) }\n}\n\n/**\n * `import a, { b as c } from 'x'` -> `const { default: a, b: c } = await import('x')`\n */\nfunction dynamicImport(node: any): string {\n const source = JSON.stringify(node.source.value)\n const namespace = node.specifiers.find((s: any) => s.type === 'ImportNamespaceSpecifier')\n const named = node.specifiers\n .filter((s: any) => s.type !== 'ImportNamespaceSpecifier')\n .map((s: any) => {\n if (s.type === 'ImportDefaultSpecifier') return `default: ${s.local.name}`\n const imported = s.imported.type === 'Identifier' ? s.imported.name : JSON.stringify(s.imported.value)\n return `${imported}: ${s.local.name}`\n })\n\n return [\n namespace && `const ${namespace.local.name} = await import(${source})`,\n named.length && `const { ${named.join(', ')} } = await import(${source})`,\n ].filter(Boolean).join('; ')\n}\n\n/**\n * Vite plugin that compiles the `definePreviewProps()` macro.\n *\n * Runs after plugin-vue (and TS stripping), so it sees plain JS. Blanks\n * out the call inside `setup()`, then re-exports the component wrapped\n * with `withPreviewProps()`, which gets the macro argument as a\n * lazy factory evaluated at module scope.\n */\nexport function previewProps(runtimePath: string): Plugin {\n return {\n name: 'maizzle:preview-props',\n enforce: 'post',\n transform(code, id) {\n if (!id.endsWith('.vue') || !code.includes(MACRO)) return\n\n const ast = parseAst(code) as any\n const calls: { node: any; block: any[] }[] = []\n\n const walk = (node: any, block: any[]): void => {\n if (!node || typeof node.type !== 'string') return\n if (\n node.type === 'ExpressionStatement'\n && node.expression.type === 'CallExpression'\n && node.expression.callee.type === 'Identifier'\n && node.expression.callee.name === MACRO\n ) {\n calls.push({ node, block })\n return\n }\n const inner = node.type === 'BlockStatement' ? node.body : block\n for (const value of Object.values(node)) {\n if (Array.isArray(value)) value.forEach(child => walk(child, inner))\n else if (value && typeof value === 'object') walk(value, inner)\n }\n }\n walk(ast, ast.body)\n\n if (calls.length === 0) return\n\n const exportDefault = ast.body.find((n: any) => n.type === 'ExportDefaultDeclaration')\n if (!exportDefault) return\n\n const [{ node: call, block }] = calls\n const arg = call.expression.arguments[0]\n\n /**\n * The argument is moved out of `setup()` to module scope, where\n * template variables don't exist. Vue hoists literal consts there\n * though, so check both scopes and reject either one, keeping\n * the rule simple: inline values and imports only.\n */\n let error: string | undefined\n if (calls.length > 1) {\n error = `${MACRO}() can only be called once per template.`\n } else if (arg) {\n const declared = new Set<string>()\n declaredNames(ast.body, declared)\n declaredNames(block, declared)\n\n const local = referencedNames(arg).find(name => declared.has(name))\n if (local) {\n error = `${MACRO}() cannot use \\`${local}\\` declared in this template.\\nMove it to an import, or write the value inline.`\n }\n }\n\n /**\n * Mistakes throw from the factory instead of failing the compile:\n * it only runs in the dev server, so preview data can never\n * break `build` or a production `render()`. Macro-only imports\n * are removed either way, and only loaded by a valid factory.\n */\n const moved = previewOnlyImports(ast, calls.flatMap(({ node }) => node.expression.arguments))\n\n let factory = '() => ({})'\n if (error) {\n factory = `() => { throw new Error(${JSON.stringify(`[maizzle] ${error}`)}) }`\n } else if (moved.imports.length) {\n factory = `async () => { ${moved.imports.map(dynamicImport).join('; ')}; return (${code.slice(arg.start, arg.end)}) }`\n } else if (arg) {\n factory = `() => (${code.slice(arg.start, arg.end)})`\n }\n\n /**\n * Blank the calls, moved imports and their getters in place (keeping\n * newlines) so line numbers don't shift. A getter takes its comma\n * along, so the `__returned__` object stays valid.\n */\n const blank = (s: string) => s.replace(/[^\\n]/g, ' ')\n const ranges = [\n ...calls.map(({ node }) => [node.start, node.end]),\n ...moved.imports.map(node => [node.start, node.end]),\n ...moved.getters.map(node => [node.start, node.end + (/^\\s*,/.exec(code.slice(node.end))?.[0].length ?? 0)]),\n ].sort((a, b) => a[0] - b[0])\n\n let out = ''\n let cursor = 0\n for (const [start, end] of ranges) {\n out += code.slice(cursor, start) + blank(code.slice(start, end))\n cursor = end\n }\n\n out += code.slice(cursor, exportDefault.start)\n + 'const __maizzle_sfc = '\n + code.slice(exportDefault.declaration.start)\n + `\\nimport { withPreviewProps as __maizzle_withPreviewProps } from ${JSON.stringify(runtimePath)}`\n + `\\nexport default __maizzle_withPreviewProps(__maizzle_sfc, ${factory})\\n`\n\n return { code: out, map: null }\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Component } from "vue";
|
|
2
|
+
//#region src/render/withPreviewProps.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Set on a per-render config by the dev server. Global symbol registry
|
|
5
|
+
* so the Node and Vite SSR module instances agree on the key.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PreviewPropsKey: unique symbol;
|
|
8
|
+
/**
|
|
9
|
+
* Wrap a template that calls `definePreviewProps()`. Passes the real props
|
|
10
|
+
* through untouched, and only in dev server renders merges the sample
|
|
11
|
+
* props underneath them. The factory is never called otherwise.
|
|
12
|
+
*/
|
|
13
|
+
export declare function withPreviewProps(component: Component, previewProps: () => Record<string, any> | Promise<Record<string, any>>): Component;
|
|
14
|
+
//#endregion
|
|
15
|
+
//# sourceMappingURL=withPreviewProps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withPreviewProps.d.ts","names":[],"sources":["../../src/render/withPreviewProps.ts"],"mappings":";;;;;;qBAQa;;;;;;wBAOG,iBACd,WAAW,WACX,oBAAoB,sBAAsB,QAAQ,uBACjD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { MaizzleConfigKey } from "../composables/useConfig.js";
|
|
2
|
+
import { defineComponent, h, inject } from "vue";
|
|
3
|
+
//#region src/render/withPreviewProps.ts
|
|
4
|
+
/**
|
|
5
|
+
* Set on a per-render config by the dev server. Global symbol registry
|
|
6
|
+
* so the Node and Vite SSR module instances agree on the key.
|
|
7
|
+
*/
|
|
8
|
+
const PreviewPropsKey = Symbol.for("maizzle.previewProps");
|
|
9
|
+
/**
|
|
10
|
+
* Wrap a template that calls `definePreviewProps()`. Passes the real props
|
|
11
|
+
* through untouched, and only in dev server renders merges the sample
|
|
12
|
+
* props underneath them. The factory is never called otherwise.
|
|
13
|
+
*/
|
|
14
|
+
function withPreviewProps(component, previewProps) {
|
|
15
|
+
return defineComponent({
|
|
16
|
+
name: component.__name,
|
|
17
|
+
inheritAttrs: false,
|
|
18
|
+
setup(_, { attrs, slots }) {
|
|
19
|
+
if (!inject(MaizzleConfigKey)?.[PreviewPropsKey]) return () => h(component, attrs, slots);
|
|
20
|
+
const withPreview = (preview) => {
|
|
21
|
+
const props = {
|
|
22
|
+
...preview,
|
|
23
|
+
...attrs
|
|
24
|
+
};
|
|
25
|
+
return () => h(component, props, slots);
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The factory is async when the sample data comes from imports,
|
|
29
|
+
* which it loads itself. Vue's SSR renderer awaits an async
|
|
30
|
+
* setup(), so those modules only load in the dev server.
|
|
31
|
+
*/
|
|
32
|
+
const preview = previewProps();
|
|
33
|
+
return preview instanceof Promise ? preview.then(withPreview) : withPreview(preview);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { PreviewPropsKey, withPreviewProps };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=withPreviewProps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withPreviewProps.js","names":[],"sources":["../../src/render/withPreviewProps.ts"],"sourcesContent":["import { defineComponent, h, inject } from 'vue'\nimport type { Component } from 'vue'\nimport { MaizzleConfigKey } from '../composables/useConfig.ts'\n\n/**\n * Set on a per-render config by the dev server. Global symbol registry\n * so the Node and Vite SSR module instances agree on the key.\n */\nexport const PreviewPropsKey = Symbol.for('maizzle.previewProps')\n\n/**\n * Wrap a template that calls `definePreviewProps()`. Passes the real props\n * through untouched, and only in dev server renders merges the sample\n * props underneath them. The factory is never called otherwise.\n */\nexport function withPreviewProps(\n component: Component,\n previewProps: () => Record<string, any> | Promise<Record<string, any>>,\n): Component {\n return defineComponent({\n name: (component as { __name?: string }).__name,\n inheritAttrs: false,\n setup(_, { attrs, slots }) {\n const config = inject(MaizzleConfigKey) as Record<symbol, unknown> | undefined\n if (!config?.[PreviewPropsKey]) return () => h(component, attrs, slots)\n\n const withPreview = (preview: Record<string, any>) => {\n const props = { ...preview, ...attrs }\n return () => h(component, props, slots)\n }\n\n /**\n * The factory is async when the sample data comes from imports,\n * which it loads itself. Vue's SSR renderer awaits an async\n * setup(), so those modules only load in the dev server.\n */\n const preview = previewProps()\n return preview instanceof Promise ? preview.then(withPreview) : withPreview(preview)\n },\n })\n}\n"],"mappings":";;;;;;;AAQA,MAAa,kBAAkB,OAAO,IAAI,sBAAsB;;;;;;AAOhE,SAAgB,iBACd,WACA,cACW;CACX,OAAO,gBAAgB;EACrB,MAAO,UAAkC;EACzC,cAAc;EACd,MAAM,GAAG,EAAE,OAAO,SAAS;GAEzB,IAAI,CADW,OAAO,gBACZ,CAAC,GAAG,kBAAkB,aAAa,EAAE,WAAW,OAAO,KAAK;GAEtE,MAAM,eAAe,YAAiC;IACpD,MAAM,QAAQ;KAAE,GAAG;KAAS,GAAG;IAAM;IACrC,aAAa,EAAE,WAAW,OAAO,KAAK;GACxC;;;;;;GAOA,MAAM,UAAU,aAAa;GAC7B,OAAO,mBAAmB,UAAU,QAAQ,KAAK,WAAW,IAAI,YAAY,OAAO;EACrF;CACF,CAAC;AACH"}
|
package/dist/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","names":[],"sources":["../src/serve.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","names":[],"sources":["../src/serve.ts"],"mappings":";;;;iBA6DiB;EACf,SAAS,QAAQ;;EAEjB;;EAEA;;EAEA;;;;;;;;;;;wBAYoB,MAAM,UAAS,eAAiB,QAAA;wBAiwBtC,YAAY,QAAQ,eAAe"}
|
package/dist/serve.js
CHANGED
|
@@ -9,6 +9,7 @@ import { stripForHtml, stripForPlaintext } from "./utils/output-markers.js";
|
|
|
9
9
|
import { _setCurrentTemplate } from "./composables/useCurrentTemplate.js";
|
|
10
10
|
import { cloneConfig } from "./utils/cloneConfig.js";
|
|
11
11
|
import { setActiveRenderer } from "./render/active.js";
|
|
12
|
+
import { PreviewPropsKey } from "./render/withPreviewProps.js";
|
|
12
13
|
import { serveLint } from "./server/linter.js";
|
|
13
14
|
import { serveCompatibility } from "./server/compatibility.js";
|
|
14
15
|
import { sendEmail } from "./server/email.js";
|
|
@@ -450,9 +451,11 @@ function getRendered(absolutePath, config, renderer, events) {
|
|
|
450
451
|
* Mirror the build's per-template event pipeline (see buildTemplate)
|
|
451
452
|
* so dev preview fires the same beforeRender / afterRender /
|
|
452
453
|
* afterTransform hooks and matches production output. Clone config so
|
|
453
|
-
* beforeRender mutations stay scoped to this render.
|
|
454
|
+
* beforeRender mutations stay scoped to this render. The one deliberate
|
|
455
|
+
* difference: flag it so `definePreviewProps()` sample data applies.
|
|
454
456
|
*/
|
|
455
457
|
const renderConfig = cloneConfig(config);
|
|
458
|
+
Object.assign(renderConfig, { [PreviewPropsKey]: true });
|
|
456
459
|
const template = {
|
|
457
460
|
source: readFileSync(absolutePath, "utf-8"),
|
|
458
461
|
path: parse(absolutePath)
|