@tramvai/module-client-hints 1.55.4 → 1.58.0
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 +70 -76
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,26 +1,16 @@
|
|
|
1
1
|
# Client Hints
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Modules provides various parameters from the client device, e.g. type of the device, screen size, etc.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
First, install `@tramvai/module-client-hints`
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```bash
|
|
9
|
+
```bash npm2yarn
|
|
12
10
|
npm i --save @tramvai/module-client-hints
|
|
13
11
|
```
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
yarn add @tramvai/module-client-hints
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### 2. Подключение модуля
|
|
22
|
-
|
|
23
|
-
Нужно передать в список модулей приложения ClientHintsModule
|
|
13
|
+
Then add `ClientHintsModule` to the modules list
|
|
24
14
|
|
|
25
15
|
```tsx
|
|
26
16
|
import { createApp } from '@tramvai/core';
|
|
@@ -31,62 +21,19 @@ createApp({
|
|
|
31
21
|
});
|
|
32
22
|
```
|
|
33
23
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
### USER_AGENT_TOKEN
|
|
37
|
-
|
|
38
|
-
Объект - результат парсинга строки юзер-агента с помощью [@tinkoff/user-agent](../libs/user-agent.md). Парсинг происходит только на сервере, на клиенте - используется инфомация с сервера.
|
|
39
|
-
|
|
40
|
-
## Сторы
|
|
41
|
-
|
|
42
|
-
### userAgent
|
|
43
|
-
|
|
44
|
-
Стор который хранит результат парсинга юзер-агента.
|
|
45
|
-
|
|
46
|
-
### media
|
|
47
|
-
|
|
48
|
-
Стор который хранит медиа-информацию о типе и размере экрана клиента.
|
|
49
|
-
|
|
50
|
-
#### API для проверки media
|
|
51
|
-
|
|
52
|
-
Данные в сторе media:
|
|
53
|
-
|
|
54
|
-
```tsx
|
|
55
|
-
type Media = {
|
|
56
|
-
width: number;
|
|
57
|
-
height: number;
|
|
58
|
-
isTouch: boolean;
|
|
59
|
-
retina: boolean;
|
|
60
|
-
supposed?: boolean;
|
|
61
|
-
synchronized?: boolean;
|
|
62
|
-
};
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
`fromClientHints(media: Media): boolean` - возвращает true, когда media синхронизированны на сервере и на клиенте
|
|
66
|
-
|
|
67
|
-
`isSupposed(media: Media): boolean` - возвращает true, когда media определены на сервере по User-Agent, и могут измениться на клиенте
|
|
68
|
-
|
|
69
|
-
`isRetina(media: Media): boolean` - вовзращает true, когда плотность пикселей на экране 2 или выше
|
|
70
|
-
|
|
71
|
-
`useMedia(): Media` - возвращает текущее состояние стора media
|
|
72
|
-
|
|
73
|
-
`useFromClientHints(): boolean` - вычисляет fromClientHints из стора media
|
|
24
|
+
## Explanation
|
|
74
25
|
|
|
75
|
-
|
|
26
|
+
### The problem with media on server and on client
|
|
76
27
|
|
|
77
|
-
|
|
28
|
+
One of the SSR problem is render of the component which depends of current screen size, e.g. image carousel that should render specific number of images depending of screen width. By default, the exact screen size can be figured out only on client-side and we can't render such content on server identical to the client render. If this content is not important for the SEO we can use skeletons and spinners, but they are not suitable for every case.
|
|
78
29
|
|
|
79
|
-
|
|
30
|
+
Client Hints modules provides the way to solve this problem in some way. It stores data about client devices in cookies and then use this cookies on server in next page loading.
|
|
80
31
|
|
|
81
|
-
|
|
32
|
+
### How does it work
|
|
82
33
|
|
|
83
|
-
|
|
34
|
+
#### First page loading
|
|
84
35
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
#### Первый заход на страницу
|
|
88
|
-
|
|
89
|
-
При первом заходе на страницу, на стороне сервере, модуль определяет тип устройство по User-Agent, и сохраняет **предположительные** данные об устройстве в стор `media`. Например, при первом заходе с компьютера, значение стора `media` будет таким:
|
|
36
|
+
When user enters the app for the first time module tries to determine type of the user device using user-agent string. Then it saves this **assumptive** data to `media` store. E.g. when user loads page from the desktop, then content of the `media` store will be following:
|
|
90
37
|
|
|
91
38
|
```tsx
|
|
92
39
|
const state = {
|
|
@@ -99,7 +46,7 @@ const state = {
|
|
|
99
46
|
};
|
|
100
47
|
```
|
|
101
48
|
|
|
102
|
-
|
|
49
|
+
On the client focusing on value `supposed: true` module resolves **real** info about client device, updates `media` store and calls the rerender for the dependent components. E.g. for the widescreen monitor the data of `media` store might be next:
|
|
103
50
|
|
|
104
51
|
```tsx
|
|
105
52
|
const state = {
|
|
@@ -112,11 +59,11 @@ const state = {
|
|
|
112
59
|
};
|
|
113
60
|
```
|
|
114
61
|
|
|
115
|
-
|
|
62
|
+
While we have value `synchronized: false` **it is not allowed** to use data from the `media` store for on the server-side as data is not synchronized with the client and it will lead to page jumps when saving real data about device.
|
|
116
63
|
|
|
117
|
-
####
|
|
64
|
+
#### Next page loads
|
|
118
65
|
|
|
119
|
-
|
|
66
|
+
When user loads the app next time the data about user device will be read from cookies and value `synchronized` will be set to true. This way on server and on client we will get the same content of the `media` store and no page rerenders on the client:
|
|
120
67
|
|
|
121
68
|
```tsx
|
|
122
69
|
const state = {
|
|
@@ -129,17 +76,58 @@ const state = {
|
|
|
129
76
|
};
|
|
130
77
|
```
|
|
131
78
|
|
|
132
|
-
####
|
|
79
|
+
#### Use ClientHints in component
|
|
80
|
+
|
|
81
|
+
If some component if depend of screen size:
|
|
82
|
+
|
|
83
|
+
1. When user loads app for the first time **is not possible** to guarantee the same exact render on server and client
|
|
84
|
+
2. On first app load you may show some skeleton to the user by checking `supposed: true` property
|
|
85
|
+
3. You can guarantee the same exact render on server and client only in case `synchronized: true`
|
|
133
86
|
|
|
134
|
-
|
|
87
|
+
## Api
|
|
135
88
|
|
|
136
|
-
|
|
89
|
+
### Stores
|
|
137
90
|
|
|
138
|
-
|
|
91
|
+
#### userAgent
|
|
139
92
|
|
|
140
|
-
|
|
93
|
+
Stores the result of the user-agent string parsing.
|
|
141
94
|
|
|
142
|
-
|
|
95
|
+
#### media
|
|
96
|
+
|
|
97
|
+
Stores the media information about type and size of the client screen.
|
|
98
|
+
|
|
99
|
+
### media helpers
|
|
100
|
+
|
|
101
|
+
`media` store has next data:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
type Media = {
|
|
105
|
+
width: number;
|
|
106
|
+
height: number;
|
|
107
|
+
isTouch: boolean;
|
|
108
|
+
retina: boolean;
|
|
109
|
+
supposed?: boolean;
|
|
110
|
+
synchronized?: boolean;
|
|
111
|
+
};
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`fromClientHints(media: Media): boolean` - returns true if media data is synchronized on client and server
|
|
115
|
+
|
|
116
|
+
`isSupposed(media: Media): boolean` - returns true if media data are determined on server by the user-agent string and will be changes on the client
|
|
117
|
+
|
|
118
|
+
`isRetina(media: Media): boolean` - returns true if pixel density is equal to 2 or higher
|
|
119
|
+
|
|
120
|
+
`useMedia(): Media` - returns current state of the `media` store
|
|
121
|
+
|
|
122
|
+
`useFromClientHints(): boolean` - calculates fromClientHints
|
|
123
|
+
|
|
124
|
+
`useIsSupposed(): boolean` - calculates isSupposed
|
|
125
|
+
|
|
126
|
+
`useIsRetina(): boolean` - calculates isRetina
|
|
127
|
+
|
|
128
|
+
## How to
|
|
129
|
+
|
|
130
|
+
### Render skeleton only when user loads pages first time
|
|
143
131
|
|
|
144
132
|
```tsx
|
|
145
133
|
const App = () => {
|
|
@@ -153,7 +141,7 @@ const App = () => {
|
|
|
153
141
|
};
|
|
154
142
|
```
|
|
155
143
|
|
|
156
|
-
|
|
144
|
+
### Render adaptive component on first time and on subsequent loads render specific component
|
|
157
145
|
|
|
158
146
|
```tsx
|
|
159
147
|
const App = () => {
|
|
@@ -169,3 +157,9 @@ const App = () => {
|
|
|
169
157
|
return <Block />;
|
|
170
158
|
};
|
|
171
159
|
```
|
|
160
|
+
|
|
161
|
+
## Exported tokens
|
|
162
|
+
|
|
163
|
+
### USER_AGENT_TOKEN
|
|
164
|
+
|
|
165
|
+
Object as a result of parsing user-agent string with [@tinkoff/user-agent](../libs/user-agent.md). Parsing happens only on server-side and parsed info is reused on client-side.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-client-hints",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.58.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/server.js",
|
|
6
6
|
"module": "lib/server.es.js",
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
"build-for-publish": "true"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@tinkoff/user-agent": "0.3.
|
|
23
|
+
"@tinkoff/user-agent": "0.3.238",
|
|
24
24
|
"@tinkoff/utils": "^2.1.2",
|
|
25
25
|
"@tramvai/safe-strings": "0.4.3"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@tramvai/core": "1.
|
|
29
|
-
"@tramvai/module-common": "1.
|
|
30
|
-
"@tramvai/state": "1.
|
|
28
|
+
"@tramvai/core": "1.58.0",
|
|
29
|
+
"@tramvai/module-common": "1.58.0",
|
|
30
|
+
"@tramvai/state": "1.58.0",
|
|
31
31
|
"@tinkoff/dippy": "0.7.38",
|
|
32
32
|
"react": ">=16.8.0",
|
|
33
33
|
"react-dom": ">=16.8.0",
|