@useavalon/avalon 0.1.11 → 0.1.13
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/README.md +54 -54
- package/mod.ts +302 -302
- package/package.json +49 -26
- package/src/build/integration-bundler-plugin.ts +116 -116
- package/src/build/integration-config.ts +168 -168
- package/src/build/integration-detection-plugin.ts +117 -117
- package/src/build/integration-resolver-plugin.ts +90 -90
- package/src/build/island-manifest.ts +269 -269
- package/src/build/island-types-generator.ts +476 -476
- package/src/build/mdx-island-transform.ts +464 -464
- package/src/build/mdx-plugin.ts +98 -98
- package/src/build/page-island-transform.ts +598 -598
- package/src/build/prop-extractors/index.ts +21 -21
- package/src/build/prop-extractors/lit.ts +140 -140
- package/src/build/prop-extractors/qwik.ts +16 -16
- package/src/build/prop-extractors/solid.ts +125 -125
- package/src/build/prop-extractors/svelte.ts +194 -194
- package/src/build/prop-extractors/vue.ts +111 -111
- package/src/build/sidecar-file-manager.ts +104 -104
- package/src/build/sidecar-renderer.ts +30 -30
- package/src/client/adapters/index.ts +21 -13
- package/src/client/components.ts +35 -35
- package/src/client/css-hmr-handler.ts +344 -344
- package/src/client/framework-adapter.ts +462 -462
- package/src/client/hmr-coordinator.ts +396 -396
- package/src/client/hmr-error-overlay.js +533 -533
- package/src/client/main.js +824 -816
- package/src/client/types/framework-runtime.d.ts +68 -68
- package/src/client/types/vite-hmr.d.ts +46 -46
- package/src/client/types/vite-virtual-modules.d.ts +70 -60
- package/src/components/Image.tsx +123 -123
- package/src/components/IslandErrorBoundary.tsx +145 -145
- package/src/components/LayoutDataErrorBoundary.tsx +141 -141
- package/src/components/LayoutErrorBoundary.tsx +127 -127
- package/src/components/PersistentIsland.tsx +52 -52
- package/src/components/StreamingErrorBoundary.tsx +233 -233
- package/src/components/StreamingLayout.tsx +538 -538
- package/src/core/components/component-analyzer.ts +192 -192
- package/src/core/components/component-detection.ts +508 -508
- package/src/core/components/enhanced-framework-detector.ts +500 -500
- package/src/core/components/framework-registry.ts +563 -563
- package/src/core/content/mdx-processor.ts +46 -46
- package/src/core/integrations/index.ts +19 -19
- package/src/core/integrations/loader.ts +125 -125
- package/src/core/integrations/registry.ts +175 -175
- package/src/core/islands/island-persistence.ts +325 -325
- package/src/core/islands/island-state-serializer.ts +258 -258
- package/src/core/islands/persistent-island-context.tsx +80 -80
- package/src/core/islands/use-persistent-state.ts +68 -68
- package/src/core/layout/enhanced-layout-resolver.ts +322 -322
- package/src/core/layout/layout-cache-manager.ts +485 -485
- package/src/core/layout/layout-composer.ts +357 -357
- package/src/core/layout/layout-data-loader.ts +516 -516
- package/src/core/layout/layout-discovery.ts +243 -243
- package/src/core/layout/layout-matcher.ts +299 -299
- package/src/core/layout/layout-types.ts +110 -110
- package/src/core/modules/framework-module-resolver.ts +273 -273
- package/src/islands/component-analysis.ts +213 -213
- package/src/islands/css-utils.ts +565 -565
- package/src/islands/discovery/index.ts +80 -80
- package/src/islands/discovery/registry.ts +340 -340
- package/src/islands/discovery/resolver.ts +477 -477
- package/src/islands/discovery/scanner.ts +386 -386
- package/src/islands/discovery/types.ts +117 -117
- package/src/islands/discovery/validator.ts +544 -544
- package/src/islands/discovery/watcher.ts +368 -368
- package/src/islands/framework-detection.ts +428 -428
- package/src/islands/integration-loader.ts +490 -490
- package/src/islands/island.tsx +565 -565
- package/src/islands/render-cache.ts +550 -550
- package/src/islands/types.ts +80 -80
- package/src/islands/universal-css-collector.ts +157 -157
- package/src/islands/universal-head-collector.ts +137 -137
- package/src/layout-system.d.ts +592 -592
- package/src/layout-system.ts +218 -218
- package/src/middleware/discovery.ts +268 -268
- package/src/middleware/executor.ts +315 -315
- package/src/middleware/index.ts +76 -76
- package/src/middleware/types.ts +99 -99
- package/src/nitro/build-config.ts +575 -575
- package/src/nitro/config.ts +483 -483
- package/src/nitro/error-handler.ts +636 -636
- package/src/nitro/index.ts +173 -173
- package/src/nitro/island-manifest.ts +584 -584
- package/src/nitro/middleware-adapter.ts +260 -260
- package/src/nitro/renderer.ts +1471 -1471
- package/src/nitro/route-discovery.ts +439 -439
- package/src/nitro/types.ts +321 -321
- package/src/render/collect-css.ts +198 -198
- package/src/render/error-pages.ts +79 -79
- package/src/render/isolated-ssr-renderer.ts +654 -654
- package/src/render/ssr.ts +1030 -1030
- package/src/schemas/api.ts +30 -30
- package/src/schemas/core.ts +64 -64
- package/src/schemas/index.ts +212 -212
- package/src/schemas/layout.ts +279 -279
- package/src/schemas/routing/index.ts +38 -38
- package/src/schemas/routing.ts +376 -376
- package/src/types/as-island.ts +20 -20
- package/src/types/image.d.ts +106 -106
- package/src/types/index.d.ts +22 -22
- package/src/types/island-jsx.d.ts +33 -33
- package/src/types/island-prop.d.ts +20 -20
- package/src/types/layout.ts +285 -285
- package/src/types/mdx.d.ts +6 -6
- package/src/types/routing.ts +555 -555
- package/src/types/types.ts +5 -5
- package/src/types/urlpattern.d.ts +49 -49
- package/src/types/vite-env.d.ts +11 -11
- package/src/utils/dev-logger.ts +299 -299
- package/src/utils/fs.ts +151 -151
- package/src/vite-plugin/auto-discover.ts +551 -551
- package/src/vite-plugin/config.ts +266 -266
- package/src/vite-plugin/errors.ts +127 -127
- package/src/vite-plugin/image-optimization.ts +156 -156
- package/src/vite-plugin/integration-activator.ts +126 -126
- package/src/vite-plugin/island-sidecar-plugin.ts +176 -176
- package/src/vite-plugin/module-discovery.ts +189 -189
- package/src/vite-plugin/nitro-integration.ts +1354 -1354
- package/src/vite-plugin/plugin.ts +403 -409
- package/src/vite-plugin/types.ts +327 -327
- package/src/vite-plugin/validation.ts +228 -228
- package/src/client/adapters/index.js +0 -12
- package/src/client/adapters/lit-adapter.js +0 -467
- package/src/client/adapters/lit-adapter.ts +0 -654
- package/src/client/adapters/preact-adapter.js +0 -223
- package/src/client/adapters/preact-adapter.ts +0 -331
- package/src/client/adapters/qwik-adapter.js +0 -259
- package/src/client/adapters/qwik-adapter.ts +0 -345
- package/src/client/adapters/react-adapter.js +0 -220
- package/src/client/adapters/react-adapter.ts +0 -353
- package/src/client/adapters/solid-adapter.js +0 -295
- package/src/client/adapters/solid-adapter.ts +0 -451
- package/src/client/adapters/svelte-adapter.js +0 -368
- package/src/client/adapters/svelte-adapter.ts +0 -524
- package/src/client/adapters/vue-adapter.js +0 -278
- package/src/client/adapters/vue-adapter.ts +0 -467
- package/src/client/components.js +0 -23
- package/src/client/css-hmr-handler.js +0 -263
- package/src/client/framework-adapter.js +0 -283
- package/src/client/hmr-coordinator.js +0 -274
package/src/islands/types.ts
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import type { JSX } from "preact";
|
|
2
|
-
import type { AnalyzerOptions } from "../core/components/component-analyzer.ts";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Framework type for island components
|
|
6
|
-
* Represents the supported UI frameworks for island architecture
|
|
7
|
-
*/
|
|
8
|
-
export type Framework =
|
|
9
|
-
| "solid"
|
|
10
|
-
| "vue"
|
|
11
|
-
| "svelte"
|
|
12
|
-
| "preact"
|
|
13
|
-
| "react"
|
|
14
|
-
| "lit"
|
|
15
|
-
| "qwik"
|
|
16
|
-
| "unknown";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Props for the Island component
|
|
20
|
-
* Defines the configuration for rendering an interactive island component
|
|
21
|
-
*/
|
|
22
|
-
export interface IslandProps {
|
|
23
|
-
/** Path to the island component (e.g., "/islands/Counter.tsx") */
|
|
24
|
-
src: string;
|
|
25
|
-
/** Hydration condition */
|
|
26
|
-
condition?:
|
|
27
|
-
| "on:visible"
|
|
28
|
-
| "on:interaction"
|
|
29
|
-
| "on:idle"
|
|
30
|
-
| "on:client"
|
|
31
|
-
| `media:${string}`;
|
|
32
|
-
/** Props to pass to the island component */
|
|
33
|
-
props?: Record<string, unknown>;
|
|
34
|
-
/** Children to render inside the island (for SSR) */
|
|
35
|
-
children?: JSX.Element | JSX.Element[] | string;
|
|
36
|
-
/** Whether to render server-side (default: true unless condition is 'on:client') */
|
|
37
|
-
ssr?: boolean;
|
|
38
|
-
/** Framework hint for client hydration */
|
|
39
|
-
framework?: "solid" | "vue" | "preact" | "react" | "svelte" | "lit" | "qwik";
|
|
40
|
-
/** Force SSR-only rendering without hydration */
|
|
41
|
-
ssrOnly?: boolean;
|
|
42
|
-
/** Component render options for intelligent detection */
|
|
43
|
-
renderOptions?: AnalyzerOptions;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Parameters for framework-specific render functions
|
|
48
|
-
* Used by all framework renderers to maintain consistent interface
|
|
49
|
-
*/
|
|
50
|
-
export interface RenderParams {
|
|
51
|
-
/** Path to the island component */
|
|
52
|
-
src: string;
|
|
53
|
-
/** Hydration condition */
|
|
54
|
-
condition: IslandProps["condition"];
|
|
55
|
-
/** Props to pass to the component */
|
|
56
|
-
props: Record<string, unknown>;
|
|
57
|
-
/** Whether to render server-side */
|
|
58
|
-
ssr: boolean;
|
|
59
|
-
/** Component render options for intelligent detection */
|
|
60
|
-
renderOptions?: AnalyzerOptions;
|
|
61
|
-
/** Force SSR-only rendering without hydration */
|
|
62
|
-
ssrOnly?: boolean;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Entry in the Svelte SSR CSS collection
|
|
67
|
-
* Tracks CSS for Svelte components during server-side rendering
|
|
68
|
-
*/
|
|
69
|
-
export interface SvelteSSRCSSEntry {
|
|
70
|
-
/** The CSS content */
|
|
71
|
-
css: string;
|
|
72
|
-
/** Unique scope identifier for the component */
|
|
73
|
-
scopeId: string;
|
|
74
|
-
/** Source path of the component */
|
|
75
|
-
src: string;
|
|
76
|
-
/** Whether this is global CSS */
|
|
77
|
-
isGlobal: boolean;
|
|
78
|
-
/** Timestamp when the CSS was added */
|
|
79
|
-
timestamp: number;
|
|
80
|
-
}
|
|
1
|
+
import type { JSX } from "preact";
|
|
2
|
+
import type { AnalyzerOptions } from "../core/components/component-analyzer.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Framework type for island components
|
|
6
|
+
* Represents the supported UI frameworks for island architecture
|
|
7
|
+
*/
|
|
8
|
+
export type Framework =
|
|
9
|
+
| "solid"
|
|
10
|
+
| "vue"
|
|
11
|
+
| "svelte"
|
|
12
|
+
| "preact"
|
|
13
|
+
| "react"
|
|
14
|
+
| "lit"
|
|
15
|
+
| "qwik"
|
|
16
|
+
| "unknown";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Props for the Island component
|
|
20
|
+
* Defines the configuration for rendering an interactive island component
|
|
21
|
+
*/
|
|
22
|
+
export interface IslandProps {
|
|
23
|
+
/** Path to the island component (e.g., "/islands/Counter.tsx") */
|
|
24
|
+
src: string;
|
|
25
|
+
/** Hydration condition */
|
|
26
|
+
condition?:
|
|
27
|
+
| "on:visible"
|
|
28
|
+
| "on:interaction"
|
|
29
|
+
| "on:idle"
|
|
30
|
+
| "on:client"
|
|
31
|
+
| `media:${string}`;
|
|
32
|
+
/** Props to pass to the island component */
|
|
33
|
+
props?: Record<string, unknown>;
|
|
34
|
+
/** Children to render inside the island (for SSR) */
|
|
35
|
+
children?: JSX.Element | JSX.Element[] | string;
|
|
36
|
+
/** Whether to render server-side (default: true unless condition is 'on:client') */
|
|
37
|
+
ssr?: boolean;
|
|
38
|
+
/** Framework hint for client hydration */
|
|
39
|
+
framework?: "solid" | "vue" | "preact" | "react" | "svelte" | "lit" | "qwik";
|
|
40
|
+
/** Force SSR-only rendering without hydration */
|
|
41
|
+
ssrOnly?: boolean;
|
|
42
|
+
/** Component render options for intelligent detection */
|
|
43
|
+
renderOptions?: AnalyzerOptions;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parameters for framework-specific render functions
|
|
48
|
+
* Used by all framework renderers to maintain consistent interface
|
|
49
|
+
*/
|
|
50
|
+
export interface RenderParams {
|
|
51
|
+
/** Path to the island component */
|
|
52
|
+
src: string;
|
|
53
|
+
/** Hydration condition */
|
|
54
|
+
condition: IslandProps["condition"];
|
|
55
|
+
/** Props to pass to the component */
|
|
56
|
+
props: Record<string, unknown>;
|
|
57
|
+
/** Whether to render server-side */
|
|
58
|
+
ssr: boolean;
|
|
59
|
+
/** Component render options for intelligent detection */
|
|
60
|
+
renderOptions?: AnalyzerOptions;
|
|
61
|
+
/** Force SSR-only rendering without hydration */
|
|
62
|
+
ssrOnly?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Entry in the Svelte SSR CSS collection
|
|
67
|
+
* Tracks CSS for Svelte components during server-side rendering
|
|
68
|
+
*/
|
|
69
|
+
export interface SvelteSSRCSSEntry {
|
|
70
|
+
/** The CSS content */
|
|
71
|
+
css: string;
|
|
72
|
+
/** Unique scope identifier for the component */
|
|
73
|
+
scopeId: string;
|
|
74
|
+
/** Source path of the component */
|
|
75
|
+
src: string;
|
|
76
|
+
/** Whether this is global CSS */
|
|
77
|
+
isGlobal: boolean;
|
|
78
|
+
/** Timestamp when the CSS was added */
|
|
79
|
+
timestamp: number;
|
|
80
|
+
}
|
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Universal CSS Collector
|
|
3
|
-
*
|
|
4
|
-
* Collects and manages CSS from all framework integrations (Vue, Svelte, Solid, Preact)
|
|
5
|
-
* during SSR rendering. Provides a unified interface for CSS injection into the document head.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
declare global {
|
|
9
|
-
var __universalSSRCSS: Map<string, UniversalCSSEntry> | undefined;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface UniversalCSSEntry {
|
|
13
|
-
css: string;
|
|
14
|
-
scopeId: string;
|
|
15
|
-
src: string;
|
|
16
|
-
framework: string;
|
|
17
|
-
timestamp: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Initialize global CSS collector
|
|
21
|
-
if (typeof globalThis !== "undefined" && !globalThis.__universalSSRCSS) {
|
|
22
|
-
globalThis.__universalSSRCSS = new Map();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Add CSS from any framework integration to the global collection
|
|
27
|
-
*/
|
|
28
|
-
export function addUniversalCSS(
|
|
29
|
-
css: string,
|
|
30
|
-
src: string,
|
|
31
|
-
framework: string,
|
|
32
|
-
scopeId?: string,
|
|
33
|
-
): void {
|
|
34
|
-
if (!css || !css.trim()) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (!globalThis.__universalSSRCSS) {
|
|
39
|
-
globalThis.__universalSSRCSS = new Map();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Generate a unique key for this CSS entry
|
|
43
|
-
const key = scopeId || `${framework}-${src}`;
|
|
44
|
-
|
|
45
|
-
const entry: UniversalCSSEntry = {
|
|
46
|
-
css: css.trim(),
|
|
47
|
-
scopeId: key,
|
|
48
|
-
src,
|
|
49
|
-
framework,
|
|
50
|
-
timestamp: Date.now(),
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
globalThis.__universalSSRCSS.set(key, entry);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Get all collected CSS from all frameworks
|
|
58
|
-
*/
|
|
59
|
-
export function getUniversalCSS(clear = false): string {
|
|
60
|
-
if (!globalThis.__universalSSRCSS || globalThis.__universalSSRCSS.size === 0) {
|
|
61
|
-
return "";
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const entries = Array.from(globalThis.__universalSSRCSS.values());
|
|
65
|
-
|
|
66
|
-
// Sort by timestamp to maintain render order
|
|
67
|
-
entries.sort((a, b) => a.timestamp - b.timestamp);
|
|
68
|
-
|
|
69
|
-
// Group by framework for better organization
|
|
70
|
-
const cssByFramework = entries.reduce((acc, entry) => {
|
|
71
|
-
if (!acc[entry.framework]) {
|
|
72
|
-
acc[entry.framework] = [];
|
|
73
|
-
}
|
|
74
|
-
acc[entry.framework].push(entry);
|
|
75
|
-
return acc;
|
|
76
|
-
}, {} as Record<string, UniversalCSSEntry[]>);
|
|
77
|
-
|
|
78
|
-
// Build CSS string with framework sections
|
|
79
|
-
const cssBlocks: string[] = [];
|
|
80
|
-
|
|
81
|
-
for (const [framework, frameworkEntries] of Object.entries(cssByFramework)) {
|
|
82
|
-
const frameworkCSS = frameworkEntries.map((entry) => {
|
|
83
|
-
const comment = `/* ${framework}: ${entry.src} (${entry.scopeId}) */`;
|
|
84
|
-
return `${comment}\n${entry.css}`;
|
|
85
|
-
}).join("\n\n");
|
|
86
|
-
|
|
87
|
-
cssBlocks.push(frameworkCSS);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const combinedCSS = cssBlocks.join("\n\n");
|
|
91
|
-
|
|
92
|
-
if (clear) {
|
|
93
|
-
globalThis.__universalSSRCSS.clear();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return combinedCSS;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Get CSS formatted for document head injection
|
|
101
|
-
*/
|
|
102
|
-
export function getUniversalCSSForHead(clear = false): string {
|
|
103
|
-
const css = getUniversalCSS(clear);
|
|
104
|
-
|
|
105
|
-
if (!css.trim()) {
|
|
106
|
-
return "";
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const timestamp = new Date().toISOString();
|
|
110
|
-
const styleTag =
|
|
111
|
-
`<style data-universal-ssr="true" data-generated="${timestamp}">\n${css}\n</style>`;
|
|
112
|
-
|
|
113
|
-
return styleTag;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Clear all collected CSS
|
|
118
|
-
*/
|
|
119
|
-
export function clearUniversalCSS(): void {
|
|
120
|
-
if (globalThis.__universalSSRCSS) {
|
|
121
|
-
globalThis.__universalSSRCSS.clear();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get CSS statistics
|
|
127
|
-
*/
|
|
128
|
-
export function getUniversalCSSStats(): {
|
|
129
|
-
totalComponents: number;
|
|
130
|
-
byFramework: Record<string, number>;
|
|
131
|
-
totalCSSSize: number;
|
|
132
|
-
averageCSSSize: number;
|
|
133
|
-
} {
|
|
134
|
-
if (!globalThis.__universalSSRCSS || globalThis.__universalSSRCSS.size === 0) {
|
|
135
|
-
return {
|
|
136
|
-
totalComponents: 0,
|
|
137
|
-
byFramework: {},
|
|
138
|
-
totalCSSSize: 0,
|
|
139
|
-
averageCSSSize: 0,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const entries = Array.from(globalThis.__universalSSRCSS.values());
|
|
144
|
-
const byFramework = entries.reduce((acc, entry) => {
|
|
145
|
-
acc[entry.framework] = (acc[entry.framework] || 0) + 1;
|
|
146
|
-
return acc;
|
|
147
|
-
}, {} as Record<string, number>);
|
|
148
|
-
|
|
149
|
-
const totalCSSSize = entries.reduce((sum, entry) => sum + entry.css.length, 0);
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
totalComponents: entries.length,
|
|
153
|
-
byFramework,
|
|
154
|
-
totalCSSSize,
|
|
155
|
-
averageCSSSize: entries.length > 0 ? Math.round(totalCSSSize / entries.length) : 0,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Universal CSS Collector
|
|
3
|
+
*
|
|
4
|
+
* Collects and manages CSS from all framework integrations (Vue, Svelte, Solid, Preact)
|
|
5
|
+
* during SSR rendering. Provides a unified interface for CSS injection into the document head.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
var __universalSSRCSS: Map<string, UniversalCSSEntry> | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UniversalCSSEntry {
|
|
13
|
+
css: string;
|
|
14
|
+
scopeId: string;
|
|
15
|
+
src: string;
|
|
16
|
+
framework: string;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Initialize global CSS collector
|
|
21
|
+
if (typeof globalThis !== "undefined" && !globalThis.__universalSSRCSS) {
|
|
22
|
+
globalThis.__universalSSRCSS = new Map();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Add CSS from any framework integration to the global collection
|
|
27
|
+
*/
|
|
28
|
+
export function addUniversalCSS(
|
|
29
|
+
css: string,
|
|
30
|
+
src: string,
|
|
31
|
+
framework: string,
|
|
32
|
+
scopeId?: string,
|
|
33
|
+
): void {
|
|
34
|
+
if (!css || !css.trim()) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!globalThis.__universalSSRCSS) {
|
|
39
|
+
globalThis.__universalSSRCSS = new Map();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Generate a unique key for this CSS entry
|
|
43
|
+
const key = scopeId || `${framework}-${src}`;
|
|
44
|
+
|
|
45
|
+
const entry: UniversalCSSEntry = {
|
|
46
|
+
css: css.trim(),
|
|
47
|
+
scopeId: key,
|
|
48
|
+
src,
|
|
49
|
+
framework,
|
|
50
|
+
timestamp: Date.now(),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
globalThis.__universalSSRCSS.set(key, entry);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get all collected CSS from all frameworks
|
|
58
|
+
*/
|
|
59
|
+
export function getUniversalCSS(clear = false): string {
|
|
60
|
+
if (!globalThis.__universalSSRCSS || globalThis.__universalSSRCSS.size === 0) {
|
|
61
|
+
return "";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const entries = Array.from(globalThis.__universalSSRCSS.values());
|
|
65
|
+
|
|
66
|
+
// Sort by timestamp to maintain render order
|
|
67
|
+
entries.sort((a, b) => a.timestamp - b.timestamp);
|
|
68
|
+
|
|
69
|
+
// Group by framework for better organization
|
|
70
|
+
const cssByFramework = entries.reduce((acc, entry) => {
|
|
71
|
+
if (!acc[entry.framework]) {
|
|
72
|
+
acc[entry.framework] = [];
|
|
73
|
+
}
|
|
74
|
+
acc[entry.framework].push(entry);
|
|
75
|
+
return acc;
|
|
76
|
+
}, {} as Record<string, UniversalCSSEntry[]>);
|
|
77
|
+
|
|
78
|
+
// Build CSS string with framework sections
|
|
79
|
+
const cssBlocks: string[] = [];
|
|
80
|
+
|
|
81
|
+
for (const [framework, frameworkEntries] of Object.entries(cssByFramework)) {
|
|
82
|
+
const frameworkCSS = frameworkEntries.map((entry) => {
|
|
83
|
+
const comment = `/* ${framework}: ${entry.src} (${entry.scopeId}) */`;
|
|
84
|
+
return `${comment}\n${entry.css}`;
|
|
85
|
+
}).join("\n\n");
|
|
86
|
+
|
|
87
|
+
cssBlocks.push(frameworkCSS);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const combinedCSS = cssBlocks.join("\n\n");
|
|
91
|
+
|
|
92
|
+
if (clear) {
|
|
93
|
+
globalThis.__universalSSRCSS.clear();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return combinedCSS;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get CSS formatted for document head injection
|
|
101
|
+
*/
|
|
102
|
+
export function getUniversalCSSForHead(clear = false): string {
|
|
103
|
+
const css = getUniversalCSS(clear);
|
|
104
|
+
|
|
105
|
+
if (!css.trim()) {
|
|
106
|
+
return "";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const timestamp = new Date().toISOString();
|
|
110
|
+
const styleTag =
|
|
111
|
+
`<style data-universal-ssr="true" data-generated="${timestamp}">\n${css}\n</style>`;
|
|
112
|
+
|
|
113
|
+
return styleTag;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Clear all collected CSS
|
|
118
|
+
*/
|
|
119
|
+
export function clearUniversalCSS(): void {
|
|
120
|
+
if (globalThis.__universalSSRCSS) {
|
|
121
|
+
globalThis.__universalSSRCSS.clear();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get CSS statistics
|
|
127
|
+
*/
|
|
128
|
+
export function getUniversalCSSStats(): {
|
|
129
|
+
totalComponents: number;
|
|
130
|
+
byFramework: Record<string, number>;
|
|
131
|
+
totalCSSSize: number;
|
|
132
|
+
averageCSSSize: number;
|
|
133
|
+
} {
|
|
134
|
+
if (!globalThis.__universalSSRCSS || globalThis.__universalSSRCSS.size === 0) {
|
|
135
|
+
return {
|
|
136
|
+
totalComponents: 0,
|
|
137
|
+
byFramework: {},
|
|
138
|
+
totalCSSSize: 0,
|
|
139
|
+
averageCSSSize: 0,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const entries = Array.from(globalThis.__universalSSRCSS.values());
|
|
144
|
+
const byFramework = entries.reduce((acc, entry) => {
|
|
145
|
+
acc[entry.framework] = (acc[entry.framework] || 0) + 1;
|
|
146
|
+
return acc;
|
|
147
|
+
}, {} as Record<string, number>);
|
|
148
|
+
|
|
149
|
+
const totalCSSSize = entries.reduce((sum, entry) => sum + entry.css.length, 0);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
totalComponents: entries.length,
|
|
153
|
+
byFramework,
|
|
154
|
+
totalCSSSize,
|
|
155
|
+
averageCSSSize: entries.length > 0 ? Math.round(totalCSSSize / entries.length) : 0,
|
|
156
|
+
};
|
|
157
|
+
}
|