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
Token with name already created!
The issue happens when @tinkoff/dippy
library is shared due to fact that root-app and child-apps will have separate instances of the same tokens packages with the same naming.
For now, just ignore that kind of warnings during development. In production these warnings won't be shown
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"]
}
},
}
}