@tramvai/module-router 2.59.4 → 2.61.2

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
@@ -2,6 +2,8 @@
2
2
 
3
3
  Module for routing in the application. Exports two sub-modules: with client SPA transitions, and no-SPA.
4
4
 
5
+ Link to complete Router documentation - https://tramvai.dev/docs/features/routing/overview/
6
+
5
7
  ## Installation
6
8
 
7
9
  You need to install `@tramvai/module-router`:
@@ -27,423 +29,6 @@ createApp({
27
29
 
28
30
  The module is based on the library [@tinkoff/router](references/libs/router.md)
29
31
 
30
- ### Default Settings
31
-
32
- Next [settings](references/libs/router.md#constructor-options) are used
33
-
34
- - `trailingSlashes = true`
35
- - `mergeSlashes = true`
36
-
37
- ### Navigation flow on the server
38
-
39
- ![Diagram](/img/router/navigate-flow-server.drawio.svg)
40
-
41
- ### Flow of the first navigation on the client
42
-
43
- ![Diagram](/img/router/rehydrate-client.drawio.svg)
44
-
45
- ### Flow of navigation on the client without SPA transitions
46
-
47
- ![Diagram](/img/router/navigate-flow-client-no-spa.drawio.svg)
48
-
49
- ### Flow of navigation on the client with SPA transitions
50
-
51
- ![Diagram](/img/router/navigate-flow-client-spa.drawio.svg)
52
-
53
- ## API
54
-
55
- ### Static routes in the application
56
-
57
- Route description format:
58
-
59
- ```ts
60
- const routes = [
61
- {
62
- // the name of the route is required
63
- name: 'route1',
64
- // the path of the route is required
65
- path: '/route/a/',
66
- // additional configs for the route
67
- config: {
68
- // layout component name
69
- layoutComponent: 'layout',
70
- // page component name
71
- pageComponent: 'page',
72
- },
73
- },
74
- ];
75
- ```
76
-
77
- You can explicitly transfer a list of routes to routing when adding a router module:
78
-
79
- ```ts
80
- import { createApp } from '@tramvai/core';
81
- import { SpaRouterModule } from '@tramvai/module-router';
82
-
83
- const routes = [
84
- // ...
85
- ];
86
-
87
- createApp({
88
- modules: [
89
- // ...,
90
- SpaRouterModule.forRoot(routes),
91
- ],
92
- });
93
- ```
94
-
95
- Or separately with the `ROUTES_TOKEN` token (you can set it several times):
96
-
97
- ```ts
98
- import { ROUTES_TOKEN } from '@tramvai/module-router';
99
- import { provide } from '@tramvai/core';
100
-
101
- const routesCommon = [
102
- // ...
103
- ];
104
- const routesSpecific = [
105
- // ...
106
- ];
107
-
108
- const providers = [
109
- // ...,
110
- provide({
111
- provide: ROUTES_TOKEN,
112
- multi: true,
113
- useValue: routesCommon,
114
- }),
115
- provide({
116
- provide: ROUTES_TOKEN,
117
- multi: true,
118
- useValue: routesSpecific,
119
- }),
120
- ];
121
- ```
122
-
123
- ### PAGE_SERVICE_TOKEN
124
-
125
- Service wrapper for working with routing. Serves to hide routing work and is the preferred way of routing work.
126
-
127
- Methods:
128
-
129
- - `getCurrentRoute()` - get the current route
130
- - `getCurrentUrl()` - object-result of parsing the current url
131
- - `getConfig()` - get the config of the current page
132
- - `getContent()` - get content for the current page
133
- - `getMeta()` - get the meta for the current page
134
- - `navigate(options)` - navigation to a new page [more](references/libs/router.md)
135
- - `updateCurrentRoute(options)` - update the current route with new parameters [more](references/libs/router.md)
136
- - `back()` - go back through history
137
- - `forward()` - go forward through history
138
- - `go(to)` - go to the specified delta by history
139
- - `addComponent(name, component)` - add new component to current page into ComponentRegistry
140
- - `getComponent(name)` - get component from current page components from ComponentRegistry
141
-
142
- ### RouterStore
143
-
144
- Store that stores information about the current and previous routes.
145
-
146
- Properties:
147
-
148
- - `currentRoute` - current route
149
- - `currentUrl` - current url
150
- - `previousRoute` - previous route
151
- - `previousUrl` - previous url
152
-
153
- ### ROUTER_GUARD_TOKEN
154
-
155
- Allows you to block or redirect the transition to the page under certain conditions. See [@tinkoff/router](/references/libs/router.md)
156
-
157
- ### Redirects
158
-
159
- Redirects can be done via [guards](#ROUTER_GUARD_TOKEN) or explicitly via the `redirect` property in the route.
160
-
161
- ```ts
162
- const routes = [
163
- // ...,
164
- {
165
- name: 'redirect',
166
- path: '/from/',
167
- redirect: '/to/',
168
- },
169
- ];
170
- ```
171
-
172
- ### Not Found route
173
-
174
- The route used if no matches were found for the current page, can be specified in a special way in the list of routes.
175
-
176
- ```ts
177
- const route = [
178
- // ...other routes,
179
- {
180
- name: 'not-found',
181
- path: '*',
182
- config: {
183
- pageComponent: 'notfoundComponentName',
184
- },
185
- },
186
- ];
187
- ```
188
-
189
- ### ROUTE_RESOLVE_TOKEN
190
-
191
- 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.
192
-
193
- ### ROUTE_TRANSFORM_TOKEN
194
-
195
- Transformer function for application routes (set statically and those that will be loaded via ROUTE_RESOLVE_TOKEN)
196
-
197
- ### Method of setting when actions should be performed during SPA transitions
198
-
199
- 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.
200
-
201
- 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.
202
-
203
- Configurable explicitly when using the routing module:
204
-
205
- ```ts
206
- import { createApp } from '@tramvai/core';
207
- import { SpaRouterModule } from '@tramvai/module-router';
208
-
209
- createApp({
210
- modules: [
211
- // ...,
212
- SpaRouterModule.forRoot([], {
213
- spaActionsMode: 'after', // default is 'before'
214
- }),
215
- ],
216
- });
217
- ```
218
-
219
- or through token `ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN`:
220
-
221
- ```ts
222
- import { ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN } from '@tramvai/module-router';
223
- import { provide } from '@tramvai/core';
224
-
225
- const providers = [
226
- // ...,
227
- provide({
228
- provide: ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN,
229
- useValue: 'after',
230
- }),
231
- ];
232
- ```
233
-
234
- ## How to
235
-
236
- ### Working with navigation in providers and actions
237
-
238
- In this case, it is best to use the [PAGE_SERVICE_TOKEN](#page_service_token)
239
-
240
- ```ts
241
- import { provide, declareAction } from '@tramvai/core';
242
- import { PAGE_SERVICE_TOKEN } from '@tramvai/module-router';
243
-
244
- const provider = provide({
245
- provide: 'token',
246
- useFactory: ({ pageService }) => {
247
- if (pageService().getCurrentUrl().pathname === '/test/') {
248
- return pageService.navigate({ url: '/redirect/', replace: true });
249
- }
250
- },
251
- deps: {
252
- pageService: PAGE_SERVICE_TOKEN,
253
- },
254
- });
255
-
256
- const action = declareAction({
257
- name: 'action',
258
- fn() {
259
- if (this.deps.pageService.getConfig().pageComponent === 'pageComponent') {
260
- return this.deps.pageService.updateCurrentRoute({ query: { test: 'true' } });
261
- }
262
- },
263
- deps: {
264
- pageService: PAGE_SERVICE_TOKEN,
265
- },
266
- });
267
- ```
268
-
269
- ### Working with navigation in React components
270
-
271
- You can work with routing inside React components using hooks and components - `useNavigate` and `useRoute` from the [@tinkoff/router](references/libs/router.md#интеграция-с-react)
272
-
273
- <p>
274
- <details>
275
- <summary>An example of working with navigation in the application</summary>
276
-
277
- @inline ../../../examples/how-to/router-navigate/index.tsx
278
-
279
- </details>
280
- </p>
281
-
282
- #### Link
283
-
284
- A wrapper for a react component that makes it clickable
285
-
286
- > If the react component is passed to the Link as children, then this passed component will be rendered and the `href`, `onClick` props will be passed as props to that component and they should be used to make the navigation. Otherwise, the `<a>` tag will be rendered with children as a child.
287
- > Your passed component need to be wrapped in the `forwardRef` for routes assets prefetching.
288
-
289
- ```ts
290
- import { Link } from '@tramvai/module-router';
291
- import CustomLink from '@custom-scope/link';
292
-
293
- export const Component = () => {
294
- return (
295
- <Link url="/test/">
296
- <CustomLink />
297
- </Link>
298
- );
299
- };
300
-
301
- export const WrapLink = () => {
302
- return <Link url="/test/">Click me</Link>;
303
- };
304
- ```
305
-
306
- ##### Page resources prefetch
307
-
308
- `Link` component will try to prefetch resources for passed `url`, if this `url` is handled by the application router.
309
-
310
- It will help to make subsequent page-loads faster because target page assets already be saved in browser cache.
311
-
312
- How it works:
313
-
314
- - Component determines when it is in the viewport (using `Intersection Observer`)
315
- - waits until the browser is idle (using `requestIdleCallback`)
316
- - checks if the user isn't on a slow connection (using `navigator.connection.effectiveType`) or has data-saver enabled (using `navigator.connection.saveData`)
317
- - triggers page resources (js, css) prefetching
318
-
319
- Main reference for this feature - [quicklink](https://github.com/GoogleChromeLabs/quicklink) library.
320
-
321
- If you want to disable this behaviour, pass `prefetch={false}` property.
322
-
323
- ```tsx
324
- export const WrapLink = () => {
325
- return <Link url="/test/" prefetch={false}>Click me</Link>;
326
- };
327
- ```
328
-
329
- ### How to set static routes
330
-
331
- [RouterModule](references/modules/router/base.md) allows you to add new routes when configuring your application. The second way is to pass static routes to DI via the `ROUTES_TOKEN` token.
332
-
333
- <p>
334
- <details>
335
- <summary>An example of adding static routes to an application</summary>
336
-
337
- @inline ../../../examples/how-to/router-static-routes/index.tsx
338
-
339
- </details>
340
- </p>
341
-
342
- ### How to set Route Guard
343
-
344
- `ROUTER_GUARD_TOKEN` is set as an asynchronous function, which allows you to perform various actions and influence the routing behavior.
345
-
346
- <p>
347
- <details>
348
- <summary>Example router guards job in application</summary>
349
-
350
- @inline ../../../examples/how-to/router-guards/index.tsx
351
-
352
- </details>
353
- </p>
354
-
355
- ### How to add transition hooks
356
-
357
- [Transition hooks](references/libs/router.md#transition-hooks) allows to subscribe on different steps of the transition
358
-
359
- 1. Get router instance with `ROUTER_TOKEN` token
360
- 2. Use methods `registerHook`, `registerSyncHook` to add new hooks to the router
361
- 3. Registration should happen as soon as possible so appropriate line is `customerStart` as it executes before navigation happens.
362
-
363
- ### How to set the Not found route
364
-
365
- The Not found route is used if the corresponding route is not found for the url.
366
-
367
- Such a route is specified in the list of routes with the special `*` character in the `path` property.
368
-
369
- <p>
370
- <details>
371
- <summary>An example of setting a Not Found route in an application</summary>
372
-
373
- @inline ../../../examples/how-to/router-not-found/index.tsx
374
-
375
- </details>
376
- </p>
377
-
378
- ### How to change Not found route response status
379
-
380
- By default, responses for the Not found route return a status of 200. You can change status in custom Route Guard, by using `RESPONSE_MANAGER_TOKEN`.
381
-
382
- <p>
383
- <details>
384
- <summary>An example of changing a Not Found route response status</summary>
385
-
386
- @inline ../../../examples/how-to/router-not-found-custom-status/index.tsx
387
-
388
- </details>
389
- </p>
390
-
391
- ### How to change response status in actions
392
-
393
- For example, you make a important request in action, and if this request will fail, application need to return 500 or 404 status.
394
-
395
- Page actions running after router navigation flow, when route is completely resolved. You can change status by using `RESPONSE_MANAGER_TOKEN`. If you want to prevent page component rendering, you can throw `NotFoundError` from `@tinkoff/errors` library.
396
-
397
- <p>
398
- <details>
399
- <summary>An example of changing response status in actions</summary>
400
-
401
- @inline ../../../examples/how-to/router-action-error/index.tsx
402
-
403
- </details>
404
- </p>
405
-
406
- ### Testing
407
-
408
- #### Testing ROUTER_GUARD_TOKEN extensions
409
-
410
- 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
411
-
412
- ```ts
413
- import { ROUTER_GUARD_TOKEN } from '@tramvai/tokens-router';
414
- import { testGuard } from '@tramvai/module-router/tests';
415
- import { CustomModule } from './module';
416
- import { providers } from './providers';
417
-
418
- describe('router guards', () => {
419
- it('should redirect from guard', async () => {
420
- const { router } = testGuard({
421
- providers,
422
- });
423
-
424
- await router.navigate('/test/');
425
-
426
- expect(router.getCurrentUrl()).toMatchObject({
427
- path: '/redirect/',
428
- });
429
- });
430
-
431
- it('should block navigation', async () => {
432
- const { router } = testGuard({
433
- modules: [CustomModule],
434
- });
435
-
436
- expect(router.getCurrentUrl()).toMatchObject({ path: '/' });
437
-
438
- await router.navigate('/test/').catch(() => null);
439
-
440
- expect(router.getCurrentUrl()).toMatchObject({
441
- path: '/',
442
- });
443
- });
444
- });
445
- ```
446
-
447
32
  ## Exported tokens
448
33
 
449
34
  [link](references/tokens/router.md)
@@ -83,7 +83,8 @@ const loadBundle = ({ bundleManager, logger, actionRegistry, responseManager, di
83
83
  bundle,
84
84
  pageComponent,
85
85
  });
86
- // если бандл не найдён, то всё ок мы должны вернуть 404 на сервере, а на клиенте просто загрузить новую страницу
86
+ // если бандл не найден, то всё ок и мы должны вернуть 404 на сервере,
87
+ // а на клиенте просто загрузить новую страницу
87
88
  responseManager.setStatus(404);
88
89
  return false;
89
90
  }
package/lib/index.es.js CHANGED
@@ -84,7 +84,8 @@ const loadBundle = ({ bundleManager, logger, actionRegistry, responseManager, di
84
84
  bundle,
85
85
  pageComponent,
86
86
  });
87
- // если бандл не найдён, то всё ок мы должны вернуть 404 на сервере, а на клиенте просто загрузить новую страницу
87
+ // если бандл не найден, то всё ок и мы должны вернуть 404 на сервере,
88
+ // а на клиенте просто загрузить новую страницу
88
89
  responseManager.setStatus(404);
89
90
  return false;
90
91
  }
package/lib/index.js CHANGED
@@ -96,7 +96,8 @@ const loadBundle = ({ bundleManager, logger, actionRegistry, responseManager, di
96
96
  bundle,
97
97
  pageComponent,
98
98
  });
99
- // если бандл не найдён, то всё ок мы должны вернуть 404 на сервере, а на клиенте просто загрузить новую страницу
99
+ // если бандл не найден, то всё ок и мы должны вернуть 404 на сервере,
100
+ // а на клиенте просто загрузить новую страницу
100
101
  responseManager.setStatus(404);
101
102
  return false;
102
103
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/module-router",
3
- "version": "2.59.4",
3
+ "version": "2.61.2",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "browser": {
@@ -27,26 +27,26 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@tinkoff/errors": "0.3.5",
30
- "@tinkoff/router": "0.2.6",
30
+ "@tinkoff/router": "0.2.7",
31
31
  "@tinkoff/url": "0.8.4",
32
- "@tramvai/react": "2.59.4",
33
- "@tramvai/tokens-child-app": "2.59.4",
34
- "@tramvai/tokens-render": "2.59.4",
35
- "@tramvai/tokens-router": "2.59.4",
36
- "@tramvai/tokens-server": "2.59.4",
37
- "@tramvai/experiments": "2.59.4"
32
+ "@tramvai/react": "2.61.2",
33
+ "@tramvai/tokens-child-app": "2.61.2",
34
+ "@tramvai/tokens-render": "2.61.2",
35
+ "@tramvai/tokens-router": "2.61.2",
36
+ "@tramvai/tokens-server": "2.61.2",
37
+ "@tramvai/experiments": "2.61.2"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@tinkoff/utils": "^2.1.2",
41
- "@tramvai/cli": "2.59.4",
42
- "@tramvai/core": "2.59.4",
43
- "@tramvai/module-log": "2.59.4",
44
- "@tramvai/module-server": "2.59.4",
45
- "@tramvai/papi": "2.59.4",
46
- "@tramvai/state": "2.59.4",
47
- "@tramvai/test-helpers": "2.59.4",
48
- "@tramvai/test-mocks": "2.59.4",
49
- "@tramvai/tokens-common": "2.59.4",
41
+ "@tramvai/cli": "2.61.2",
42
+ "@tramvai/core": "2.61.2",
43
+ "@tramvai/module-log": "2.61.2",
44
+ "@tramvai/module-server": "2.61.2",
45
+ "@tramvai/papi": "2.61.2",
46
+ "@tramvai/state": "2.61.2",
47
+ "@tramvai/test-helpers": "2.61.2",
48
+ "@tramvai/test-mocks": "2.61.2",
49
+ "@tramvai/tokens-common": "2.61.2",
50
50
  "@tinkoff/dippy": "0.8.11",
51
51
  "react": "*",
52
52
  "tslib": "^2.4.0"