@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 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
- Необходимо установить `@tramvai/module-router`
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
- Модуль основан на библиотеке [@tinkoff/router](references/libs/router.md)
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
- ![Диаграмма](/img/router/navigate-flow-server.drawio.svg)
33
+ ![Diagramm](/img/router/navigate-flow-server.drawio.svg)
33
34
 
34
- ### Флоу работы первой навигации на клиенте
35
+ ### Flow of the first navigation on the client
35
36
 
36
- ![Диаграмма](/img/router/rehydrate-client.drawio.svg)
37
+ ![Diagramm](/img/router/rehydrate-client.drawio.svg)
37
38
 
38
- ### Флоу работы навигации на клиенте без спа
39
+ ### Flow of navigation on the client without SPA transitions
39
40
 
40
- ![Диаграмма](/img/router/navigate-flow-client-no-spa.drawio.svg)
41
+ ![Diagramm](/img/router/navigate-flow-client-no-spa.drawio.svg)
41
42
 
42
- ### Флоу работы навигации на клиенте со спа
43
+ ### Flow of navigation on the client with SPA transitions
43
44
 
44
- ![Диаграмма](/img/router/navigate-flow-client-spa.drawio.svg)
45
+ ![Diagramm](/img/router/navigate-flow-client-spa.drawio.svg)
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
- // обязательно соответствующий path для роута
58
+ // the path of the route is required
58
59
  path: '/route/a/',
59
- // дополнительные конфиги для роута
60
+ // additional configs for the route
60
61
  config: {
61
- // имя компонента для layout
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
- Или отдельно токеном `ROUTES_TOKEN` (можно задавать несколько раз):
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)` - навигация на новую страницу [подробнее](references/libs/router.md)
128
- - `updateCurrentRoute(options)` - обновить текущий роут новыми параметрами [подробнее](references/libs/router.md)
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
- Позволяет блокировать или перенаправлять переход на страницу при определённых условиях. Подробнее смотри доку [@tinkoff/router](/references/libs/router.md)
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
- Редиректы могут выполняться через [guards](#ROUTER_GUARD_TOKEN) или явно через свойство `redirect` в роуте.
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
- Функция-трансформер для роутов приложения (заданных статично и тех, что будут загружены через ROUTE_RESOLVE_TOKEN)
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', // по умолчанию 'before'
207
+ spaActionsMode: 'after', // default is 'before'
205
208
  }),
206
209
  ],
207
210
  });
208
211
  ```
209
212
 
210
- или токеном `ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN`:
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
- В этом случае лучше всего использовать токен [PAGE_SERVICE_TOKEN](#page_service_token)
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
- ### Работа с навигацией в React-компонентах
263
+ ### Working with navigation in React components
261
264
 
262
- Работать с роутингом внутри React компонентов можно с помощью хуков и компонентов - useNavigate, useRoute, Link из пакета [@tinkoff/router](references/libs/router.md#интеграция-с-react)
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>Пример работы с навигацией в приложение</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) позволяет добавить новые роуты при конфигурации приложения. Второй способ, передавать статичные роуты в DI через токен `ROUTES_TOKEN`.
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>Пример добавления статичных роутов в приложение</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
- ### Как задать Route Guard
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>Пример задания router guards в приложении</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
- ### Как задать Not found роут
303
+ ### How to set the Not found route
300
304
 
301
- Not-found роут используется в том случае, если для урла не найден соответствующий роут.
305
+ The Not found route is used if the corresponding route is not found for the url.
302
306
 
303
- Такой роут задаётся в списке роутов со специальным символом `*` в свойстве `path`.
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>Пример задания Not-found роута в приложении</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
- #### Тестирование расширений ROUTER_GUARD_TOKEN
320
+ #### Testing ROUTER_GUARD_TOKEN extensions
317
321
 
318
- Если у вас имеется модуль или провайдеры которые определяют ROUTER_GUARD_TOKEN, то удобно будет использовать специальные утилиты для того чтобы протестировать их отдельно
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
- [ссылка](references/tokens/router-tokens.md)
361
+ [link](references/tokens/router-tokens.md)
@@ -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, COMPONENT_REGISTRY_TOKEN, ACTION_REGISTRY_TOKEN, RESPONSE_MANAGER_TOKEN, CONTEXT_TOKEN, COMBINE_REDUCERS, STORE_TOKEN, ACTION_PAGE_RUNNER_TOKEN } from '@tramvai/tokens-common';
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, componentRegistry, responseManager, }) => {
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('route:file-system-pages');
273
+ const log = logger('file-system-pages:route');
256
274
  const pagesNames = Object.keys(getStaticFileSystemPages());
257
275
  const routes = pagesNames.map(fileSystemPageToRoute);
258
- log.debug({
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, COMPONENT_REGISTRY_TOKEN, ACTION_REGISTRY_TOKEN, RESPONSE_MANAGER_TOKEN, CONTEXT_TOKEN, COMBINE_REDUCERS, REQUEST_MANAGER_TOKEN, ACTION_PAGE_RUNNER_TOKEN } from '@tramvai/tokens-common';
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, componentRegistry, responseManager, }) => {
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('route:file-system-pages');
276
+ const log = logger('file-system-pages:route');
259
277
  const pagesNames = Object.keys(getStaticFileSystemPages());
260
278
  const routes = pagesNames.map(fileSystemPageToRoute);
261
- log.debug({
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.debug({
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, componentRegistry, responseManager, }) => {
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('route:file-system-pages');
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.debug({
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.debug({
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, COMPONENT_REGISTRY_TOKEN, ACTION_REGISTRY_TOKEN, LOGGER_TOKEN, RESPONSE_MANAGER_TOKEN } from '@tramvai/tokens-common';
3
- export declare const loadBundle: ({ bundleManager, logger, actionRegistry, componentRegistry, responseManager, }: {
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;
@@ -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
- constructor({ router }: {
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.30.0",
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.61",
26
+ "@tinkoff/router": "0.1.62",
27
27
  "@tinkoff/url": "0.7.37",
28
- "@tramvai/tokens-render": "1.30.0",
29
- "@tramvai/tokens-router": "1.30.0",
30
- "@tramvai/tokens-server": "1.30.0",
31
- "@tramvai/experiments": "1.30.0"
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.30.0",
36
- "@tramvai/core": "1.30.0",
37
- "@tramvai/module-log": "1.30.0",
38
- "@tramvai/module-server": "1.30.0",
39
- "@tramvai/papi": "1.30.0",
40
- "@tramvai/state": "1.30.0",
41
- "@tramvai/test-helpers": "1.30.0",
42
- "@tramvai/test-mocks": "1.30.0",
43
- "@tramvai/tokens-common": "1.30.0",
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
- ![Diagramm](/img/router/navigate-flow-server.drawio.svg)
34
-
35
- ### Flow of the first navigation on the client
36
-
37
- ![Diagramm](/img/router/rehydrate-client.drawio.svg)
38
-
39
- ### Flow of navigation on the client without SPA transitions
40
-
41
- ![Diagramm](/img/router/navigate-flow-client-no-spa.drawio.svg)
42
-
43
- ### Flow of navigation on the client with SPA transitions
44
-
45
- ![Diagramm](/img/router/navigate-flow-client-spa.drawio.svg)
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)