@teambit/ui 0.0.802 → 0.0.805
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/create-root.js +1 -1
- package/dist/create-root.js.map +1 -1
- package/dist/index.d.ts +12 -5
- package/dist/index.js.map +1 -1
- package/dist/ssr-middleware/ssr-middleware.d.ts +2 -2
- package/dist/ssr-middleware/ssr-middleware.js +20 -18
- package/dist/ssr-middleware/ssr-middleware.js.map +1 -1
- package/dist/ui-root.d.ts +3 -3
- package/dist/ui-root.js.map +1 -1
- package/dist/ui.main.runtime.d.ts +1 -1
- package/dist/ui.main.runtime.js +2 -2
- package/dist/ui.main.runtime.js.map +1 -1
- package/dist/ui.ui.runtime.d.ts +4 -5
- package/dist/ui.ui.runtime.js +27 -17
- package/dist/ui.ui.runtime.js.map +1 -1
- package/package-tar/teambit-ui-0.0.805.tgz +0 -0
- package/package.json +19 -22
- package/{preview-1659151732866.js → preview-1659456045857.js} +2 -2
- package/ssr-middleware/ssr-middleware.ts +15 -16
- package/ui-root.tsx +7 -3
- package/ui.ui.runtime.tsx +21 -18
- package/dist/react-ssr/index.d.ts +0 -5
- package/dist/react-ssr/index.js +0 -23
- package/dist/react-ssr/index.js.map +0 -1
- package/dist/react-ssr/react-ssr.d.ts +0 -21
- package/dist/react-ssr/react-ssr.js +0 -285
- package/dist/react-ssr/react-ssr.js.map +0 -1
- package/dist/react-ssr/render-lifecycle.d.ts +0 -56
- package/dist/react-ssr/render-lifecycle.js +0 -3
- package/dist/react-ssr/render-lifecycle.js.map +0 -1
- package/dist/react-ssr/request-browser.d.ts +0 -56
- package/dist/react-ssr/request-browser.js +0 -3
- package/dist/react-ssr/request-browser.js.map +0 -1
- package/dist/react-ssr/request-server.d.ts +0 -9
- package/dist/react-ssr/request-server.js +0 -3
- package/dist/react-ssr/request-server.js.map +0 -1
- package/dist/react-ssr/ssr-content.d.ts +0 -8
- package/dist/react-ssr/ssr-content.js +0 -3
- package/dist/react-ssr/ssr-content.js.map +0 -1
- package/dist/ssr-middleware/extract-browser-data.d.ts +0 -6
- package/dist/ssr-middleware/extract-browser-data.js +0 -35
- package/dist/ssr-middleware/extract-browser-data.js.map +0 -1
- package/package-tar/teambit-ui-0.0.802.tgz +0 -0
- package/react-ssr/index.ts +0 -6
- package/react-ssr/react-ssr.tsx +0 -183
- package/react-ssr/render-lifecycle.tsx +0 -58
- package/react-ssr/request-browser.ts +0 -55
- package/react-ssr/request-server.ts +0 -10
- package/react-ssr/ssr-content.ts +0 -9
- package/ssr-middleware/extract-browser-data.ts +0 -31
package/react-ssr/react-ssr.tsx
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import React, { ReactNode } from 'react';
|
|
2
|
-
import { merge } from 'webpack-merge';
|
|
3
|
-
import compact from 'lodash.compact';
|
|
4
|
-
import ReactDOM from 'react-dom';
|
|
5
|
-
import ReactDOMServer from 'react-dom/server';
|
|
6
|
-
|
|
7
|
-
import { Html, MountPoint, mountPointId, ssrCleanup, Assets } from '@teambit/ui-foundation.ui.rendering.html';
|
|
8
|
-
import { Composer, Wrapper } from '@teambit/base-ui.utils.composer';
|
|
9
|
-
|
|
10
|
-
import type { RenderPlugins } from './render-lifecycle';
|
|
11
|
-
import type { SsrContent } from './ssr-content';
|
|
12
|
-
import type { RequestServer } from './request-server';
|
|
13
|
-
import type { BrowserData } from './request-browser';
|
|
14
|
-
|
|
15
|
-
type RenderPluginsWithId = [key: string, hooks: RenderPlugins];
|
|
16
|
-
|
|
17
|
-
export class ReactSSR {
|
|
18
|
-
constructor(
|
|
19
|
-
// create array once to keep consistent indexes
|
|
20
|
-
private lifecycleHooks: RenderPluginsWithId[]
|
|
21
|
-
) {}
|
|
22
|
-
|
|
23
|
-
/** render and rehydrate client-side */
|
|
24
|
-
async renderBrowser(children: ReactNode) {
|
|
25
|
-
// (*) load state from the dom
|
|
26
|
-
const deserializedState = await this.deserialize();
|
|
27
|
-
|
|
28
|
-
// (1) init setup client plugins
|
|
29
|
-
let renderContexts = await this.triggerBrowserInit(deserializedState);
|
|
30
|
-
|
|
31
|
-
// (2) make react dom
|
|
32
|
-
const reactContexts = this.getReactContexts(renderContexts);
|
|
33
|
-
const app = <Composer components={reactContexts}>{children}</Composer>;
|
|
34
|
-
|
|
35
|
-
renderContexts = await this.triggerBeforeHydrateHook(renderContexts, app);
|
|
36
|
-
|
|
37
|
-
// (3) render / rehydrate
|
|
38
|
-
const mountPoint = document.getElementById(mountPointId);
|
|
39
|
-
// .render() already runs `.hydrate()` behind the scenes.
|
|
40
|
-
// in the future, we may want to replace it with .hydrate()
|
|
41
|
-
ReactDOM.render(app, mountPoint);
|
|
42
|
-
|
|
43
|
-
await this.triggerHydrateHook(renderContexts, mountPoint);
|
|
44
|
-
|
|
45
|
-
// (3.1) remove ssr only styles
|
|
46
|
-
ssrCleanup();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** render dehydrated server-side */
|
|
50
|
-
async renderServer(children: ReactNode, { assets, browser, server }: SsrContent = {}): Promise<string> {
|
|
51
|
-
// (1) init
|
|
52
|
-
let renderContexts = await this.triggerServerInit(browser, server);
|
|
53
|
-
|
|
54
|
-
// (2) make React dom
|
|
55
|
-
const reactContexts = this.getReactContexts(renderContexts);
|
|
56
|
-
const app = (
|
|
57
|
-
<MountPoint>
|
|
58
|
-
<Composer components={reactContexts}>{children}</Composer>
|
|
59
|
-
</MountPoint>
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
renderContexts = await this.triggerBeforeRender(renderContexts, app);
|
|
63
|
-
|
|
64
|
-
// (3) render (to string)
|
|
65
|
-
const renderedApp = ReactDOMServer.renderToString(app);
|
|
66
|
-
|
|
67
|
-
// (*) serialize state
|
|
68
|
-
const realtimeAssets = await this.serialize(renderContexts, app);
|
|
69
|
-
// @ts-ignore // TODO upgrade 'webpack-merge'
|
|
70
|
-
const totalAssets = merge(assets, realtimeAssets) as Assets;
|
|
71
|
-
|
|
72
|
-
// (4) render html-template (to string)
|
|
73
|
-
const html = <Html assets={totalAssets} withDevTools fullHeight ssr />;
|
|
74
|
-
const renderedHtml = `<!DOCTYPE html>${ReactDOMServer.renderToStaticMarkup(html)}`;
|
|
75
|
-
const fullHtml = Html.fillContent(renderedHtml, renderedApp);
|
|
76
|
-
|
|
77
|
-
// (5) serve
|
|
78
|
-
return fullHtml;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
private triggerBrowserInit(deserializedState: any[]) {
|
|
82
|
-
const { lifecycleHooks } = this;
|
|
83
|
-
|
|
84
|
-
const initPromises = lifecycleHooks.map(([, hooks], idx) => {
|
|
85
|
-
const state = deserializedState[idx];
|
|
86
|
-
return hooks.browserInit?.(state);
|
|
87
|
-
});
|
|
88
|
-
return Promise.all(initPromises);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
private triggerServerInit(browser?: BrowserData, server?: RequestServer) {
|
|
92
|
-
const { lifecycleHooks } = this;
|
|
93
|
-
const promises = lifecycleHooks.map(([, hooks]) => hooks.serverInit?.({ browser, server }));
|
|
94
|
-
return Promise.all(promises);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private triggerBeforeHydrateHook(renderContexts: any[], app: JSX.Element) {
|
|
98
|
-
const { lifecycleHooks } = this;
|
|
99
|
-
|
|
100
|
-
const promises = lifecycleHooks.map(async ([, hooks], idx) => {
|
|
101
|
-
const ctx = renderContexts[idx];
|
|
102
|
-
const nextCtx = await hooks.onBeforeHydrate?.(ctx, app);
|
|
103
|
-
return nextCtx || ctx;
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
return Promise.all(promises);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
private async triggerHydrateHook(renderContexts: any[], mountPoint: HTMLElement | null) {
|
|
110
|
-
const { lifecycleHooks } = this;
|
|
111
|
-
|
|
112
|
-
const promises = lifecycleHooks.map(([, hooks], idx) => {
|
|
113
|
-
const renderCtx = renderContexts[idx];
|
|
114
|
-
return hooks.onHydrate?.(renderCtx, mountPoint);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
await Promise.all(promises);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
private async triggerBeforeRender(renderContexts: any[], app: JSX.Element) {
|
|
121
|
-
const { lifecycleHooks } = this;
|
|
122
|
-
|
|
123
|
-
const promises = lifecycleHooks.map(async ([, hooks], idx) => {
|
|
124
|
-
const ctx = renderContexts[idx];
|
|
125
|
-
const nextCtx = await hooks.onBeforeRender?.(ctx, app);
|
|
126
|
-
return nextCtx || ctx;
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
await Promise.all(promises);
|
|
130
|
-
|
|
131
|
-
return renderContexts;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private getReactContexts(renderContexts: any[]): Wrapper[] {
|
|
135
|
-
const { lifecycleHooks } = this;
|
|
136
|
-
|
|
137
|
-
return compact(
|
|
138
|
-
lifecycleHooks.map(([, hooks], idx) => {
|
|
139
|
-
const renderCtx = renderContexts[idx];
|
|
140
|
-
const props = { renderCtx };
|
|
141
|
-
return hooks.reactContext ? [hooks.reactContext, props] : undefined;
|
|
142
|
-
})
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private async deserialize() {
|
|
147
|
-
const { lifecycleHooks } = this;
|
|
148
|
-
const rawAssets = Html.popAssets();
|
|
149
|
-
|
|
150
|
-
const deserialized = await Promise.all(
|
|
151
|
-
lifecycleHooks.map(async ([key, hooks]) => {
|
|
152
|
-
try {
|
|
153
|
-
const raw = rawAssets.get(key);
|
|
154
|
-
return hooks.deserialize?.(raw);
|
|
155
|
-
} catch (e) {
|
|
156
|
-
// eslint-disable-next-line no-console
|
|
157
|
-
console.error(`failed deserializing server state for aspect ${key}`, e);
|
|
158
|
-
return undefined;
|
|
159
|
-
}
|
|
160
|
-
})
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
return deserialized;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private async serialize(renderContexts: any[], app: ReactNode): Promise<Assets> {
|
|
167
|
-
const { lifecycleHooks } = this;
|
|
168
|
-
const json = {};
|
|
169
|
-
|
|
170
|
-
const promises = lifecycleHooks.map(async ([key, hooks], idx) => {
|
|
171
|
-
const renderCtx = renderContexts[idx];
|
|
172
|
-
const result = await hooks.serialize?.(renderCtx, app);
|
|
173
|
-
|
|
174
|
-
if (!result) return;
|
|
175
|
-
if (result.json) json[key] = result.json;
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
await Promise.all(promises);
|
|
179
|
-
|
|
180
|
-
// more assets will be available in the future
|
|
181
|
-
return { json };
|
|
182
|
-
}
|
|
183
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { ReactNode, ComponentType } from 'react';
|
|
2
|
-
import { BrowserData } from './request-browser';
|
|
3
|
-
import { RequestServer } from './request-server';
|
|
4
|
-
|
|
5
|
-
export type ContextProps<T = any> = { renderCtx?: T; children: ReactNode };
|
|
6
|
-
|
|
7
|
-
/** Plugins for each step of the SSR and regular rendering lifecycle */
|
|
8
|
-
export type RenderPlugins<RenderCtx = any, Serialized = any> = {
|
|
9
|
-
/**
|
|
10
|
-
* Initialize a context state for this specific rendering.
|
|
11
|
-
* Context state will only be available to the current Aspect, in the other hooks, as well as a prop to the react context component.
|
|
12
|
-
*/
|
|
13
|
-
serverInit?: (state: {
|
|
14
|
-
browser?: BrowserData;
|
|
15
|
-
server?: RequestServer;
|
|
16
|
-
}) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
17
|
-
/**
|
|
18
|
-
* Executes before running ReactDOM.renderToString(). Return value will replace the existing context state.
|
|
19
|
-
*/
|
|
20
|
-
onBeforeRender?: (
|
|
21
|
-
ctx: RenderCtx,
|
|
22
|
-
app: ReactNode
|
|
23
|
-
) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
24
|
-
/**
|
|
25
|
-
* Produce html assets. Runs after the body is rendered, and before rendering the final html.
|
|
26
|
-
* @returns
|
|
27
|
-
* json: will be rendered to the dom as a `<script type="json"/>`.
|
|
28
|
-
* More assets will be available in the future.
|
|
29
|
-
*/
|
|
30
|
-
serialize?: (ctx: RenderCtx, app: ReactNode) => { json: string } | Promise<{ json: string }> | undefined;
|
|
31
|
-
/**
|
|
32
|
-
* Converts serialized data from raw string back to structured data.
|
|
33
|
-
* @example deserialize: (data) => { const parsed = JSON.parse(data); return { analytics: new AnalyticsService(parsed); } }
|
|
34
|
-
*/
|
|
35
|
-
deserialize?: (data?: string) => Serialized;
|
|
36
|
-
/**
|
|
37
|
-
* Initialize the context state for client side rendering.
|
|
38
|
-
* Context state will only be available to the current Aspect, in the other hooks, as well as a prop to the react context component.
|
|
39
|
-
*/
|
|
40
|
-
browserInit?: (deserializedData: Serialized) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
41
|
-
/**
|
|
42
|
-
* Executes before running ReactDOM.hydrate() (or .render() in case server side rendering is skipped). Receives the context produced by `deserialize()`
|
|
43
|
-
*/
|
|
44
|
-
onBeforeHydrate?: (
|
|
45
|
-
context: RenderCtx,
|
|
46
|
-
app: ReactNode
|
|
47
|
-
) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
48
|
-
/**
|
|
49
|
-
* Executes after browser rendering is complete. Receives context from the previous steps.
|
|
50
|
-
* @example onHydrate: (ref, { analytics }) => { analytics.reportPageView() }
|
|
51
|
-
*/
|
|
52
|
-
onHydrate?: (context: RenderCtx, ref: HTMLElement | null) => void;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Wraps dom with a context. Will receive render context, produced by `onBeforeRender()` (at server-side) or `deserialize()` (at the browser)
|
|
56
|
-
*/
|
|
57
|
-
reactContext?: ComponentType<ContextProps<RenderCtx>>;
|
|
58
|
-
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { IncomingHttpHeaders } from 'http';
|
|
2
|
-
|
|
3
|
-
export type ParsedQuery = { [key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[] };
|
|
4
|
-
|
|
5
|
-
export type BrowserData = {
|
|
6
|
-
connection: {
|
|
7
|
-
secure: boolean;
|
|
8
|
-
headers: IncomingHttpHeaders;
|
|
9
|
-
body: any;
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* isomorphic location object, resembling the browser's window.location
|
|
13
|
-
*/
|
|
14
|
-
location: {
|
|
15
|
-
/** hostname + port
|
|
16
|
-
* @example localhost:3000
|
|
17
|
-
*/
|
|
18
|
-
host: string;
|
|
19
|
-
/**
|
|
20
|
-
* @example localhost
|
|
21
|
-
*/
|
|
22
|
-
hostname: string;
|
|
23
|
-
/** full url
|
|
24
|
-
* @example http://localhost:3000/components?q=button
|
|
25
|
-
*/
|
|
26
|
-
href: string;
|
|
27
|
-
/** full url without query
|
|
28
|
-
* @example http://localhost:3000/components
|
|
29
|
-
*/
|
|
30
|
-
origin: string;
|
|
31
|
-
/**
|
|
32
|
-
* @example /component
|
|
33
|
-
*/
|
|
34
|
-
pathname: string;
|
|
35
|
-
/**
|
|
36
|
-
* @example 3000
|
|
37
|
-
*/
|
|
38
|
-
port: number;
|
|
39
|
-
/**
|
|
40
|
-
* @example http
|
|
41
|
-
*/
|
|
42
|
-
protocol: string;
|
|
43
|
-
/**
|
|
44
|
-
* parsed search params
|
|
45
|
-
* @example { one: 1, two: [2,3]}
|
|
46
|
-
*/
|
|
47
|
-
query: ParsedQuery;
|
|
48
|
-
/**
|
|
49
|
-
* full resource path, including query, without hostname
|
|
50
|
-
* @example /components?q=button
|
|
51
|
-
*/
|
|
52
|
-
url: string;
|
|
53
|
-
};
|
|
54
|
-
cookie?: string;
|
|
55
|
-
};
|
package/react-ssr/ssr-content.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Assets } from '@teambit/ui-foundation.ui.rendering.html';
|
|
2
|
-
import { BrowserData } from './request-browser';
|
|
3
|
-
import { RequestServer } from './request-server';
|
|
4
|
-
|
|
5
|
-
export type SsrContent = {
|
|
6
|
-
assets?: Assets;
|
|
7
|
-
browser?: BrowserData;
|
|
8
|
-
server?: RequestServer;
|
|
9
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Request } from 'express';
|
|
2
|
-
import { BrowserData } from '../react-ssr';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* extract relevant information from Express request.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export function extractBrowserData(req: Request, port: number) {
|
|
9
|
-
const browser: BrowserData = {
|
|
10
|
-
connection: {
|
|
11
|
-
secure: req.secure,
|
|
12
|
-
headers: req.headers,
|
|
13
|
-
body: req.body,
|
|
14
|
-
},
|
|
15
|
-
// rebuild browser location from request, +port
|
|
16
|
-
location: {
|
|
17
|
-
host: `${req.hostname}:${port}`,
|
|
18
|
-
hostname: req.hostname,
|
|
19
|
-
href: `${req.protocol}://${req.hostname}:${port}${req.url}`,
|
|
20
|
-
origin: `${req.protocol}://${req.hostname}:${port}`,
|
|
21
|
-
pathname: req.path,
|
|
22
|
-
port,
|
|
23
|
-
protocol: `${req.protocol}:`,
|
|
24
|
-
query: req.query,
|
|
25
|
-
url: req.url,
|
|
26
|
-
},
|
|
27
|
-
cookie: req.header('Cookie'),
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
return browser;
|
|
31
|
-
}
|