@tramvai/module-router 1.30.0 → 1.31.1
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 +78 -74
- package/lib/index.browser.js +28 -9
- package/lib/index.es.js +29 -10
- package/lib/index.js +27 -8
- package/lib/modules/guards/common/loadBundle.d.ts +2 -3
- package/lib/services/page.d.ts +6 -1
- package/package.json +15 -15
- package/README.en.md +0 -359
package/README.md
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
# @tramvai/module-router
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Module for routing in the application.
|
|
4
|
+
Exports two sub-modules: with client SPA transitions, and no-SPA.
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
+
## Installation
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
You need to install `@tramvai/module-router`:
|
|
8
9
|
|
|
9
10
|
```bash
|
|
10
11
|
yarn add @tramvai/module-router
|
|
11
12
|
```
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
And connect in the project:
|
|
14
15
|
|
|
15
16
|
```tsx
|
|
16
17
|
import { createApp } from '@tramvai/core';
|
|
@@ -19,55 +20,55 @@ import { NoSpaRouterModule, SpaRouterModule } from '@tramvai/module-router';
|
|
|
19
20
|
createApp({
|
|
20
21
|
name: 'tincoin',
|
|
21
22
|
modules: [SpaRouterModule],
|
|
22
|
-
//modules: [ NoSpaRouterModule ],
|
|
23
|
+
// modules: [ NoSpaRouterModule ], if you want to disable client SPA transitions
|
|
23
24
|
});
|
|
24
25
|
```
|
|
25
26
|
|
|
26
27
|
## Explanation
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
The module is based on the library [@tinkoff/router](references/libs/router.md)
|
|
29
30
|
|
|
30
|
-
###
|
|
31
|
+
### Navigation flow on the server
|
|
31
32
|
|
|
32
|
-

|
|
33
34
|
|
|
34
|
-
###
|
|
35
|
+
### Flow of the first navigation on the client
|
|
35
36
|
|
|
36
|
-

|
|
37
38
|
|
|
38
|
-
###
|
|
39
|
+
### Flow of navigation on the client without SPA transitions
|
|
39
40
|
|
|
40
|
-

|
|
41
42
|
|
|
42
|
-
###
|
|
43
|
+
### Flow of navigation on the client with SPA transitions
|
|
43
44
|
|
|
44
|
-

|
|
45
46
|
|
|
46
47
|
## API
|
|
47
48
|
|
|
48
|
-
###
|
|
49
|
+
### Static routes in the application
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
Route description format:
|
|
51
52
|
|
|
52
53
|
```ts
|
|
53
54
|
const routes = [
|
|
54
55
|
{
|
|
55
|
-
//
|
|
56
|
+
// the name of the route is required
|
|
56
57
|
name: 'route1',
|
|
57
|
-
//
|
|
58
|
+
// the path of the route is required
|
|
58
59
|
path: '/route/a/',
|
|
59
|
-
//
|
|
60
|
+
// additional configs for the route
|
|
60
61
|
config: {
|
|
61
|
-
//
|
|
62
|
+
// layout component name
|
|
62
63
|
layoutComponent: 'layout',
|
|
63
|
-
//
|
|
64
|
+
// page component name
|
|
64
65
|
pageComponent: 'page',
|
|
65
66
|
},
|
|
66
67
|
},
|
|
67
68
|
];
|
|
68
69
|
```
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
You can explicitly transfer a list of routes to routing when adding a router module:
|
|
71
72
|
|
|
72
73
|
```ts
|
|
73
74
|
import { createApp } from '@tramvai/core';
|
|
@@ -85,7 +86,7 @@ createApp({
|
|
|
85
86
|
});
|
|
86
87
|
```
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
Or separately with the `ROUTES_TOKEN` token (you can set it several times):
|
|
89
90
|
|
|
90
91
|
```ts
|
|
91
92
|
import { ROUTES_TOKEN } from '@tramvai/module-router';
|
|
@@ -115,39 +116,41 @@ const providers = [
|
|
|
115
116
|
|
|
116
117
|
### PAGE_SERVICE_TOKEN
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
Service wrapper for working with routing. Serves to hide routing work and is the preferred way of routing work.
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
Methods:
|
|
121
122
|
|
|
122
|
-
- `getCurrentRoute()` -
|
|
123
|
-
- `getCurrentUrl()` -
|
|
124
|
-
- `getConfig()` -
|
|
125
|
-
- `getContent()` -
|
|
126
|
-
- `getMeta()` -
|
|
127
|
-
- `navigate(options)` -
|
|
128
|
-
- `updateCurrentRoute(options)` -
|
|
129
|
-
- `back()` -
|
|
130
|
-
- `forward()` -
|
|
131
|
-
- `go(to)` -
|
|
123
|
+
- `getCurrentRoute()` - get the current route
|
|
124
|
+
- `getCurrentUrl()` - object-result of parsing the current url
|
|
125
|
+
- `getConfig()` - get the config of the current page
|
|
126
|
+
- `getContent()` - get content for the current page
|
|
127
|
+
- `getMeta()` - get the meta for the current page
|
|
128
|
+
- `navigate(options)` - navigation to a new page [more](references/libs/router.md)
|
|
129
|
+
- `updateCurrentRoute(options)` - update the current route with new parameters [more](references/libs/router.md)
|
|
130
|
+
- `back()` - go back through history
|
|
131
|
+
- `forward()` - go forward through history
|
|
132
|
+
- `go(to)` - go to the specified delta by history
|
|
133
|
+
- `addComponent(name, component)` - add new component to current page into ComponentRegistry
|
|
134
|
+
- `getComponent(name)` - get component from current page components from ComponentRegistry
|
|
132
135
|
|
|
133
136
|
### RouterStore
|
|
134
137
|
|
|
135
|
-
|
|
138
|
+
Store that stores information about the current and previous routes.
|
|
136
139
|
|
|
137
|
-
|
|
140
|
+
Properties:
|
|
138
141
|
|
|
139
|
-
- `currentRoute` -
|
|
140
|
-
- `currentUrl` -
|
|
141
|
-
- `previousRoute` -
|
|
142
|
-
- `previousUrl` -
|
|
142
|
+
- `currentRoute` - current route
|
|
143
|
+
- `currentUrl` - current url
|
|
144
|
+
- `previousRoute` - previous route
|
|
145
|
+
- `previousUrl` - previous url
|
|
143
146
|
|
|
144
147
|
### ROUTER_GUARD_TOKEN
|
|
145
148
|
|
|
146
|
-
|
|
149
|
+
Allows you to block or redirect the transition to the page under certain conditions. See [@tinkoff/router](/references/libs/router.md)
|
|
147
150
|
|
|
148
|
-
###
|
|
151
|
+
### Redirects
|
|
149
152
|
|
|
150
|
-
|
|
153
|
+
Redirects can be done via [guards](#ROUTER_GUARD_TOKEN) or explicitly via the `redirect` property in the route.
|
|
151
154
|
|
|
152
155
|
```ts
|
|
153
156
|
const routes = [
|
|
@@ -160,9 +163,9 @@ const routes = [
|
|
|
160
163
|
];
|
|
161
164
|
```
|
|
162
165
|
|
|
163
|
-
### Not Found
|
|
166
|
+
### Not Found route
|
|
164
167
|
|
|
165
|
-
|
|
168
|
+
The route used if no matches were found for the current page, can be specified in a special way in the list of routes.
|
|
166
169
|
|
|
167
170
|
```ts
|
|
168
171
|
const route = [
|
|
@@ -179,19 +182,19 @@ const route = [
|
|
|
179
182
|
|
|
180
183
|
### ROUTE_RESOLVE_TOKEN
|
|
181
184
|
|
|
182
|
-
|
|
185
|
+
Allows you to define an asynchronous function that returns a route object that will be called if no suitable static route was found in the application.
|
|
183
186
|
|
|
184
187
|
### ROUTE_TRANSFORM_TOKEN
|
|
185
188
|
|
|
186
|
-
|
|
189
|
+
Transformer function for application routes (set statically and those that will be loaded via ROUTE_RESOLVE_TOKEN)
|
|
187
190
|
|
|
188
|
-
###
|
|
191
|
+
### Method of setting when actions should be performed during SPA transitions
|
|
189
192
|
|
|
190
|
-
|
|
193
|
+
By default, SPA transitions execute actions after defining the next route, but before the actual transition, which allows the page to be displayed immediately with new data, but can cause a noticeable visual lag if the actions are taken long enough.
|
|
191
194
|
|
|
192
|
-
|
|
195
|
+
It is possible to change the behavior and make the execution of actions after the transition itself. Then, when developing components, you will need to take into account that data will be loaded as it becomes available.
|
|
193
196
|
|
|
194
|
-
|
|
197
|
+
Configurable explicitly when using the routing module:
|
|
195
198
|
|
|
196
199
|
```ts
|
|
197
200
|
import { createApp } from '@tramvai/core';
|
|
@@ -201,13 +204,13 @@ createApp({
|
|
|
201
204
|
modules: [
|
|
202
205
|
// ...,
|
|
203
206
|
SpaRouterModule.forRoot([], {
|
|
204
|
-
spaActionsMode: 'after', //
|
|
207
|
+
spaActionsMode: 'after', // default is 'before'
|
|
205
208
|
}),
|
|
206
209
|
],
|
|
207
210
|
});
|
|
208
211
|
```
|
|
209
212
|
|
|
210
|
-
|
|
213
|
+
or through token `ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN`:
|
|
211
214
|
|
|
212
215
|
```ts
|
|
213
216
|
import { ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN } from '@tramvai/module-router';
|
|
@@ -224,9 +227,9 @@ const providers = [
|
|
|
224
227
|
|
|
225
228
|
## How to
|
|
226
229
|
|
|
227
|
-
###
|
|
230
|
+
### Working with navigation in providers and actions
|
|
228
231
|
|
|
229
|
-
|
|
232
|
+
In this case, it is best to use the [PAGE_SERVICE_TOKEN](#page_service_token)
|
|
230
233
|
|
|
231
234
|
```ts
|
|
232
235
|
import { provide, createAction } from '@tramvai/core';
|
|
@@ -257,65 +260,66 @@ const action = createAction({
|
|
|
257
260
|
});
|
|
258
261
|
```
|
|
259
262
|
|
|
260
|
-
###
|
|
263
|
+
### Working with navigation in React components
|
|
261
264
|
|
|
262
|
-
|
|
265
|
+
You can work with routing inside React components using hooks and components - `useNavigate`, `useRoute`, `Link` from the [@tinkoff/router](references/libs/router.md#интеграция-с-react)
|
|
263
266
|
|
|
264
267
|
<p>
|
|
265
268
|
<details>
|
|
266
|
-
<summary
|
|
269
|
+
<summary>An example of working with navigation in the application</summary>
|
|
267
270
|
|
|
268
271
|
@inline ../../../examples/how-to/router-navigate/index.tsx
|
|
269
272
|
|
|
270
273
|
</details>
|
|
271
274
|
</p>
|
|
272
275
|
|
|
273
|
-
###
|
|
276
|
+
### How to set static routes
|
|
274
277
|
|
|
275
|
-
[RouterModule](references/modules/router.md)
|
|
278
|
+
[RouterModule](references/modules/router.md) allows you to add new routes when configuring your application.
|
|
279
|
+
The second way is to pass static routes to DI via the `ROUTES_TOKEN` token.
|
|
276
280
|
|
|
277
281
|
<p>
|
|
278
282
|
<details>
|
|
279
|
-
<summary
|
|
283
|
+
<summary>An example of adding static routes to an application</summary>
|
|
280
284
|
|
|
281
285
|
@inline ../../../examples/how-to/router-static-routes/index.tsx
|
|
282
286
|
|
|
283
287
|
</details>
|
|
284
288
|
</p>
|
|
285
289
|
|
|
286
|
-
###
|
|
290
|
+
### How to set Route Guard
|
|
287
291
|
|
|
288
|
-
[ROUTER_GUARD_TOKEN](references/modules/router.md#router_guard_token)
|
|
292
|
+
[ROUTER_GUARD_TOKEN](references/modules/router.md#router_guard_token) is set as an asynchronous function, which allows you to perform various actions and influence the routing behavior.
|
|
289
293
|
|
|
290
294
|
<p>
|
|
291
295
|
<details>
|
|
292
|
-
<summary
|
|
296
|
+
<summary>Example router guards job in application</summary>
|
|
293
297
|
|
|
294
298
|
@inline ../../../examples/how-to/router-guards/index.tsx
|
|
295
299
|
|
|
296
300
|
</details>
|
|
297
301
|
</p>
|
|
298
302
|
|
|
299
|
-
###
|
|
303
|
+
### How to set the Not found route
|
|
300
304
|
|
|
301
|
-
Not
|
|
305
|
+
The Not found route is used if the corresponding route is not found for the url.
|
|
302
306
|
|
|
303
|
-
|
|
307
|
+
Such a route is specified in the list of routes with the special `*` character in the `path` property.
|
|
304
308
|
|
|
305
309
|
<p>
|
|
306
310
|
<details>
|
|
307
|
-
<summary
|
|
311
|
+
<summary>An example of setting a Not Found route in an application</summary>
|
|
308
312
|
|
|
309
313
|
@inline ../../../examples/how-to/router-not-found/index.tsx
|
|
310
314
|
|
|
311
315
|
</details>
|
|
312
316
|
</p>
|
|
313
317
|
|
|
314
|
-
###
|
|
318
|
+
### Testing
|
|
315
319
|
|
|
316
|
-
####
|
|
320
|
+
#### Testing ROUTER_GUARD_TOKEN extensions
|
|
317
321
|
|
|
318
|
-
|
|
322
|
+
If you have a module or providers that define `ROUTER_GUARD_TOKEN`, then it will be convenient to use special utilities to test them separately
|
|
319
323
|
|
|
320
324
|
```ts
|
|
321
325
|
import { ROUTER_GUARD_TOKEN } from '@tramvai/tokens-router';
|
|
@@ -352,6 +356,6 @@ describe('router guards', () => {
|
|
|
352
356
|
});
|
|
353
357
|
```
|
|
354
358
|
|
|
355
|
-
##
|
|
359
|
+
## Exported tokens
|
|
356
360
|
|
|
357
|
-
[
|
|
361
|
+
[link](references/tokens/router-tokens.md)
|
package/lib/index.browser.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { provide, commandLineListTokens, Module, DI_TOKEN, COMMAND_LINE_RUNNER_TOKEN } from '@tramvai/core';
|
|
2
2
|
import { Provider, setLogger, NoSpaRouter, Router } from '@tinkoff/router';
|
|
3
3
|
export { Link, Provider, useNavigate, useRoute, useRouter, useUrl } from '@tinkoff/router';
|
|
4
|
-
import { LOGGER_TOKEN, BUNDLE_MANAGER_TOKEN,
|
|
4
|
+
import { LOGGER_TOKEN, BUNDLE_MANAGER_TOKEN, ACTION_REGISTRY_TOKEN, RESPONSE_MANAGER_TOKEN, CONTEXT_TOKEN, COMPONENT_REGISTRY_TOKEN, COMBINE_REDUCERS, STORE_TOKEN, ACTION_PAGE_RUNNER_TOKEN } from '@tramvai/tokens-common';
|
|
5
5
|
import { ROUTER_GUARD_TOKEN, ROUTE_TRANSFORM_TOKEN, ROUTER_TOKEN, ROUTES_TOKEN, ROUTE_RESOLVE_TOKEN, ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN, PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
6
6
|
export * from '@tramvai/tokens-router';
|
|
7
7
|
import { createEvent, createReducer } from '@tramvai/state';
|
|
@@ -12,7 +12,7 @@ import identity from '@tinkoff/utils/function/identity';
|
|
|
12
12
|
import compose from '@tinkoff/utils/function/compose';
|
|
13
13
|
import replace from '@tinkoff/utils/string/replace';
|
|
14
14
|
import React from 'react';
|
|
15
|
-
import { fileSystemPagesEnabled, getStaticFileSystemPages, fileSystemPageToRoute } from '@tramvai/experiments';
|
|
15
|
+
import { isFileSystemPageComponent, fileSystemPagesEnabled, getStaticFileSystemPages, fileSystemPageToRoute } from '@tramvai/experiments';
|
|
16
16
|
import uniq from '@tinkoff/utils/array/uniq';
|
|
17
17
|
import { isRedirectFoundError, isNotFoundError } from '@tinkoff/errors';
|
|
18
18
|
import noop from '@tinkoff/utils/function/noop';
|
|
@@ -62,7 +62,7 @@ const afterUpdateCurrentHooksToken = createToken('router afterUpdateCurrentHooks
|
|
|
62
62
|
const routeTransformToken = createToken('router finalRouteTransform');
|
|
63
63
|
createToken('router bundleInfoAdditional');
|
|
64
64
|
|
|
65
|
-
const loadBundle = ({ bundleManager, logger, actionRegistry,
|
|
65
|
+
const loadBundle = ({ bundleManager, logger, actionRegistry, responseManager, }) => {
|
|
66
66
|
const log = logger('route:load-bundles');
|
|
67
67
|
return async ({ to }) => {
|
|
68
68
|
log.debug({
|
|
@@ -71,6 +71,11 @@ const loadBundle = ({ bundleManager, logger, actionRegistry, componentRegistry,
|
|
|
71
71
|
});
|
|
72
72
|
const { bundle, pageComponent } = to.config;
|
|
73
73
|
if (!bundleManager.has(bundle, pageComponent)) {
|
|
74
|
+
log.info({
|
|
75
|
+
event: 'load-bundle-not-found',
|
|
76
|
+
bundle,
|
|
77
|
+
pageComponent,
|
|
78
|
+
});
|
|
74
79
|
// если бандл не найдён, то всё ок мы должны вернуть 404 на сервере, а на клиенте просто загрузить новую страницу
|
|
75
80
|
responseManager.setStatus(404);
|
|
76
81
|
return false;
|
|
@@ -113,7 +118,6 @@ const commonGuards = [
|
|
|
113
118
|
deps: {
|
|
114
119
|
logger: LOGGER_TOKEN,
|
|
115
120
|
bundleManager: BUNDLE_MANAGER_TOKEN,
|
|
116
|
-
componentRegistry: COMPONENT_REGISTRY_TOKEN,
|
|
117
121
|
actionRegistry: ACTION_REGISTRY_TOKEN,
|
|
118
122
|
responseManager: RESPONSE_MANAGER_TOKEN,
|
|
119
123
|
},
|
|
@@ -208,8 +212,9 @@ const commonTokens = [
|
|
|
208
212
|
];
|
|
209
213
|
|
|
210
214
|
class PageService {
|
|
211
|
-
constructor({ router }) {
|
|
215
|
+
constructor({ router, componentRegistry }) {
|
|
212
216
|
this.router = router;
|
|
217
|
+
this.componentRegistry = componentRegistry;
|
|
213
218
|
}
|
|
214
219
|
getCurrentRoute() {
|
|
215
220
|
return this.router.getCurrentRoute();
|
|
@@ -244,6 +249,19 @@ class PageService {
|
|
|
244
249
|
go(to, options) {
|
|
245
250
|
return this.router.go(to, options);
|
|
246
251
|
}
|
|
252
|
+
addComponent(name, component) {
|
|
253
|
+
const group = this.getComponentsGroupName();
|
|
254
|
+
return this.componentRegistry.add(name, component, group);
|
|
255
|
+
}
|
|
256
|
+
getComponent(name) {
|
|
257
|
+
const group = this.getComponentsGroupName();
|
|
258
|
+
return this.componentRegistry.get(name, group);
|
|
259
|
+
}
|
|
260
|
+
getComponentsGroupName() {
|
|
261
|
+
const { bundle, pageComponent } = this.getConfig();
|
|
262
|
+
const group = isFileSystemPageComponent(pageComponent) ? pageComponent : bundle;
|
|
263
|
+
return group;
|
|
264
|
+
}
|
|
247
265
|
}
|
|
248
266
|
|
|
249
267
|
const providers$2 = [
|
|
@@ -252,10 +270,10 @@ const providers$2 = [
|
|
|
252
270
|
provide: ROUTES_TOKEN,
|
|
253
271
|
multi: true,
|
|
254
272
|
useFactory: ({ logger }) => {
|
|
255
|
-
const log = logger('
|
|
273
|
+
const log = logger('file-system-pages:route');
|
|
256
274
|
const pagesNames = Object.keys(getStaticFileSystemPages());
|
|
257
275
|
const routes = pagesNames.map(fileSystemPageToRoute);
|
|
258
|
-
log.
|
|
276
|
+
log.info({
|
|
259
277
|
event: 'create static routes from file-system pages',
|
|
260
278
|
routes,
|
|
261
279
|
});
|
|
@@ -375,13 +393,14 @@ const providers$1 = [
|
|
|
375
393
|
// рассмотреть возможность замены после доработок экшенов
|
|
376
394
|
useValue: 'after',
|
|
377
395
|
},
|
|
378
|
-
{
|
|
396
|
+
provide({
|
|
379
397
|
provide: PAGE_SERVICE_TOKEN,
|
|
380
398
|
useClass: PageService,
|
|
381
399
|
deps: {
|
|
382
400
|
router: ROUTER_TOKEN,
|
|
401
|
+
componentRegistry: COMPONENT_REGISTRY_TOKEN,
|
|
383
402
|
},
|
|
384
|
-
},
|
|
403
|
+
}),
|
|
385
404
|
{
|
|
386
405
|
provide: COMBINE_REDUCERS,
|
|
387
406
|
multi: true,
|
package/lib/index.es.js
CHANGED
|
@@ -2,7 +2,7 @@ import { __decorate } from 'tslib';
|
|
|
2
2
|
import { provide, commandLineListTokens, Module } from '@tramvai/core';
|
|
3
3
|
import { Provider, setLogger, Router } from '@tinkoff/router';
|
|
4
4
|
export { Link, Provider, useNavigate, useRoute, useRouter, useUrl } from '@tinkoff/router';
|
|
5
|
-
import { LOGGER_TOKEN, BUNDLE_MANAGER_TOKEN,
|
|
5
|
+
import { LOGGER_TOKEN, BUNDLE_MANAGER_TOKEN, ACTION_REGISTRY_TOKEN, RESPONSE_MANAGER_TOKEN, CONTEXT_TOKEN, COMPONENT_REGISTRY_TOKEN, COMBINE_REDUCERS, REQUEST_MANAGER_TOKEN, ACTION_PAGE_RUNNER_TOKEN } from '@tramvai/tokens-common';
|
|
6
6
|
import { ROUTER_GUARD_TOKEN, ROUTE_TRANSFORM_TOKEN, ROUTER_TOKEN, ROUTES_TOKEN, ROUTE_RESOLVE_TOKEN, ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN, PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
7
7
|
export * from '@tramvai/tokens-router';
|
|
8
8
|
import flatten from '@tinkoff/utils/array/flatten';
|
|
@@ -13,7 +13,7 @@ import identity from '@tinkoff/utils/function/identity';
|
|
|
13
13
|
import compose from '@tinkoff/utils/function/compose';
|
|
14
14
|
import replace from '@tinkoff/utils/string/replace';
|
|
15
15
|
import React from 'react';
|
|
16
|
-
import { fileSystemPagesEnabled, getStaticFileSystemPages, fileSystemPageToRoute } from '@tramvai/experiments';
|
|
16
|
+
import { isFileSystemPageComponent, fileSystemPagesEnabled, getStaticFileSystemPages, fileSystemPageToRoute } from '@tramvai/experiments';
|
|
17
17
|
import uniq from '@tinkoff/utils/array/uniq';
|
|
18
18
|
import { isRedirectFoundError, isNotFoundError, throwHttpError, throwRedirectFoundError } from '@tinkoff/errors';
|
|
19
19
|
import { SERVER_MODULE_PAPI_PUBLIC_ROUTE } from '@tramvai/tokens-server';
|
|
@@ -65,7 +65,7 @@ const RouterStore = createReducer('router', initialState)
|
|
|
65
65
|
};
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
const loadBundle = ({ bundleManager, logger, actionRegistry,
|
|
68
|
+
const loadBundle = ({ bundleManager, logger, actionRegistry, responseManager, }) => {
|
|
69
69
|
const log = logger('route:load-bundles');
|
|
70
70
|
return async ({ to }) => {
|
|
71
71
|
log.debug({
|
|
@@ -74,6 +74,11 @@ const loadBundle = ({ bundleManager, logger, actionRegistry, componentRegistry,
|
|
|
74
74
|
});
|
|
75
75
|
const { bundle, pageComponent } = to.config;
|
|
76
76
|
if (!bundleManager.has(bundle, pageComponent)) {
|
|
77
|
+
log.info({
|
|
78
|
+
event: 'load-bundle-not-found',
|
|
79
|
+
bundle,
|
|
80
|
+
pageComponent,
|
|
81
|
+
});
|
|
77
82
|
// если бандл не найдён, то всё ок мы должны вернуть 404 на сервере, а на клиенте просто загрузить новую страницу
|
|
78
83
|
responseManager.setStatus(404);
|
|
79
84
|
return false;
|
|
@@ -116,7 +121,6 @@ const commonGuards = [
|
|
|
116
121
|
deps: {
|
|
117
122
|
logger: LOGGER_TOKEN,
|
|
118
123
|
bundleManager: BUNDLE_MANAGER_TOKEN,
|
|
119
|
-
componentRegistry: COMPONENT_REGISTRY_TOKEN,
|
|
120
124
|
actionRegistry: ACTION_REGISTRY_TOKEN,
|
|
121
125
|
responseManager: RESPONSE_MANAGER_TOKEN,
|
|
122
126
|
},
|
|
@@ -211,8 +215,9 @@ const commonTokens = [
|
|
|
211
215
|
];
|
|
212
216
|
|
|
213
217
|
class PageService {
|
|
214
|
-
constructor({ router }) {
|
|
218
|
+
constructor({ router, componentRegistry }) {
|
|
215
219
|
this.router = router;
|
|
220
|
+
this.componentRegistry = componentRegistry;
|
|
216
221
|
}
|
|
217
222
|
getCurrentRoute() {
|
|
218
223
|
return this.router.getCurrentRoute();
|
|
@@ -247,6 +252,19 @@ class PageService {
|
|
|
247
252
|
go(to, options) {
|
|
248
253
|
return this.router.go(to, options);
|
|
249
254
|
}
|
|
255
|
+
addComponent(name, component) {
|
|
256
|
+
const group = this.getComponentsGroupName();
|
|
257
|
+
return this.componentRegistry.add(name, component, group);
|
|
258
|
+
}
|
|
259
|
+
getComponent(name) {
|
|
260
|
+
const group = this.getComponentsGroupName();
|
|
261
|
+
return this.componentRegistry.get(name, group);
|
|
262
|
+
}
|
|
263
|
+
getComponentsGroupName() {
|
|
264
|
+
const { bundle, pageComponent } = this.getConfig();
|
|
265
|
+
const group = isFileSystemPageComponent(pageComponent) ? pageComponent : bundle;
|
|
266
|
+
return group;
|
|
267
|
+
}
|
|
250
268
|
}
|
|
251
269
|
|
|
252
270
|
const providers$1 = [
|
|
@@ -255,10 +273,10 @@ const providers$1 = [
|
|
|
255
273
|
provide: ROUTES_TOKEN,
|
|
256
274
|
multi: true,
|
|
257
275
|
useFactory: ({ logger }) => {
|
|
258
|
-
const log = logger('
|
|
276
|
+
const log = logger('file-system-pages:route');
|
|
259
277
|
const pagesNames = Object.keys(getStaticFileSystemPages());
|
|
260
278
|
const routes = pagesNames.map(fileSystemPageToRoute);
|
|
261
|
-
log.
|
|
279
|
+
log.info({
|
|
262
280
|
event: 'create static routes from file-system pages',
|
|
263
281
|
routes,
|
|
264
282
|
});
|
|
@@ -378,13 +396,14 @@ const providers = [
|
|
|
378
396
|
// рассмотреть возможность замены после доработок экшенов
|
|
379
397
|
useValue: 'after',
|
|
380
398
|
},
|
|
381
|
-
{
|
|
399
|
+
provide({
|
|
382
400
|
provide: PAGE_SERVICE_TOKEN,
|
|
383
401
|
useClass: PageService,
|
|
384
402
|
deps: {
|
|
385
403
|
router: ROUTER_TOKEN,
|
|
404
|
+
componentRegistry: COMPONENT_REGISTRY_TOKEN,
|
|
386
405
|
},
|
|
387
|
-
},
|
|
406
|
+
}),
|
|
388
407
|
{
|
|
389
408
|
provide: COMBINE_REDUCERS,
|
|
390
409
|
multi: true,
|
|
@@ -399,7 +418,7 @@ const httpMethod = ({ requestManager, responseManager, logger, }) => {
|
|
|
399
418
|
if (httpMethods) {
|
|
400
419
|
const currentMethod = requestManager.getMethod().toLowerCase();
|
|
401
420
|
if (!httpMethods.split(',').includes(currentMethod)) {
|
|
402
|
-
log.
|
|
421
|
+
log.info({
|
|
403
422
|
event: 'check-failed',
|
|
404
423
|
currentMethod,
|
|
405
424
|
route: to,
|
package/lib/index.js
CHANGED
|
@@ -77,7 +77,7 @@ const RouterStore = state.createReducer('router', initialState)
|
|
|
77
77
|
};
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
const loadBundle = ({ bundleManager, logger, actionRegistry,
|
|
80
|
+
const loadBundle = ({ bundleManager, logger, actionRegistry, responseManager, }) => {
|
|
81
81
|
const log = logger('route:load-bundles');
|
|
82
82
|
return async ({ to }) => {
|
|
83
83
|
log.debug({
|
|
@@ -86,6 +86,11 @@ const loadBundle = ({ bundleManager, logger, actionRegistry, componentRegistry,
|
|
|
86
86
|
});
|
|
87
87
|
const { bundle, pageComponent } = to.config;
|
|
88
88
|
if (!bundleManager.has(bundle, pageComponent)) {
|
|
89
|
+
log.info({
|
|
90
|
+
event: 'load-bundle-not-found',
|
|
91
|
+
bundle,
|
|
92
|
+
pageComponent,
|
|
93
|
+
});
|
|
89
94
|
// если бандл не найдён, то всё ок мы должны вернуть 404 на сервере, а на клиенте просто загрузить новую страницу
|
|
90
95
|
responseManager.setStatus(404);
|
|
91
96
|
return false;
|
|
@@ -128,7 +133,6 @@ const commonGuards = [
|
|
|
128
133
|
deps: {
|
|
129
134
|
logger: tokensCommon.LOGGER_TOKEN,
|
|
130
135
|
bundleManager: tokensCommon.BUNDLE_MANAGER_TOKEN,
|
|
131
|
-
componentRegistry: tokensCommon.COMPONENT_REGISTRY_TOKEN,
|
|
132
136
|
actionRegistry: tokensCommon.ACTION_REGISTRY_TOKEN,
|
|
133
137
|
responseManager: tokensCommon.RESPONSE_MANAGER_TOKEN,
|
|
134
138
|
},
|
|
@@ -223,8 +227,9 @@ const commonTokens = [
|
|
|
223
227
|
];
|
|
224
228
|
|
|
225
229
|
class PageService {
|
|
226
|
-
constructor({ router }) {
|
|
230
|
+
constructor({ router, componentRegistry }) {
|
|
227
231
|
this.router = router;
|
|
232
|
+
this.componentRegistry = componentRegistry;
|
|
228
233
|
}
|
|
229
234
|
getCurrentRoute() {
|
|
230
235
|
return this.router.getCurrentRoute();
|
|
@@ -259,6 +264,19 @@ class PageService {
|
|
|
259
264
|
go(to, options) {
|
|
260
265
|
return this.router.go(to, options);
|
|
261
266
|
}
|
|
267
|
+
addComponent(name, component) {
|
|
268
|
+
const group = this.getComponentsGroupName();
|
|
269
|
+
return this.componentRegistry.add(name, component, group);
|
|
270
|
+
}
|
|
271
|
+
getComponent(name) {
|
|
272
|
+
const group = this.getComponentsGroupName();
|
|
273
|
+
return this.componentRegistry.get(name, group);
|
|
274
|
+
}
|
|
275
|
+
getComponentsGroupName() {
|
|
276
|
+
const { bundle, pageComponent } = this.getConfig();
|
|
277
|
+
const group = experiments.isFileSystemPageComponent(pageComponent) ? pageComponent : bundle;
|
|
278
|
+
return group;
|
|
279
|
+
}
|
|
262
280
|
}
|
|
263
281
|
|
|
264
282
|
const providers$1 = [
|
|
@@ -267,10 +285,10 @@ const providers$1 = [
|
|
|
267
285
|
provide: tokensRouter.ROUTES_TOKEN,
|
|
268
286
|
multi: true,
|
|
269
287
|
useFactory: ({ logger }) => {
|
|
270
|
-
const log = logger('
|
|
288
|
+
const log = logger('file-system-pages:route');
|
|
271
289
|
const pagesNames = Object.keys(experiments.getStaticFileSystemPages());
|
|
272
290
|
const routes = pagesNames.map(experiments.fileSystemPageToRoute);
|
|
273
|
-
log.
|
|
291
|
+
log.info({
|
|
274
292
|
event: 'create static routes from file-system pages',
|
|
275
293
|
routes,
|
|
276
294
|
});
|
|
@@ -390,13 +408,14 @@ const providers = [
|
|
|
390
408
|
// рассмотреть возможность замены после доработок экшенов
|
|
391
409
|
useValue: 'after',
|
|
392
410
|
},
|
|
393
|
-
{
|
|
411
|
+
core.provide({
|
|
394
412
|
provide: tokensRouter.PAGE_SERVICE_TOKEN,
|
|
395
413
|
useClass: PageService,
|
|
396
414
|
deps: {
|
|
397
415
|
router: tokensRouter.ROUTER_TOKEN,
|
|
416
|
+
componentRegistry: tokensCommon.COMPONENT_REGISTRY_TOKEN,
|
|
398
417
|
},
|
|
399
|
-
},
|
|
418
|
+
}),
|
|
400
419
|
{
|
|
401
420
|
provide: tokensCommon.COMBINE_REDUCERS,
|
|
402
421
|
multi: true,
|
|
@@ -411,7 +430,7 @@ const httpMethod = ({ requestManager, responseManager, logger, }) => {
|
|
|
411
430
|
if (httpMethods) {
|
|
412
431
|
const currentMethod = requestManager.getMethod().toLowerCase();
|
|
413
432
|
if (!httpMethods.split(',').includes(currentMethod)) {
|
|
414
|
-
log.
|
|
433
|
+
log.info({
|
|
415
434
|
event: 'check-failed',
|
|
416
435
|
currentMethod,
|
|
417
436
|
route: to,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { NavigationGuard } from '@tinkoff/router';
|
|
2
|
-
import type { BUNDLE_MANAGER_TOKEN,
|
|
3
|
-
export declare const loadBundle: ({ bundleManager, logger, actionRegistry,
|
|
2
|
+
import type { BUNDLE_MANAGER_TOKEN, ACTION_REGISTRY_TOKEN, LOGGER_TOKEN, RESPONSE_MANAGER_TOKEN } from '@tramvai/tokens-common';
|
|
3
|
+
export declare const loadBundle: ({ bundleManager, logger, actionRegistry, responseManager, }: {
|
|
4
4
|
bundleManager: typeof BUNDLE_MANAGER_TOKEN;
|
|
5
5
|
logger: typeof LOGGER_TOKEN;
|
|
6
6
|
actionRegistry: typeof ACTION_REGISTRY_TOKEN;
|
|
7
|
-
componentRegistry: typeof COMPONENT_REGISTRY_TOKEN;
|
|
8
7
|
responseManager: typeof RESPONSE_MANAGER_TOKEN;
|
|
9
8
|
}) => NavigationGuard;
|
package/lib/services/page.d.ts
CHANGED
|
@@ -4,8 +4,10 @@ import type { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
|
4
4
|
declare type PageServiceInterface = typeof PAGE_SERVICE_TOKEN;
|
|
5
5
|
export declare class PageService implements PageServiceInterface {
|
|
6
6
|
private router;
|
|
7
|
-
|
|
7
|
+
private componentRegistry;
|
|
8
|
+
constructor({ router, componentRegistry }: {
|
|
8
9
|
router: any;
|
|
10
|
+
componentRegistry: any;
|
|
9
11
|
});
|
|
10
12
|
getCurrentRoute(): NavigationRoute;
|
|
11
13
|
getCurrentUrl(): Url;
|
|
@@ -17,5 +19,8 @@ export declare class PageService implements PageServiceInterface {
|
|
|
17
19
|
back(options?: HistoryOptions): Promise<void>;
|
|
18
20
|
forward(): Promise<void>;
|
|
19
21
|
go(to: number, options?: HistoryOptions): Promise<void>;
|
|
22
|
+
addComponent(name: string, component: any): void;
|
|
23
|
+
getComponent(name: string): any;
|
|
24
|
+
private getComponentsGroupName;
|
|
20
25
|
}
|
|
21
26
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-router",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.31.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"browser": {
|
|
@@ -23,24 +23,24 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@tinkoff/errors": "0.2.18",
|
|
26
|
-
"@tinkoff/router": "0.1.
|
|
26
|
+
"@tinkoff/router": "0.1.62",
|
|
27
27
|
"@tinkoff/url": "0.7.37",
|
|
28
|
-
"@tramvai/tokens-render": "1.
|
|
29
|
-
"@tramvai/tokens-router": "1.
|
|
30
|
-
"@tramvai/tokens-server": "1.
|
|
31
|
-
"@tramvai/experiments": "1.
|
|
28
|
+
"@tramvai/tokens-render": "1.31.1",
|
|
29
|
+
"@tramvai/tokens-router": "1.31.1",
|
|
30
|
+
"@tramvai/tokens-server": "1.31.1",
|
|
31
|
+
"@tramvai/experiments": "1.31.1"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@tinkoff/utils": "^2.1.2",
|
|
35
|
-
"@tramvai/cli": "1.
|
|
36
|
-
"@tramvai/core": "1.
|
|
37
|
-
"@tramvai/module-log": "1.
|
|
38
|
-
"@tramvai/module-server": "1.
|
|
39
|
-
"@tramvai/papi": "1.
|
|
40
|
-
"@tramvai/state": "1.
|
|
41
|
-
"@tramvai/test-helpers": "1.
|
|
42
|
-
"@tramvai/test-mocks": "1.
|
|
43
|
-
"@tramvai/tokens-common": "1.
|
|
35
|
+
"@tramvai/cli": "1.31.1",
|
|
36
|
+
"@tramvai/core": "1.31.1",
|
|
37
|
+
"@tramvai/module-log": "1.31.1",
|
|
38
|
+
"@tramvai/module-server": "1.31.1",
|
|
39
|
+
"@tramvai/papi": "1.31.1",
|
|
40
|
+
"@tramvai/state": "1.31.1",
|
|
41
|
+
"@tramvai/test-helpers": "1.31.1",
|
|
42
|
+
"@tramvai/test-mocks": "1.31.1",
|
|
43
|
+
"@tramvai/tokens-common": "1.31.1",
|
|
44
44
|
"@tinkoff/dippy": "0.7.35",
|
|
45
45
|
"react": "*",
|
|
46
46
|
"tslib": "^2.0.3"
|
package/README.en.md
DELETED
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
# @tramvai/module-router
|
|
2
|
-
|
|
3
|
-
Module for routing in the application.
|
|
4
|
-
Exports two sub-modules: with client SPA transitions, and no-SPA.
|
|
5
|
-
|
|
6
|
-
## Installation
|
|
7
|
-
|
|
8
|
-
You need to install `@tramvai/module-router`:
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
yarn add @tramvai/module-router
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
And connect in the project:
|
|
15
|
-
|
|
16
|
-
```tsx
|
|
17
|
-
import { createApp } from '@tramvai/core';
|
|
18
|
-
import { NoSpaRouterModule, SpaRouterModule } from '@tramvai/module-router';
|
|
19
|
-
|
|
20
|
-
createApp({
|
|
21
|
-
name: 'tincoin',
|
|
22
|
-
modules: [SpaRouterModule],
|
|
23
|
-
// modules: [ NoSpaRouterModule ], if you want to disable client SPA transitions
|
|
24
|
-
});
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Explanation
|
|
28
|
-
|
|
29
|
-
The module is based on the library [@tinkoff/router](../libs/router)
|
|
30
|
-
|
|
31
|
-
### Navigation flow on the server
|
|
32
|
-
|
|
33
|
-

|
|
34
|
-
|
|
35
|
-
### Flow of the first navigation on the client
|
|
36
|
-
|
|
37
|
-

|
|
38
|
-
|
|
39
|
-
### Flow of navigation on the client without SPA transitions
|
|
40
|
-
|
|
41
|
-

|
|
42
|
-
|
|
43
|
-
### Flow of navigation on the client with SPA transitions
|
|
44
|
-
|
|
45
|
-

|
|
46
|
-
|
|
47
|
-
## API
|
|
48
|
-
|
|
49
|
-
### Static routes in the application
|
|
50
|
-
|
|
51
|
-
Route description format:
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
const routes = [
|
|
55
|
-
{
|
|
56
|
-
// the name of the route is required
|
|
57
|
-
name: 'route1',
|
|
58
|
-
// the path of the route is required
|
|
59
|
-
path: '/route/a/',
|
|
60
|
-
// additional configs for the route
|
|
61
|
-
config: {
|
|
62
|
-
// layout component name
|
|
63
|
-
layoutComponent: 'layout',
|
|
64
|
-
// page component name
|
|
65
|
-
pageComponent: 'page',
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
];
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
You can explicitly transfer a list of routes to routing when adding a router module:
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
import { createApp } from '@tramvai/core';
|
|
75
|
-
import { SpaRouterModule } from '@tramvai/module-router';
|
|
76
|
-
|
|
77
|
-
const routes = [
|
|
78
|
-
// ...
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
createApp({
|
|
82
|
-
modules: [
|
|
83
|
-
// ...,
|
|
84
|
-
SpaRouterModule.forRoot(routes),
|
|
85
|
-
],
|
|
86
|
-
});
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Or separately with the `ROUTES_TOKEN` token (you can set it several times):
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
import { ROUTES_TOKEN } from '@tramvai/module-router';
|
|
93
|
-
import { provide } from '@tramvai/core';
|
|
94
|
-
|
|
95
|
-
const routesCommon = [
|
|
96
|
-
// ...
|
|
97
|
-
];
|
|
98
|
-
const routesSpecific = [
|
|
99
|
-
// ...
|
|
100
|
-
];
|
|
101
|
-
|
|
102
|
-
const providers = [
|
|
103
|
-
// ...,
|
|
104
|
-
provide({
|
|
105
|
-
provide: ROUTES_TOKEN,
|
|
106
|
-
multi: true,
|
|
107
|
-
useValue: routesCommon,
|
|
108
|
-
}),
|
|
109
|
-
provide({
|
|
110
|
-
provide: ROUTES_TOKEN,
|
|
111
|
-
multi: true,
|
|
112
|
-
useValue: routesSpecific,
|
|
113
|
-
}),
|
|
114
|
-
];
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### PAGE_SERVICE_TOKEN
|
|
118
|
-
|
|
119
|
-
Service wrapper for working with routing. Serves to hide routing work and is the preferred way of routing work.
|
|
120
|
-
|
|
121
|
-
Методы:
|
|
122
|
-
|
|
123
|
-
- `getCurrentRoute()` - get the current route,
|
|
124
|
-
- `getCurrentUrl()` - object-result of parsing the current url
|
|
125
|
-
- `getConfig()` - get the config of the current page
|
|
126
|
-
- `getContent()` - get content for the current page
|
|
127
|
-
- `getMeta()` - get the meta for the current page
|
|
128
|
-
- `navigate(options)` - navigation to a new page [more](references/libs/router.md)
|
|
129
|
-
- `updateCurrentRoute(options)` - update the current route with new parameters [more](references/libs/router.md)
|
|
130
|
-
- `back()` - go back through history
|
|
131
|
-
- `forward()` - go forward through history
|
|
132
|
-
- `go(to)` - go to the specified delta by history
|
|
133
|
-
|
|
134
|
-
### RouterStore
|
|
135
|
-
|
|
136
|
-
Store that stores information about the current and previous routes.
|
|
137
|
-
|
|
138
|
-
Properties:
|
|
139
|
-
|
|
140
|
-
- `currentRoute` - current route
|
|
141
|
-
- `currentUrl` - current url
|
|
142
|
-
- `previousRoute` - previous route
|
|
143
|
-
- `previousUrl` - previous url
|
|
144
|
-
|
|
145
|
-
### ROUTER_GUARD_TOKEN
|
|
146
|
-
|
|
147
|
-
Allows you to block or redirect the transition to the page under certain conditions. See [@tinkoff/router](/references/libs/router.md)
|
|
148
|
-
|
|
149
|
-
### Redirects
|
|
150
|
-
|
|
151
|
-
Redirects can be done via [guards](#ROUTER_GUARD_TOKEN) or explicitly via the `redirect` property in the route.
|
|
152
|
-
|
|
153
|
-
```ts
|
|
154
|
-
const routes = [
|
|
155
|
-
// ...,
|
|
156
|
-
{
|
|
157
|
-
name: 'redirect',
|
|
158
|
-
path: '/from/',
|
|
159
|
-
redirect: '/to/',
|
|
160
|
-
},
|
|
161
|
-
];
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Not Found route
|
|
165
|
-
|
|
166
|
-
The route used if no matches were found for the current page, can be specified in a special way in the list of routes.
|
|
167
|
-
|
|
168
|
-
```ts
|
|
169
|
-
const route = [
|
|
170
|
-
// ...other routes,
|
|
171
|
-
{
|
|
172
|
-
name: 'not-found',
|
|
173
|
-
path: '*',
|
|
174
|
-
config: {
|
|
175
|
-
pageComponent: 'notfoundComponentName',
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
];
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### ROUTE_RESOLVE_TOKEN
|
|
182
|
-
|
|
183
|
-
Allows you to define an asynchronous function that returns a route object that will be called if no suitable static route was found in the application.
|
|
184
|
-
|
|
185
|
-
### ROUTE_TRANSFORM_TOKEN
|
|
186
|
-
|
|
187
|
-
Transformer function for application routes (set statically and those that will be loaded via ROUTE_RESOLVE_TOKEN)
|
|
188
|
-
|
|
189
|
-
### Method of setting when actions should be performed during SPA transitions
|
|
190
|
-
|
|
191
|
-
By default, SPA transitions execute actions after defining the next route, but before the actual transition, which allows the page to be displayed immediately with new data, but can cause a noticeable visual lag if the actions are taken long enough.
|
|
192
|
-
|
|
193
|
-
It is possible to change the behavior and make the execution of actions after the transition itself. Then, when developing components, you will need to take into account that data will be loaded as it becomes available.
|
|
194
|
-
|
|
195
|
-
Configurable explicitly when using the routing module:
|
|
196
|
-
|
|
197
|
-
```ts
|
|
198
|
-
import { createApp } from '@tramvai/core';
|
|
199
|
-
import { SpaRouterModule } from '@tramvai/module-router';
|
|
200
|
-
|
|
201
|
-
createApp({
|
|
202
|
-
modules: [
|
|
203
|
-
// ...,
|
|
204
|
-
SpaRouterModule.forRoot([], {
|
|
205
|
-
spaActionsMode: 'after', // default is 'before'
|
|
206
|
-
}),
|
|
207
|
-
],
|
|
208
|
-
});
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
or through token `ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN`:
|
|
212
|
-
|
|
213
|
-
```ts
|
|
214
|
-
import { ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN } from '@tramvai/module-router';
|
|
215
|
-
import { provide } from '@tramvai/core';
|
|
216
|
-
|
|
217
|
-
const providers = [
|
|
218
|
-
// ...,
|
|
219
|
-
provide({
|
|
220
|
-
provide: ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN,
|
|
221
|
-
useValue: 'after',
|
|
222
|
-
}),
|
|
223
|
-
];
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
## How to
|
|
227
|
-
|
|
228
|
-
### Working with navigation in providers and actions
|
|
229
|
-
|
|
230
|
-
In this case, it is best to use the [PAGE_SERVICE_TOKEN](#page_service_token)
|
|
231
|
-
|
|
232
|
-
```ts
|
|
233
|
-
import { provide, createAction } from '@tramvai/core';
|
|
234
|
-
import { PAGE_SERVICE_TOKEN } from '@tramvai/module-router';
|
|
235
|
-
|
|
236
|
-
const provider = provide({
|
|
237
|
-
provide: 'token',
|
|
238
|
-
useFactory: ({ pageService }) => {
|
|
239
|
-
if (pageService().getCurrentUrl().pathname === '/test/') {
|
|
240
|
-
return pageService.navigate({ url: '/redirect/', replace: true });
|
|
241
|
-
}
|
|
242
|
-
},
|
|
243
|
-
deps: {
|
|
244
|
-
pageService: PAGE_SERVICE_TOKEN,
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
const action = createAction({
|
|
249
|
-
name: 'action',
|
|
250
|
-
fn: (_, __, { pageService }) => {
|
|
251
|
-
if (pageService.getConfig().pageComponent === 'pageComponent') {
|
|
252
|
-
return page.updateCurrentRoute({ query: { test: 'true' } });
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
deps: {
|
|
256
|
-
pageService: PAGE_SERVICE_TOKEN,
|
|
257
|
-
},
|
|
258
|
-
});
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
### Working with navigation in React components
|
|
262
|
-
|
|
263
|
-
You can work with routing inside React components using hooks and components - `useNavigate`, `useRoute`, `Link` from the [@tinkoff/router](references/libs/router.md#интеграция-с-react)
|
|
264
|
-
|
|
265
|
-
<p>
|
|
266
|
-
<details>
|
|
267
|
-
<summary>An example of working with navigation in the application</summary>
|
|
268
|
-
|
|
269
|
-
@inline ../../../examples/how-to/router-navigate/index.tsx
|
|
270
|
-
|
|
271
|
-
</details>
|
|
272
|
-
</p>
|
|
273
|
-
|
|
274
|
-
### How to set static routes
|
|
275
|
-
|
|
276
|
-
[RouterModule](references/modules/router.md) allows you to add new routes when configuring your application.
|
|
277
|
-
The second way is to pass static routes to DI via the `ROUTES_TOKEN` token.
|
|
278
|
-
|
|
279
|
-
<p>
|
|
280
|
-
<details>
|
|
281
|
-
<summary>An example of adding static routes to an application</summary>
|
|
282
|
-
|
|
283
|
-
@inline ../../../examples/how-to/router-static-routes/index.tsx
|
|
284
|
-
|
|
285
|
-
</details>
|
|
286
|
-
</p>
|
|
287
|
-
|
|
288
|
-
### How to set Route Guard
|
|
289
|
-
|
|
290
|
-
[ROUTER_GUARD_TOKEN](references/modules/router.md#router_guard_token) is set as an asynchronous function, which allows you to perform various actions and influence the routing behavior.
|
|
291
|
-
|
|
292
|
-
<p>
|
|
293
|
-
<details>
|
|
294
|
-
<summary>Example router guards job in application</summary>
|
|
295
|
-
|
|
296
|
-
@inline ../../../examples/how-to/router-guards/index.tsx
|
|
297
|
-
|
|
298
|
-
</details>
|
|
299
|
-
</p>
|
|
300
|
-
|
|
301
|
-
### How to set the Not found route
|
|
302
|
-
|
|
303
|
-
The Not found route is used if the corresponding route is not found for the url.
|
|
304
|
-
|
|
305
|
-
Such a route is specified in the list of routes with the special `*` character in the `path` property.
|
|
306
|
-
|
|
307
|
-
<p>
|
|
308
|
-
<details>
|
|
309
|
-
<summary>An example of setting a Not Found route in an application</summary>
|
|
310
|
-
|
|
311
|
-
@inline ../../../examples/how-to/router-not-found/index.tsx
|
|
312
|
-
|
|
313
|
-
</details>
|
|
314
|
-
</p>
|
|
315
|
-
|
|
316
|
-
### Testing
|
|
317
|
-
|
|
318
|
-
#### Testing ROUTER_GUARD_TOKEN extensions
|
|
319
|
-
|
|
320
|
-
If you have a module or providers that define `ROUTER_GUARD_TOKEN`, then it will be convenient to use special utilities to test them separately
|
|
321
|
-
|
|
322
|
-
```ts
|
|
323
|
-
import { ROUTER_GUARD_TOKEN } from '@tramvai/tokens-router';
|
|
324
|
-
import { testGuard } from '@tramvai/module-router/tests';
|
|
325
|
-
import { CustomModule } from './module';
|
|
326
|
-
import { providers } from './providers';
|
|
327
|
-
|
|
328
|
-
describe('router guards', () => {
|
|
329
|
-
it('should redirect from guard', async () => {
|
|
330
|
-
const { router } = testGuard({
|
|
331
|
-
providers,
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
await router.navigate('/test/');
|
|
335
|
-
|
|
336
|
-
expect(router.getCurrentUrl()).toMatchObject({
|
|
337
|
-
path: '/redirect/',
|
|
338
|
-
});
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
it('should block navigation', async () => {
|
|
342
|
-
const { router } = testGuard({
|
|
343
|
-
modules: [CustomModule],
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
expect(router.getCurrentUrl()).toMatchObject({ path: '/' });
|
|
347
|
-
|
|
348
|
-
await router.navigate('/test/').catch(() => null);
|
|
349
|
-
|
|
350
|
-
expect(router.getCurrentUrl()).toMatchObject({
|
|
351
|
-
path: '/',
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
## Exported tokens
|
|
358
|
-
|
|
359
|
-
[link](references/tokens/router-tokens.md)
|