@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.
Files changed (47) hide show
  1. package/dist/index.d.ts +12 -5
  2. package/dist/index.js.map +1 -1
  3. package/dist/ssr-middleware/ssr-middleware.d.ts +2 -2
  4. package/dist/ssr-middleware/ssr-middleware.js +19 -17
  5. package/dist/ssr-middleware/ssr-middleware.js.map +1 -1
  6. package/dist/ui-root.d.ts +3 -3
  7. package/dist/ui-root.js.map +1 -1
  8. package/dist/ui.main.runtime.js +1 -1
  9. package/dist/ui.main.runtime.js.map +1 -1
  10. package/dist/ui.ui.runtime.d.ts +4 -5
  11. package/dist/ui.ui.runtime.js +27 -17
  12. package/dist/ui.ui.runtime.js.map +1 -1
  13. package/package-tar/teambit-ui-0.0.803.tgz +0 -0
  14. package/package.json +19 -22
  15. package/{preview-1659151732866.js → preview-1659271062546.js} +2 -2
  16. package/ssr-middleware/ssr-middleware.ts +14 -15
  17. package/ui-root.tsx +7 -3
  18. package/ui.ui.runtime.tsx +21 -18
  19. package/dist/react-ssr/index.d.ts +0 -5
  20. package/dist/react-ssr/index.js +0 -23
  21. package/dist/react-ssr/index.js.map +0 -1
  22. package/dist/react-ssr/react-ssr.d.ts +0 -21
  23. package/dist/react-ssr/react-ssr.js +0 -285
  24. package/dist/react-ssr/react-ssr.js.map +0 -1
  25. package/dist/react-ssr/render-lifecycle.d.ts +0 -56
  26. package/dist/react-ssr/render-lifecycle.js +0 -3
  27. package/dist/react-ssr/render-lifecycle.js.map +0 -1
  28. package/dist/react-ssr/request-browser.d.ts +0 -56
  29. package/dist/react-ssr/request-browser.js +0 -3
  30. package/dist/react-ssr/request-browser.js.map +0 -1
  31. package/dist/react-ssr/request-server.d.ts +0 -9
  32. package/dist/react-ssr/request-server.js +0 -3
  33. package/dist/react-ssr/request-server.js.map +0 -1
  34. package/dist/react-ssr/ssr-content.d.ts +0 -8
  35. package/dist/react-ssr/ssr-content.js +0 -3
  36. package/dist/react-ssr/ssr-content.js.map +0 -1
  37. package/dist/ssr-middleware/extract-browser-data.d.ts +0 -6
  38. package/dist/ssr-middleware/extract-browser-data.js +0 -35
  39. package/dist/ssr-middleware/extract-browser-data.js.map +0 -1
  40. package/package-tar/teambit-ui-0.0.802.tgz +0 -0
  41. package/react-ssr/index.ts +0 -6
  42. package/react-ssr/react-ssr.tsx +0 -183
  43. package/react-ssr/render-lifecycle.tsx +0 -58
  44. package/react-ssr/request-browser.ts +0 -55
  45. package/react-ssr/request-server.ts +0 -10
  46. package/react-ssr/ssr-content.ts +0 -9
  47. 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,3 +0,0 @@
1
- "use strict";
2
-
3
- //# sourceMappingURL=render-lifecycle.js.map
@@ -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,3 +0,0 @@
1
- "use strict";
2
-
3
- //# sourceMappingURL=request-browser.js.map
@@ -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,9 +0,0 @@
1
- import type { Request, Response } from 'express';
2
- /**
3
- * Represents the server configuration for the current request
4
- */
5
- export declare type RequestServer = {
6
- port: number;
7
- request: Request;
8
- response: Response;
9
- };
@@ -1,3 +0,0 @@
1
- "use strict";
2
-
3
- //# sourceMappingURL=request-server.js.map
@@ -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,3 +0,0 @@
1
- "use strict";
2
-
3
- //# sourceMappingURL=ssr-content.js.map
@@ -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,6 +0,0 @@
1
- import { Request } from 'express';
2
- import { BrowserData } from '../react-ssr';
3
- /**
4
- * extract relevant information from Express request.
5
- */
6
- export declare function extractBrowserData(req: Request, port: number): BrowserData;
@@ -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
@@ -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';
@@ -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
- };
@@ -1,10 +0,0 @@
1
- import type { Request, Response } from 'express';
2
-
3
- /**
4
- * Represents the server configuration for the current request
5
- */
6
- export type RequestServer = {
7
- port: number;
8
- request: Request;
9
- response: Response;
10
- };
@@ -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
- }