@sigx/server-renderer 0.1.4 → 0.1.6

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/src/jsx.d.ts ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * JSX type augmentation for SSR client directives.
3
+ *
4
+ * Import this module to enable client:* directive types in your JSX.
5
+ * These directives control selective hydration behavior.
6
+ *
7
+ * Usage:
8
+ * ```tsx
9
+ * import '@sigx/server-renderer/jsx';
10
+ *
11
+ * <Counter client:visible />
12
+ * <HeavyWidget client:idle />
13
+ * <Modal client:load />
14
+ * <Sidebar client:media="(min-width: 768px)" />
15
+ * <ClientOnlyMap client:only />
16
+ * ```
17
+ */
18
+
19
+ /**
20
+ * Client hydration directive props
21
+ */
22
+ export interface ClientDirectives {
23
+ /**
24
+ * Hydrate this component immediately when the page loads.
25
+ * Use for critical interactive components above the fold.
26
+ */
27
+ 'client:load'?: boolean;
28
+
29
+ /**
30
+ * Hydrate this component during browser idle time (requestIdleCallback).
31
+ * Use for non-critical components that don't need immediate interactivity.
32
+ */
33
+ 'client:idle'?: boolean;
34
+
35
+ /**
36
+ * Hydrate this component when it enters the viewport (IntersectionObserver).
37
+ * Use for below-the-fold components to improve initial load performance.
38
+ */
39
+ 'client:visible'?: boolean;
40
+
41
+ /**
42
+ * Hydrate this component when the media query matches.
43
+ * Pass the media query string as the value.
44
+ * @example <Sidebar client:media="(min-width: 768px)" />
45
+ */
46
+ 'client:media'?: string;
47
+
48
+ /**
49
+ * Skip server rendering entirely; only render on client.
50
+ * Use for components that cannot run on the server (e.g., use browser APIs).
51
+ * A placeholder will be rendered on the server.
52
+ */
53
+ 'client:only'?: boolean;
54
+ }
55
+
56
+ // Augment the component attribute extensions in runtime-core
57
+ // This adds client directives to all components using the pluggable type system
58
+ declare module '@sigx/runtime-core' {
59
+ interface ComponentAttributeExtensions extends ClientDirectives { }
60
+ }
61
+
62
+ export { };
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["defaults: Partial<TProps>","ctx: ComponentSetupContext","ESCAPE: Record<string, string>"],"sources":["../src/index.ts"],"sourcesContent":["import { VNode, Fragment, JSXElement, ComponentSetupContext, setCurrentInstance, signal, Text, SlotsObject, PropsAccessor } from '@sigx/runtime-core';\n\n/**\n * Creates a simple props accessor for SSR (no reactivity needed)\n */\nfunction createSSRPropsAccessor<TProps extends Record<string, any>>(rawProps: TProps): PropsAccessor<TProps> {\n let defaults: Partial<TProps> = {};\n\n const handler: ProxyHandler<any> = {\n get(_, key: string | symbol) {\n if (typeof key === 'symbol') return undefined;\n const value = (rawProps as any)[key];\n // Return prop value if defined (not null/undefined), otherwise fall back to default\n return value != null ? value : (defaults as any)[key];\n },\n apply(_, __, args: [Partial<TProps>]) {\n if (args[0] && typeof args[0] === 'object') {\n defaults = { ...defaults, ...args[0] };\n }\n return proxy;\n },\n has(_, key: string | symbol) {\n if (typeof key === 'symbol') return false;\n return key in rawProps || key in defaults;\n },\n ownKeys() {\n return [...new Set([...Object.keys(rawProps), ...Object.keys(defaults)])];\n },\n getOwnPropertyDescriptor(_, key: string | symbol) {\n if (typeof key === 'symbol') return undefined;\n if (key in rawProps || key in defaults) {\n return { enumerable: true, configurable: true, writable: false };\n }\n return undefined;\n }\n };\n\n const proxy = new Proxy(\n function propsAccessor() { } as unknown as PropsAccessor<TProps>,\n handler\n );\n return proxy;\n}\n\n/**\n * Check if a vnode type is a component (has __setup)\n */\nfunction isComponent(type: any): type is { __setup: Function; __name?: string } {\n return typeof type === 'function' && '__setup' in type;\n}\n\nexport async function renderToString(element: JSXElement): Promise<string> {\n if (element == null || element === false || element === true) {\n return '';\n }\n\n if (typeof element === 'string' || typeof element === 'number') {\n return escapeHtml(String(element));\n }\n\n const vnode = element as VNode;\n\n if (vnode.type === Text) {\n return escapeHtml(String(vnode.text));\n }\n\n if (vnode.type === Fragment) {\n const children = await Promise.all(vnode.children.map(renderToString));\n return children.join('');\n }\n\n // Handle Components (function with __setup)\n if (isComponent(vnode.type)) {\n const setup = vnode.type.__setup;\n const { children, ...propsData } = vnode.props || {};\n\n // Create slots from children\n const slots: SlotsObject<any> = {\n default: () => children ? (Array.isArray(children) ? children : [children]) : []\n };\n\n const ctx: ComponentSetupContext = {\n el: null as any, // No DOM element in SSR\n signal: signal,\n props: createSSRPropsAccessor(propsData),\n slots: slots,\n emit: () => { }, // No-op emit\n parent: null,\n onMount: () => { }, // No-op lifecycle\n onCleanup: () => { },\n expose: () => { }, // No-op expose\n renderFn: null, // SSR doesn't need renderFn\n update: () => { } // No-op update (SSR is single render)\n };\n\n const prev = setCurrentInstance(ctx);\n try {\n const renderFn = setup(ctx);\n if (renderFn) {\n const result = renderFn();\n if (result) {\n // Handle array results (fragments)\n if (Array.isArray(result)) {\n const children = await Promise.all(result.map(renderToString));\n return children.join('');\n }\n return await renderToString(result);\n }\n }\n } catch (e) {\n console.error(`Error rendering component:`, e);\n } finally {\n setCurrentInstance(prev || null);\n }\n\n return '';\n }\n\n // Handle host elements\n if (typeof vnode.type === 'string') {\n const tagName = vnode.type;\n let props = '';\n let children = '';\n\n // Serialize props\n for (const key in vnode.props) {\n const value = vnode.props[key];\n if (key === 'children' || key === 'key' || key === 'ref') continue;\n\n if (key === 'style') {\n const styleString = typeof value === 'object'\n ? Object.entries(value).map(([k, v]) => `${k}:${v}`).join(';')\n : String(value);\n props += ` style=\"${escapeHtml(styleString)}\"`;\n } else if (key === 'className') {\n props += ` class=\"${escapeHtml(String(value))}\"`;\n } else if (key.startsWith('on')) {\n // Ignore event listeners\n } else if (value === true) {\n props += ` ${key}`;\n } else if (value !== false && value != null) {\n props += ` ${key}=\"${escapeHtml(String(value))}\"`;\n }\n }\n\n // Serialize children\n if (vnode.children.length > 0) {\n const renderedChildren = await Promise.all(vnode.children.map(renderToString));\n children = renderedChildren.join('');\n }\n\n // Void elements\n const voidElements = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];\n if (voidElements.includes(tagName)) {\n return `<${tagName}${props}>`;\n }\n\n return `<${tagName}${props}>${children}</${tagName}>`;\n }\n\n return '';\n}\n\nconst ESCAPE: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;'\n};\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, c => ESCAPE[c]);\n}\n"],"mappings":"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"}