@coraltravelcenter/b2c-landing-builder 2.14.2 → 3.0.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 +388 -204
- package/bin/b2c-landing-vite.mjs +5 -3
- package/npm-shrinkwrap.json +122 -122
- package/package.json +2 -2
- package/src/blocks/add.mjs +9 -4
- package/src/blocks/rename.mjs +9 -4
- package/src/cli/index.mjs +135 -62
- package/src/cli/terminal-ui.mjs +78 -0
- package/src/deploy/assets-command.mjs +32 -19
- package/src/deploy/assets.mjs +23 -1
- package/src/deploy/deploy.mjs +184 -53
- package/src/deploy/state.mjs +33 -0
- package/src/deploy/widgets.mjs +95 -49
- package/src/lib/build-cms.mjs +11 -11
- package/src/lib/rewriteAssetsBuild.mjs +38 -61
- package/src/lib/rewriteImageAssets.mjs +2 -2
- package/src/update/check-update.mjs +24 -9
- package/src/vite/config.mjs +16 -3
package/README.md
CHANGED
|
@@ -1,224 +1,174 @@
|
|
|
1
1
|
# @coraltravelcenter/b2c-landing-builder
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
CMS-готовых HTML
|
|
3
|
+
CLI для разработки B2C-лендингов, локального предпросмотра через Tampermonkey,
|
|
4
|
+
сборки CMS-готовых HTML-блоков и управляемой публикации ассетов и виджетов в
|
|
5
|
+
Backoffice.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Builder устанавливается глобально и запускается из каталога проекта. Исходники
|
|
8
|
+
builder, `vite.config.js` и собственные build-скрипты проекту не нужны.
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
## Требования и установка
|
|
11
|
+
|
|
12
|
+
- Node.js 20.19 или новее;
|
|
13
|
+
- Tampermonkey для локального предпросмотра;
|
|
14
|
+
- офисная сеть или VPN для работы с Backoffice.
|
|
9
15
|
|
|
10
16
|
```bash
|
|
11
17
|
npm install --global @coraltravelcenter/b2c-landing-builder
|
|
18
|
+
b2c-landing-vite --help
|
|
12
19
|
```
|
|
13
20
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## Команды
|
|
17
|
-
|
|
18
|
-
Команды выполняются из корня проекта:
|
|
21
|
+
## Создание проекта
|
|
19
22
|
|
|
20
23
|
```bash
|
|
21
|
-
b2c-landing-vite
|
|
24
|
+
npm create @coraltravelcenter/b2c-landing-vite
|
|
25
|
+
cd <project-directory>
|
|
26
|
+
npm install
|
|
27
|
+
b2c-landing-vite check --strict
|
|
22
28
|
b2c-landing-vite dev
|
|
23
|
-
b2c-landing-vite build
|
|
24
|
-
b2c-landing-vite deploy
|
|
25
|
-
b2c-landing-vite deploy --section hero
|
|
26
|
-
b2c-landing-vite deploy assets
|
|
27
|
-
b2c-landing-vite block:add hero
|
|
28
|
-
b2c-landing-vite block:rename hero main-hero
|
|
29
|
-
b2c-landing-vite update
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
-
|
|
33
|
-
- `dev` запускает Vite и отдельный userscript с названием проекта для
|
|
34
|
-
Tampermonkey.
|
|
35
|
-
- `build` создаёт CMS-файлы в `@CMS/` и переписывает пути ассетов на CDN.
|
|
36
|
-
- `deploy` собирает проект, синхронизирует ассеты с CDN и после успешной
|
|
37
|
-
синхронизации разворачивает CMS-виджеты.
|
|
38
|
-
- `deploy --section <key>` разворачивает только выбранную CMS-секцию, не изменяя
|
|
39
|
-
и не удаляя соседние секции.
|
|
40
|
-
- `deploy assets` собирает проект и синхронизирует ассеты с B2C CDN.
|
|
41
|
-
- При первом deploy builder запрашивает backoffice-логин и скрытый пароль через
|
|
42
|
-
ADFS. На диск сохраняется только токен. Для CI можно передать
|
|
43
|
-
`B2C_BACKOFFICE_TOKEN`.
|
|
44
|
-
- Backoffice-запросы ограничены 30 секундами. Безопасные GET-запросы повторяются
|
|
45
|
-
до двух раз при сетевом сбое, timeout, HTTP 429, 502, 503 или 504. Изменяющие
|
|
46
|
-
CMS запросы автоматически не повторяются, чтобы не создать дубликаты.
|
|
47
|
-
- После успешного deploy builder сохраняет снимок секций в `.b2c/deploy/` как
|
|
48
|
-
достоверный `base`. Следующий deploy структурно сравнивает секции `local`,
|
|
49
|
-
актуальный `remote` и `base`. Изменения разных секций объединяются; изменение
|
|
50
|
-
одной секции с обеих сторон считается конфликтом.
|
|
51
|
-
- Если `base` ещё отсутствует, отличие local от remote считается потенциальным
|
|
52
|
-
конфликтом. Обычный deploy не выполняет silent overwrite и предлагает явно
|
|
53
|
-
сохранить CMS-версию, применить local или отменить операцию.
|
|
54
|
-
- Стабильные `pageId`, `layoutAreaId` и позиция сохраняются отдельно в
|
|
55
|
-
`.b2c/deploy/<site>--<folder>.binding.json`. Этот файл можно хранить в Git,
|
|
56
|
-
чтобы команда находила ту же CMS-страницу после нового клонирования проекта.
|
|
57
|
-
- Перед deploy builder получает список версий сохранённой страницы. Published
|
|
58
|
-
выбирается по умолчанию; из Published или Unpublished создаётся checkout,
|
|
59
|
-
существующий Checkout обновляется напрямую. Потерянную привязку можно
|
|
60
|
-
восстановить интерактивным выбором существующей страницы.
|
|
61
|
-
- Одновременные deploy одного проекта на компьютере блокируются lock-файлом в
|
|
62
|
-
`.b2c/deploy/`; аварийно оставленный lock автоматически признаётся устаревшим.
|
|
63
|
-
- Непосредственно перед первой записью CMS-состояние читается повторно. Если оно
|
|
64
|
-
изменилось во время проверки/выбора стратегии, deploy останавливается.
|
|
65
|
-
- `block:add` создаёт файлы в выбранных форматах разметки и стилей.
|
|
66
|
-
- `block:rename` атомарно переименовывает все файлы блока и обновляет порядок.
|
|
67
|
-
- `update` проверяет npm registry и показывает команду ручного обновления.
|
|
68
|
-
|
|
69
|
-
После успешного выполнения рабочих команд builder коротко и независимо
|
|
70
|
-
проверяет в npm registry версии самого builder и шаблона проекта. Для проекта
|
|
71
|
-
без `template.version` шаблон помечается как `legacy`. Ошибки сети не влияют на
|
|
72
|
-
работу CLI; ничего не обновляется автоматически:
|
|
31
|
+
Генератор: [CoralTravelCenter/create-b2c-landing-vite](https://github.com/CoralTravelCenter/create-b2c-landing-vite).
|
|
73
32
|
|
|
74
|
-
|
|
75
|
-
b2c-landing-vite update
|
|
76
|
-
# Update manually: npm install --global @coraltravelcenter/b2c-landing-builder@latest
|
|
77
|
-
# Update project template: npx @coraltravelcenter/create-b2c-landing-vite@latest migrate
|
|
78
|
-
```
|
|
33
|
+
## Основной рабочий процесс
|
|
79
34
|
|
|
80
|
-
|
|
35
|
+
1. Добавьте или измените блоки в `src/`.
|
|
36
|
+
2. Запустите `b2c-landing-vite check --strict`.
|
|
37
|
+
3. Проверьте результат через `b2c-landing-vite dev` и Tampermonkey.
|
|
38
|
+
4. Перед публикацией выполните `b2c-landing-vite deploy --dry-run`.
|
|
39
|
+
5. Примените проверенный план командой `b2c-landing-vite deploy`.
|
|
81
40
|
|
|
82
|
-
|
|
41
|
+
Для предварительной загрузки ассетов без изменения CMS используйте
|
|
42
|
+
`b2c-landing-vite deploy assets`.
|
|
83
43
|
|
|
84
|
-
|
|
85
|
-
|
|
44
|
+
### Терминальный интерфейс
|
|
45
|
+
|
|
46
|
+
Каждая команда показывает единый структурированный сценарий: название команды и
|
|
47
|
+
проекта, текущие стадии, важные параметры, подтверждения и итог. Терминальные
|
|
48
|
+
подписи остаются на английском и одинаково используются в `check`, `dev`,
|
|
49
|
+
`build`, block-командах и всех вариантах deploy.
|
|
50
|
+
|
|
51
|
+
Полный deploy открывает одну terminal-сессию. Вложенные build, CDN и CMS-этапы
|
|
52
|
+
отображаются внутри неё, без повторных заголовков и ложных промежуточных
|
|
53
|
+
`complete`. Ошибка сохраняет исходную диагностику и ненулевой exit code.
|
|
54
|
+
|
|
55
|
+
В интерактивном терминале прогресс может отображаться spinner-анимацией. При
|
|
56
|
+
перенаправлении вывода содержательные подписи, пути и URL остаются текстовыми.
|
|
57
|
+
|
|
58
|
+
## Структура проекта
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
src/
|
|
62
|
+
order.json
|
|
63
|
+
markup/
|
|
64
|
+
welcome.html | welcome.pug
|
|
65
|
+
styles/
|
|
66
|
+
welcome.css | welcome.scss | welcome.less
|
|
67
|
+
scripts/
|
|
68
|
+
welcome.js | welcome.ts
|
|
69
|
+
utils/ # общие JS/TS-утилиты
|
|
70
|
+
components/ # компоненты проекта для Vue-стека
|
|
71
|
+
public/ # исходные статические файлы
|
|
72
|
+
pug.rc # настройки Pug, если выбран Pug
|
|
73
|
+
landing.config.mjs
|
|
74
|
+
package.json
|
|
86
75
|
```
|
|
87
76
|
|
|
88
|
-
|
|
89
|
-
|
|
77
|
+
Каталог `@CMS/` создаётся во время сборки. Это производный артефакт: его не нужно
|
|
78
|
+
редактировать вручную или хранить в Git.
|
|
90
79
|
|
|
91
80
|
## Конфигурация
|
|
92
81
|
|
|
93
|
-
|
|
82
|
+
Проект настраивается в `landing.config.mjs`:
|
|
94
83
|
|
|
95
84
|
```js
|
|
96
85
|
export default {
|
|
97
86
|
schemaVersion: 2,
|
|
98
|
-
builder: {
|
|
99
|
-
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
version: "2.13.0",
|
|
103
|
-
},
|
|
104
|
-
project: {
|
|
105
|
-
name: "uae-promo",
|
|
106
|
-
},
|
|
107
|
-
site: {
|
|
108
|
-
preset: "coral",
|
|
109
|
-
},
|
|
87
|
+
builder: {minVersion: "2.10.0"},
|
|
88
|
+
template: {version: "2.13.0"},
|
|
89
|
+
project: {name: "uae-promo"},
|
|
90
|
+
site: {preset: "coral"},
|
|
110
91
|
stack: {
|
|
111
92
|
script: "vue",
|
|
112
93
|
markup: "pug",
|
|
113
94
|
styles: "less",
|
|
114
95
|
},
|
|
115
|
-
blocks: {
|
|
116
|
-
static: ["html-only"],
|
|
117
|
-
},
|
|
96
|
+
blocks: {static: ["html-only"]},
|
|
118
97
|
};
|
|
119
98
|
```
|
|
120
99
|
|
|
121
|
-
|
|
122
|
-
создан проект. Для старых проектов поле необязательно; его отсутствие позволяет
|
|
123
|
-
builder распознать legacy-шаблон и предложить миграцию в будущих версиях.
|
|
124
|
-
|
|
125
|
-
Имя проекта должно соответствовать `^[a-z0-9][a-z0-9-]*$`.
|
|
100
|
+
### Версии
|
|
126
101
|
|
|
127
|
-
|
|
102
|
+
- `schemaVersion` — версия формата конфигурации; поддерживаются `1` и `2`.
|
|
103
|
+
- Для схемы `2` обязателен `builder.minVersion`. Слишком старая версия builder
|
|
104
|
+
блокирует выполнение команд.
|
|
105
|
+
- `template.version` записывает генератор. В legacy-проектах поле может
|
|
106
|
+
отсутствовать; проверка обновлений тогда предложит миграцию шаблона.
|
|
128
107
|
|
|
129
|
-
|
|
130
|
-
- разметка: `html`, `pug`;
|
|
131
|
-
- стили: `css`, `scss`, `less`;
|
|
132
|
-
- сайты: `coral`, `sunmar`.
|
|
108
|
+
### Проект, сайт и стек
|
|
133
109
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
`sass` для SCSS.
|
|
137
|
-
Builder загружает Vue-плагин из проекта, поэтому Vue-зависимости не
|
|
138
|
-
устанавливаются вместе с глобальным builder.
|
|
110
|
+
- `project.name` должен соответствовать `^[a-z0-9][a-z0-9-]*$`.
|
|
111
|
+
- `site.preset` принимает `coral` или `sunmar` и определяет домен и CDN.
|
|
139
112
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
113
|
+
| Поле | Поддерживаемые значения |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `stack.script` | `js`, `ts`, `vue`, `vue-ts`; `vanilla` — legacy-алиас |
|
|
116
|
+
| `stack.markup` | `html`, `pug` |
|
|
117
|
+
| `stack.styles` | `css`, `scss`, `less` |
|
|
143
118
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
119
|
+
Зависимости стека устанавливаются локально в проект: `typescript` для TS,
|
|
120
|
+
`vue` и `@vitejs/plugin-vue` для Vue, `pug` для Pug, `sass` для SCSS и `less`
|
|
121
|
+
для Less. Глобальный builder не заменяет эти зависимости.
|
|
147
122
|
|
|
148
|
-
|
|
149
|
-
Изображения JPG, JPEG и PNG конвертируются в WebP с качеством 80, а ссылки в
|
|
150
|
-
CMS-файлах автоматически переключаются на новые имена. Исходные файлы в
|
|
151
|
-
`public/` не изменяются. Если WebP с таким именем уже существует, используется
|
|
152
|
-
он. SVG, GIF, шрифты и остальные файлы копируются без преобразования.
|
|
123
|
+
### Статические блоки
|
|
153
124
|
|
|
154
|
-
|
|
125
|
+
`blocks.static` перечисляет блоки без JavaScript/TypeScript initializer.
|
|
126
|
+
`check --strict` требует, чтобы каждый блок либо имел initializer, либо был явно
|
|
127
|
+
объявлен статическим. Статический блок не может одновременно иметь script entry.
|
|
155
128
|
|
|
156
|
-
|
|
157
|
-
- контейнер: `#monkey-app`;
|
|
158
|
-
- CDN prefix: `landing-pages/<project.name>`.
|
|
129
|
+
## Блоки и порядок
|
|
159
130
|
|
|
160
|
-
|
|
161
|
-
свободный порт, поэтому несколько проектов можно запускать одновременно. Если
|
|
162
|
-
задан `B2C_PORT`, порт считается обязательным и занятое значение завершает
|
|
163
|
-
команду ошибкой.
|
|
131
|
+
`src/order.json` — единственный источник порядка блоков и CDN-папки:
|
|
164
132
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
Userscript ограничен доменом выбранного бренда и дополнительно проверяет hostname
|
|
172
|
-
перед монтированием. Namespace также содержит бренд, поэтому Coral и Sunmar не
|
|
173
|
-
конфликтуют даже при одинаковом названии проекта.
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"folder": "uae-promo",
|
|
136
|
+
"blocks": ["hero", "welcome"]
|
|
137
|
+
}
|
|
138
|
+
```
|
|
174
139
|
|
|
175
|
-
|
|
176
|
-
|
|
140
|
+
- `folder` должен соответствовать `^[a-z0-9][a-z0-9-]*$`;
|
|
141
|
+
- CDN prefix — `<assetsBase>/landing-pages/<folder>/`;
|
|
142
|
+
- ключи блоков должны быть уникальными;
|
|
143
|
+
- каждому ключу нужны разметка и стили выбранных форматов.
|
|
177
144
|
|
|
178
|
-
|
|
145
|
+
Создание и переименование:
|
|
179
146
|
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
markup/
|
|
184
|
-
welcome.html | welcome.pug
|
|
185
|
-
styles/
|
|
186
|
-
welcome.css | welcome.scss | welcome.less
|
|
187
|
-
scripts/
|
|
188
|
-
welcome.js | welcome.ts
|
|
189
|
-
utils/ # общие JavaScript-утилиты проекта
|
|
190
|
-
components/ # только для Vue
|
|
191
|
-
public/
|
|
192
|
-
pug.rc # только для Pug
|
|
193
|
-
landing.config.mjs
|
|
194
|
-
package.json
|
|
147
|
+
```bash
|
|
148
|
+
b2c-landing-vite block:add hero
|
|
149
|
+
b2c-landing-vite block:rename hero main-hero
|
|
195
150
|
```
|
|
196
151
|
|
|
197
|
-
|
|
152
|
+
`block:add` создаёт файлы выбранного стека и добавляет ключ в конец order.
|
|
153
|
+
`block:rename` сначала проверяет все пути, затем переименовывает имеющиеся
|
|
154
|
+
варианты разметки, стилей и скрипта и обновляет order. Конфликт целевого файла
|
|
155
|
+
останавливает команду до частичных изменений.
|
|
198
156
|
|
|
199
|
-
|
|
157
|
+
### HTML include
|
|
200
158
|
|
|
201
|
-
|
|
159
|
+
HTML поддерживает относительные вложенные include:
|
|
202
160
|
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
"folder": "uae-promo",
|
|
206
|
-
"blocks": ["hero", "welcome"]
|
|
207
|
-
}
|
|
161
|
+
```html
|
|
162
|
+
<include src="./partials/card.html"></include>
|
|
208
163
|
```
|
|
209
164
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
`<assetsBase>/landing-pages/<folder>/`.
|
|
213
|
-
|
|
214
|
-
Для каждого ключа обязательны разметка и стиль с тем же именем. JS/TS-файл
|
|
215
|
-
необязателен. Форматы определяются `landing.config.mjs`; отсутствие обязательного
|
|
216
|
-
файла блокирует `check`, `dev` и `build` с указанием ожидаемого пути.
|
|
165
|
+
Путь разрешается относительно исходного файла. Отсутствующий файл или
|
|
166
|
+
рекурсивная цепочка блокируют проверку и сборку.
|
|
217
167
|
|
|
218
168
|
## Контракт JavaScript и TypeScript
|
|
219
169
|
|
|
220
|
-
|
|
221
|
-
|
|
170
|
+
Script entry `src/scripts/<key>.js` или `.ts` экспортирует initializer по
|
|
171
|
+
умолчанию:
|
|
222
172
|
|
|
223
173
|
```js
|
|
224
174
|
export default function hero() {
|
|
@@ -229,79 +179,313 @@ export default function hero() {
|
|
|
229
179
|
}
|
|
230
180
|
```
|
|
231
181
|
|
|
232
|
-
Builder вставляет разметку, затем вызывает функцию без аргументов.
|
|
233
|
-
|
|
234
|
-
|
|
182
|
+
Builder вставляет разметку, затем вызывает функцию без аргументов. Функция сама
|
|
183
|
+
находит блок в `document`. Дополнительные контейнеры builder не создаёт.
|
|
184
|
+
|
|
185
|
+
Расширение entry определяется `stack.script`: например, при `ts` файл `hero.js`
|
|
186
|
+
считается конфликтующим, а не альтернативным entry.
|
|
187
|
+
|
|
188
|
+
## Проверка проекта
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
b2c-landing-vite check
|
|
192
|
+
b2c-landing-vite check --strict
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Проверяются конфигурация и версии, локальные зависимости стека, `src/order.json`,
|
|
196
|
+
файлы блоков, HTML include, расширение script entry и default initializer.
|
|
197
|
+
Strict-режим дополнительно проверяет контракт статических блоков. Команда не
|
|
198
|
+
собирает проект и не обращается к CDN или CMS.
|
|
235
199
|
|
|
236
|
-
##
|
|
200
|
+
## Локальная разработка
|
|
237
201
|
|
|
238
|
-
|
|
202
|
+
```bash
|
|
203
|
+
b2c-landing-vite dev
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Builder запускает Vite на `127.0.0.1`, создаёт Tampermonkey userscript с
|
|
207
|
+
названием проекта и открывает его установку и Target URL:
|
|
208
|
+
|
|
209
|
+
- `https://www.coral.ru/monkey/`;
|
|
210
|
+
- `https://www.sunmar.ru/monkey/`.
|
|
211
|
+
|
|
212
|
+
Userscript ограничен доменом выбранного бренда, проверяет hostname и использует
|
|
213
|
+
namespace с site preset. Проекты Coral и Sunmar с одинаковым названием поэтому
|
|
214
|
+
не конфликтуют.
|
|
215
|
+
|
|
216
|
+
На Target URL userscript ждёт контейнер `#monkey-app`, последовательно вставляет
|
|
217
|
+
в него блоки из `src/order.json`, а затем вызывает их initializer. Повторное
|
|
218
|
+
монтирование в тот же контейнер блокируется.
|
|
219
|
+
|
|
220
|
+
### Порт и вкладки
|
|
221
|
+
|
|
222
|
+
Первый запуск начинается с `5173` и при необходимости выбирает следующий
|
|
223
|
+
свободный порт. Он сохраняется в `.b2c/dev-port`; следующие запуски используют
|
|
224
|
+
его строго.
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
B2C_PORT=5175 b2c-landing-vite dev
|
|
228
|
+
B2C_NO_OPEN=1 b2c-landing-vite dev
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`B2C_PORT` назначает обязательный порт от `1` до `65535`.
|
|
232
|
+
`B2C_NO_OPEN=1` отключает автоматическое открытие вкладок.
|
|
233
|
+
|
|
234
|
+
### Обновление страницы
|
|
235
|
+
|
|
236
|
+
- Стили и Vue-компоненты используют штатный HMR Vite.
|
|
237
|
+
- Разметка, script entry, `src/order.json` и `pug.rc` вызывают полную перезагрузку.
|
|
238
|
+
- Добавление и удаление разметки или script entry также перезагружает страницу.
|
|
239
|
+
|
|
240
|
+
Root-relative URL из `public/` в dev направляются на origin текущего Vite-сервера.
|
|
241
|
+
|
|
242
|
+
## Production build
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
b2c-landing-vite build
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Сборка:
|
|
249
|
+
|
|
250
|
+
1. Проверяет проект и зависимости стека.
|
|
251
|
+
2. Создаёт отдельный `@CMS/<key>.html` для каждого блока.
|
|
252
|
+
3. Переписывает root-relative media URL на production CDN site preset.
|
|
253
|
+
4. Готовит копию ассетов в `@CMS/assets/`.
|
|
254
|
+
5. Конвертирует JPG, JPEG и PNG в WebP с качеством `80`.
|
|
255
|
+
6. Обновляет CMS HTML после конвертации.
|
|
256
|
+
7. Создаёт `@CMS/manifest.json` с путями, размерами и SHA-256.
|
|
257
|
+
|
|
258
|
+
Исходники в `public/` не меняются. Существующий WebP с нужным именем имеет
|
|
259
|
+
приоритет. Коллизия нескольких исходников в один итоговый путь блокирует build.
|
|
260
|
+
|
|
261
|
+
Builder переписывает root-relative ссылки на `jpg`, `jpeg`, `png`, `webp`,
|
|
262
|
+
`avif`, `gif`, `svg`, `mov`, `webm` и `mp4`. Внешние URL, шрифты и прочие
|
|
263
|
+
root-relative ресурсы не изменяются.
|
|
264
|
+
|
|
265
|
+
Файлы подключаются от корня:
|
|
239
266
|
|
|
240
267
|
```html
|
|
241
|
-
<img src="/hero.webp" alt="">
|
|
268
|
+
<img src="/images/hero.webp" alt="">
|
|
242
269
|
```
|
|
243
270
|
|
|
244
271
|
```css
|
|
245
|
-
.hero {
|
|
246
|
-
background-image: url("/hero.webp");
|
|
247
|
-
}
|
|
272
|
+
.hero { background-image: url("/images/hero.webp"); }
|
|
248
273
|
```
|
|
249
274
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
преобразуются в `<assetsBase>/landing-pages/<folder>/...`. Builder
|
|
253
|
-
переписывает изображения `jpg`, `jpeg`, `png`, `webp`, `avif`, `gif`, `svg` и
|
|
254
|
-
видео `mov`, `webm`, `mp4`; остальные root-relative ресурсы не изменяются.
|
|
275
|
+
Вложенная структура сохраняется: `public/hotels/room.webp` публикуется как
|
|
276
|
+
`landing-pages/<folder>/hotels/room.webp`.
|
|
255
277
|
|
|
256
|
-
|
|
278
|
+
## Deploy ассетов
|
|
257
279
|
|
|
258
280
|
```bash
|
|
259
281
|
b2c-landing-vite deploy assets
|
|
260
282
|
```
|
|
261
283
|
|
|
262
|
-
Команда выполняет
|
|
263
|
-
|
|
264
|
-
|
|
284
|
+
Команда выполняет свежий build, сравнивает manifest с deploy-state и CDN,
|
|
285
|
+
показывает план и запрашивает подтверждение новых загрузок. По умолчанию выбран
|
|
286
|
+
ответ `No`. Deploy-state обновляется атомарно только после успешной загрузки
|
|
287
|
+
всего плана.
|
|
288
|
+
|
|
289
|
+
### Immutable CDN
|
|
290
|
+
|
|
291
|
+
Существующие CDN-файлы не перезаписываются и не удаляются. Новое содержимое нужно
|
|
292
|
+
публиковать под новым именем и обновлять ссылку.
|
|
293
|
+
|
|
294
|
+
Если локальный файл изменился, а тот же путь уже занят на CDN, команда сообщает
|
|
295
|
+
immutable conflict и не обновляет state. При частичном сетевом сбое она выводит
|
|
296
|
+
уже загруженные пути, но также не принимает новый state целиком.
|
|
297
|
+
|
|
298
|
+
## Dry-run
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
b2c-landing-vite deploy --dry-run
|
|
302
|
+
b2c-landing-vite deploy --dry-run --section hero
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Dry-run выполняет свежий локальный build, читает CDN и CMS и показывает
|
|
306
|
+
фактический план ассетов, страницу, placement и операции над виджетами. Он не
|
|
307
|
+
загружает ассеты, не создаёт checkout, не изменяет CMS и не записывает
|
|
308
|
+
deploy-state, binding или pending-журнал.
|
|
309
|
+
|
|
310
|
+
Каталог `@CMS/` при этом обновляется, поскольку dry-run начинается с build.
|
|
311
|
+
|
|
312
|
+
## Полный deploy
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
b2c-landing-vite deploy
|
|
316
|
+
b2c-landing-vite deploy --section hero
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Deploy последовательно выполняет свежий build, синхронизацию ассетов и CMS
|
|
320
|
+
operation plan. CMS не меняется, если обязательная загрузка ассетов отменена или
|
|
321
|
+
завершилась ошибкой. Перед CMS builder проверяет наличие всех manifest-ассетов
|
|
322
|
+
на CDN.
|
|
323
|
+
|
|
324
|
+
### Страница и checkout
|
|
325
|
+
|
|
326
|
+
При первом запуске можно создать страницу или выбрать существующую. Builder
|
|
327
|
+
сохраняет `pageId`, `layoutAreaId` и позицию в binding-файле. Затем:
|
|
328
|
+
|
|
329
|
+
- Published выбирается по умолчанию;
|
|
330
|
+
- из Published или Unpublished создаётся Checkout;
|
|
331
|
+
- существующий Checkout обновляется напрямую;
|
|
332
|
+
- потерянную привязку можно восстановить интерактивным выбором.
|
|
333
|
+
|
|
334
|
+
При пустом CMS-плане checkout не создаётся.
|
|
335
|
+
|
|
336
|
+
### Согласование local, remote и base
|
|
337
|
+
|
|
338
|
+
Builder сравнивает:
|
|
339
|
+
|
|
340
|
+
- `local` — текущие файлы `@CMS/`;
|
|
341
|
+
- `remote` — управляемые виджеты выбранной версии;
|
|
342
|
+
- `base` — подтверждённый снимок последнего deploy.
|
|
343
|
+
|
|
344
|
+
Независимые изменения разных секций объединяются. Конкурирующее изменение одной
|
|
345
|
+
секции не перезаписывается молча: нужно сохранить remote, явно применить local
|
|
346
|
+
или отменить deploy. Без `base` различие local и remote также считается
|
|
347
|
+
потенциальным конфликтом.
|
|
348
|
+
|
|
349
|
+
### Operation plan и публикация
|
|
350
|
+
|
|
351
|
+
Перед записью показывается исполнимый план добавления, обновления, перестановки и
|
|
352
|
+
удаления управляемых виджетов. Он строится по фактическому checkout и повторно
|
|
353
|
+
проверяется после подготовки версии. Подтверждение по умолчанию — `No`.
|
|
354
|
+
|
|
355
|
+
Изменяющие Backoffice-запросы автоматически не повторяются. После синхронизации
|
|
356
|
+
builder предлагает публикацию. Для неё должны быть заполнены title, URL, SEO
|
|
357
|
+
title и SEO description. В конце выводятся Preview, Backoffice URL и, после
|
|
358
|
+
публикации, live URL.
|
|
359
|
+
|
|
360
|
+
### Deploy одной секции
|
|
361
|
+
|
|
362
|
+
`deploy --section <key>` ограничивает reconciliation и CMS-план указанной
|
|
363
|
+
секцией. Соседние секции не обновляются и не удаляются. Asset-стадия остаётся
|
|
364
|
+
полной: builder собирает и проверяет весь manifest.
|
|
365
|
+
|
|
366
|
+
Pending полного deploy нельзя продолжить через `--section`, и наоборот: resume
|
|
367
|
+
требует исходный scope.
|
|
368
|
+
|
|
369
|
+
### Частичная ошибка и resume
|
|
370
|
+
|
|
371
|
+
Перед первой CMS-операцией создаётся pending-журнал. После каждой подтверждённой
|
|
372
|
+
операции в него атомарно записываются deployment id, scope, checkout placement,
|
|
373
|
+
binding, завершённые операции и ожидаемая ревизия.
|
|
265
374
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
375
|
+
После ошибки следующий deploy того же scope открывает тот же checkout,
|
|
376
|
+
перечитывает его и продолжает по свежему фактическому плану. Новый checkout не
|
|
377
|
+
создаётся. После полного успеха pending удаляется.
|
|
269
378
|
|
|
270
|
-
|
|
271
|
-
изменилось, файл нужно переименовать, чтобы опубликовать его по новому URL.
|
|
272
|
-
Deploy-state обновляется атомарно только после успешной загрузки всех файлов.
|
|
273
|
-
В итоговом блоке команда также выводит корневой URL `CDN folder`, например
|
|
274
|
-
`https://b2ccdn.coral.ru/content/landing-pages/uae-promo/`.
|
|
379
|
+
### Revision guard и ограничения
|
|
275
380
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
Отдельная команда `deploy assets` полезна, когда нужно загрузить файлы заранее,
|
|
280
|
-
не меняя CMS.
|
|
381
|
+
Перед каждой операцией, перед resume и после последней операции builder повторно
|
|
382
|
+
читает checkout и сравнивает ревизию. При несовпадении следующая операция не
|
|
383
|
+
запускается, а pending сохраняется для проверки.
|
|
281
384
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
публикации по умолчанию имеют значение `No`. После deploy выводятся Preview и
|
|
285
|
-
прямая ссылка на созданную checkout-версию в BackOffice.
|
|
385
|
+
Это best-effort защита, не транзакционная блокировка. Без используемого ETag или
|
|
386
|
+
server-side lock остаются:
|
|
286
387
|
|
|
287
|
-
|
|
388
|
+
- TOCTOU-окно между контрольным GET и изменяющим запросом;
|
|
389
|
+
- окно между успешной CMS-операцией и записью pending-журнала.
|
|
390
|
+
|
|
391
|
+
После такого сбоя проверьте checkout в Backoffice перед повторным deploy.
|
|
392
|
+
|
|
393
|
+
### Локальная блокировка
|
|
394
|
+
|
|
395
|
+
Lock не допускает параллельные deploy одного проекта на одном компьютере, но не
|
|
396
|
+
защищает от другого клона или ручных действий в Backoffice. Lock старше двух
|
|
397
|
+
часов или от завершившегося процесса считается устаревшим.
|
|
398
|
+
|
|
399
|
+
## Служебные файлы
|
|
400
|
+
|
|
401
|
+
| Путь | Назначение | Git |
|
|
402
|
+
| --- | --- | --- |
|
|
403
|
+
| `.b2c/dev-port` | Локальный dev-порт | Не хранить |
|
|
404
|
+
| `.b2c/deploy/<site>--<folder>.state.json` | Хэши ассетов и CMS base | Хранить для общего state команды |
|
|
405
|
+
| `.b2c/deploy/<site>--<folder>.binding.json` | Привязка к странице и layout area | Хранить, если привязка общая |
|
|
406
|
+
| `.b2c/deploy/<site>--<folder>.pending.json` | Незавершённый deploy | Не хранить |
|
|
407
|
+
| `.b2c/deploy/<site>--<folder>.lock` | Локальная блокировка | Не хранить; удаляется автоматически |
|
|
408
|
+
|
|
409
|
+
Не редактируйте pending и lock во время работающего deploy.
|
|
410
|
+
|
|
411
|
+
## Аутентификация и окружение
|
|
412
|
+
|
|
413
|
+
При первом обращении к Backoffice builder запрашивает ADFS login и скрытый
|
|
414
|
+
password. Сохраняется только access token, отдельно для каждого бренда, максимум
|
|
415
|
+
на 23 часа. Путь по умолчанию: `~/.b2c-landing-vite/auth.json`.
|
|
416
|
+
|
|
417
|
+
| Переменная | Назначение |
|
|
418
|
+
| --- | --- |
|
|
419
|
+
| `B2C_BACKOFFICE_TOKEN` | Готовый token без ADFS login |
|
|
420
|
+
| `B2C_BACKOFFICE_LOGIN` | Login для неинтерактивного входа |
|
|
421
|
+
| `B2C_BACKOFFICE_PASSWORD` | Password для неинтерактивного входа |
|
|
422
|
+
| `B2C_AUTH_CACHE` | Другой путь к token cache |
|
|
423
|
+
| `B2C_PORT` | Обязательный dev-порт |
|
|
424
|
+
| `B2C_NO_OPEN=1` | Не открывать вкладки автоматически |
|
|
425
|
+
|
|
426
|
+
Не добавляйте cache, пароли и токены в Git. Backoffice GET-запросы имеют timeout
|
|
427
|
+
30 секунд и до двух повторов при сетевой ошибке, timeout, HTTP 429, 502, 503 или
|
|
428
|
+
504. Изменяющие запросы не повторяются.
|
|
429
|
+
|
|
430
|
+
## Обновления
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
b2c-landing-vite update
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Команда проверяет npm registry и печатает инструкции, но ничего не устанавливает.
|
|
437
|
+
Короткая проверка также выполняется после рабочих команд; ошибка registry не
|
|
438
|
+
меняет их результат.
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
npm install --global @coraltravelcenter/b2c-landing-builder@latest
|
|
442
|
+
npx @coraltravelcenter/create-b2c-landing-vite@latest migrate
|
|
443
|
+
```
|
|
288
444
|
|
|
289
|
-
|
|
290
|
-
блокирует работу. Для аварийной сборки старого проекта можно использовать:
|
|
445
|
+
Аварийная сборка конкретной версией:
|
|
291
446
|
|
|
292
447
|
```bash
|
|
293
448
|
npx @coraltravelcenter/b2c-landing-builder@<version> build
|
|
294
449
|
```
|
|
295
450
|
|
|
296
|
-
##
|
|
451
|
+
## Диагностика
|
|
452
|
+
|
|
453
|
+
- **Missing local dependency:** установите зависимость выбранного стека в проект.
|
|
454
|
+
- **Port already in use:** остановите процесс или задайте свободный `B2C_PORT`.
|
|
455
|
+
- **Backoffice is unavailable:** подключитесь к офисной сети или VPN.
|
|
456
|
+
- **Immutable asset conflict:** переименуйте файл и обновите ссылки.
|
|
457
|
+
- **Remote CMS changes:** сравните local и remote и явно выберите стратегию.
|
|
458
|
+
- **Incomplete deploy:** повторите deploy с тем же scope; при revision conflict
|
|
459
|
+
сначала проверьте checkout и не удаляйте pending ради обхода защиты.
|
|
460
|
+
|
|
461
|
+
## Справочник команд
|
|
462
|
+
|
|
463
|
+
Все команды выполняются из корня проекта.
|
|
464
|
+
|
|
465
|
+
| Команда | Результат |
|
|
466
|
+
| --- | --- |
|
|
467
|
+
| `b2c-landing-vite check` | Проверить проект |
|
|
468
|
+
| `b2c-landing-vite check --strict` | Проверить static/initializer-контракт |
|
|
469
|
+
| `b2c-landing-vite dev` | Запустить Vite и userscript |
|
|
470
|
+
| `b2c-landing-vite build` | Собрать `@CMS/`, ассеты и manifest |
|
|
471
|
+
| `b2c-landing-vite deploy assets` | Синхронизировать только CDN-ассеты |
|
|
472
|
+
| `b2c-landing-vite deploy --dry-run` | Показать полный CDN/CMS-план |
|
|
473
|
+
| `b2c-landing-vite deploy --dry-run --section <key>` | Показать план секции |
|
|
474
|
+
| `b2c-landing-vite deploy` | Синхронизировать ассеты и CMS |
|
|
475
|
+
| `b2c-landing-vite deploy --section <key>` | Синхронизировать ассеты и одну секцию |
|
|
476
|
+
| `b2c-landing-vite block:add <key>` | Создать блок |
|
|
477
|
+
| `b2c-landing-vite block:rename <old> <new>` | Переименовать блок |
|
|
478
|
+
| `b2c-landing-vite update` | Показать ручные обновления |
|
|
479
|
+
|
|
480
|
+
## Разработка builder
|
|
297
481
|
|
|
298
482
|
```bash
|
|
299
483
|
npm ci
|
|
300
484
|
npm test
|
|
301
485
|
npm run check
|
|
302
486
|
npm run build
|
|
487
|
+
npm run test:dev
|
|
303
488
|
npm pack --dry-run
|
|
304
489
|
```
|
|
305
490
|
|
|
306
|
-
|
|
307
|
-
dist-tag `next`, стабильная версия — с `latest`.
|
|
491
|
+
Инструкции по публикации: [RELEASING.md](./RELEASING.md).
|