@flexireact/core 1.0.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/LICENSE +21 -0
- package/README.md +549 -0
- package/cli/index.js +992 -0
- package/cli/index.ts +1129 -0
- package/core/api.js +143 -0
- package/core/build/index.js +357 -0
- package/core/cli/logger.js +347 -0
- package/core/client/hydration.js +137 -0
- package/core/client/index.js +8 -0
- package/core/client/islands.js +138 -0
- package/core/client/navigation.js +204 -0
- package/core/client/runtime.js +36 -0
- package/core/config.js +113 -0
- package/core/context.js +83 -0
- package/core/dev.js +47 -0
- package/core/index.js +76 -0
- package/core/islands/index.js +281 -0
- package/core/loader.js +111 -0
- package/core/logger.js +242 -0
- package/core/middleware/index.js +393 -0
- package/core/plugins/index.js +370 -0
- package/core/render/index.js +765 -0
- package/core/render.js +134 -0
- package/core/router/index.js +296 -0
- package/core/router.js +141 -0
- package/core/rsc/index.js +198 -0
- package/core/server/index.js +653 -0
- package/core/server.js +197 -0
- package/core/ssg/index.js +321 -0
- package/core/utils.js +176 -0
- package/package.json +73 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlexiReact React Server Components (RSC) System
|
|
3
|
+
*
|
|
4
|
+
* RSC allows components to run exclusively on the server, reducing client bundle size
|
|
5
|
+
* and enabling direct database/filesystem access in components.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* - Add 'use server' at the top of a component file to make it a Server Component
|
|
9
|
+
* - Add 'use client' at the top to make it a Client Component (hydrated on client)
|
|
10
|
+
* - Server Components can import Client Components, but not vice versa
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { renderToString } from 'react-dom/server';
|
|
15
|
+
import { isServerComponent, isClientComponent } from '../utils.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* RSC Payload format for streaming
|
|
19
|
+
*/
|
|
20
|
+
export const RSC_CONTENT_TYPE = 'text/x-component';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Processes a component tree for RSC
|
|
24
|
+
* Server components are rendered to HTML, client components are serialized
|
|
25
|
+
*/
|
|
26
|
+
export async function processServerComponent(Component, props, context) {
|
|
27
|
+
const componentInfo = {
|
|
28
|
+
isServer: true,
|
|
29
|
+
rendered: null,
|
|
30
|
+
clientComponents: [],
|
|
31
|
+
serverData: {}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
// If component has async data fetching
|
|
36
|
+
if (Component.getServerData) {
|
|
37
|
+
componentInfo.serverData = await Component.getServerData(context);
|
|
38
|
+
props = { ...props, ...componentInfo.serverData };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Render the server component
|
|
42
|
+
const element = React.createElement(Component, props);
|
|
43
|
+
componentInfo.rendered = renderToString(element);
|
|
44
|
+
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('RSC Error:', error);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return componentInfo;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates a client component reference for RSC payload
|
|
55
|
+
*/
|
|
56
|
+
export function createClientReference(componentPath, props) {
|
|
57
|
+
return {
|
|
58
|
+
$$typeof: Symbol.for('react.client.reference'),
|
|
59
|
+
$$id: componentPath,
|
|
60
|
+
$$props: props
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Serializes RSC payload for streaming
|
|
66
|
+
*/
|
|
67
|
+
export function serializeRSCPayload(componentTree) {
|
|
68
|
+
const payload = {
|
|
69
|
+
type: 'rsc',
|
|
70
|
+
tree: serializeNode(componentTree),
|
|
71
|
+
timestamp: Date.now()
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return JSON.stringify(payload);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Serializes a React node for RSC
|
|
79
|
+
*/
|
|
80
|
+
function serializeNode(node) {
|
|
81
|
+
if (node === null || node === undefined) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (typeof node === 'string' || typeof node === 'number' || typeof node === 'boolean') {
|
|
86
|
+
return node;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (Array.isArray(node)) {
|
|
90
|
+
return node.map(serializeNode);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (React.isValidElement(node)) {
|
|
94
|
+
const { type, props } = node;
|
|
95
|
+
|
|
96
|
+
// Handle client component references
|
|
97
|
+
if (type.$$typeof === Symbol.for('react.client.reference')) {
|
|
98
|
+
return {
|
|
99
|
+
$$type: 'client',
|
|
100
|
+
$$id: type.$$id,
|
|
101
|
+
props: serializeProps(props)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Handle regular elements
|
|
106
|
+
const typeName = typeof type === 'string' ? type : type.displayName || type.name || 'Unknown';
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
$$type: 'element',
|
|
110
|
+
type: typeName,
|
|
111
|
+
props: serializeProps(props)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return String(node);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Serializes props, handling special cases
|
|
120
|
+
*/
|
|
121
|
+
function serializeProps(props) {
|
|
122
|
+
const serialized = {};
|
|
123
|
+
|
|
124
|
+
for (const [key, value] of Object.entries(props)) {
|
|
125
|
+
if (key === 'children') {
|
|
126
|
+
serialized.children = serializeNode(value);
|
|
127
|
+
} else if (typeof value === 'function') {
|
|
128
|
+
// Functions can't be serialized - mark as client action
|
|
129
|
+
serialized[key] = { $$type: 'action', name: value.name };
|
|
130
|
+
} else if (value instanceof Date) {
|
|
131
|
+
serialized[key] = { $$type: 'date', value: value.toISOString() };
|
|
132
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
133
|
+
serialized[key] = JSON.parse(JSON.stringify(value));
|
|
134
|
+
} else {
|
|
135
|
+
serialized[key] = value;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return serialized;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Server Actions support
|
|
144
|
+
* Allows calling server functions from client components
|
|
145
|
+
*/
|
|
146
|
+
export function createServerAction(fn, actionId) {
|
|
147
|
+
// Mark function as server action
|
|
148
|
+
fn.$$typeof = Symbol.for('react.server.action');
|
|
149
|
+
fn.$$id = actionId;
|
|
150
|
+
|
|
151
|
+
return fn;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Handles server action invocation
|
|
156
|
+
*/
|
|
157
|
+
export async function handleServerAction(actionId, args, context) {
|
|
158
|
+
// Actions are registered during build
|
|
159
|
+
const action = globalThis.__FLEXI_ACTIONS__?.[actionId];
|
|
160
|
+
|
|
161
|
+
if (!action) {
|
|
162
|
+
throw new Error(`Server action not found: ${actionId}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return await action(...args, context);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* RSC Boundary component
|
|
170
|
+
* Marks the boundary between server and client rendering
|
|
171
|
+
*/
|
|
172
|
+
export function ServerBoundary({ children, fallback }) {
|
|
173
|
+
return children;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Client Boundary component
|
|
178
|
+
* Marks components that should be hydrated on the client
|
|
179
|
+
*/
|
|
180
|
+
export function ClientBoundary({ children, fallback }) {
|
|
181
|
+
// On server, render children normally
|
|
182
|
+
// On client, this will be hydrated
|
|
183
|
+
return React.createElement('div', {
|
|
184
|
+
'data-flexi-client': 'true',
|
|
185
|
+
children
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export default {
|
|
190
|
+
processServerComponent,
|
|
191
|
+
createClientReference,
|
|
192
|
+
serializeRSCPayload,
|
|
193
|
+
createServerAction,
|
|
194
|
+
handleServerAction,
|
|
195
|
+
ServerBoundary,
|
|
196
|
+
ClientBoundary,
|
|
197
|
+
RSC_CONTENT_TYPE
|
|
198
|
+
};
|