@tramvai/module-render 1.79.0 → 1.81.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/README.md CHANGED
@@ -32,20 +32,16 @@ createApp({
32
32
 
33
33
  ## Explanation
34
34
 
35
- ### Different React rendering modes
35
+ ### React Strict Mode
36
36
 
37
- More information about rendering modes can be found in the [official documentation](https://reactjs.org/docs/concurrent-mode-adoption.html), `RenderModule` has support for all rendering types and you can choose the right one for your application.
37
+ More information about Strict Mode can be found in the [official documentation](https://reactjs.org/docs/strict-mode.html).
38
38
 
39
- To set the mode, you must pass the `mode` parameter when initializing the `RenderModule`.
39
+ To set the mode, you must pass the `useStrictMode` parameter when initializing the `RenderModule`.
40
40
 
41
41
  ```typescript
42
- RenderModule.forRoot({ mode: 'concurrent' });
42
+ RenderModule.forRoot({ useStrictMode: true });
43
43
  ```
44
44
 
45
- Available modes: `'legacy' | 'strict' | 'blocking' | 'concurrent'`
46
-
47
- [Gradual concurrent mode adoption](#gradual-concurrent-mode-adoption)
48
-
49
45
  ### Application static assets
50
46
 
51
47
  For static assets (JS, CSS, fonts, etc.) we create special resources registry module, which allow to provide in DI list of resources, and then render them to specifics slots in final HTML.
@@ -283,56 +279,20 @@ Example:
283
279
  </details>
284
280
  </p>
285
281
 
286
- ### Gradual concurrent mode adoption
287
-
288
- React allows a gradual migration of an application
289
-
290
- **Stages of migration:**
291
-
292
- 1. [Strict Mode](https://reactjs.org/docs/strict-mode.html) - strict mode, in which React warns about using the legacy API
293
-
294
- To connect, you must configure the `RenderModule`
295
-
296
- ```js
297
- modules: [
298
- RenderModule.forRoot({ mode: 'strict' })
299
- ]
300
- ```
282
+ ### React 18 concurrent features
301
283
 
302
- Then you need to fix any new warnings, such as using legacy lifecycle methods and string refs.
284
+ `tramvai` will automatically detect React version, and use hydrateRoot API on the client for 18+ version.
303
285
 
304
- 2. [Blocking Mode](https://reactjs.org/docs/concurrent-mode-adoption.html#migration-step-blocking-mode) - adds some Concurrent Mode features, such as Suspense on the server. Suitable for gradual migration to Concurrent Mode.
286
+ Before switch to React 18, we recommended to activate [Strict Mode](https://reactjs.org/docs/strict-mode.html) in your application.
287
+ In Strict Mode which React warns about using the legacy API.
305
288
 
306
- To connect, install an experimental version of React and configure the `RenderModule`
307
-
308
- ```bash npm2yarn
309
- npm install react@experimental react-dom@experimental
310
- ```
289
+ To connect, you must configure the `RenderModule`:
311
290
 
312
291
  ```js
313
292
  modules: [
314
- RenderModule.forRoot({ mode: 'blocking' })
293
+ RenderModule.forRoot({ useStrictMode: true })
315
294
  ]
316
295
  ```
317
-
318
- At this stage, you need to check the performance of the application, and you can try new APIs, for example [SuspenseList](https://reactjs.org/docs/concurrent-mode-patterns.html#suspenselist)
319
-
320
- 3. Concurrent Mode
321
-
322
- To connect, install an experimental version of React and configure the `RenderModule`
323
-
324
- ```bash npm2yarn
325
- npm install react@experimental react-dom@experimental
326
- ```
327
-
328
- ```js
329
- modules: [
330
- RenderModule.forRoot({ mode: 'concurrent' })
331
- ]
332
- ```
333
-
334
- At this stage, you need to check the performance of the application, and you can try new APIs, for example [useTransition](https://reactjs.org/docs/concurrent-mode-patterns.html#transitions)
335
-
336
296
  ### Testing
337
297
 
338
298
  #### Testing render extensions via RENDER_SLOTS or RESOURCES_REGISTRY tokens
package/lib/browser.d.ts CHANGED
@@ -3,7 +3,7 @@ export * from './shared/pageErrorStore';
3
3
  export * from '@tramvai/tokens-render';
4
4
  export declare const DEFAULT_POLYFILL_CONDITION = "";
5
5
  export declare class RenderModule {
6
- static forRoot({ mode }: RenderModuleConfig): {
6
+ static forRoot({ mode, useStrictMode }: RenderModuleConfig): {
7
7
  mainModule: typeof RenderModule;
8
8
  providers: any[];
9
9
  };
package/lib/browser.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import { Module, provide, commandLineListTokens, DI_TOKEN } from '@tramvai/core';
3
3
  import { STORE_TOKEN, LOGGER_TOKEN, CONTEXT_TOKEN } from '@tramvai/module-common';
4
- import { DEFAULT_LAYOUT_COMPONENT, LAYOUT_OPTIONS, DEFAULT_FOOTER_COMPONENT, DEFAULT_HEADER_COMPONENT, TRAMVAI_RENDER_MODE, RESOURCES_REGISTRY, CUSTOM_RENDER, EXTEND_RENDER, RENDERER_CALLBACK, RENDER_MODE } from '@tramvai/tokens-render';
4
+ import { DEFAULT_LAYOUT_COMPONENT, LAYOUT_OPTIONS, DEFAULT_FOOTER_COMPONENT, DEFAULT_HEADER_COMPONENT, TRAMVAI_RENDER_MODE, RESOURCES_REGISTRY, CUSTOM_RENDER, EXTEND_RENDER, RENDERER_CALLBACK, USE_REACT_STRICT_MODE, RENDER_MODE } from '@tramvai/tokens-render';
5
5
  export * from '@tramvai/tokens-render';
6
6
  import { ROUTER_TOKEN, PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
7
7
  import each from '@tinkoff/utils/array/each';
8
- import React, { PureComponent, useMemo, createElement, StrictMode, useEffect } from 'react';
8
+ import React, { PureComponent, useMemo, createElement, StrictMode } from 'react';
9
9
  import { createEvent, createReducer, useStore, Provider } from '@tramvai/state';
10
10
  import { useDi, ERROR_BOUNDARY_TOKEN, ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, UniversalErrorBoundary, DIContext } from '@tramvai/react';
11
11
  import { useRoute, useUrl } from '@tramvai/module-router';
12
- import ReactDOM, { hydrate } from 'react-dom';
12
+ import { useIsomorphicLayoutEffect } from '@tinkoff/react-hooks';
13
13
  import { composeLayoutOptions, createLayout } from '@tinkoff/layout-factory';
14
14
  import { COMBINE_REDUCERS } from '@tramvai/tokens-common';
15
15
 
@@ -72,76 +72,62 @@ function renderReact({ pageService, di }, context) {
72
72
  React.createElement(Root, { pageService: pageService }))));
73
73
  }
74
74
 
75
- const legacyRenderer = ({ element, container, callback }) => hydrate(element, container, callback);
76
-
77
- const strictRenderer = (params) => {
78
- const element = createElement(StrictMode, null, params.element);
79
- return legacyRenderer({ ...params, element });
80
- };
81
-
82
- const WARNING_TEXT = '\n--->\n-->\n->\nInstall experemental version of React and ReactDOM for blocking and concurrent modes!\n->\n-->\n--->';
83
75
  const ExecuteRenderCallback = ({ children, callback }) => {
84
76
  // eslint-disable-next-line react-hooks/exhaustive-deps
85
- useEffect(callback, []);
77
+ useIsomorphicLayoutEffect(callback, []);
86
78
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
79
  return children;
88
80
  };
89
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
90
- const rendererFactory = (createRoot) => ({ element, container, callback, log }) => {
91
- if (process.env.NODE_ENV === 'development' && !createRoot) {
92
- log.error(WARNING_TEXT);
81
+ const renderer = ({ element, container, callback }) => {
82
+ if (process.env.__TRAMVAI_CONCURRENT_FEATURES) {
83
+ const wrappedElement = createElement(ExecuteRenderCallback, { callback }, element);
84
+ // eslint-disable-next-line import/no-unresolved, import/extensions
85
+ const { hydrateRoot } = require('react-dom/client');
86
+ return hydrateRoot(container, wrappedElement);
93
87
  }
94
- const wrappedElement = createElement(ExecuteRenderCallback, { callback }, element);
95
- return createRoot(container, { hydrate: true }).render(wrappedElement);
88
+ const { hydrate } = require('react-dom');
89
+ return hydrate(element, container, callback);
96
90
  };
97
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
- const blockingRenderer = rendererFactory(ReactDOM.createBlockingRoot);
99
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
- const concurrentRenderer = rendererFactory(ReactDOM.createRoot);
101
91
 
102
- function rendering({ pageService, log, consumerContext, customRender, extendRender, di, mode, rendererCallback, }) {
103
- let renderResult = renderReact({ pageService, di }, consumerContext);
104
- if (extendRender) {
105
- each((render) => {
106
- renderResult = render(renderResult);
107
- }, extendRender);
108
- }
109
- if (customRender) {
110
- return customRender(renderResult);
111
- }
112
- const container = document.querySelector('.application');
113
- const executeRendererCallbacks = (renderErr) => rendererCallback === null || rendererCallback === void 0 ? void 0 : rendererCallback.forEach((cb) => {
92
+ function rendering({ pageService, log, consumerContext, customRender, extendRender, di, useStrictMode, rendererCallback, }) {
93
+ return new Promise((resolve, reject) => {
94
+ let renderResult = renderReact({ pageService, di }, consumerContext);
95
+ if (extendRender) {
96
+ each((render) => {
97
+ renderResult = render(renderResult);
98
+ }, extendRender);
99
+ }
100
+ if (customRender) {
101
+ return customRender(renderResult);
102
+ }
103
+ if (useStrictMode) {
104
+ renderResult = createElement(StrictMode, null, renderResult);
105
+ }
106
+ const container = document.querySelector('.application');
107
+ const executeRendererCallbacks = (renderErr) => rendererCallback === null || rendererCallback === void 0 ? void 0 : rendererCallback.forEach((cb) => {
108
+ try {
109
+ cb(renderErr);
110
+ }
111
+ catch (cbError) {
112
+ // eslint-disable-next-line no-console
113
+ console.error(cbError);
114
+ }
115
+ });
116
+ const callback = () => {
117
+ log.debug('App rendering');
118
+ document.querySelector('html').classList.remove('no-js');
119
+ executeRendererCallbacks();
120
+ resolve();
121
+ };
122
+ const params = { element: renderResult, container, callback, log };
114
123
  try {
115
- cb(renderErr);
124
+ renderer(params);
116
125
  }
117
- catch (cbError) {
118
- // eslint-disable-next-line no-console
119
- console.error(cbError);
126
+ catch (e) {
127
+ executeRendererCallbacks(e);
128
+ reject(e);
120
129
  }
121
130
  });
122
- const callback = () => {
123
- log.debug('App rendering');
124
- document.querySelector('html').classList.remove('no-js');
125
- executeRendererCallbacks();
126
- };
127
- const params = { element: renderResult, container, callback, log };
128
- try {
129
- switch (mode) {
130
- case 'strict':
131
- return strictRenderer(params);
132
- case 'blocking':
133
- return blockingRenderer(params);
134
- case 'concurrent':
135
- return concurrentRenderer(params);
136
- case 'legacy':
137
- default:
138
- return legacyRenderer(params);
139
- }
140
- }
141
- catch (e) {
142
- executeRendererCallbacks(e);
143
- throw e;
144
- }
145
131
  }
146
132
 
147
133
  let LayoutModule = class LayoutModule {
@@ -193,12 +179,12 @@ const throwErrorInDev = (logger) => {
193
179
  }
194
180
  };
195
181
  let RenderModule = RenderModule_1 = class RenderModule {
196
- static forRoot({ mode }) {
182
+ static forRoot({ mode, useStrictMode }) {
197
183
  const providers = [];
198
- if (typeof mode === 'string') {
184
+ if (typeof mode === 'string' || typeof useStrictMode === 'boolean') {
199
185
  providers.push({
200
- provide: RENDER_MODE,
201
- useValue: mode,
186
+ provide: USE_REACT_STRICT_MODE,
187
+ useValue: useStrictMode !== null && useStrictMode !== void 0 ? useStrictMode : mode === 'strict',
202
188
  });
203
189
  }
204
190
  return {
@@ -247,7 +233,7 @@ RenderModule = RenderModule_1 = __decorate([
247
233
  useFactory: (deps) => {
248
234
  return function renderClientCommand() {
249
235
  window.contextExternal = deps.consumerContext;
250
- return Promise.resolve(rendering(deps));
236
+ return rendering(deps);
251
237
  };
252
238
  },
253
239
  deps: {
@@ -258,10 +244,22 @@ RenderModule = RenderModule_1 = __decorate([
258
244
  rendererCallback: { token: RENDERER_CALLBACK, optional: true },
259
245
  consumerContext: CONTEXT_TOKEN,
260
246
  di: DI_TOKEN,
261
- mode: RENDER_MODE,
247
+ useStrictMode: USE_REACT_STRICT_MODE,
262
248
  },
263
249
  multi: true,
264
250
  }),
251
+ provide({
252
+ provide: USE_REACT_STRICT_MODE,
253
+ useFactory: ({ deprecatedMode }) => {
254
+ if (deprecatedMode === 'strict') {
255
+ return true;
256
+ }
257
+ return false;
258
+ },
259
+ deps: {
260
+ deprecatedMode: RENDER_MODE,
261
+ },
262
+ }),
265
263
  provide({
266
264
  provide: RENDER_MODE,
267
265
  useValue: 'legacy',
@@ -1,12 +1,12 @@
1
- import type { EXTEND_RENDER, RenderMode, RENDERER_CALLBACK } from '@tramvai/tokens-render';
1
+ import type { EXTEND_RENDER, RENDERER_CALLBACK, USE_REACT_STRICT_MODE } from '@tramvai/tokens-render';
2
2
  import type { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
3
- export declare function rendering({ pageService, log, consumerContext, customRender, extendRender, di, mode, rendererCallback, }: {
3
+ export declare function rendering({ pageService, log, consumerContext, customRender, extendRender, di, useStrictMode, rendererCallback, }: {
4
4
  pageService: typeof PAGE_SERVICE_TOKEN;
5
5
  log: any;
6
6
  consumerContext: any;
7
7
  extendRender?: typeof EXTEND_RENDER;
8
8
  customRender?: any;
9
9
  di: any;
10
- mode: RenderMode;
10
+ useStrictMode: typeof USE_REACT_STRICT_MODE;
11
11
  rendererCallback?: typeof RENDERER_CALLBACK;
12
- }): any;
12
+ }): Promise<void>;
@@ -0,0 +1,3 @@
1
+ import type { Renderer } from './types';
2
+ declare const renderer: Renderer;
3
+ export { renderer };
@@ -1,5 +1,10 @@
1
1
  declare type RenderModuleConfig = {
2
2
  polyfillCondition?: string;
3
+ /**
4
+ * @deprecated tramvai will automatically detect React version, and use hydrateRoot API for 18+ version
5
+ * For Strict Mode, use options `useStrictMode`
6
+ */
3
7
  mode?: 'legacy' | 'strict' | 'blocking' | 'concurrent';
8
+ useStrictMode?: boolean;
4
9
  };
5
10
  export { RenderModuleConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/module-render",
3
- "version": "1.79.0",
3
+ "version": "1.81.0",
4
4
  "description": "",
5
5
  "browser": "lib/browser.js",
6
6
  "main": "lib/server.js",
@@ -24,27 +24,28 @@
24
24
  "@tinkoff/htmlpagebuilder": "0.4.22",
25
25
  "@tinkoff/layout-factory": "0.2.28",
26
26
  "@tinkoff/url": "0.7.37",
27
- "@tinkoff/user-agent": "0.3.279",
28
- "@tramvai/module-client-hints": "1.79.0",
29
- "@tramvai/module-router": "1.79.0",
30
- "@tramvai/react": "1.79.0",
27
+ "@tinkoff/user-agent": "0.3.281",
28
+ "@tramvai/module-client-hints": "1.81.0",
29
+ "@tramvai/module-router": "1.81.0",
30
+ "@tramvai/react": "1.81.0",
31
31
  "@tramvai/safe-strings": "0.4.3",
32
- "@tramvai/tokens-render": "1.79.0",
33
- "@tramvai/experiments": "1.79.0",
32
+ "@tramvai/tokens-render": "1.81.0",
33
+ "@tramvai/experiments": "1.81.0",
34
34
  "@types/loadable__server": "^5.12.6",
35
35
  "node-fetch": "^2.6.1"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@tinkoff/dippy": "0.7.39",
39
39
  "@tinkoff/utils": "^2.1.2",
40
- "@tramvai/cli": "1.79.0",
41
- "@tramvai/core": "1.79.0",
42
- "@tramvai/module-common": "1.79.0",
43
- "@tramvai/state": "1.79.0",
44
- "@tramvai/test-helpers": "1.79.0",
45
- "@tramvai/tokens-common": "1.79.0",
46
- "@tramvai/tokens-router": "1.79.0",
47
- "@tramvai/tokens-server": "1.79.0",
40
+ "@tinkoff/react-hooks": "0.0.24",
41
+ "@tramvai/cli": "1.81.0",
42
+ "@tramvai/core": "1.81.0",
43
+ "@tramvai/module-common": "1.81.0",
44
+ "@tramvai/state": "1.81.0",
45
+ "@tramvai/test-helpers": "1.81.0",
46
+ "@tramvai/tokens-common": "1.81.0",
47
+ "@tramvai/tokens-router": "1.81.0",
48
+ "@tramvai/tokens-server": "1.81.0",
48
49
  "express": "^4.17.1",
49
50
  "prop-types": "^15.6.2",
50
51
  "react": ">=16.8.0",
@@ -1,4 +0,0 @@
1
- import type { Renderer } from './types';
2
- declare const blockingRenderer: Renderer;
3
- declare const concurrentRenderer: Renderer;
4
- export { blockingRenderer, concurrentRenderer };
@@ -1,3 +0,0 @@
1
- import type { Renderer } from './types';
2
- declare const legacyRenderer: Renderer;
3
- export { legacyRenderer };
@@ -1,3 +0,0 @@
1
- import type { Renderer } from './types';
2
- declare const strictRenderer: Renderer;
3
- export { strictRenderer };