@webnumseoagent/next 0.7.3 → 0.7.4
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 +6 -0
- package/bin/cli.mjs +35 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,6 +105,12 @@ Vercel и `git push`. **Проверь `git diff`** перед коммитом
|
|
|
105
105
|
контент = git-коммит → редеплой пересобирает страницы.
|
|
106
106
|
- Тема оформления (фирменный цвет) и канонический URL-префикс берутся из `content/blog/.blogfs.json`.
|
|
107
107
|
- Sitemap блога добавляется автоматически (раздел `sitemap/blog.xml`).
|
|
108
|
+
- Роуты карты сайта/`robots`/merchant — `force-dynamic` (не `revalidate`): статический путь Vercel
|
|
109
|
+
пре-рендерит на сборке и раздаёт из edge-кэша, из-за чего при смене данных на платформе (напр. появился
|
|
110
|
+
блог) индекс `/sitemap.xml` «застревает» и не обновляется, а `revalidateTag` пре-рендер не сбрасывает.
|
|
111
|
+
`force-dynamic` убирает пре-рендер; внутренний fetch к платформе остаётся кэшированным (300с + тег
|
|
112
|
+
`seo-<SITE>`), поэтому нагрузка почти не растёт. `init`/`blog` проставляют это идемпотентно (и на
|
|
113
|
+
авто-обновлении), так что старые сайты чинятся сами.
|
|
108
114
|
- `init`/`blog` **сами** прописывают в `next.config` `outputFileTracingIncludes` для `content/blog` —
|
|
109
115
|
без этого на Vercel файлы блога не попадают в serverless-бандл, и рантайм-чтение (ISR-ревалидация
|
|
110
116
|
страниц + route-handler карты сайта) находит пусто → блог исчезает с сайта и из sitemap. Идемпотентно;
|
package/bin/cli.mjs
CHANGED
|
@@ -143,6 +143,35 @@ async function ensureContentTracing(contentDir = "content/blog") {
|
|
|
143
143
|
ok(`${rel} (outputFileTracingIncludes → content/blog в бандле)`);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
// Делает наши платформенные роуты ДИНАМИЧЕСКИМИ (force-dynamic) вместо ISR (revalidate 300).
|
|
147
|
+
// ЗАЧЕМ: /sitemap.xml (и robots/merchant) — статический путь, Vercel пре-рендерит его на сборке и
|
|
148
|
+
// раздаёт из edge-кэша. При смене данных на платформе (напр. появился блог) такой роут «застревает»:
|
|
149
|
+
// фоновая ре-валидация ненадёжна, а revalidateTag пре-рендер не сбрасывает — и карта отдаёт старое,
|
|
150
|
+
// пока сайт не пересоберут. force-dynamic убирает пре-рендер: роут исполняется на каждый запрос и всегда
|
|
151
|
+
// отражает платформу (внутренний fetch остаётся кэшированным на 300с + тег seo-<SITE>, так что нагрузка
|
|
152
|
+
// почти не растёт, а сброс по revalidateTag работает мгновенно). Идемпотентно; правит ТОЛЬКО наши роуты.
|
|
153
|
+
// Запускается и на self-update (`npx … blog --force`) — поэтому чинит все сайты сам, без разработчика.
|
|
154
|
+
async function ensureDynamicRoutes(appDir) {
|
|
155
|
+
const ext = (await exists(path.join(root, "tsconfig.json"))) ? "ts" : "js";
|
|
156
|
+
const targets = [
|
|
157
|
+
`sitemap.xml/route.${ext}`,
|
|
158
|
+
`sitemap/[name]/route.${ext}`,
|
|
159
|
+
`robots.txt/route.${ext}`,
|
|
160
|
+
`seoagent-merchant-feed.xml/route.${ext}`,
|
|
161
|
+
];
|
|
162
|
+
for (const rel of targets) {
|
|
163
|
+
const p = path.join(root, appDir, rel);
|
|
164
|
+
const src = await fs.readFile(p, "utf8").catch(() => null);
|
|
165
|
+
if (src == null) continue;
|
|
166
|
+
if (!/seoSitemapXml|seoWrapSitemap|seoRobotsTxt|seoMerchantFeedXml/.test(src)) continue; // не наш роут
|
|
167
|
+
if (/dynamic\s*=\s*["']force-dynamic["']/.test(src)) { skip(`${appDir}/${rel} — уже force-dynamic`); continue; }
|
|
168
|
+
const patched = src.replace(/export const revalidate\s*=\s*300\s*;?/, 'export const dynamic = "force-dynamic";');
|
|
169
|
+
if (patched === src) continue; // нет revalidate=300 — незнакомая форма, не трогаем
|
|
170
|
+
await fs.writeFile(p, patched);
|
|
171
|
+
ok(`${appDir}/${rel} → force-dynamic (не застревает в edge-кэше Vercel)`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
146
175
|
async function init() {
|
|
147
176
|
log("\n\x1b[1m@webnumseoagent/next — установка\x1b[0m\n");
|
|
148
177
|
// Проверяем чистоту git ДО создания файлов (чтобы весь дифф установки был обозрим).
|
|
@@ -486,6 +515,9 @@ async function init() {
|
|
|
486
515
|
await ensureContentTracing();
|
|
487
516
|
}
|
|
488
517
|
|
|
518
|
+
// Наши sitemap/robots/merchant-роуты → force-dynamic (не застревают в edge-кэше Vercel).
|
|
519
|
+
await ensureDynamicRoutes(appDir);
|
|
520
|
+
|
|
489
521
|
log("\n\x1b[1mЗатем:\x1b[0m задай эти же env-переменные в Vercel (Settings → Environment Variables) и сделай git push.\n");
|
|
490
522
|
}
|
|
491
523
|
|
|
@@ -779,6 +811,9 @@ async function blogPage() {
|
|
|
779
811
|
// Файлы блога должны попасть в serverless-бандл Vercel (ISR-ревалидация + карта сайта читают их в
|
|
780
812
|
// рантайме). Идемпотентно — запускается и на self-update (`npx … blog --force`), авто-чиня сайт.
|
|
781
813
|
await ensureContentTracing();
|
|
814
|
+
// Наши sitemap/robots/merchant-роуты → force-dynamic (иначе индекс карты застревает в кэше Vercel).
|
|
815
|
+
// Тоже гоняется на self-update — фикс сам доезжает до всех сайтов без правок разработчика.
|
|
816
|
+
await ensureDynamicRoutes(appDir);
|
|
782
817
|
|
|
783
818
|
log(`\n \x1b[32m✓\x1b[0m Готово. Проверь \x1b[36mgit diff\x1b[0m, затем commit + push. Блог: \x1b[1m${localeDir ? `/${param}/blog` : "/blog"}\x1b[0m — дизайн/шапка с сайта, список 4-в-ряд, статический рендер из файлов.\n`);
|
|
784
819
|
}
|
package/package.json
CHANGED