Known Issues
This Suspense boundary received an update before it finished hydrating
When React
>= 18
version is used, child-app will be wrapped in Suspense
boundary for Selective Hydration. This optimization can significantly decrease Total Blocking Time metric of the page.
There is one drawback of this optimization - if you will try rerender child-app during selective hydration, React
will switch to deopt mode and made full client-rendering of the child-app component. Potential ways to fix this problem described here. ChildApp
component already wrapped in React.memo
.
Few advices to avoid this problem:
- Memoize object, passed to child-app
props
property - Prevent pass to child-app properties, which can be changed during hydration, for example at client-side in page actions
Shared dependency are still loaded although the root-app shares it
Refer to the FAQ about the details. In summary:
- it is more reliable to provide shared dependency from the root-app than relying on sharing between several child-apps
- make sure all versions of the shared dependencies are semver compatible
Possible problems with shared dependency
react-query: No QueryClient set, use QueryClientProvider to set one
The issue may happen if there are different instances of @tramvai/module-react-query
and @tramvai/react-query
and therefore internal code inside @tramvai/react-query
resolves React Context that differs from the QueryClient Provided inside @tramvai/module-react-query
To resolve the issue:
- when defining shared dependencies add both
@tramvai/module-react-query
and@tramvai/module-react-query
- make sure that both packages are used in the root-app (or none) as both instances should resolve to one place and if it isn't apply then for example
@tramvai/react-query
might instantiate with different React Context - another option would be to add underlying library
@tanstack/react-query
to both child-app and root-app shared dependencies to make sure that required React Context is created only in single instance
Shared module is not available for eager consumption
Uncaught Error: Shared module is not available for eager consumption
- this error can occure when:
- Dependency is shared between Child App and Root App
- Dependency is
eager
in Root App configuration (e.g.@tramvai/core
,@tramvai/react
and@tinkoff/dippy
) - Dependency in Child App has higher version than same dependency in Root App
- Application running in production mode (after deployment or
tramvai start-prod
command, unfortunately you can't catch this issue when usetramvai start
) - You have a component loaded by dynamic import (e.g. with
lazy
from@tramvai/react
) and this component uses some of this shared deps underhood
Reason
More information why this problem exists you can find in Module Federation documentation
Solution
Simple and fast solution - is to always update Root Application before Child Apps. If it is not possible, you need to create "async boundary" for application dependencies at the higher level - entry point is good enough for it.
- At first, create
bootstrap.ts
file nearindex.ts
, and copy there allindex.ts
content - Then change
index.ts
content to dynamic import ofbootstrap.ts
withwebpackChunkName
magic comment specified - At least, add
bootstrap
(use herewebpackChunkName
value) chunk for critical chunks list -shared.criticalChunks: ['bootstrap']
option in `tramvai.json (it is important to load all main application assets in parallel)
Full example (with simplified content):
- src/index.ts
- src/bootstrap.ts
- tramvai.json
import(/* webpackChunkName: "bootstrap" */ './bootstrap');
import { createApp } from '@tramvai/core';
import { CommonModule } from '@tramvai/module-common';
import { SpaRouterModule } from '@tramvai/module-router';
import { RenderModule } from '@tramvai/module-render';
import { SeoModule } from '@tramvai/module-seo';
import { ServerModule } from '@tramvai/module-server';
import { ErrorInterceptorModule } from '@tramvai/module-error-interceptor';
createApp({
name: 'tincoin',
modules: [
CommonModule,
SpaRouterModule,
RenderModule,
SeoModule,
ServerModule,
ErrorInterceptorModule,
],
providers: [],
});
{
"$schema": "../../node_modules/@tramvai/cli/schema.json",
"projects": {
"root-app": {
"name": "tincoin",
"root": "src",
"type": "application",
"shared": {
"criticalChunks": ["bootstrap"]
}
},
}
}