Route'y i strony
Do Twojej aplikacji docierają trzy kształty żądań i każdy potrzebuje czegoś innego. Oto okablowanie, które obsługuje wszystkie trzy.
Skopiuj to w całości. Elementy zależą od siebie nawzajem, a te zależności nie są oczywiste.
Model myślowy
Do Twojej aplikacji docierają trzy kształty żądań i każdy potrzebuje czegoś innego:
- Odwiedzający - treść opublikowana, renderowana na serwerze, statycznie gdzie się da. Szybkość i trzymanie CMS-a poza ścieżką renderowania.
- Podgląd roboczy (ciasteczko
/api/draft) - treść robocza na publicznym routcie, bez edytora. Ktoś przegląda zmianę, a nie ją edytuje. - Ramka edytora (
cmssyEdit=1plus pasującycmssySecret) - treść robocza plus most edycyjny, na własnym dynamicznym routcie.
Ten trzeci punkt zaskakuje ludzi. Statyczna strona nigdy nie widzi query stringa, więc nie może wiedzieć, że jest edytowana. Dlatego istnieje /cmssy-edit, i wszystko poniżej z tego wynika.
1. Konfiguracja
// cmssy.config.ts
import { defineCmssyConfig } from "@cmssy/next";
export const cmssy = defineCmssyConfig({
org: process.env.CMSSY_ORG_SLUG,
workspaceSlug: process.env.CMSSY_WORKSPACE_SLUG,
draftSecret: process.env.CMSSY_DRAFT_SECRET,
});Przekazuj process.env surowo. Fallback ?? "" zamienia brakującą zmienną w pustą, a błąd wychodzi później, w zupełnie niezwiązanym miejscu.
Ten moduł czyta env serwera. Nigdy nie importuj z niego wartości - ani z modułu, który go importuje - w komponencie "use client". Typy są w porządku, są wymazywane. Wartości wciągają process.env do bundla przeglądarki.
2. Middleware
// proxy.ts
import { createCmssyProxy } from "@cmssy/next/middleware";
import { cmssy } from "@/cmssy.config";
export const proxy = createCmssyProxy(cmssy, {
// Tylko jeśli Twoje URL-e niosą język (/pl/about) ORAZ Twoje route'y to
// ścieżki statyczne, a nie catch-all.
stripLocalePrefix: true,
});
// Next parsuje to w czasie kompilacji, więc matcher musi być literałem -
// zaimportowana stała jest odrzucana.
export const config = { matcher: ["/((?!_next/|api/|.*\\..*).*)"] };Preset rozwiązuje język, kieruje zweryfikowany ruch edytora na /cmssy-edit niosąc ten język i flagę edycji, nakłada CSP pozwalające panelowi osadzić Twój serwis w ramce i ścina prefiks języka, jeśli o to poprosiłeś - w tej kolejności.
Kolejność to nie szczegół, a każdy sposób jej zepsucia już raz trafił na produkcję:
- Rozwiąż locale po przepisaniu, a podgląd w edytorze wyrenderuje się w złym języku - route nie odczyta prefiksu, którego nigdy nie widzi.
- Zapomnij o fladze edycji, a header i footer przyjdą jako markup, który edytor może zaznaczyć, ale nie może wypełnić.
3. Strona publiczna
Jeden catch-all route renderuje każdą opublikowaną stronę. Metadane biorą się z helpera, który należy do Ciebie, zbudowanego na API dostawczym - SDK daje dane, Twoja aplikacja jest właścicielem swoich route'ów:
// app/[[...path]]/page.tsx
import { createCmssyPage } from "@cmssy/next/server";
import { cmssy } from "@/cmssy/config";
import { blocks } from "@/cmssy/blocks";
import { buildPageMetadata } from "@/services/seo";
export const revalidate = 3600;
export const dynamicParams = true;
export async function generateMetadata({ params }) {
const { path } = await params;
// Tak jak w routingu, z prefiksem: prefiks JEST językiem.
return buildPageMetadata(path);
}
export default createCmssyPage(cmssy, blocks);buildPageMetadata jest Twój, nie SDK. Odpytuje pola SEO strony i zwraca obiekt Metadata Next.js - zobacz SEO, co dokładnie zawiera.
4. Route edycyjny
// app/cmssy-edit/[[...path]]/page.tsx
import { createCmssyEditPage } from "@cmssy/next/server";
import { cmssy } from "@/cmssy.config";
import { blocks } from "@/cmssy/blocks";
import { CmssyEditor } from "@/cmssy/editor";
export const dynamic = "force-dynamic";
export default createCmssyEditPage(cmssy, blocks, { editor: CmssyEditor });Pomiń ten plik, a podgląd w edytorze będzie pusty. To najczęstszy sposób na zepsucie aplikacji cmssy, a nic w buildzie Cię nie ostrzeże - zobacz testowanie.
5. Most edytora
// cmssy/editor.tsx
"use client";
import { CmssyLazyEditor } from "@cmssy/react/client";
import type { CmssyEditorProps } from "@cmssy/next";
export function CmssyEditor(props: CmssyEditorProps) {
return <CmssyLazyEditor {...props} load={() => import("./blocks")} />;
}Rejestr ładuje się leniwie na kliencie, więc Twoje loadery bloków - które działają po stronie serwera i czytają konfigurację - nigdy nie trafiają do bundla przeglądarki.
Cache
Publikacja to nie deploy. Publiczny route cache'uje się według własnego revalidate, a cmssy może przy publikacji wywołać webhook rewalidacji, żeby unieważnić go wcześniej:
export const revalidate = 3600;
export const dynamicParams = true;Route edycyjny jest wyjątkiem: jest force-dynamic celowo, bo scache'owana strona edycji pokazywałaby wczorajszy draft.
Następne kroki
- Layouty - header i footer jako edytowalne bloki.
- Testowanie - dowód, że route edycyjny dalej działa.
- Jak działa cmssy - co dzieje się między żądaniem a renderem.