<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>koryto.net</title>
  <subtitle>Blog o technologii, programowaniu i projektach</subtitle>
  <link href="https://koryto.net/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://koryto.net/" rel="alternate" type="text/html"/><updated>2026-03-28T00:00:00.000Z</updated>
  <id>https://koryto.net/</id>
  <author>
    <name>Dariusz Koryto</name>
  </author>
  <entry>
    <title>Architektura i implementacja bloga na Eleventy — od koncepcji do deploymentu</title>
    <link href="https://koryto.net/posts/jak-stworzylem-bloga/" rel="alternate" type="text/html"/>
    <published>2026-03-28T00:00:00.000Z</published>
    <updated>2026-03-28T00:00:00.000Z</updated>
    <id>https://koryto.net/posts/jak-stworzylem-bloga/</id>
    <summary type="html">Kompletny przewodnik techniczny budowy nowoczesnego bloga z użyciem Eleventy. Architektura projektu, konfiguracja środowiska, lokalny development i zdalny deployment na GitHub Pages.</summary>
    <content type="html"><![CDATA[<p>Ten artykuł dokumentuje kompletny proces budowy bloga opartego na <strong>Eleventy (11ty)</strong> — od decyzji architektonicznych, przez konfigurację środowiska developerskiego, aż po automatyzację deploymentu. Nie jest to tutorial krok-po-kroku, lecz techniczna dokumentacja decyzji projektowych z gotowymi do użycia fragmentami kodu.</p>
<h2>Dlaczego Eleventy?</h2>
<p>Przed wyborem technologii przeanalizowałem dostępne opcje w kategoriach kluczowych dla projektu długoterminowego:</p>
<table>
<thead>
<tr>
<th>Kryterium</th>
<th>WordPress</th>
<th>Gatsby/Next.js</th>
<th>Eleventy</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Złożoność</strong></td>
<td>Wysoka (PHP + baza)</td>
<td>Średnia (React + GraphQL)</td>
<td>Minimalna</td>
</tr>
<tr>
<td><strong>Wydajność</strong></td>
<td>Wymaga optymalizacji</td>
<td>Dobra (ale JS hydration)</td>
<td>Optymalna (czysty HTML)</td>
</tr>
<tr>
<td><strong>Bezpieczeństwo</strong></td>
<td>Wymaga aktualizacji</td>
<td>Zależy od konfiguracji</td>
<td>Maksymalne (statyczne pliki)</td>
</tr>
<tr>
<td><strong>Koszty hostingu</strong></td>
<td>Wymagany serwer PHP</td>
<td>CDN (darmowy)</td>
<td>CDN (darmowy)</td>
</tr>
<tr>
<td><strong>Kontrola nad HTML</strong></td>
<td>Ograniczona</td>
<td>Średnia (abstrakcja React)</td>
<td>Całkowita</td>
</tr>
<tr>
<td><strong>Czas buildu</strong></td>
<td>N/A</td>
<td>30-120s (duże projekty)</td>
<td>&lt; 5s</td>
</tr>
</tbody>
</table>
<p>Eleventy wygrał ze względu na <strong>zero-abstrakcyjność</strong> — dostaję dokładnie ten HTML, który napiszę, bez narzutu frameworka. To fundamentalne dla:</p>
<ul>
<li>Optymalizacji SEO (pełna kontrola nad strukturą)</li>
<li>Czasu ładowania (brak JavaScriptu do hydracji)</li>
<li>Długowieczności projektu (niezależność od trendów frontendowych)</li>
</ul>
<h2>Architektura projektu</h2>
<p>Zastosowałem podejście <strong>folder-per-feature</strong> z separacją odpowiedzialności:</p>
<pre><code>project-root/
├── src/                          # Źródła (input dla 11ty)
│   ├── _data/                    # Globalny stan aplikacji
│   │   └── site.json             # Konfiguracja domeny, autora, SEO
│   ├── _includes/                # Komponenty wielokrotnego użytku
│   │   ├── layouts/              # Layouty stron
│   │   │   ├── base.njk          # Layout główny z pełnym SEO
│   │   │   └── post.njk          # Layout artykułu
│   │   └── partials/             # Częściowe szablony
│   │       ├── header.njk
│   │       ├── footer.njk
│   │       └── breadcrumbs.njk
│   ├── assets/                   # Zasoby statyczne (kopiowane 1:1)
│   │   ├── css/
│   │   ├── js/
│   │   └── images/
│   ├── posts/                    # Treść artykułów
│   │   └── [slug]/               # Folder na wpis + jego zasoby
│   │       ├── index.md
│   │       └── images/
│   ├── index.njk                 # Strona główna
│   ├── blog.njk                  # Archiwum wpisów
│   ├── o-mnie.md                 # Strona statyczna
│   └── 404.md                    # Strona błędu
├── _site/                        # Output (generowany, gitignored)
├── .github/
│   └── workflows/
│       └── deploy.yml            # CI/CD pipeline
├── eleventy.config.js            # Konfiguracja builda
├── package.json
└── .gitignore
</code></pre>
<h3>Dlaczego taka struktura?</h3>
<p><strong><code>_data/site.json</code></strong> — centralna konfiguracja eliminująca magiczne stringi z szablonów. Zmiana domeny wymaga edycji jednego pliku.</p>
<p><strong><code>_includes/layouts/</code> vs <code>_includes/partials/</code></strong> — rozdzielenie layoutów (pełne strony) od partials (komponenty). Layouty używają dziedziczenia, partials są includowane.</p>
<p><strong><code>posts/[slug]/index.md</code></strong> — każdy wpis w osobnym folderze umożliwia:</p>
<ul>
<li>Kolokację treści i zasobów (obrazy obok markdown)</li>
<li>Przenoszenie wpisów jako atomowych jednostek</li>
<li>Łatwe zarządzanie permalinkami (<code>/posts/nazwa/</code> zamiast <code>/posts/nazwa.html</code>)</li>
</ul>
<h2>Konfiguracja środowiska lokalnego</h2>
<h3>Wymagania systemowe</h3>
<ul>
<li><strong>Node.js</strong> w wersji LTS (obecnie 20.x) — sprawdź <code>node --version</code></li>
<li><strong>npm</strong> lub <strong>yarn</strong> — do zarządzania zależnościami</li>
<li><strong>Git</strong> — do kontroli wersji</li>
<li><strong>Edytor kodu</strong> z obsługą Nunjucks (VS Code + rozszerzenie &quot;Nunjucks Template&quot;)</li>
</ul>
<h3>Inicjalizacja projektu</h3>
<pre><code class="language-bash"># 1. Utworzenie katalogu projektu
mkdir moj-blog &amp;&amp; cd moj-blog

# 2. Inicjalizacja repozytorium git
git init

# 3. Inicjalizacja projektu Node.js
npm init -y

# 4. Instalacja Eleventy
npm install @11ty/eleventy --save-dev

# 5. Instalacja dodatkowych zależności (opcjonalne)
npm install html-minifier --save-dev  # Minifikacja w produkcji
npm install luxon --save-dev          # Zaawansowana obsługa dat
</code></pre>
<h3>Konfiguracja 11ty (<code>eleventy.config.js</code>)</h3>
<p>Plik konfiguracyjny definiuje transformacje, kolekcje i filtry:</p>
<pre><code class="language-javascript">const { DateTime } = require(&quot;luxon&quot;);

module.exports = function(eleventyConfig) {
  // ═══════════════════════════════════════════════════
  // PASSTHROUGH COPY — pliki kopiowane bez zmian
  // ═══════════════════════════════════════════════════
  eleventyConfig.addPassthroughCopy(&quot;src/assets/css&quot;);
  eleventyConfig.addPassthroughCopy(&quot;src/assets/js&quot;);
  eleventyConfig.addPassthroughCopy(&quot;src/assets/images&quot;);
  eleventyConfig.addPassthroughCopy(&quot;src/favicon.ico&quot;);

  // ═══════════════════════════════════════════════════
  // KOLEKCJE — grupowanie treści
  // ═══════════════════════════════════════════════════
  eleventyConfig.addCollection(&quot;posts&quot;, function(collectionApi) {
    return collectionApi
      .getFilteredByGlob(&quot;src/posts/**/*.md&quot;)
      .sort((a, b) =&gt; b.date - a.date); // Sortowanie od najnowszych
  });

  // ═══════════════════════════════════════════════════
  // FILTRY — przetwarzanie danych w szablonach
  // ═══════════════════════════════════════════════════
  
  // Formatowanie daty dla czytelnika (np. &quot;28 marca 2026&quot;)
  eleventyConfig.addFilter(&quot;dateDisplay&quot;, (dateObj) =&gt; {
    return DateTime.fromJSDate(dateObj, { zone: 'utc' })
      .setLocale('pl')
      .toFormat('d MMMM yyyy');
  });

  // Formatowanie ISO dla meta tagów i JSON-LD
  eleventyConfig.addFilter(&quot;isoDate&quot;, (dateObj) =&gt; {
    return DateTime.fromJSDate(dateObj, { zone: 'utc' }).toISO();
  });

  // Szacowanie czasu czytania (200 słów/min)
  eleventyConfig.addFilter(&quot;readingTime&quot;, (content) =&gt; {
    const wordsPerMinute = 200;
    const wordCount = content.split(/\s+/).length;
    return Math.ceil(wordCount / wordsPerMinute);
  });

  // Skracanie tekstu dla meta description
  eleventyConfig.addFilter(&quot;truncate&quot;, (text, length = 160) =&gt; {
    if (!text || text.length &lt;= length) return text;
    return text.substring(0, length).replace(/\s+\S*$/, '') + '...';
  });

  // ═══════════════════════════════════════════════════
  // TRANSFORMACJE — modyfikacja wygenerowanego HTML
  // ═══════════════════════════════════════════════════
  
  // Lazy loading dla obrazków
  eleventyConfig.addTransform(&quot;lazyImages&quot;, function(content, outputPath) {
    if (!outputPath || !outputPath.endsWith(&quot;.html&quot;)) return content;
    return content.replace(
      /&lt;img(?![^&gt;]*loading=)([^&gt;]*)&gt;/gi,
      '&lt;img$1 loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;'
    );
  });

  // Minifikacja HTML w produkcji
  if (process.env.NODE_ENV === 'production') {
    const htmlmin = require(&quot;html-minifier&quot;);
    eleventyConfig.addTransform(&quot;htmlmin&quot;, function(content, outputPath) {
      if (!outputPath || !outputPath.endsWith(&quot;.html&quot;)) return content;
      return htmlmin.minify(content, {
        useShortDoctype: true,
        removeComments: true,
        collapseWhitespace: true,
        minifyCSS: true,
        minifyJS: true
      });
    });
  }

  // ═══════════════════════════════════════════════════
  // KONFIGURACJA KATALOGÓW
  // ═══════════════════════════════════════════════════
  return {
    dir: {
      input: &quot;src&quot;,           // Katalog źródłowy
      output: &quot;_site&quot;,        // Katalog wyjściowy (gitignored)
      includes: &quot;_includes&quot;,  // Ścieżka względem input
      data: &quot;_data&quot;           // Ścieżka względem input
    },
    templateFormats: [&quot;md&quot;, &quot;njk&quot;, &quot;html&quot;],
    markdownTemplateEngine: &quot;njk&quot;,  // Nunjucks w Markdown
    pathPrefix: &quot;/&quot;  // Dla GitHub Pages: &quot;/nazwa-repo/&quot;
  };
};
</code></pre>
<h3>Skrypty w <code>package.json</code></h3>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;moj-blog&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;eleventy --serve --watch&quot;,
    &quot;build&quot;: &quot;eleventy&quot;,
    &quot;build:prod&quot;: &quot;NODE_ENV=production eleventy&quot;,
    &quot;clean&quot;: &quot;rm -rf _site&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@11ty/eleventy&quot;: &quot;^3.0.0&quot;,
    &quot;html-minifier&quot;: &quot;^4.5.0&quot;,
    &quot;luxon&quot;: &quot;^3.4.0&quot;
  }
}
</code></pre>
<h2>Lokalny development</h2>
<h3>Uruchomienie serwera deweloperskiego</h3>
<pre><code class="language-bash"># Development z hot-reload
npm start

# Lub bezpośrednio
npx eleventy --serve --watch
</code></pre>
<p>Serwer deweloperski dostępny pod <code>http://localhost:8080</code>. Flagi:</p>
<ul>
<li><code>--serve</code> — uruchamia lokalny serwer HTTP</li>
<li><code>--watch</code> — obserwuje zmiany w plikach i przebudowuje automatycznie</li>
</ul>
<h3>Workflow podczas pisania artykułu</h3>
<pre><code class="language-bash"># 1. Utwórz folder dla nowego wpisu
mkdir -p src/posts/moj-nowy-wpis

# 2. Utwórz plik z frontmatter
cat &gt; src/posts/moj-nowy-wpis/index.md &lt;&lt; 'EOF'
---
title: Tytuł artykułu
description: Krótki opis dla SEO
date: 2026-03-28
tags:
  - 11ty
  - tutorial
---

Treść artykułu w Markdown...
EOF

# 3. Serwer automatycznie przebuduje i odświeży stronę
</code></pre>
<h3>Debugowanie i inspekcja</h3>
<p>Sprawdź wygenerowany kod w katalogu <code>_site/</code>:</p>
<ul>
<li><code>_site/index.html</code> — strona główna</li>
<li><code>_site/posts/nazwa-wpisu/index.html</code> — pojedynczy artykuł</li>
<li><code>_site/sitemap.xml</code> — mapa witryny</li>
</ul>
<h2>System szablonów Nunjucks</h2>
<h3>Layout bazowy (<code>base.njk</code>)</h3>
<p>Layout to szablon, który otacza treść. Używa dziedziczenia (dziecko rozszerza rodzica):</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;pl&quot; dir=&quot;ltr&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  
  {# Zmienne SEO z hierarchią: frontmatter &gt; site.json &gt; defaults #}
  {% set pageTitle = title | default(site.title) %}
  {% set pageDesc = description | default(site.description) | truncate(160) %}
  
  &lt;title&gt;{% if title %}{{ title }} | {% endif %}{{ site.title }}&lt;/title&gt;
  &lt;meta name=&quot;description&quot; content=&quot;{{ pageDesc }}&quot;&gt;
  
  {# Preconnect dla wydajności #}
  &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.googleapis.com&quot;&gt;
  &lt;link rel=&quot;dns-prefetch&quot; href=&quot;https://fonts.gstatic.com&quot;&gt;
  
  {# Style #}
  &lt;link rel=&quot;stylesheet&quot; href=&quot;{{ '/assets/css/main.css' | url }}&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
  {% include &quot;partials/header.njk&quot; %}
  
  &lt;main id=&quot;main-content&quot;&gt;
    {{ content | safe }}
  &lt;/main&gt;
  
  {% include &quot;partials/footer.njk&quot; %}
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3>Layout artykułu (<code>post.njk</code>)</h3>
<p>Rozszerza layout bazowy i dodaje specyficzne dla artykułu elementy:</p>
<pre><code class="language-html">---
layout: layouts/base.njk
---

&lt;article class=&quot;post&quot;&gt;
  &lt;header class=&quot;post-header&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;div class=&quot;post-meta&quot;&gt;
        &lt;time datetime=&quot;{{ date | isoDate }}&quot;&gt;
          {{ date | dateDisplay }}
        &lt;/time&gt;
        &lt;span class=&quot;reading-time&quot;&gt;
          {{ content | readingTime }} min czytania
        &lt;/span&gt;
      &lt;/div&gt;
      &lt;h1 class=&quot;post-title&quot;&gt;{{ title }}&lt;/h1&gt;
      {% if description %}
      &lt;p class=&quot;post-description&quot;&gt;{{ description }}&lt;/p&gt;
      {% endif %}
    &lt;/div&gt;
  &lt;/header&gt;
  
  &lt;div class=&quot;post-content&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      {{ content | safe }}
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/article&gt;
</code></pre>
<h3>Składnia Nunjucks — kluczowe elementy</h3>
<pre><code class="language-html">{# Komentarz (nie pojawia się w HTML) #}

{# Wydruk zmiennej #}
{{ zmienna }}

{# Filtry (przetwarzanie potokowe) #}
{{ tekst | truncate(100) | upper }}

{# Logika warunkowa #}
{% if warunek %}
  &lt;p&gt;Prawda&lt;/p&gt;
{% elif inny_warunek %}
  &lt;p&gt;Alternatywa&lt;/p&gt;
{% else %}
  &lt;p&gt;Fałsz&lt;/p&gt;
{% endif %}

{# Pętla #}
{% for post in collections.posts %}
  &lt;article&gt;
    &lt;h2&gt;&lt;a href=&quot;{{ post.url }}&quot;&gt;{{ post.data.title }}&lt;/a&gt;&lt;/h2&gt;
  &lt;/article&gt;
{% endfor %}

{# Include (wstawianie partiali) #}
{% include &quot;partials/header.njk&quot; %}

{# Rozszerzanie layoutu #}
{% extends &quot;layouts/base.njk&quot; %}
{% block content %}
  &lt;p&gt;Treść bloku&lt;/p&gt;
{% endblock %}
</code></pre>
<h2>Zdalny deployment na GitHub Pages</h2>
<h3>Strategia CI/CD</h3>
<p>Zastosowałem podejście <strong>GitOps</strong> — repozytorium jest jedynym źródłem prawdy, a deployment jest efektem ubocznym pusha:</p>
<pre><code>Local: git push origin main
              ↓
GitHub: trigger workflow (on: push)
              ↓
Actions: checkout → setup-node → npm ci → npm run build
              ↓
Deploy: artifact ./_site → deploy to gh-pages branch
              ↓
GitHub Pages: serve static files via CDN
</code></pre>
<h3>Konfiguracja repozytorium</h3>
<ol>
<li>
<p><strong>Utwórz repozytorium</strong> na GitHub (np. <code>username.github.io</code> dla głównej strony lub <code>nazwa-repo</code> dla subścieżki)</p>
</li>
<li>
<p><strong>Dodaj <code>.gitignore</code></strong>:</p>
</li>
</ol>
<pre><code class="language-gitignore"># Dependencies
node_modules/
package-lock.json

# Build output
_site/

# Environment
.env
.env.local

# Editor
.vscode/
.idea/
*.swp
</code></pre>
<ol start="3">
<li><strong>Włącz GitHub Pages</strong> w ustawieniach repozytorium:
<ul>
<li>Settings → Pages → Source: &quot;Deploy from a branch&quot;</li>
<li>Branch: <code>gh-pages</code> / <code>root</code></li>
</ul>
</li>
</ol>
<h3>Workflow GitHub Actions</h3>
<p>Plik <code>.github/workflows/deploy.yml</code>:</p>
<pre><code class="language-yaml">name: Deploy to GitHub Pages

on:
  push:
    branches: [main, master]
  workflow_dispatch:  # Ręczne uruchomienie z UI

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: &quot;pages&quot;
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build site
        run: npm run build
        env:
          NODE_ENV: production

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./_site

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: $
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
</code></pre>
<h3>Konfiguracja dla subścieżki (pathPrefix)</h3>
<p>Jeśli repozytorium nie nazywa się <code>username.github.io</code>, strona będzie dostępna pod <code>username.github.io/nazwa-repo/</code>. Wymaga to modyfikacji:</p>
<pre><code class="language-javascript">// eleventy.config.js
return {
  pathPrefix: &quot;/nazwa-repo/&quot;,  // Ważne: prowadzący i kończący slash
  // ...
};
</code></pre>
<p>W szablonach używaj filtra <code>url</code>:</p>
<pre><code class="language-html">&lt;!-- Zawsze generuje poprawną ścieżkę --&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;/assets/css/main.css&quot;&gt;

&lt;!-- Dla subścieżki wygeneruje: /nazwa-repo/assets/css/main.css --&gt;
</code></pre>
<h3>Weryfikacja deploymentu</h3>
<p>Po każdym pushu sprawdź:</p>
<ol>
<li><strong>Status workflow</strong>: GitHub → Actions → wybierz workflow → sprawdź logi</li>
<li><strong>Dostępność</strong>: Otwórz <code>https://username.github.io/nazwa-repo/</code></li>
<li><strong>Konsola przeglądarki</strong>: Brak błędów 404 dla zasobów</li>
<li><strong>Sieć</strong>: Wszystkie zasoby ładują się poprawnie</li>
</ol>
<h3>Rozwiązywanie problemów</h3>
<p><strong>Błąd 404 dla zasobów CSS/JS</strong></p>
<ul>
<li>Sprawdź czy używasz filtra <code>| url</code> we wszystkich ścieżkach</li>
<li>Zweryfikuj <code>pathPrefix</code> w konfiguracji</li>
</ul>
<p><strong>Zmiany nie pojawiają się</strong></p>
<ul>
<li>GitHub Pages cache — odczekaj 2-5 minut</li>
<li>Sprawdź czy workflow zakończył się sukcesem</li>
</ul>
<p><strong>Błędy w buildzie</strong></p>
<ul>
<li>Lokalnie uruchom <code>NODE_ENV=production npm run build</code></li>
<li>Sprawdź logi w GitHub Actions</li>
</ul>
<h2>Podsumowanie architektoniczne</h2>
<p>Kluczowe decyzje projektowe:</p>
<ol>
<li><strong>SSG zamiast CMS</strong> — maksymalna kontrola, minimalna złożoność, zero kosztów hostingu</li>
<li><strong>Folder-per-post</strong> — kolokacja treści i zasobów ułatwia zarządzanie</li>
<li><strong>Nunjucks zamiast React</strong> — czysty HTML bez runtime overhead</li>
<li><strong>GitHub Actions</strong> — automatyczny deployment bez konfiguracji serwera</li>
<li><strong>Path prefix</strong> — projekt gotowy do deploy na GitHub Pages od pierwszego commita</li>
</ol>
<p>Następny krok: <a href="/posts/seo-w-11ty-kompletny-przewodnik/">optymalizacja SEO dla Eleventy</a></p>
]]></content>
    
    
    
    
    
    <category term="11ty"/>
    
    
    
    <category term="tutorial"/>
    
    
    
    <category term="architektura"/>
    
    
    
  </entry>
  <entry>
    <title>Witaj na moim blogu!</title>
    <link href="https://koryto.net/posts/pierwszy-wpis/" rel="alternate" type="text/html"/>
    <published>2026-03-29T00:00:00.000Z</published>
    <updated>2026-03-29T00:00:00.000Z</updated>
    <id>https://koryto.net/posts/pierwszy-wpis/</id>
    <summary type="html">Pierwszy wpis na nowym blogu o technologii i programowaniu</summary>
    <content type="html"><![CDATA[<p>To jest pierwszy wpis na moim nowym blogu! 🎉</p>
<h2>Dlaczego zaczynam pisać?</h2>
<p>Postanowiłem stworzyć to miejsce, aby dokumentować moją naukę, dzielić się przydatnymi rozwiązaniami oraz tworzyć portfolio moich projektów. Wierzę, że nauka przez nauczanie jest jedną z najskuteczniejszych metod nauki.</p>
<h2>Czego możesz się spodziewać?</h2>
<p>Na tym blogu będę pisał o:</p>
<ul>
<li><strong>Programowaniu</strong> – JavaScript, TypeScript, Node.js, Pythonaaaaaa</li>
<li><strong>Narzędziach deweloperskich</strong> – Git, Docker, systemy CI/CD</li>
<li><strong>Projektach open source</strong> – moje własne projekty i przydatne biblioteki</li>
<li><strong>Best practices</strong> – wzorce projektowe, testowanie, architektura aplikacji</li>
</ul>
<h2>Technologia</h2>
<p>Ten blog został zbudowany przy użyciu <a href="https://www.11ty.dev/">11ty (Eleventy)</a> – statycznego generatora stron, który jest szybki, elastyczny i nie narzuca żadnego konkretnego frameworka frontendowego. Strona jest hostowana na GitHub Pages.</p>
<pre><code class="language-javascript">// Przykładowy kod w JavaScript
const greeting = &quot;Witaj świecie!&quot;;
console.log(greeting);
</code></pre>
<h2>Podsumowanie</h2>
<p>Zapraszam do regularnego odwiedzania bloga! Jeśli masz jakieś pytania lub sugestie, śmiało skontaktuj się ze mną przez GitHub.</p>
<p>Do zobaczenia w kolejnych wpisach! 👋</p>
]]></content>
    
    
    
    
    
    <category term="ogłoszenia"/>
    
    
    
  </entry>
  <entry>
    <title>Jak dodawać obrazki do artykułów - przykład</title>
    <link href="https://koryto.net/posts/jak-dodawac-obrazki/" rel="alternate" type="text/html"/>
    <published>2026-03-29T00:00:00.000Z</published>
    <updated>2026-03-29T00:00:00.000Z</updated>
    <id>https://koryto.net/posts/jak-dodawac-obrazki/</id>
    <summary type="html">Praktyczny przykład użycia obrazków w artykułach na blogu. Zobacz jak to działa!</summary>
    <content type="html"><![CDATA[<h1>Jak dodawać obrazki do artykułów - przykład</h1>
<p>Ten artykuł pokazuje jak używać obrazków w treści wpisów. Jest to przykład praktyczny - zobacz źródło tego pliku aby zobaczyć składnię.</p>
<h2>Podstawowa składnia</h2>
<p>Aby dodać obrazek, użyj następującej składni Markdown:</p>
<pre><code class="language-markdown">![Opis obrazka](/assets/images/posts/nazwa-pliku.jpg)
</code></pre>
<h2>Ważne zasady</h2>
<h3>1. Lokalizacja obrazków</h3>
<p>Wszystkie obrazki do artykułów wrzucamy do folderu:</p>
<pre><code>src/assets/images/posts/
</code></pre>
<h3>2. Formaty plików</h3>
<table>
<thead>
<tr>
<th>Format</th>
<th>Kiedy używać</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>WebP</strong></td>
<td>Najlepszy - używaj zawsze gdy możliwe</td>
</tr>
<tr>
<td><strong>JPG</strong></td>
<td>Zdjęcia, obrazy z wieloma kolorami</td>
</tr>
<tr>
<td><strong>PNG</strong></td>
<td>Zrzuty ekranu, grafiki z przezroczystością</td>
</tr>
<tr>
<td><strong>SVG</strong></td>
<td>Ikony, loga, proste grafiki wektorowe</td>
</tr>
</tbody>
</table>
<h3>3. Optymalizacja</h3>
<p>Przed dodaniem obrazka:</p>
<ul>
<li>Zmień rozmiar do <strong>max 1200px</strong> szerokości</li>
<li>Skonwertuj do WebP jeśli to możliwe</li>
<li>Upewnij się, że plik ma <strong>poniżej 500 KB</strong></li>
</ul>
<h2>Przykłady użycia</h2>
<h3>Obrazek z tytułem (tooltip)</h3>
<pre><code class="language-markdown">![Ekran startowy](url &quot;Tytuł pojawiający się po najechaniu&quot;)
</code></pre>
<h3>Obrazek jako link</h3>
<pre><code class="language-markdown">[![Miniaturka](url-miniatury)](url-pełnego-obrazka)
</code></pre>
<h2>Placeholdery (tymczasowe obrazki)</h2>
<p>Jeśli nie masz jeszcze własnych obrazków, możesz użyć placeholderów:</p>
<p><strong>via.placeholder.com:</strong></p>
<pre><code class="language-markdown">![Przykładowy obrazek](https://via.placeholder.com/800x400/6366f1/ffffff?text=Przykładowy+obrazek)
</code></pre>
<p><strong>picsum.photos (losowe zdjęcia):</strong></p>
<pre><code class="language-markdown">![Losowe zdjęcie](https://picsum.photos/800/400)
</code></pre>
<p><strong>placehold.co (z tekstem):</strong></p>
<pre><code class="language-markdown">![Obrazek z tekstem](https://placehold.co/600x400/1a1a1e/818cf8?text=Twój+tekst)
</code></pre>
<h2>SVG jako obrazki</h2>
<p>Możesz też tworzyć proste diagramy w SVG:</p>
<pre><code class="language-markdown">![Diagram](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjMWE0MDJlIi8+CiAgPHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0iIzgxOGNmOCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iPlByenkaxhhxWRvd3kgU1ZHPC90ZXh0Pgo8L3N2Zz4=)
</code></pre>
<h2>Galeria</h2>
<p>Aby stworzyć galerię, użyj HTML wewnątrz Markdown:</p>
<pre><code class="language-markdown">&lt;div style=&quot;display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem;&quot;&gt;

![Obrazek 1](url1)
![Obrazek 2](url2)

&lt;/div&gt;
</code></pre>
<h2>Checklista przed publikacją</h2>
<ul>
<li>[ ] Obrazek ma opisową nazwę pliku</li>
<li>[ ] Obrazek jest zoptymalizowany (rozmiar, format)</li>
<li>[ ] Dodano tekst alt (<code>![alt text]</code>) dla dostępności</li>
<li>[ ] Ścieżka jest poprawna (<code>/assets/images/posts/</code>)</li>
<li>[ ] Obrazek wyświetla się poprawnie lokalnie</li>
<li>[ ] Obrazek jest dodany do git (<code>git add</code>)</li>
</ul>
<h2>Więcej informacji</h2>
<p>Pełną dokumentację znajdziesz w pliku: <a href="https://github.com/dkoryto/koryto_net/blob/main/docs/JAK-DODAC-OBRAZKI.md">docs/JAK-DODAC-OBRAZKI.md</a></p>
<hr>
<p><strong>Podsumowanie:</strong></p>
<ol>
<li>Wrzuć obrazek do <code>src/assets/images/posts/</code></li>
<li>Użyj <code>![opis](/assets/images/posts/nazwa.jpg)</code> w artykule</li>
<li>Zoptymalizuj przed dodaniem</li>
<li>Zrób commit i push</li>
</ol>
<p>To wszystko! 🎉</p>
]]></content>
    
    
    
    
    
    <category term="tutorial"/>
    
    
    
    <category term="11ty"/>
    
    
    
    <category term="obrazki"/>
    
    
    
  </entry>
  <entry>
    <title>SEO w 11ty - kompletny przewodnik techniczny z wdrożeniem produkcyjnym</title>
    <link href="https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/" rel="alternate" type="text/html"/>
    <published>2026-03-30T00:00:00.000Z</published>
    <updated>2026-03-30T00:00:00.000Z</updated>
    <id>https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/</id>
    <summary type="html">Profesjonalny przewodnik po optymalizacji SEO dla statycznych stron generowanych przez Eleventy. Od fundamentów po zaawansowane techniki strukturalnych danych, Core Web Vitals i architektury informacji.</summary>
    <content type="html"><![CDATA[<p>SEO (Search Engine Optimization) to proces systematycznego dostosowywania strony internetowej do wymagań algorytmów wyszukiwarek. W kontekście statycznych generatorów stron, takich jak <strong>Eleventy (11ty)</strong>, uzyskujemy unikalną przewagę: pełną kontrolę nad generowanym kodem HTML bez narzutu frameworków JavaScriptowych.</p>
<p>Ten artykuł to kompletny przewodnik techniczny, który przeprowadzi Cię przez proces budowy bloga zoptymalizowanego pod kątem wyszukiwarek — od fundamentów architektonicznych po zaawansowane techniki implementacji.</p>
<h2>Dlaczego statyczna architektura ma znaczenie dla SEO?</h2>
<p>Przed przystąpieniem do implementacji, zrozummy fundamentalną przewagę architektury statycznej:</p>
<h3>Mechanizm działania algorytmów wyszukiwarek</h3>
<p>Wyszukiwarki internetowe, przede wszystkim Google, funkcjonują w oparciu o <strong>crawling</strong> (przeglądanie stron) i <strong>indexing</strong> (indeksowanie treści). Proces ten realizowany jest przez automatyczne roboty (boty/crawlery), które:</p>
<ol>
<li>Odwiedzają stronę i pobierają jej kod źródłowy</li>
<li>Analizują strukturę HTML, CSS i JavaScript</li>
<li>Ekstrahują treść, metadane i relacje między stronami</li>
<li>Przechowują dane w indeksie wyszukiwarki</li>
<li>Klasyfikują stronę pod kątem zapytań użytkowników</li>
</ol>
<h3>Problemy z CSR (Client-Side Rendering)</h3>
<p>Tradycyjne aplikacje SPA (Single Page Application), takie jak te zbudowane na React, Vue czy Angular, generują treść dynamicznie w przeglądarce użytkownika. To stwarza fundamentalne wyzwanie:</p>
<ul>
<li>Bot może otrzymać pusty lub częściowy HTML</li>
<li>Wymagane jest renderowanie JavaScriptu (JavaScript Rendering), które zużywa zasoby Googlebot</li>
<li>Opóźnienia w indeksowaniu nowych treści</li>
<li>Potencjalne błędy przy skomplikowanym kodzie JS</li>
</ul>
<h3>Przewaga SSG (Static Site Generation)</h3>
<p>Eleventy generuje <strong>czysty, statyczny HTML</strong> w fazie builda:</p>
<table>
<thead>
<tr>
<th>Aspekt</th>
<th>Aplikacja SPA</th>
<th>Strona statyczna (11ty)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Czas do pierwszego bajta (TTFB)</strong></td>
<td>Średni-wysoki (serwer + render)</td>
<td>Minimalny (CDN)</td>
</tr>
<tr>
<td><strong>Widoczność dla crawlera</strong></td>
<td>Wymaga JS</td>
<td>Pełna treść w HTML</td>
</tr>
<tr>
<td><strong>Zużycie zasobów Google</strong></td>
<td>Wysokie (rendering JS)</td>
<td>Minimalne</td>
</tr>
<tr>
<td><strong>Szybkość indeksowania</strong></td>
<td>Opóźniona</td>
<td>Natychmiastowa</td>
</tr>
<tr>
<td><strong>Core Web Vitals</strong></td>
<td>Wymagają optymalizacji</td>
<td>Optymalne domyślnie</td>
</tr>
</tbody>
</table>
<h2>Architektura informacji i struktura projektu</h2>
<p>Zanim przejdziemy do kodu, zaprojektujmy strukturę projektu zoptymalizowaną pod kątem SEO i utrzymania:</p>
<pre><code>src/
├── _data/
│   └── site.json              # Centralna konfiguracja domeny
├── _includes/
│   ├── layouts/
│   │   ├── base.njk           # Layout główny z kompletnym SEO
│   │   └── post.njk           # Layout dla artykułów
│   └── partials/
│       ├── head-seo.njk       # Izolowane komponenty SEO
│       ├── breadcrumbs.njk    # Nawigacja okruszkowa
│       └── schema-org.njk     # Strukturalne dane
├── assets/
│   ├── css/                   # Krytyczne CSS inline, reszta async
│   ├── js/                    # Minimalny JS, defer/async
│   └── images/                # WebP z fallbackiem
├── posts/                     # Treść: frontmatter + markdown
│   └── [slug]/
│       └── index.md           # Wpis z własnym folderem na obrazy
├── sitemap.xml.njk            # Dynamiczna mapa witryny
├── robots.txt.njk             # Instrukcje dla robotów
├── manifest.json.njk          # PWA i ikony systemowe
├── feed.xml.njk               # Atom/RSS dla subskrypcji
└── opensearch.xml.njk         # Wyszukiwarka w pasku adresu
</code></pre>
<h3>Dlaczego ten układ jest optymalny?</h3>
<ul>
<li><strong>Separacja odpowiedzialności</strong>: SEO w osobnych partials, łatwe do modyfikacji</li>
<li><strong>Organizacja treści</strong>: Każdy wpis w osobnym folderze ułatwia zarządzanie zasobami</li>
<li><strong>Automatyzacja</strong>: Pliki <code>.njk</code> z <code>permalink</code> generują pliki statyczne automatycznie</li>
<li><strong>Skalowalność</strong>: Struktura działa dla 10, 100 i 1000 wpisów</li>
</ul>
<h2>1. System zarządzania metadanymi</h2>
<h3>Fundamentalne znaczenie meta tagów</h3>
<p>Meta tagi to dane o danych — informacje, które nie są widoczne bezpośrednio na stronie, ale są fundamentalne dla:</p>
<ul>
<li><strong>Wyszukiwarek</strong>: <code>description</code> wpływa na CTR (Click-Through Rate) w SERP</li>
<li><strong>Mediów społecznościowych</strong>: Open Graph kontroluje wygląd udostępnień</li>
<li><strong>Platform wiadomości</strong>: Twitter Cards, LinkedIn rich previews</li>
<li><strong>Przeglądarek</strong>: <code>viewport</code>, <code>theme-color</code>, <code>canonical</code></li>
</ul>
<h3>Implementacja systemu zmiennych SEO</h3>
<p>W pliku <code>src/_includes/layouts/base.njk</code> implementujemy hierarchiczną logikę metadanych:</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;pl&quot; dir=&quot;ltr&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
  
  
  &lt;title&gt;SEO w 11ty - kompletny przewodnik techniczny z wdrożeniem produkcyjnym | koryto.net&lt;/title&gt;
  
  
  &lt;meta name=&quot;description&quot; content=&quot;Profesjonalny przewodnik po optymalizacji SEO dla statycznych stron generowanych przez Eleventy. Od fundamentów po zaawansowane techniki strukturalnych...&quot;&gt;
  &lt;meta name=&quot;keywords&quot; content=&quot;posts, 11ty, seo, tutorial, optymalizacja&quot;&gt;
  &lt;meta name=&quot;author&quot; content=&quot;&quot;&gt;
  &lt;meta name=&quot;copyright&quot; content=&quot;&quot;&gt;
  &lt;meta name=&quot;robots&quot; content=&quot;index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1&quot;&gt;
  
  
  &lt;link rel=&quot;canonical&quot; href=&quot;https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/&quot;&gt;
  
  
  &lt;link rel=&quot;alternate&quot; hreflang=&quot;pl&quot; href=&quot;https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/&quot;&gt;
  &lt;link rel=&quot;alternate&quot; hreflang=&quot;x-default&quot; href=&quot;https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/&quot;&gt;
  
  
  &lt;meta property=&quot;og:site_name&quot; content=&quot;koryto.net&quot;&gt;
  &lt;meta property=&quot;og:title&quot; content=&quot;SEO w 11ty - kompletny przewodnik techniczny z wdrożeniem produkcyjnym&quot;&gt;
  &lt;meta property=&quot;og:description&quot; content=&quot;Profesjonalny przewodnik po optymalizacji SEO dla statycznych stron generowanych przez Eleventy. Od fundamentów po zaawansowane techniki strukturalnych...&quot;&gt;
  &lt;meta property=&quot;og:type&quot; content=&quot;article&quot;&gt;
  &lt;meta property=&quot;og:url&quot; content=&quot;https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/&quot;&gt;
  &lt;meta property=&quot;og:image&quot; content=&quot;https://koryto.net/assets/images/og-default.png&quot;&gt;
  &lt;meta property=&quot;og:image:width&quot; content=&quot;1200&quot;&gt;
  &lt;meta property=&quot;og:image:height&quot; content=&quot;630&quot;&gt;
  &lt;meta property=&quot;og:image:alt&quot; content=&quot;SEO w 11ty - kompletny przewodnik techniczny z wdrożeniem produkcyjnym&quot;&gt;
  &lt;meta property=&quot;og:locale&quot; content=&quot;pl_PL&quot;&gt;
  
  
  &lt;meta name=&quot;twitter:card&quot; content=&quot;summary_large_image&quot;&gt;
  &lt;meta name=&quot;twitter:site&quot; content=&quot;&quot;&gt;
  &lt;meta name=&quot;twitter:creator&quot; content=&quot;&quot;&gt;
  &lt;meta name=&quot;twitter:title&quot; content=&quot;SEO w 11ty - kompletny przewodnik techniczny z wdrożeniem produkcyjnym&quot;&gt;
  &lt;meta name=&quot;twitter:description&quot; content=&quot;Profesjonalny przewodnik po optymalizacji SEO dla statycznych stron generowanych przez Eleventy. Od fundamentów po zaawansowane techniki strukturalnych...&quot;&gt;
  &lt;meta name=&quot;twitter:image&quot; content=&quot;https://koryto.net/assets/images/og-default.png&quot;&gt;
  
  
  &lt;link rel=&quot;manifest&quot; href=&quot;/manifest.json&quot;&gt;
  &lt;meta name=&quot;theme-color&quot; content=&quot;#6366f1&quot;&gt;
  &lt;link rel=&quot;apple-touch-icon&quot; href=&quot;/assets/icons/apple-touch-icon.png&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
  
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3>Konfiguracja globalna (site.json)</h3>
<p>Plik <code>src/_data/site.json</code> stanowi centralne źródło prawdy:</p>
<pre><code class="language-json">{
  &quot;title&quot;: &quot;koryto.net&quot;,
  &quot;tagline&quot;: &quot;Blog o technologii, programowaniu i architekturze oprogramowania&quot;,
  &quot;description&quot;: &quot;Praktyczne artykuły o web development, JavaScript, Node.js i optymalizacji wydajności. Od fundamentów po zaawansowane wzorce projektowe.&quot;,
  &quot;url&quot;: &quot;https://dkoryto.github.io/koryto_net&quot;,
  &quot;buildDate&quot;: &quot;2026-03-30&quot;,
  &quot;defaultKeywords&quot;: &quot;blog, technologia, programowanie, web development, javascript&quot;,
  &quot;author&quot;: {
    &quot;name&quot;: &quot;Dariusz Koryto&quot;,
    &quot;email&quot;: &quot;dariusz@example.com&quot;,
    &quot;jobTitle&quot;: &quot;Software Engineer&quot;,
    &quot;url&quot;: &quot;https://github.com/dkoryto&quot;
  },
  &quot;social&quot;: {
    &quot;twitter&quot;: &quot;@dkoryto&quot;,
    &quot;github&quot;: &quot;https://github.com/dkoryto&quot;,
    &quot;linkedin&quot;: &quot;https://linkedin.com/in/dkoryto&quot;
  },
  &quot;organization&quot;: {
    &quot;name&quot;: &quot;koryto.net&quot;,
    &quot;logo&quot;: &quot;https://dkoryto.github.io/koryto_net/assets/images/logo.png&quot;
  }
}
</code></pre>
<h3>Dlaczego te metadane są kluczowe?</h3>
<p><strong>Meta Description (155-160 znaków)</strong>
Nie wpływa bezpośrednio na ranking, ale fundamentalnie na CTR. Dobrze napisany opis może zwiększyć klikalność o 5-15%.</p>
<p><strong>Canonical URL</strong>
Eliminuje problem duplikatów treści (duplicate content), który może rozpraszać &quot;moc SEO&quot; między wieloma URL-ami tej samej treści.</p>
<p><strong>Open Graph Image (1200×630px)</strong>
To standardowy format dla Facebooka, LinkedIn i innych platform. Obrazy z tekstem nakładanym zwiększają zaangażowanie o 30-80%.</p>
<h2>2. Strukturalne dane Schema.org (JSON-LD)</h2>
<h3>Czym są strukturalne dane?</h3>
<p>Strukturalne dane to ustandaryzowany format (JSON-LD) opisu zawartości strony, który pozwala wyszukiwarkom nie tylko indeksować treść, ale <strong>rozumieć jej znaczenie semantyczne</strong>.
n
Implementacja strukturalnych danych umożliwia:</p>
<ul>
<li><strong>Rich Snippets</strong> — rozszerzone wyniki wyszukiwania (gwiazdki, ceny, daty)</li>
<li><strong>Knowledge Graph</strong> — panel wiedzy z boku wyników wyszukiwania</li>
<li><strong>Voice Search Optimization</strong> — odpowiedzi asystentów głosowych</li>
<li><strong>Breadcrumbs w SERP</strong> — ścieżka nawigacyjna pod wynikiem</li>
</ul>
<h3>Implementacja dla artykułów (BlogPosting)</h3>
<p>W pliku <code>src/_includes/partials/schema-org.njk</code>:</p>
<pre><code class="language-html">
&lt;script type=&quot;application/ld+json&quot;&gt;
{
  &quot;@context&quot;: &quot;https://schema.org&quot;,
  &quot;@type&quot;: &quot;BlogPosting&quot;,
  &quot;mainEntityOfPage&quot;: {
    &quot;@type&quot;: &quot;WebPage&quot;,
    &quot;@id&quot;: &quot;https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/&quot;
  },
  &quot;headline&quot;: &quot;SEO w 11ty - kompletny przewodnik techniczny z wdrożeniem produkcyjnym&quot;,
  &quot;description&quot;: &quot;Profesjonalny przewodnik po optymalizacji SEO dla statycznych stron generowanych przez Eleventy. Od fundamentów po zaawansowane techniki strukturalnych danych, Core Web Vitals i architektury informacji.&quot;,
  &quot;image&quot;: {
    &quot;@type&quot;: &quot;ImageObject&quot;,
    &quot;url&quot;: &quot;https://koryto.net/assets/images/og-default.png&quot;,
    &quot;width&quot;: 1200,
    &quot;height&quot;: 630
  },
  &quot;author&quot;: {
    &quot;@type&quot;: &quot;Person&quot;,
    &quot;name&quot;: &quot;&quot;,
    &quot;url&quot;: &quot;&quot;,
    &quot;jobTitle&quot;: &quot;&quot;
  },
  &quot;publisher&quot;: {
    &quot;@type&quot;: &quot;Organization&quot;,
    &quot;name&quot;: &quot;&quot;,
    &quot;logo&quot;: {
      &quot;@type&quot;: &quot;ImageObject&quot;,
      &quot;url&quot;: &quot;&quot;,
      &quot;width&quot;: 600,
      &quot;height&quot;: 60
    }
  },
  &quot;datePublished&quot;: &quot;2026-03-30T00:00:00.000Z&quot;,
  &quot;dateModified&quot;: &quot;2026-03-30T00:00:00.000Z&quot;,
  &quot;keywords&quot;: &quot;posts, 11ty, seo, tutorial, optymalizacja&quot;,
  &quot;articleSection&quot;: &quot;posts&quot;,
  &quot;inLanguage&quot;: &quot;pl-PL&quot;,
  &quot;isAccessibleForFree&quot;: true
}
&lt;/script&gt;

</code></pre>
<h3>Struktura WebSite z akcją wyszukiwania</h3>
<p>Implementacja &quot;Sitelinks Searchbox&quot; — wyszukiwarki bezpośrednio w wynikach Google:</p>
<pre><code class="language-html">&lt;script type=&quot;application/ld+json&quot;&gt;
{
  &quot;@context&quot;: &quot;https://schema.org&quot;,
  &quot;@type&quot;: &quot;WebSite&quot;,
  &quot;name&quot;: &quot;koryto.net&quot;,
  &quot;description&quot;: &quot;Blog o technologii, programowaniu i projektach&quot;,
  &quot;url&quot;: &quot;https://koryto.net&quot;,
  &quot;publisher&quot;: {
    &quot;@type&quot;: &quot;Organization&quot;,
    &quot;name&quot;: &quot;&quot;,
    &quot;logo&quot;: &quot;&quot;
  },
  &quot;potentialAction&quot;: {
    &quot;@type&quot;: &quot;SearchAction&quot;,
    &quot;target&quot;: {
      &quot;@type&quot;: &quot;EntryPoint&quot;,
      &quot;urlTemplate&quot;: &quot;https://koryto.net/search/?q={search_term_string}&quot;
    },
    &quot;query-input&quot;: &quot;required name=search_term_string&quot;
  },
  &quot;inLanguage&quot;: &quot;pl-PL&quot;
}
&lt;/script&gt;
</code></pre>
<h3>Breadcrumbs z mikrodanymi</h3>
<p>Nawigacja okruszkowa (breadcrumbs) poprawia UX i pozwala Google wyświetlić ścieżkę w wynikach wyszukiwania:</p>
<pre><code class="language-html">


  
  



&lt;nav aria-label=&quot;Nawigacja okruszkowa&quot;&gt;
  &lt;ol itemscope itemtype=&quot;https://schema.org/BreadcrumbList&quot;&gt;
    
    &lt;li itemprop=&quot;itemListElement&quot; itemscope itemtype=&quot;https://schema.org/ListItem&quot;&gt;
      
        &lt;a href=&quot;/&quot; itemprop=&quot;item&quot;&gt;
          &lt;span itemprop=&quot;name&quot;&gt;Strona główna&lt;/span&gt;
        &lt;/a&gt;
      
      &lt;meta itemprop=&quot;position&quot; content=&quot;1&quot;&gt;
    &lt;/li&gt;
    
    &lt;li itemprop=&quot;itemListElement&quot; itemscope itemtype=&quot;https://schema.org/ListItem&quot;&gt;
      
        &lt;a href=&quot;/blog/&quot; itemprop=&quot;item&quot;&gt;
          &lt;span itemprop=&quot;name&quot;&gt;Blog&lt;/span&gt;
        &lt;/a&gt;
      
      &lt;meta itemprop=&quot;position&quot; content=&quot;2&quot;&gt;
    &lt;/li&gt;
    
    &lt;li itemprop=&quot;itemListElement&quot; itemscope itemtype=&quot;https://schema.org/ListItem&quot;&gt;
      
        &lt;span itemprop=&quot;name&quot; aria-current=&quot;page&quot;&gt;SEO w 11ty - kompletny przewodnik techniczny z wdrożeniem produkcyjnym&lt;/span&gt;
      
      &lt;meta itemprop=&quot;position&quot; content=&quot;3&quot;&gt;
    &lt;/li&gt;
    
  &lt;/ol&gt;
&lt;/nav&gt;

</code></pre>
<h2>3. Mapa witryny i instrukcje dla robotów</h2>
<h3>Protokół Sitemaps</h3>
<p>XML Sitemap to plik informujący wyszukiwarki o strukturze witryny. Jest fundamentalny dla:</p>
<ul>
<li>Dużych witryn (&gt;500 stron)</li>
<li>Stron z izolowanymi stronami (osierocone)</li>
<li>Nowych witryn z małą liczbą linków zwrotnych</li>
<li>Stron z treścią multimedialną</li>
</ul>
<p>Implementacja <code>src/sitemap.xml.njk</code>:</p>
<pre><code class="language-xml">---
permalink: /sitemap.xml
layout: null
---
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;urlset xmlns=&quot;http://www.sitemaps.org/schemas/sitemap/0.9&quot;
        xmlns:image=&quot;http://www.google.com/schemas/sitemap-image/1.1&quot;
        xmlns:news=&quot;http://www.google.com/schemas/sitemap-news/0.9&quot;&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/posts/jak-stworzylem-bloga/&lt;/loc&gt;
    &lt;lastmod&gt;2026-03-28T00:00:00.000Z&lt;/lastmod&gt;
    &lt;changefreq&gt;weekly&lt;/changefreq&gt;
    &lt;priority&gt;0.8&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/posts/jak-dodawac-obrazki/&lt;/loc&gt;
    &lt;lastmod&gt;2026-03-29T00:00:00.000Z&lt;/lastmod&gt;
    &lt;changefreq&gt;weekly&lt;/changefreq&gt;
    &lt;priority&gt;0.8&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/posts/pierwszy-wpis/&lt;/loc&gt;
    &lt;lastmod&gt;2026-03-29T00:00:00.000Z&lt;/lastmod&gt;
    &lt;changefreq&gt;weekly&lt;/changefreq&gt;
    &lt;priority&gt;0.8&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/&lt;/loc&gt;
    &lt;lastmod&gt;2026-03-30T00:00:00.000Z&lt;/lastmod&gt;
    &lt;changefreq&gt;weekly&lt;/changefreq&gt;
    &lt;priority&gt;0.8&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/archiwum/&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.313Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/blog/&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.314Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/edytor/&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.314Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/feed.xml&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.314Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.314Z&lt;/lastmod&gt;
    &lt;changefreq&gt;daily&lt;/changefreq&gt;
    &lt;priority&gt;1.0&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/llms.txt&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.314Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/manifest.json&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.314Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/o-mnie/&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.314Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/robots.txt&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.316Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/search/&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.316Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
  &lt;url&gt;
    &lt;loc&gt;https://koryto.net/sitemap.xml&lt;/loc&gt;
    &lt;lastmod&gt;2026-04-06T16:01:41.316Z&lt;/lastmod&gt;
    &lt;changefreq&gt;monthly&lt;/changefreq&gt;
    &lt;priority&gt;0.5&lt;/priority&gt;
  &lt;/url&gt;
&lt;/urlset&gt;
</code></pre>
<h3>Robots.txt — protokół wykluczania robotów</h3>
<p>Plik <code>src/robots.txt.njk</code> kontroluje dostęp crawlerów:</p>
<pre><code class="language-txt">---
permalink: /robots.txt
layout: null
---
# Protocol: robots.txt
# Documentation: https://www.robotstxt.org/robotstxt.html

User-agent: *
Allow: /

# Optymalizacja crawl budget
Disallow: /tag/
Disallow: /404.html

# Sitemap location
Sitemap: https://koryto.net/sitemap.xml

# Host directive (opcjonalnie, dla Yandex)
Host: koryto.net
</code></pre>
<h3>Dlaczego wykluczamy /tag/?</h3>
<p>Strony tagów często generują <strong>thin content</strong> (treść niskiej jakości) lub duplikaty. Wykluczenie ich z indeksu:</p>
<ul>
<li>Koncentruje &quot;moc SEO&quot; na wartościowych stronach artykułów</li>
<li>Zapobiega kanibalizacji słów kluczowych</li>
<li>Optymalizuje crawl budget</li>
</ul>
<h2>4. Wydajność jako czynnik rankingowy (Core Web Vitals)</h2>
<p>Od czerwca 2021 Google oficjalnie uwzględnia <strong>Core Web Vitals</strong> jako czynnik rankingowy. To trzy metryki:</p>
<table>
<thead>
<tr>
<th>Metryka</th>
<th>Cel</th>
<th>Mierzy</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>LCP</strong> (Largest Contentful Paint)</td>
<td>&lt; 2.5s</td>
<td>Czas wyrenderowania największego elementu</td>
</tr>
<tr>
<td><strong>FID</strong> (First Input Delay)</td>
<td>&lt; 100ms</td>
<td>Responsywność na pierwszą interakcję</td>
</tr>
<tr>
<td><strong>CLS</strong> (Cumulative Layout Shift)</td>
<td>&lt; 0.1</td>
<td>Stabilność wizualną (przesunięcia layoutu)</td>
</tr>
</tbody>
</table>
<h3>Optymalizacja zasobów krytycznych</h3>
<p>W sekcji <code>&lt;head&gt;</code> implementujemy hierarchię ładowania:</p>
<pre><code class="language-html">
&lt;link rel=&quot;dns-prefetch&quot; href=&quot;https://fonts.googleapis.com&quot;&gt;
&lt;link rel=&quot;dns-prefetch&quot; href=&quot;https://unpkg.com&quot;&gt;


&lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.gstatic.com&quot; crossorigin&gt;
&lt;link rel=&quot;preconnect&quot; href=&quot;https://koryto.net&quot; crossorigin&gt;


&lt;link rel=&quot;preload&quot; href=&quot;/assets/css/critical.css&quot; as=&quot;style&quot;&gt;
&lt;link rel=&quot;preload&quot; href=&quot;/assets/fonts/inter-var.woff2&quot; as=&quot;font&quot; type=&quot;font/woff2&quot; crossorigin&gt;


&lt;style&gt;
  /* Krytyczne style: layout, typografia, kolory */
  :root{--bg:#0f0f11;--text:#e8e8ec;--font:sans-serif}
  *,*::before,*::after{box-sizing:border-box;margin:0}
  body{font-family:var(--font);background:var(--bg);color:var(--text)}
  /* ... więcej krytycznych stylów ... */
&lt;/style&gt;


&lt;link rel=&quot;stylesheet&quot; href=&quot;/assets/css/main.css&quot; media=&quot;print&quot; onload=&quot;this.media='all'&quot;&gt;
&lt;noscript&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/assets/css/main.css&quot;&gt;&lt;/noscript&gt;
</code></pre>
<h3>Transformacje HTML dla optymalizacji</h3>
<p>W <code>eleventy.config.js</code> dodajemy transformacje:</p>
<pre><code class="language-javascript">// Lazy loading dla wszystkich obrazków bez atrybutu loading
eleventyConfig.addTransform(&quot;lazyImages&quot;, function(content, outputPath) {
  if (!outputPath || !outputPath.endsWith(&quot;.html&quot;)) return content;
  
  // Dodaj loading=&quot;lazy&quot; i decoding=&quot;async&quot;
  content = content.replace(
    /&lt;img(?![^&gt;]*loading=)([^&gt;]*)&gt;/gi,
    '&lt;img$1 loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;'
  );
  
  // Priorytet dla pierwszego obrazka (LCP optimization)
  content = content.replace(
    /&lt;img([^&gt;]*)class=&quot;([^&quot;]*hero[^&quot;]*)&quot;([^&gt;]*)&gt;/i,
    '&lt;img$1class=&quot;$2&quot;$3 fetchpriority=&quot;high&quot; loading=&quot;eager&quot;&gt;'
  );
  
  return content;
});

// Minifikacja HTML w produkcji
if (process.env.NODE_ENV === 'production') {
  const htmlmin = require(&quot;html-minifier&quot;);
  eleventyConfig.addTransform(&quot;htmlmin&quot;, function(content, outputPath) {
    if (!outputPath || !outputPath.endsWith(&quot;.html&quot;)) return content;
    
    return htmlmin.minify(content, {
      useShortDoctype: true,
      removeComments: true,
      collapseWhitespace: true,
      conservativeCollapse: true,
      minifyCSS: true,
      minifyJS: true,
      removeEmptyAttributes: true,
      removeRedundantAttributes: true
    });
  });
}
</code></pre>
<h3>Optymalizacja obrazków</h3>
<p>Praktyki dla obrazków w treści:</p>
<pre><code class="language-html">&lt;!-- Format WebP z fallbackiem --&gt;
&lt;picture&gt;
  &lt;source srcset=&quot;/assets/images/photo.webp&quot; type=&quot;image/webp&quot;&gt;
  &lt;img src=&quot;/assets/images/photo.jpg&quot; 
       alt=&quot;Opisz co widoczne na zdjęciu, nie że to zdjęcie&quot;
       width=&quot;800&quot; height=&quot;600&quot;
       loading=&quot;lazy&quot; 
       decoding=&quot;async&quot;&gt;
&lt;/picture&gt;

&lt;!-- Responsive images dla różnych urządzeń --&gt;
&lt;img srcset=&quot;
    /assets/images/photo-400.webp 400w,
    /assets/images/photo-800.webp 800w,
    /assets/images/photo-1200.webp 1200w
  &quot;
  sizes=&quot;(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px&quot;
  src=&quot;/assets/images/photo-800.webp&quot;
  alt=&quot;Deskryptywny opis obrazka&quot;&gt;
</code></pre>
<h2>5. Feeds syndykacji treści (RSS/Atom)</h2>
<p>Feed Atom (nowocześniejszy niż RSS 2.0) umożliwia subskrypcję i szybsze indeksowanie nowych wpisów.</p>
<pre><code class="language-xml">---
permalink: /feed.xml
layout: null
---
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;feed xmlns=&quot;http://www.w3.org/2005/Atom&quot; xml:lang=&quot;pl&quot;&gt;
  &lt;title&gt;koryto.net&lt;/title&gt;
  &lt;subtitle&gt;&lt;/subtitle&gt;
  &lt;link href=&quot;https://koryto.net/feed.xml&quot; rel=&quot;self&quot; type=&quot;application/atom+xml&quot;/&gt;
  &lt;link href=&quot;https://koryto.net/&quot; rel=&quot;alternate&quot; type=&quot;text/html&quot;/&gt;
  &lt;updated&gt;&lt;/updated&gt;
  &lt;id&gt;https://koryto.net/&lt;/id&gt;
  &lt;author&gt;
    &lt;name&gt;&lt;/name&gt;
    &lt;uri&gt;&lt;/uri&gt;
  &lt;/author&gt;
  &lt;entry&gt;
    &lt;title&gt;Architektura i implementacja bloga na Eleventy — od koncepcji do deploymentu&lt;/title&gt;
    &lt;link href=&quot;https://koryto.net/posts/jak-stworzylem-bloga/&quot; rel=&quot;alternate&quot; type=&quot;text/html&quot;/&gt;
    &lt;published&gt;2026-03-28T00:00:00.000Z&lt;/published&gt;
    &lt;updated&gt;2026-03-28T00:00:00.000Z&lt;/updated&gt;
    &lt;id&gt;https://koryto.net/posts/jak-stworzylem-bloga/&lt;/id&gt;
    &lt;summary type=&quot;html&quot;&gt;Kompletny przewodnik techniczny budowy nowoczesnego bloga z użyciem Eleventy. Architektura projektu, konfiguracja środowiska, lokalny development i zdalny deployment na GitHub Pages.&lt;/summary&gt;
    &lt;category term=&quot;posts&quot; /&gt;
  &lt;/entry&gt;
  &lt;entry&gt;
    &lt;title&gt;Witaj na moim blogu!&lt;/title&gt;
    &lt;link href=&quot;https://koryto.net/posts/pierwszy-wpis/&quot; rel=&quot;alternate&quot; type=&quot;text/html&quot;/&gt;
    &lt;published&gt;2026-03-29T00:00:00.000Z&lt;/published&gt;
    &lt;updated&gt;2026-03-29T00:00:00.000Z&lt;/updated&gt;
    &lt;id&gt;https://koryto.net/posts/pierwszy-wpis/&lt;/id&gt;
    &lt;summary type=&quot;html&quot;&gt;Pierwszy wpis na nowym blogu o technologii i programowaniu&lt;/summary&gt;
    &lt;category term=&quot;posts&quot; /&gt;
  &lt;/entry&gt;
  &lt;entry&gt;
    &lt;title&gt;Jak dodawać obrazki do artykułów - przykład&lt;/title&gt;
    &lt;link href=&quot;https://koryto.net/posts/jak-dodawac-obrazki/&quot; rel=&quot;alternate&quot; type=&quot;text/html&quot;/&gt;
    &lt;published&gt;2026-03-29T00:00:00.000Z&lt;/published&gt;
    &lt;updated&gt;2026-03-29T00:00:00.000Z&lt;/updated&gt;
    &lt;id&gt;https://koryto.net/posts/jak-dodawac-obrazki/&lt;/id&gt;
    &lt;summary type=&quot;html&quot;&gt;Praktyczny przykład użycia obrazków w artykułach na blogu. Zobacz jak to działa!&lt;/summary&gt;
    &lt;category term=&quot;posts&quot; /&gt;
  &lt;/entry&gt;
  &lt;entry&gt;
    &lt;title&gt;SEO w 11ty - kompletny przewodnik techniczny z wdrożeniem produkcyjnym&lt;/title&gt;
    &lt;link href=&quot;https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/&quot; rel=&quot;alternate&quot; type=&quot;text/html&quot;/&gt;
    &lt;published&gt;2026-03-30T00:00:00.000Z&lt;/published&gt;
    &lt;updated&gt;2026-03-30T00:00:00.000Z&lt;/updated&gt;
    &lt;id&gt;https://koryto.net/posts/seo-w-11ty-kompletny-przewodnik/&lt;/id&gt;
    &lt;summary type=&quot;html&quot;&gt;Profesjonalny przewodnik po optymalizacji SEO dla statycznych stron generowanych przez Eleventy. Od fundamentów po zaawansowane techniki strukturalnych danych, Core Web Vitals i architektury informacji.&lt;/summary&gt;
    &lt;category term=&quot;posts&quot; /&gt;
  &lt;/entry&gt;
&lt;/feed&gt;
</code></pre>
<h2>6. Architektura URL i linkowanie wewnętrzne</h2>
<h3>Przyjazne URL-e (slugi)</h3>
<p>Implementacja w <code>eleventy.config.js</code>:</p>
<pre><code class="language-javascript">eleventyConfig.addFilter(&quot;slugify&quot;, (input) =&gt; {
  const slug = String(input)
    .normalize('NFD')                    // Rozkład polskich znaków
    .replace(/[\u0300-\u036f]/g, '')     // Usuń diakrytyki
    .toLowerCase()
    .trim()
    .replace(/[^\w\s-]/g, '')           // Usuń znaki specjalne
    .replace(/[\s_-]+/g, '-')            // Zamień spacje na myślniki
    .replace(/^-+|-+$/g, '');            // Trim myślniki
  
  return slug;
});
</code></pre>
<h3>Strategia linkowania wewnętrznego</h3>
<p>Linkowanie wewnętrzne przekazuje &quot;link juice&quot; i pomaga Google zrozumieć hierarchię treści:</p>
<pre><code class="language-html">&lt;!-- Link kontekstowy z anchor text opisującym docelową stronę --&gt;
&lt;p&gt;W artykule o &lt;a href=&quot;/blog/seo-w-11ty/&quot;&gt;optymalizacji SEO dla Eleventy&lt;/a&gt; 
dokładnie opisałem proces implementacji strukturalnych danych.&lt;/p&gt;

&lt;!-- Unikaj &quot;click here&quot; lub &quot;czytaj więcej&quot; --&gt;
&lt;!-- ❌ Źle: --&gt;
&lt;a href=&quot;/blog/seo/&quot;&gt;Czytaj więcej →&lt;/a&gt;

&lt;!-- ✅ Dobrze: --&gt;
&lt;a href=&quot;/blog/seo/&quot;&gt;Kompletny przewodnik SEO dla 11ty z przykładami&lt;/a&gt;
</code></pre>
<h2>7. Walidacja i monitoring</h2>
<h3>Narzędzia do weryfikacji wdrożenia</h3>
<p>Po wdrożeniu przetestuj stronę w następujących narzędziach:</p>
<table>
<thead>
<tr>
<th>Narzędzie</th>
<th>URL</th>
<th>Co sprawdza</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Rich Results Test</strong></td>
<td>search.google.com/test/rich-results</td>
<td>Poprawność Schema.org</td>
</tr>
<tr>
<td><strong>PageSpeed Insights</strong></td>
<td>pagespeed.web.dev</td>
<td>Core Web Vitals</td>
</tr>
<tr>
<td><strong>Mobile-Friendly Test</strong></td>
<td>search.google.com/test/mobile-friendly</td>
<td>Responsywność</td>
</tr>
<tr>
<td><strong>RSS Validator</strong></td>
<td>validator.w3.org/feed</td>
<td>Poprawność feedu</td>
</tr>
<tr>
<td><strong>Schema Markup Validator</strong></td>
<td>validator.schema.org</td>
<td>Strukturalne dane</td>
</tr>
</tbody>
</table>
<h3>Google Search Console — podstawowy monitoring</h3>
<p>Dodaj stronę do GSC i monitoruj:</p>
<ul>
<li><strong>Coverage</strong> — indeksowanie i błędy</li>
<li><strong>Core Web Vitals</strong> — raport wydajności</li>
<li><strong>Performance</strong> — zapytania, CTR, pozycje</li>
<li><strong>Enhancements</strong> — rich results i breadcrumbs</li>
</ul>
<h2>Checklist produkcyjnego wdrożenia SEO</h2>
<p>Przed publikacją zweryfikuj:</p>
<h3>Meta i struktura</h3>
<ul>
<li>[ ] Unikalny <code>&lt;title&gt;</code> na każdej stronie (50-60 znaków)</li>
<li>[ ] Unikalny <code>meta description</code> (150-160 znaków)</li>
<li>[ ] Canonical URL poprawnie ustawiony</li>
<li>[ ] Open Graph tags dla wszystkich stron</li>
<li>[ ] Twitter Cards skonfigurowane</li>
</ul>
<h3>Techniczne SEO</h3>
<ul>
<li>[ ] Schema.org JSON-LD dla artykułów</li>
<li>[ ] Breadcrumbs z mikrodanymi</li>
<li>[ ] XML Sitemap generowany automatycznie</li>
<li>[ ] Robots.txt zezwalający na indeksowanie</li>
<li>[ ] HTTPS wymuszony</li>
<li>[ ] Hreflang dla wersji językowych</li>
</ul>
<h3>Wydajność</h3>
<ul>
<li>[ ] LCP &lt; 2.5s (PageSpeed Insights)</li>
<li>[ ] CLS &lt; 0.1</li>
<li>[ ] Lazy loading obrazków</li>
<li>[ ] Minifikacja HTML/CSS/JS</li>
<li>[ ] Preload krytycznych zasobów</li>
<li>[ ] WebP dla obrazków z fallbackiem</li>
</ul>
<h3>Treść i nawigacja</h3>
<ul>
<li>[ ] Jednoznaczna hierarchia H1-H6 (tylko jeden H1)</li>
<li>[ ] Atrybuty <code>alt</code> dla wszystkich obrazków</li>
<li>[ ] Linkowanie wewnętrzne między powiązanymi artykułami</li>
<li>[ ] Przyjazne URL-e ze słowami kluczowymi</li>
<li>[ ] Atom/RSS feed działający</li>
</ul>
<h3>Monitoring</h3>
<ul>
<li>[ ] Strona dodana do Google Search Console</li>
<li>[ ] Sitemap zgłoszony w GSC</li>
<li>[ ] Test Rich Results przechodzi bez błędów</li>
<li>[ ] Test Mobile-Friendly pozytywny</li>
</ul>
<hr>
<p>Implementacja powyższych praktyk zapewnia solidne fundamenty SEO dla bloga opartego na Eleventy. Pamiętaj, że SEO to proces ciągły — regularnie monitoruj wyniki w Google Search Console i iteracyjnie poprawiaj stronę na podstawie zebranych danych.</p>
]]></content>
    
    
    
    
    
    <category term="11ty"/>
    
    
    
    <category term="seo"/>
    
    
    
    <category term="tutorial"/>
    
    
    
    <category term="optymalizacja"/>
    
    
    
  </entry>
</feed>
