@teambit/ui 0.0.802 → 0.0.803
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/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 +19 -17
- 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.js +1 -1
- 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.803.tgz +0 -0
- package/package.json +19 -22
- package/{preview-1659151732866.js → preview-1659271062546.js} +2 -2
- package/ssr-middleware/ssr-middleware.ts +14 -15
- 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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["ReactSSR","constructor","lifecycleHooks","renderBrowser","children","deserializedState","deserialize","renderContexts","triggerBrowserInit","reactContexts","getReactContexts","app","triggerBeforeHydrateHook","mountPoint","document","getElementById","mountPointId","ReactDOM","render","triggerHydrateHook","ssrCleanup","renderServer","assets","browser","server","triggerServerInit","triggerBeforeRender","renderedApp","ReactDOMServer","renderToString","realtimeAssets","serialize","totalAssets","merge","html","renderedHtml","renderToStaticMarkup","fullHtml","Html","fillContent","initPromises","map","hooks","idx","state","browserInit","Promise","all","promises","serverInit","ctx","nextCtx","onBeforeHydrate","renderCtx","onHydrate","onBeforeRender","compact","props","reactContext","undefined","rawAssets","popAssets","deserialized","key","raw","get","e","console","error","json","result"],"sources":["react-ssr.tsx"],"sourcesContent":["import React, { ReactNode } from 'react';\nimport { merge } from 'webpack-merge';\nimport compact from 'lodash.compact';\nimport ReactDOM from 'react-dom';\nimport ReactDOMServer from 'react-dom/server';\n\nimport { Html, MountPoint, mountPointId, ssrCleanup, Assets } from '@teambit/ui-foundation.ui.rendering.html';\nimport { Composer, Wrapper } from '@teambit/base-ui.utils.composer';\n\nimport type { RenderPlugins } from './render-lifecycle';\nimport type { SsrContent } from './ssr-content';\nimport type { RequestServer } from './request-server';\nimport type { BrowserData } from './request-browser';\n\ntype RenderPluginsWithId = [key: string, hooks: RenderPlugins];\n\nexport class ReactSSR {\n constructor(\n // create array once to keep consistent indexes\n private lifecycleHooks: RenderPluginsWithId[]\n ) {}\n\n /** render and rehydrate client-side */\n async renderBrowser(children: ReactNode) {\n // (*) load state from the dom\n const deserializedState = await this.deserialize();\n\n // (1) init setup client plugins\n let renderContexts = await this.triggerBrowserInit(deserializedState);\n\n // (2) make react dom\n const reactContexts = this.getReactContexts(renderContexts);\n const app = <Composer components={reactContexts}>{children}</Composer>;\n\n renderContexts = await this.triggerBeforeHydrateHook(renderContexts, app);\n\n // (3) render / rehydrate\n const mountPoint = document.getElementById(mountPointId);\n // .render() already runs `.hydrate()` behind the scenes.\n // in the future, we may want to replace it with .hydrate()\n ReactDOM.render(app, mountPoint);\n\n await this.triggerHydrateHook(renderContexts, mountPoint);\n\n // (3.1) remove ssr only styles\n ssrCleanup();\n }\n\n /** render dehydrated server-side */\n async renderServer(children: ReactNode, { assets, browser, server }: SsrContent = {}): Promise<string> {\n // (1) init\n let renderContexts = await this.triggerServerInit(browser, server);\n\n // (2) make React dom\n const reactContexts = this.getReactContexts(renderContexts);\n const app = (\n <MountPoint>\n <Composer components={reactContexts}>{children}</Composer>\n </MountPoint>\n );\n\n renderContexts = await this.triggerBeforeRender(renderContexts, app);\n\n // (3) render (to string)\n const renderedApp = ReactDOMServer.renderToString(app);\n\n // (*) serialize state\n const realtimeAssets = await this.serialize(renderContexts, app);\n // @ts-ignore // TODO upgrade 'webpack-merge'\n const totalAssets = merge(assets, realtimeAssets) as Assets;\n\n // (4) render html-template (to string)\n const html = <Html assets={totalAssets} withDevTools fullHeight ssr />;\n const renderedHtml = `<!DOCTYPE html>${ReactDOMServer.renderToStaticMarkup(html)}`;\n const fullHtml = Html.fillContent(renderedHtml, renderedApp);\n\n // (5) serve\n return fullHtml;\n }\n\n private triggerBrowserInit(deserializedState: any[]) {\n const { lifecycleHooks } = this;\n\n const initPromises = lifecycleHooks.map(([, hooks], idx) => {\n const state = deserializedState[idx];\n return hooks.browserInit?.(state);\n });\n return Promise.all(initPromises);\n }\n\n private triggerServerInit(browser?: BrowserData, server?: RequestServer) {\n const { lifecycleHooks } = this;\n const promises = lifecycleHooks.map(([, hooks]) => hooks.serverInit?.({ browser, server }));\n return Promise.all(promises);\n }\n\n private triggerBeforeHydrateHook(renderContexts: any[], app: JSX.Element) {\n const { lifecycleHooks } = this;\n\n const promises = lifecycleHooks.map(async ([, hooks], idx) => {\n const ctx = renderContexts[idx];\n const nextCtx = await hooks.onBeforeHydrate?.(ctx, app);\n return nextCtx || ctx;\n });\n\n return Promise.all(promises);\n }\n\n private async triggerHydrateHook(renderContexts: any[], mountPoint: HTMLElement | null) {\n const { lifecycleHooks } = this;\n\n const promises = lifecycleHooks.map(([, hooks], idx) => {\n const renderCtx = renderContexts[idx];\n return hooks.onHydrate?.(renderCtx, mountPoint);\n });\n\n await Promise.all(promises);\n }\n\n private async triggerBeforeRender(renderContexts: any[], app: JSX.Element) {\n const { lifecycleHooks } = this;\n\n const promises = lifecycleHooks.map(async ([, hooks], idx) => {\n const ctx = renderContexts[idx];\n const nextCtx = await hooks.onBeforeRender?.(ctx, app);\n return nextCtx || ctx;\n });\n\n await Promise.all(promises);\n\n return renderContexts;\n }\n\n private getReactContexts(renderContexts: any[]): Wrapper[] {\n const { lifecycleHooks } = this;\n\n return compact(\n lifecycleHooks.map(([, hooks], idx) => {\n const renderCtx = renderContexts[idx];\n const props = { renderCtx };\n return hooks.reactContext ? [hooks.reactContext, props] : undefined;\n })\n );\n }\n\n private async deserialize() {\n const { lifecycleHooks } = this;\n const rawAssets = Html.popAssets();\n\n const deserialized = await Promise.all(\n lifecycleHooks.map(async ([key, hooks]) => {\n try {\n const raw = rawAssets.get(key);\n return hooks.deserialize?.(raw);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.error(`failed deserializing server state for aspect ${key}`, e);\n return undefined;\n }\n })\n );\n\n return deserialized;\n }\n\n private async serialize(renderContexts: any[], app: ReactNode): Promise<Assets> {\n const { lifecycleHooks } = this;\n const json = {};\n\n const promises = lifecycleHooks.map(async ([key, hooks], idx) => {\n const renderCtx = renderContexts[idx];\n const result = await hooks.serialize?.(renderCtx, app);\n\n if (!result) return;\n if (result.json) json[key] = result.json;\n });\n\n await Promise.all(promises);\n\n // more assets will be available in the future\n return { json };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { ReactNode, ComponentType } from 'react';
|
|
2
|
-
import { BrowserData } from './request-browser';
|
|
3
|
-
import { RequestServer } from './request-server';
|
|
4
|
-
export declare type ContextProps<T = any> = {
|
|
5
|
-
renderCtx?: T;
|
|
6
|
-
children: ReactNode;
|
|
7
|
-
};
|
|
8
|
-
/** Plugins for each step of the SSR and regular rendering lifecycle */
|
|
9
|
-
export declare type RenderPlugins<RenderCtx = any, Serialized = any> = {
|
|
10
|
-
/**
|
|
11
|
-
* Initialize a context state for this specific rendering.
|
|
12
|
-
* Context state will only be available to the current Aspect, in the other hooks, as well as a prop to the react context component.
|
|
13
|
-
*/
|
|
14
|
-
serverInit?: (state: {
|
|
15
|
-
browser?: BrowserData;
|
|
16
|
-
server?: RequestServer;
|
|
17
|
-
}) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
18
|
-
/**
|
|
19
|
-
* Executes before running ReactDOM.renderToString(). Return value will replace the existing context state.
|
|
20
|
-
*/
|
|
21
|
-
onBeforeRender?: (ctx: RenderCtx, app: ReactNode) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
22
|
-
/**
|
|
23
|
-
* Produce html assets. Runs after the body is rendered, and before rendering the final html.
|
|
24
|
-
* @returns
|
|
25
|
-
* json: will be rendered to the dom as a `<script type="json"/>`.
|
|
26
|
-
* More assets will be available in the future.
|
|
27
|
-
*/
|
|
28
|
-
serialize?: (ctx: RenderCtx, app: ReactNode) => {
|
|
29
|
-
json: string;
|
|
30
|
-
} | Promise<{
|
|
31
|
-
json: string;
|
|
32
|
-
}> | undefined;
|
|
33
|
-
/**
|
|
34
|
-
* Converts serialized data from raw string back to structured data.
|
|
35
|
-
* @example deserialize: (data) => { const parsed = JSON.parse(data); return { analytics: new AnalyticsService(parsed); } }
|
|
36
|
-
*/
|
|
37
|
-
deserialize?: (data?: string) => Serialized;
|
|
38
|
-
/**
|
|
39
|
-
* Initialize the context state for client side rendering.
|
|
40
|
-
* Context state will only be available to the current Aspect, in the other hooks, as well as a prop to the react context component.
|
|
41
|
-
*/
|
|
42
|
-
browserInit?: (deserializedData: Serialized) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
43
|
-
/**
|
|
44
|
-
* Executes before running ReactDOM.hydrate() (or .render() in case server side rendering is skipped). Receives the context produced by `deserialize()`
|
|
45
|
-
*/
|
|
46
|
-
onBeforeHydrate?: (context: RenderCtx, app: ReactNode) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
47
|
-
/**
|
|
48
|
-
* Executes after browser rendering is complete. Receives context from the previous steps.
|
|
49
|
-
* @example onHydrate: (ref, { analytics }) => { analytics.reportPageView() }
|
|
50
|
-
*/
|
|
51
|
-
onHydrate?: (context: RenderCtx, ref: HTMLElement | null) => void;
|
|
52
|
-
/**
|
|
53
|
-
* Wraps dom with a context. Will receive render context, produced by `onBeforeRender()` (at server-side) or `deserialize()` (at the browser)
|
|
54
|
-
*/
|
|
55
|
-
reactContext?: ComponentType<ContextProps<RenderCtx>>;
|
|
56
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["render-lifecycle.tsx"],"sourcesContent":["import { ReactNode, ComponentType } from 'react';\nimport { BrowserData } from './request-browser';\nimport { RequestServer } from './request-server';\n\nexport type ContextProps<T = any> = { renderCtx?: T; children: ReactNode };\n\n/** Plugins for each step of the SSR and regular rendering lifecycle */\nexport type RenderPlugins<RenderCtx = any, Serialized = any> = {\n /**\n * Initialize a context state for this specific rendering.\n * Context state will only be available to the current Aspect, in the other hooks, as well as a prop to the react context component.\n */\n serverInit?: (state: {\n browser?: BrowserData;\n server?: RequestServer;\n }) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;\n /**\n * Executes before running ReactDOM.renderToString(). Return value will replace the existing context state.\n */\n onBeforeRender?: (\n ctx: RenderCtx,\n app: ReactNode\n ) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;\n /**\n * Produce html assets. Runs after the body is rendered, and before rendering the final html.\n * @returns\n * json: will be rendered to the dom as a `<script type=\"json\"/>`.\n * More assets will be available in the future.\n */\n serialize?: (ctx: RenderCtx, app: ReactNode) => { json: string } | Promise<{ json: string }> | undefined;\n /**\n * Converts serialized data from raw string back to structured data.\n * @example deserialize: (data) => { const parsed = JSON.parse(data); return { analytics: new AnalyticsService(parsed); } }\n */\n deserialize?: (data?: string) => Serialized;\n /**\n * Initialize the context state for client side rendering.\n * Context state will only be available to the current Aspect, in the other hooks, as well as a prop to the react context component.\n */\n browserInit?: (deserializedData: Serialized) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;\n /**\n * Executes before running ReactDOM.hydrate() (or .render() in case server side rendering is skipped). Receives the context produced by `deserialize()`\n */\n onBeforeHydrate?: (\n context: RenderCtx,\n app: ReactNode\n ) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;\n /**\n * Executes after browser rendering is complete. Receives context from the previous steps.\n * @example onHydrate: (ref, { analytics }) => { analytics.reportPageView() }\n */\n onHydrate?: (context: RenderCtx, ref: HTMLElement | null) => void;\n\n /**\n * Wraps dom with a context. Will receive render context, produced by `onBeforeRender()` (at server-side) or `deserialize()` (at the browser)\n */\n reactContext?: ComponentType<ContextProps<RenderCtx>>;\n};\n"],"mappings":""}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import type { IncomingHttpHeaders } from 'http';
|
|
3
|
-
export declare type ParsedQuery = {
|
|
4
|
-
[key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[];
|
|
5
|
-
};
|
|
6
|
-
export declare type BrowserData = {
|
|
7
|
-
connection: {
|
|
8
|
-
secure: boolean;
|
|
9
|
-
headers: IncomingHttpHeaders;
|
|
10
|
-
body: any;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* isomorphic location object, resembling the browser's window.location
|
|
14
|
-
*/
|
|
15
|
-
location: {
|
|
16
|
-
/** hostname + port
|
|
17
|
-
* @example localhost:3000
|
|
18
|
-
*/
|
|
19
|
-
host: string;
|
|
20
|
-
/**
|
|
21
|
-
* @example localhost
|
|
22
|
-
*/
|
|
23
|
-
hostname: string;
|
|
24
|
-
/** full url
|
|
25
|
-
* @example http://localhost:3000/components?q=button
|
|
26
|
-
*/
|
|
27
|
-
href: string;
|
|
28
|
-
/** full url without query
|
|
29
|
-
* @example http://localhost:3000/components
|
|
30
|
-
*/
|
|
31
|
-
origin: string;
|
|
32
|
-
/**
|
|
33
|
-
* @example /component
|
|
34
|
-
*/
|
|
35
|
-
pathname: string;
|
|
36
|
-
/**
|
|
37
|
-
* @example 3000
|
|
38
|
-
*/
|
|
39
|
-
port: number;
|
|
40
|
-
/**
|
|
41
|
-
* @example http
|
|
42
|
-
*/
|
|
43
|
-
protocol: string;
|
|
44
|
-
/**
|
|
45
|
-
* parsed search params
|
|
46
|
-
* @example { one: 1, two: [2,3]}
|
|
47
|
-
*/
|
|
48
|
-
query: ParsedQuery;
|
|
49
|
-
/**
|
|
50
|
-
* full resource path, including query, without hostname
|
|
51
|
-
* @example /components?q=button
|
|
52
|
-
*/
|
|
53
|
-
url: string;
|
|
54
|
-
};
|
|
55
|
-
cookie?: string;
|
|
56
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["request-browser.ts"],"sourcesContent":["import type { IncomingHttpHeaders } from 'http';\n\nexport type ParsedQuery = { [key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[] };\n\nexport type BrowserData = {\n connection: {\n secure: boolean;\n headers: IncomingHttpHeaders;\n body: any;\n };\n /**\n * isomorphic location object, resembling the browser's window.location\n */\n location: {\n /** hostname + port\n * @example localhost:3000\n */\n host: string;\n /**\n * @example localhost\n */\n hostname: string;\n /** full url\n * @example http://localhost:3000/components?q=button\n */\n href: string;\n /** full url without query\n * @example http://localhost:3000/components\n */\n origin: string;\n /**\n * @example /component\n */\n pathname: string;\n /**\n * @example 3000\n */\n port: number;\n /**\n * @example http\n */\n protocol: string;\n /**\n * parsed search params\n * @example { one: 1, two: [2,3]}\n */\n query: ParsedQuery;\n /**\n * full resource path, including query, without hostname\n * @example /components?q=button\n */\n url: string;\n };\n cookie?: string;\n};\n"],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["request-server.ts"],"sourcesContent":["import type { Request, Response } from 'express';\n\n/**\n * Represents the server configuration for the current request\n */\nexport type RequestServer = {\n port: number;\n request: Request;\n response: Response;\n};\n"],"mappings":""}
|
|
@@ -1,8 +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
|
-
export declare type SsrContent = {
|
|
5
|
-
assets?: Assets;
|
|
6
|
-
browser?: BrowserData;
|
|
7
|
-
server?: RequestServer;
|
|
8
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["ssr-content.ts"],"sourcesContent":["import type { Assets } from '@teambit/ui-foundation.ui.rendering.html';\nimport { BrowserData } from './request-browser';\nimport { RequestServer } from './request-server';\n\nexport type SsrContent = {\n assets?: Assets;\n browser?: BrowserData;\n server?: RequestServer;\n};\n"],"mappings":""}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.extractBrowserData = extractBrowserData;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* extract relevant information from Express request.
|
|
10
|
-
*/
|
|
11
|
-
function extractBrowserData(req, port) {
|
|
12
|
-
const browser = {
|
|
13
|
-
connection: {
|
|
14
|
-
secure: req.secure,
|
|
15
|
-
headers: req.headers,
|
|
16
|
-
body: req.body
|
|
17
|
-
},
|
|
18
|
-
// rebuild browser location from request, +port
|
|
19
|
-
location: {
|
|
20
|
-
host: `${req.hostname}:${port}`,
|
|
21
|
-
hostname: req.hostname,
|
|
22
|
-
href: `${req.protocol}://${req.hostname}:${port}${req.url}`,
|
|
23
|
-
origin: `${req.protocol}://${req.hostname}:${port}`,
|
|
24
|
-
pathname: req.path,
|
|
25
|
-
port,
|
|
26
|
-
protocol: `${req.protocol}:`,
|
|
27
|
-
query: req.query,
|
|
28
|
-
url: req.url
|
|
29
|
-
},
|
|
30
|
-
cookie: req.header('Cookie')
|
|
31
|
-
};
|
|
32
|
-
return browser;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
//# sourceMappingURL=extract-browser-data.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["extractBrowserData","req","port","browser","connection","secure","headers","body","location","host","hostname","href","protocol","url","origin","pathname","path","query","cookie","header"],"sources":["extract-browser-data.ts"],"sourcesContent":["import { Request } from 'express';\nimport { BrowserData } from '../react-ssr';\n\n/**\n * extract relevant information from Express request.\n */\n\nexport function extractBrowserData(req: Request, port: number) {\n const browser: BrowserData = {\n connection: {\n secure: req.secure,\n headers: req.headers,\n body: req.body,\n },\n // rebuild browser location from request, +port\n location: {\n host: `${req.hostname}:${port}`,\n hostname: req.hostname,\n href: `${req.protocol}://${req.hostname}:${port}${req.url}`,\n origin: `${req.protocol}://${req.hostname}:${port}`,\n pathname: req.path,\n port,\n protocol: `${req.protocol}:`,\n query: req.query,\n url: req.url,\n },\n cookie: req.header('Cookie'),\n };\n\n return browser;\n}\n"],"mappings":";;;;;;;AAGA;AACA;AACA;AAEO,SAASA,kBAAT,CAA4BC,GAA5B,EAA0CC,IAA1C,EAAwD;EAC7D,MAAMC,OAAoB,GAAG;IAC3BC,UAAU,EAAE;MACVC,MAAM,EAAEJ,GAAG,CAACI,MADF;MAEVC,OAAO,EAAEL,GAAG,CAACK,OAFH;MAGVC,IAAI,EAAEN,GAAG,CAACM;IAHA,CADe;IAM3B;IACAC,QAAQ,EAAE;MACRC,IAAI,EAAG,GAAER,GAAG,CAACS,QAAS,IAAGR,IAAK,EADtB;MAERQ,QAAQ,EAAET,GAAG,CAACS,QAFN;MAGRC,IAAI,EAAG,GAAEV,GAAG,CAACW,QAAS,MAAKX,GAAG,CAACS,QAAS,IAAGR,IAAK,GAAED,GAAG,CAACY,GAAI,EAHlD;MAIRC,MAAM,EAAG,GAAEb,GAAG,CAACW,QAAS,MAAKX,GAAG,CAACS,QAAS,IAAGR,IAAK,EAJ1C;MAKRa,QAAQ,EAAEd,GAAG,CAACe,IALN;MAMRd,IANQ;MAORU,QAAQ,EAAG,GAAEX,GAAG,CAACW,QAAS,GAPlB;MAQRK,KAAK,EAAEhB,GAAG,CAACgB,KARH;MASRJ,GAAG,EAAEZ,GAAG,CAACY;IATD,CAPiB;IAkB3BK,MAAM,EAAEjB,GAAG,CAACkB,MAAJ,CAAW,QAAX;EAlBmB,CAA7B;EAqBA,OAAOhB,OAAP;AACD"}
|
|
Binary file
|
package/react-ssr/index.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { ReactSSR } from './react-ssr';
|
|
2
|
-
|
|
3
|
-
export type { ContextProps, RenderPlugins } from './render-lifecycle';
|
|
4
|
-
export type { BrowserData, ParsedQuery } from './request-browser';
|
|
5
|
-
export type { RequestServer } from './request-server';
|
|
6
|
-
export type { SsrContent } from './ssr-content';
|
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
|
-
}
|