JS SDK

Cea mai rapidă integrare: două linii de HTML, fără build, fără CMS. SDK-ul randează blogul într-un container pe pagina ta existentă și gestionează navigarea client-side.

<div data-baas-blog
     data-key="pk_YOUR_KEY"
     data-base-path="/blog"
     data-api="https://api.dailysmith.com"></div>
<script src="https://api.dailysmith.com/v1/sdk/blog.js" async></script>

Pune asta pe pagina servită la calea de bază a blogului tău (/blog implicit). Header-ul, footer-ul și stilurile tale rămân neschimbate — blogul se randează în interiorul containerului și moștenește tipografia site-ului tău.

Atribute

AtributObligatoriuSens
data-keydaCheia publică a site-ului tău (pk_…, afișată pe pagina site-ului)
data-apidaOriginea API-ului de unde se încarcă conținutul — setează-l mereu; fragmentul de mai sus îl fixează la https://api.dailysmith.com
data-base-pathnuCalea pe care e montat blogul; implicit /blog. Trebuie să corespundă cu calea de bază a blogului configurată în dashboard și cu calea URL sub care e servită această pagină.
data-baas-headnuSetează la "false" ca să ții SDK-ul complet în afara <head>-ului tău — vezi „Dacă site-ul tău își gestionează propriul head” mai jos.
data-baas-themenu"light" sau "dark" fixează blogul pe o singură schemă de culoare, indiferent ce face pagina din jur; "inherit" retrage paleta blogului, ca propriul tău CSS să furnizeze fiecare token. Nesetat, blogul urmează data-theme de pe site-ul tău, apoi preferința de sistem a cititorului. Vezi Teme.

SDK-ul folosește primul element [data-baas-blog] de pe pagină; un singur container de blog per pagină. Expune și window.baasBlog, cu init(el?) și destroy(), pentru aplicații cu rutare client-side — vezi mai jos.

Servește shell-ul pentru fiecare URL de blog

Cum faci asta pe configurațiile obișnuite:

Netlify_redirects:

/blog/*   /blog/index.html   200

Vercelvercel.json:

{ "rewrites": [{ "source": "/blog/:path*", "destination": "/blog" }] }

nginx:

location /blog {
    try_files $uri /blog/index.html;
}

Framework-uri — folosește o rută catch-all ca pagină de blog și pune fragmentul în ea: app/blog/[[...slug]]/page.tsx (Next.js), src/routes/blog/[...rest]/+page.svelte (SvelteKit), src/pages/blog/[...slug].astro (Astro).

Compromisul: acum orice URL de blog răspunde cu 200

Rewrite-ul de shell înseamnă că /blog/orice-cale returnează HTTP 200 cu shell-ul — statusul real se află la un hop distanță, în API. Iată ce se întâmplă în această zonă de soft-404:

  • Când API-ul returnează 404 pentru un articol lipsă, SDK-ul randează o stare distinctă de „nu a fost găsit”, setează <meta name="robots" content="noindex">, golește canonical-ul și JSON-LD-ul, și declanșează un eveniment anulabil baas:notfound — apelează preventDefault() pe el ca să randezi propriul tău UI de 404 în loc.
  • Eșecurile de rețea și erorile de server sunt separate: SDK-ul declanșează baas:error cu {status} (0 înseamnă că fetch-ul însuși a eșuat) și afișează un mesaj de „temporar indisponibil”.
  • Dacă ai nevoie ca URL-urile necunoscute să răspundă cu un HTTP 404 real pentru crawlere, exact asta oferă căile de edge proxy și prerender static — statusul API-ului trece direct.

Aplicații cu rutare client-side (React, Vue, SvelteKit, …)

Scriptul se leagă (bind) când se execută, iar re-executarea lui (sau apelarea window.baasBlog.init()) se re-leagă idempotent: instanța anterioară e distrusă mai întâi, deci nu se acumulează niciodată listeneri. destroy() dezleagă listenerul de popstate, golește containerul și restaurează fiecare nod din <head> pe care SDK-ul l-a creat sau suprascris.

Într-o aplicație care schimbă rutele client-side, conectează-l la ciclul de viață al rutei de blog:

// Exemplu React — aceeași structură funcționează în hook-ul de mount al oricărui framework
useEffect(() => {
  if (window.baasBlog) {
    window.baasBlog.init();            // SDK deja încărcat: re-leagă la acest container
  } else {
    const s = document.createElement('script');
    s.src = 'https://api.dailysmith.com/v1/sdk/blog.js';
    s.async = true;
    document.body.appendChild(s);      // se execută și se leagă la load
  }
  return () => window.baasBlog && window.baasBlog.destroy();
}, []);

return <div data-baas-blog data-key="pk_YOUR_KEY"
            data-base-path="/blog" data-api="https://api.dailysmith.com" />;

Alternativă: navigare hard (full page load) către blog. Dacă linkurile tale către blog sunt tag-uri <a> simple care declanșează un page load complet (scoate ruta de blog din interceptarea de linkuri a routerului tău), fragmentul static funcționează așa cum e.

Încă o observație despre router: SDK-ul navighează cu history.pushState, lucru pe care routerele client-side nu îl pot observa. Declanșează baas:navigate după fiecare push, ca analytics-ul, breadcrumbs-urile sau managerii de scroll să se poată conecta la el (vezi Evenimente).

Dacă site-ul tău își gestionează propriul head

Sub calea de bază, SDK-ul deține document.title, meta-tagurile de descriere și og:*, link-ul canonical și JSON-LD-ul. Acesta e contractul — nu le mai gestiona și din routerul tău propriu cât timp un URL de blog e activ, altfel cele două sisteme se vor lupta între ele. SDK-ul marchează fiecare nod pe care îl creează cu un atribut data-baas, reține valoarea originală a oricărui nod-gazdă pe care îl suprascrie și pune totul înapoi la destroy().

Dacă site-ul tău are propriul strat de SEO, renunță în schimb: setează data-baas-head="false" pe container și aplică tu metadatele, din evenimentul baas:page, care poartă tot ce are nevoie head-ul.

Evenimente

Toate evenimentele sunt CustomEvent-uri care urcă (bubble) din container, deci poți asculta pe document:

EvenimentDetaliuNote
baas:page{path, kind, title, description, canonical, json_ld, locale, og_locale, hero_image_url}După fiecare randare reușită (kind e index sau post)
baas:notfound{path}Articol lipsă (API 404). Anulabil — preventDefault() și randează propriul tău 404
baas:error{status, path}Fetch eșuat; status: 0 înseamnă eroare de rețea. Anulabil
baas:navigate{path}După history.pushState — routerele nu îl pot vedea, acesta e hook-ul tău
document.addEventListener('baas:notfound', (e) => {
  e.preventDefault();
  renderMyOwn404();
});
document.addEventListener('baas:navigate', (e) => {
  analytics.pageview(e.detail.path);
});

Content-Security-Policy

Un site cu CSP strict are nevoie de originea API-ului în patru directive:

script-src  'self' https://api.dailysmith.com          # scriptul SDK-ului propriu-zis
connect-src 'self' https://api.dailysmith.com          # fetch-urile de conținut (fragment)
img-src     'self' data: https://api.dailysmith.com    # imaginile hero ale articolelor
style-src   'self' https://api.dailysmith.com 'unsafe-inline'

style-src are nevoie de originea API-ului pentru foaia de stil a conținutului bogat (încărcată ca <link>), iar 'unsafe-inline' doar dacă blogul tău are o paletă de temă — tema per-blog e injectată ca un singur element <style> inline, mic.

Ce face SDK-ul

  • Preia fragmente HTML randate server-side și le injectează în container (aria-busy e setat cât timp se încarcă).
  • Actualizează document.title, meta descrierea, tagurile Open Graph, link-ul canonical și JSON-LD-ul per pagină — marcate cu data-baas, restaurate la destroy().
  • Interceptează linkurile din interiorul blogului pentru navigare instantanee prin History API; back/forward funcționează cum te aștepți; baas:navigate se declanșează pentru routerul sau analytics-ul tău.
  • Încarcă o singură dată foaia de stil a componentelor de conținut bogat, ca un <link> cacheable (#baas-md2-csshttps://api.dailysmith.com/v1/sdk/md2.css) și injectează paleta de temă a blogului tău ca un <style> inline mic (#baas-theme-css), înlocuindu-l când se schimbă.

Site-uri statice și hosturi prerandate

Două lucruri contează când site-ul tău e prerandat sau complet static:

  • Regula de rewrite de la „Servește shell-ul” trebuie emisă de build-ul tău (un fișier _redirects commit-uit, un vercel.json în repo) — o regulă adăugată manual dintr-un dashboard dispare la următoarea schimbare a pipeline-ului de deploy.
  • Până rulează JavaScript-ul, fiecare URL de articol servește <head>-ul shell-ului prerandat — titlul și canonical-ul shell-ului, nu ale articolului. Crawlerele care execută JS primesc valorile corecte; pentru HTML garantat per URL, rulează CLI-ul de prerender la build — output-ul lui dublează și rolul de shell.

Verifică că funcționează

  1. Deschide indexul blogului

    Vizitează /blog pe site-ul tău. Lista de articole ar trebui să se randeze în interiorul chrome-ului paginii tale. În tab-ul network din devtools vei vedea o cerere către https://api.dailysmith.com/v1/render/pk_…/blog?format=fragment — acesta e și verificarea care funcționează pentru instalările SPA, unde script tag-ul e injectat la runtime și nu apare niciodată în HTML-ul servit.

  2. Intră într-un articol, apoi dă refresh

    URL-ul ar trebui să se schimbe în /blog/<slug>, titlul documentului ar trebui să se actualizeze — iar un hard refresh pe acel URL trebuie să randeze același articol. Dacă refresh-ul dă 404, revizitează „Servește shell-ul pentru fiecare URL de blog” mai sus.

  3. Verifică head-ul și starea de 404

    După ce deschizi un articol, head-ul documentului ar trebui să poarte titlul, meta descrierea, URL-ul canonical și un tag #baas-jsonld de script. Apoi vizitează /blog/definitely-not-a-post: ar trebui să vezi starea de „nu a fost găsit”, iar head-ul ar trebui să poarte <meta name="robots" content="noindex">.

SEO: combină-l cu livrare server-side

SDK-ul de unul singur randează după ce se încarcă JavaScript-ul. Crawlerele moderne execută JS, dar pentru SEO garantat la nivel de crawler, servește același conținut și static:

  • Edge proxy — o regulă de rewrite servește pagini SSR complete de pe domeniul tău; SDK-ul apoi face upgrade la navigare client-side. (Regula de proxy satisface și cerința de shell de mai sus, iar URL-urile necunoscute returnează 404-uri reale.)
  • Prerender static — generează fișiere HTML la deploy; paginile prerandate dublează și rolul de shell pentru fiecare URL de articol.
enro