@coraltravelcenter/b2c-landing-builder 2.11.0 → 2.12.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 +20 -6
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/cli/index.mjs +12 -2
- package/src/deploy/assets.mjs +11 -3
- package/src/vite/client.js +6 -3
- package/src/vite/config.mjs +18 -3
package/README.md
CHANGED
|
@@ -30,9 +30,11 @@ b2c-landing-vite update
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
- `check` проверяет конфигурацию, `order.json` и контракт JS-блоков.
|
|
33
|
-
- `dev` запускает Vite и userscript для
|
|
33
|
+
- `dev` запускает Vite и отдельный userscript с названием проекта для
|
|
34
|
+
Tampermonkey.
|
|
34
35
|
- `build` создаёт CMS-файлы в `@CMS/` и переписывает пути ассетов на CDN.
|
|
35
|
-
- `deploy` собирает проект,
|
|
36
|
+
- `deploy` собирает проект, синхронизирует ассеты с CDN и после успешной
|
|
37
|
+
синхронизации разворачивает CMS-виджеты.
|
|
36
38
|
- `deploy --section <key>` разворачивает только выбранную CMS-секцию, не изменяя
|
|
37
39
|
и не удаляя соседние секции.
|
|
38
40
|
- `deploy assets` собирает проект и синхронизирует ассеты с B2C CDN.
|
|
@@ -144,6 +146,15 @@ Monkey URL, контейнер и CDN prefix не задаются вручну
|
|
|
144
146
|
- контейнер: `#monkey-app`;
|
|
145
147
|
- CDN prefix: `landing-pages/<project.name>`.
|
|
146
148
|
|
|
149
|
+
Dev-сервер начинает с `127.0.0.1:5173` и автоматически выбирает следующий
|
|
150
|
+
свободный порт, поэтому несколько проектов можно запускать одновременно. Если
|
|
151
|
+
задан `B2C_PORT`, порт считается обязательным и занятое значение завершает
|
|
152
|
+
команду ошибкой.
|
|
153
|
+
|
|
154
|
+
Userscript ограничен доменом выбранного бренда и дополнительно проверяет hostname
|
|
155
|
+
перед монтированием. Namespace также содержит бренд, поэтому Coral и Sunmar не
|
|
156
|
+
конфликтуют даже при одинаковом названии проекта.
|
|
157
|
+
|
|
147
158
|
Для Coral и Sunmar настроены отдельные production CDN. Команда `build`
|
|
148
159
|
автоматически выбирает CDN по `site.preset`.
|
|
149
160
|
|
|
@@ -219,7 +230,8 @@ build; дополнительные контейнеры builder не созда
|
|
|
219
230
|
}
|
|
220
231
|
```
|
|
221
232
|
|
|
222
|
-
В dev пути направляются на
|
|
233
|
+
В dev пути направляются на фактический origin текущего Vite-сервера. При
|
|
234
|
+
production build они
|
|
223
235
|
преобразуются в `<assetsBase>/landing-pages/<folder>/...`. Builder
|
|
224
236
|
переписывает только изображения `jpg`, `jpeg`, `png`, `webp`, `avif`, `gif` и
|
|
225
237
|
`svg`; остальные root-relative ресурсы не изменяются.
|
|
@@ -244,9 +256,11 @@ Deploy-state обновляется атомарно только после у
|
|
|
244
256
|
В итоговом блоке команда также выводит корневой URL `CDN folder`, например
|
|
245
257
|
`https://b2ccdn.coral.ru/content/landing-pages/uae-promo/`.
|
|
246
258
|
|
|
247
|
-
Обычный `deploy`
|
|
248
|
-
|
|
249
|
-
|
|
259
|
+
Обычный `deploy` выполняет этот же план синхронизации ассетов перед изменением
|
|
260
|
+
CMS. Если нужны новые файлы, он запрашивает подтверждение загрузки и продолжает
|
|
261
|
+
CMS-deploy только после её успешного завершения. При отказе CMS не изменяется.
|
|
262
|
+
Отдельная команда `deploy assets` полезна, когда нужно загрузить файлы заранее,
|
|
263
|
+
не меняя CMS.
|
|
250
264
|
|
|
251
265
|
Перед изменением CMS команда показывает план добавления, обновления, удаления и
|
|
252
266
|
перестановки управляемых виджетов. Подтверждение и последующее предложение
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coraltravelcenter/b2c-landing-builder",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@coraltravelcenter/b2c-landing-builder",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.12.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@babel/parser": "7.28.6",
|
package/package.json
CHANGED
package/src/cli/index.mjs
CHANGED
|
@@ -100,14 +100,24 @@ export async function runCli(args) {
|
|
|
100
100
|
},
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
-
await runCli(["build"]);
|
|
104
103
|
const {getBackofficeToken} = await import("../deploy/auth.mjs");
|
|
105
104
|
const token = await getBackofficeToken({brand: preset.id});
|
|
105
|
+
const {BackofficeClient} = await import("../deploy/backoffice-client.mjs");
|
|
106
|
+
const client = new BackofficeClient({brand: preset.id, token});
|
|
107
|
+
const {deployAssetsCommand} = await import("../deploy/assets-command.mjs");
|
|
108
|
+
const assets = await deployAssetsCommand({
|
|
109
|
+
config,
|
|
110
|
+
project,
|
|
111
|
+
preset,
|
|
112
|
+
build: () => runCli(["build"]),
|
|
113
|
+
client,
|
|
114
|
+
});
|
|
115
|
+
if (assets.cancelled) return assets;
|
|
106
116
|
const {deployProject} = await import("../deploy/deploy.mjs");
|
|
107
117
|
return deployProject({
|
|
108
118
|
config,
|
|
109
119
|
preset,
|
|
110
|
-
|
|
120
|
+
client,
|
|
111
121
|
section: sectionOnly ? rest[1] : null,
|
|
112
122
|
});
|
|
113
123
|
});
|
package/src/deploy/assets.mjs
CHANGED
|
@@ -36,16 +36,24 @@ export async function planAssetChanges({manifest, state, listFiles, remoteRoot =
|
|
|
36
36
|
};
|
|
37
37
|
const upload = [];
|
|
38
38
|
const skip = [];
|
|
39
|
-
|
|
39
|
+
let unchanged = 0;
|
|
40
|
+
const pendingPaths = new Set(pending.map((asset) => asset.path));
|
|
41
|
+
await Promise.all(manifest.assets.map(async (asset) => {
|
|
40
42
|
const remotePath = path.posix.join("/", remoteRoot, manifest.assetsPrefix, asset.path);
|
|
41
43
|
const names = await namesInDirectory(path.posix.dirname(remotePath));
|
|
42
|
-
|
|
44
|
+
const exists = names.has(path.posix.basename(remotePath));
|
|
45
|
+
if (!pendingPaths.has(asset.path)) {
|
|
46
|
+
if (exists) unchanged += 1;
|
|
47
|
+
else upload.push(asset);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
(exists ? skip : upload).push(asset);
|
|
43
51
|
}));
|
|
44
52
|
const byPath = (left, right) => left.path.localeCompare(right.path);
|
|
45
53
|
return {
|
|
46
54
|
upload: upload.sort(byPath),
|
|
47
55
|
skip: skip.sort(byPath),
|
|
48
|
-
unchanged
|
|
56
|
+
unchanged,
|
|
49
57
|
remove: prune ? obsoleteAssets(manifest, state) : [],
|
|
50
58
|
};
|
|
51
59
|
}
|
package/src/vite/client.js
CHANGED
|
@@ -30,6 +30,9 @@ function waitForContainer() {
|
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
if (window.location.hostname === __B2C_TARGET_HOST__) {
|
|
34
|
+
const container = await waitForContainer();
|
|
35
|
+
mount(container, parts);
|
|
36
|
+
const devOrigin = new URL("/", import.meta.url).origin;
|
|
37
|
+
setupLocalCdnAssetRewrite({root: container, cdnBase: devOrigin});
|
|
38
|
+
}
|
package/src/vite/config.mjs
CHANGED
|
@@ -18,6 +18,18 @@ export function toViteFsUrl(filePath) {
|
|
|
18
18
|
const clientEntryUrl = toViteFsUrl(clientEntry);
|
|
19
19
|
let monkeyPlugin;
|
|
20
20
|
|
|
21
|
+
export function resolveDevServerPort(env = process.env) {
|
|
22
|
+
const explicitPort = env.B2C_PORT;
|
|
23
|
+
if (explicitPort === undefined || explicitPort === "") {
|
|
24
|
+
return {port: 5173, strictPort: false};
|
|
25
|
+
}
|
|
26
|
+
const port = Number(explicitPort);
|
|
27
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
28
|
+
throw new Error("B2C_PORT must be an integer between 1 and 65535");
|
|
29
|
+
}
|
|
30
|
+
return {port, strictPort: true};
|
|
31
|
+
}
|
|
32
|
+
|
|
21
33
|
async function loadMonkeyPlugin() {
|
|
22
34
|
if (monkeyPlugin) return monkeyPlugin;
|
|
23
35
|
|
|
@@ -36,6 +48,7 @@ export async function createViteConfig(root = process.cwd()) {
|
|
|
36
48
|
const preset = resolvePreset(config.site.preset);
|
|
37
49
|
const monkey = await loadMonkeyPlugin();
|
|
38
50
|
const shouldOpen = process.env.B2C_NO_OPEN !== "1";
|
|
51
|
+
const devPort = resolveDevServerPort();
|
|
39
52
|
const vue = resolveScriptStack(config.stack.script).vue
|
|
40
53
|
? await loadProjectVuePlugin(root)
|
|
41
54
|
: null;
|
|
@@ -45,8 +58,7 @@ export async function createViteConfig(root = process.cwd()) {
|
|
|
45
58
|
configFile: false,
|
|
46
59
|
server: {
|
|
47
60
|
host: "127.0.0.1",
|
|
48
|
-
|
|
49
|
-
strictPort: true,
|
|
61
|
+
...devPort,
|
|
50
62
|
cors: true,
|
|
51
63
|
open: shouldOpen ? "/__vite-plugin-monkey.install.user.js" : false,
|
|
52
64
|
fs: {allow: [root, builderRoot]},
|
|
@@ -59,13 +71,16 @@ export async function createViteConfig(root = process.cwd()) {
|
|
|
59
71
|
server: {open: shouldOpen, prefix: false},
|
|
60
72
|
userscript: {
|
|
61
73
|
name: config.project.name,
|
|
62
|
-
namespace:
|
|
74
|
+
namespace: `b2c-landing-builder:${preset.id}`,
|
|
63
75
|
match: [`https://${preset.domain}/monkey/*`],
|
|
64
76
|
grant: "none",
|
|
65
77
|
"run-at": "document-idle",
|
|
66
78
|
},
|
|
67
79
|
}),
|
|
68
80
|
].filter(Boolean),
|
|
81
|
+
define: {
|
|
82
|
+
__B2C_TARGET_HOST__: JSON.stringify(preset.domain),
|
|
83
|
+
},
|
|
69
84
|
};
|
|
70
85
|
}
|
|
71
86
|
|