๐Ÿš€ Panduan Membuat Static Site dengan Layar Kosong

Selamat datang! Panduan ini akan membantumu membangun situs statis yang super cepat, ringan, dan otomatis ter-deploy ke Cloudflare Pages menggunakan repository Layar Kosong.

Konsepnya simpel: Kamu cukup fokus menulis di GitHub, dan biarkan GitHub Actions + Cloudflare Wrangler yang bekerja mengirimkan artikelmu ke internet secara instan.

โœจ Fitur Unggulan:

๐Ÿง  Arsitektur Otomatisasi (CI/CD)

Penasaran bagaimana "Layar Kosong" memproses draf kasarmu menjadi situs yang live? Berikut adalah alur kerja estafet otomatisnya:

graph TD subgraph WF1 ["๐Ÿ”„ Workflow 1: Proses ArtikelX (Persiapan Awal)"] direction TB Start1(((Mulai))) --> Trig1{"Trigger:
Push (artikelx/*.html)
atau Manual"} Trig1 --> Check1["1๏ธโƒฃ Checkout Repo & Setup Bun.js"] Check1 --> S_HTML[/"2๏ธโƒฃ Edit Komponen HTML"/] S_HTML --> S_Clean[/"3๏ธโƒฃ Sterilize Schema"/] S_Clean --> S_Font[/"4๏ธโƒฃ Ganti Aset ke Lokal"/] S_Font --> S_SEO[/"5๏ธโƒฃ Injeksi SEO, Mirror, WebP"/] S_SEO --> Move["6๏ธโƒฃ Pindah file ke 'artikel/'"] Move --> Commit1["7๏ธโƒฃ Commit & Push Perubahan"] end subgraph WF2 ["โ˜ข๏ธ Workflow 2: Build & Generate Site Files (Pabrik Produksi)"] direction TB Trig2{"Trigger:
WF1 Sukses"} --> Build1{"Generate Data?"} Build1 -- Ya --> S_Gen[/"generator-pro.ts"/] --> Build2{"Generate Srcset?"} Build1 -- Tidak --> Build2 Build2 -- Ya --> S_Srcset[/"srcset-generator.ts"/] --> Build3{"Update Sitemap?"} Build2 -- Tidak --> Build3 Build3 -- Ya --> S_SiteTXT[/"koki.ts, dll"/] --> Build4{"Inject Schema?"} Build3 -- Tidak --> Build4 Build4 -- Ya --> S_Inject[/"inject-schema.ts"/] --> Build5{"Ubah Markdown?"} Build4 -- Tidak --> Build5 Build5 -- Ya --> S_MD[/"html-to-markdown.ts"/] --> Build6{"Minify File?"} Build5 -- Tidak --> Build6 Build6 -- Ya --> S_Min[/"Minify HTML/JSON/XML"/] --> Commit2["Commit, Pull --rebase & Push Data"] Build6 -- Tidak --> Commit2 end subgraph WF3 ["๐Ÿš€ Workflow 3: Cloudflare Deployer (Peluncuran Publik)"] direction TB Trig3{"Trigger:
WF2 Sukses"} --> Rsync["1๏ธโƒฃ Bersihkan Direktori (rsync)"] Rsync --> Config["2๏ธโƒฃ Injeksi Kredensial ke /tmp/wrangler.toml"] Config --> D1Build[/"3๏ธโƒฃ Eksekusi build-d1.ts"/] D1Build --> Deploy{"4๏ธโƒฃ Deploy ke Cloudflare Pages"} Deploy -- "Berhasil" --> Success(((Layar Kosong
Go Live! ๐ŸŽ‰))) end Commit1 --> Trig2 Commit2 --> Trig3

๐Ÿ› ๏ธ Dapur Rahasia: Script Otomatisasi (Bun.js & TypeScript)

Tertarik melihat jeroan kode di balik arsitektur di atas? Silakan ngintip "resep rahasia" di bawah ini beserta kode utuh workflow YAML-nya:

1๏ธโƒฃ Script Tahap Persiapan (Proses ArtikelX)

File: .github/workflows/proses-artikelx.yml

name: ๐Ÿ”„ Proses ArtikelX
on:
  push:
    branches: ['main']
    paths:
      - 'artikelx/*.html'
  workflow_dispatch:
permissions:
  contents: write
jobs:
  process_articles:
    runs-on: ubuntu-latest
    timeout-minutes: 1
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 1
          persist-credentials: true
      - name: '2. Setup Bun.js'
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
        with:
          bun-version: latest
      - name: Install Node dependencies
        run: bun install
      - name: ๐Ÿ”ฐ Edit Komponen HTML (Bun.js)
        run: bun run dapur/Edit-Komponen-HTML.ts
      - name: ๐Ÿงน Sterilize Schema (Bun.js)
        run: bun run dapur/clean-schema.ts artikelx/
      - name: ๐Ÿ› ๏ธ Ganti ke Rumah aja, fontaws dan highlight.js (Bun Mode)
        run: |
          set -euo pipefail
          bun dapur/gantifontshighlight.ts --quiet --no-backup
      # Menjalankan Mirroring & WebP Optimization di folder artikelx
      - name: Inject SEO, Mirror Images & WebP (seo-fixer.ts)
        run: |
          set -euo pipefail
          bun run dapur/seo-fixer.ts artikelx/
      - name: Move to artikel/
        run: |
          set -euo pipefail
          shopt -s nullglob
          files=(artikelx/*.html)
          if [[ ${#files[@]} -gt 0 ]]; then
            mv -f "${files[@]}" artikel/
            echo "Berhasil pindahkan ${#files[@]} file ke artikel/"
          else
            echo "Tidak ada file di artikelx/"
          fi
      - name: Commit & Push
        run: |
          set -euo pipefail
          git config --local user.email "github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          # PERBAIKAN: img/ ditambahkan agar gambar hasil mirroring ikut ter-upload
          git add .
          if git diff --staged --quiet; then
            echo "Tidak ada perubahan."
            exit 0
          fi
          git commit -m "Proses ArtikelX: Move, Mirror & WebP"
          git push origin main
2๏ธโƒฃ Script Tahap Produksi (Build & Generate)

File: .github/workflows/generate-json-xml.yml

name: โ˜ข๏ธ Build and Generate Site Files
on:
  workflow_run:
    workflows: ["๐Ÿ”„ Proses ArtikelX"]
    types: [completed]
    branches: ['main']
  workflow_dispatch:
    inputs:
      run_generator:
        description: 'Generator (JSON, RSS, Sitemap XML)'
        type: boolean
        default: true
      run_sitemap_txt:
        description: 'Update sitemap.txt'
        type: boolean
        default: true
      run_schema:
        description: 'Inject Schema.org'
        type: boolean
        default: true
      run_minify_html:
        description: 'HTML Minify'
        type: boolean
        default: true
      run_minify_jsonxml:
        description: 'JSONXML Minify'
        type: boolean
        default: true
      run_convert_markdown:
        description: 'Ubah ke format Markdown'
        type: boolean
        default: true
      run_srcset:
        description: 'Image Optimize & Srcset Generator'
        type: boolean
        default: true
env:
  DO_GENERATOR: ${{ github.event.inputs.run_generator || 'true' }}
  DO_SITEMAP_TXT: ${{ github.event.inputs.run_sitemap_txt || 'true' }}
  DO_SCHEMA: ${{ github.event.inputs.run_schema || 'true' }}
  DO_MINIFY_HTML: ${{ github.event.inputs.run_minify_html || 'true' }}
  DO_MINIFY_JSONXML: ${{ github.event.inputs.run_minify_jsonxml || 'true' }}
  DO_CONVERT_MARKDOWN: ${{ github.event.inputs.run_convert_markdown || 'true' }}
  DO_SRCSET: ${{ github.event.inputs.run_srcset || 'true' }}
jobs:
  build:
    runs-on: ubuntu-latest
    if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
    permissions:
      contents: write
    steps:
      - name: '1. Checkout Repository'
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          fetch-depth: 1
          persist-credentials: true
      - name: '2. Setup Bun.js'
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
        with:
          bun-version: latest
      - name: '3. Install Dependencies'
        run: bun install
      - name: '4. Generate artikel.json, Sitemap XML & RSS'
        if: env.DO_GENERATOR == 'true'
        run: bun run dapur/generator-pro.ts
        env:
          RSS_LIMIT: 30
      - name: '5. Optimize Images & Generate Srcset'
        if: env.DO_SRCSET == 'true'
        run: bun run dapur/srcset-generator.ts
      - name: '6. Update sitemap.txt (Native Bun - Sorted by Date)'
        if: env.DO_SITEMAP_TXT == 'true'
        run: |
          bun run dapur/koki.ts --once
          bun run dapur/bikin-sitemap-txt.ts
          bun run dapur/generate_llms.ts
          bun run dapur/redirectmap.ts
      - name: '7. Inject SEO Schema'
        if: env.DO_SCHEMA == 'true'
        run: bun run dapur/inject-schema.ts
      - name: '8. Convert HTML to Markdown'
        if: env.DO_CONVERT_MARKDOWN == 'true'
        run: bun run dapur/html-to-markdown.ts
      - name: '9. Minify HTML'
        if: env.DO_MINIFY_HTML == 'true'
        run: bun run dapur/minify-html.ts
      - name: '10. Minify Data (JSON & XML)'
        if: env.DO_MINIFY_JSONXML == 'true'
        run: bun run dapur/minify-jsonxml.ts
      - name: '11. Commit and Push'
        run: |
          git config --local user.email "github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          # Add semua perubahan lainnya (JSON, XML, dan CACHE di folder mini/)
          git add .
          if git diff --staged --quiet; then
            echo "โœ… Tidak ada perubahan data."
          else
            git commit -m "beres: ๐Ÿš€ update data site [$(date +'%Y-%m-%d %H:%M')]"
            git pull --rebase origin main
            git push origin main
          fi
3๏ธโƒฃ Script Tahap Deploy (Cloudflare)

File: .github/workflows/CloudflarePages.yml

  • build-d1.ts โ€” Membangun indeks pencarian dan melemparnya ke Cloudflare D1 Database.
name: ๐Ÿš€ Cloudflare Deployer Filter & Direct
on:
  workflow_run:
    workflows: ["โ˜ข๏ธ Build and Generate Site Files"]
    types: [completed]
  push:
    branches:
      - main
    paths:
      # Daftar filter trigger tetap sama (untuk efisiensi trigger)
      #- 'wrangler.toml'  # Tambahkan ini biar kalau config berubah, dia auto-run
      - '_redirects'
      - '_headers'
  workflow_dispatch:
permissions:
  contents: read # Cukup READ saja, karena kita gak perlu push balik ke repo!
  deployments: write
jobs:
  deploy-direct:
    runs-on: ubuntu-latest
    if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
    steps:
      # 1. Ambil source code dari main
      - name: Checkout source branch
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          path: source
          fetch-depth: 1
          persist-credentials: true
      - name: '1.5 Setup Node.js v22'
        uses: actions/setup-node@v6
        with:
          node-version: 24.16.0
      - name: '2. Setup Bun.js'
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
        with:
          bun-version: latest
      - name: Install dependencies
        run:  bun install
        working-directory: source
      - name: ๐Ÿงน Prepare Clean Directory (rsync)
        run: |
          mkdir deploy_dir
          # rsync tetap bersih karena wrangler.toml masih di /tmp/
          rsync -a --delete \
            --include='gaya-hidup/*' \
            --include='jejak-sejarah/*' \
            --include='lainnya/*' \
            --include='olah-media/*' \
            --include='opini-sosial/*' \
            --include='sistem-terbuka/*' \
            --include='warta-tekno/*' \
            --include='functions/*' \
            --include='search/*' \
            --include='ext/*' \
            --include='.well-known/*' \
            --include='img/*' \
            --include='artikel.json' \
            --include='redirectmap.json' \
            --include='llms.md' \
            --include='_redirects' \
            --include='_headers' \
            --include='*.html' \
            --include='*.xml' \
            --include='*.xsl' \
            --include='*.txt' \
            --include='favicon.*' \
            --include='icon.*' \
            --include='logo.*' \
            --include='thumbnail.*' \
            --include='thumbnail-sm.*' \
            --include='*.webmanifest' \
            --exclude='*' \
            source/ deploy_dir/
      # ๐Ÿ”‘ 2. CREATE CONFIG (Tetap di /tmp agar aman)
      - name: Create Temporary Wrangler Config
        run: |
          cat < /tmp/wrangler.toml
          #:schema https://raw.githubusercontent.com/cloudflare/wrangler2/sys-types/pages/modules/config-schema.json
          name = "layarkosong"
          compatibility_date = "2025-12-01"
          pages_build_output_dir = "deploy_dir"
          [vars]
          BUN_VERSION = "latest"
          NODE_VERSION = "24"
          [[d1_databases]]
          binding = "DB"
          database_name = "layarkosong-db"
          database_id = "${{ secrets.CLOUDFLARE_ID_D1 }}"
          [[kv_namespaces]]
          binding = "COUNTS_KV"
          id = "${{ secrets.CLOUDFLARE_ID_KV }}"
          EOF
      # ๐Ÿณ 3. RUN DAPUR (Membaca deploy_dir)
      - name: Run Dapur (Build D1)
        run: bun run source/search/build-d1.ts
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
      # ๐Ÿš€ 4. DEPLOY (Retry 3x)
      - name: Deploy to Cloudflare Pages
        run: |
          # 1. Pastikan wrangler.toml ada di root untuk dibaca wrangler
          cp /tmp/wrangler.toml ./wrangler.toml
          # 2. PENTING: Copy folder functions dari source ke ROOT (.)
          # agar sejajar dengan deploy_dir
          cp -r source/functions ./functions
          max_attempts=3
          attempt=1
          until [ $attempt -gt $max_attempts ]
          do
            echo "๐Ÿš€ Attempt $attempt to deploy..."
            # 3. Jalankan deploy dari root (.) mengarah ke folder statis (deploy_dir)
            # Wrangler otomatis akan mencari folder ./functions di root!
            if bunx wrangler pages deploy deploy_dir --project-name=layarkosong --branch=main --commit-dirty=true; then
              echo "โœ… Deploy succeeded on attempt $attempt"
              break
            else
              echo "โš ๏ธ Deploy failed on attempt $attempt"
              attempt=$((attempt+1))
              [ $attempt -le $max_attempts ] && sleep 15
            fi
          done
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}

๐Ÿ› ๏ธ Tahap 1: Persiapan Lingkungan (Git & Bun)

Langkah pertama: Pastikan Git dan Bun sudah terpasang di komputermu. Karena kita ingin performa super cepat, seluruh eksekusi script dan deployment akan menggunakan perintah bunx wrangler karena tidak menggunakan Node.js.

๐ŸชŸ Windows

Unduh dan instal Git dari git-scm.com (atau gunakan winget install --id Git.Git -e --source winget). Setelah itu, instal Bun secara native melalui PowerShell:

powershell -c "irm bun.sh/install.ps1 | iex"

๐ŸŽ macOS / ๐Ÿง Linux

Buka terminal dan ketik perintah berikut untuk menginstal Bun:

curl -fsSL https://bun.sh/install | bash

Sedangkan untuk menginstal Git, sesuaikan dengan sistem operasimu:

# macOS (menggunakan Homebrew)
brew install git
# Debian/Ubuntu
sudo apt update && sudo apt install git
# Fedora/RHEL
sudo dnf install git
# Arch Linux
sudo pacman -S git

๐Ÿงฌ Tahap 2: Setup Repository (Fork & Cloudflare)

  1. Fork Repository: Lakukan Fork pada repository ini ke akunmu. Cukup centang branch main saja.
๐Ÿ‘‰ Klik di sini untuk Fork Repo
  1. Mendaftar Cloudflare Pages: Login ke dashboard Cloudflare. Pilih Workers & Pages > Create application > Pages > Upload assets. Beri nama proyekmu.
  2. Ambil API Token: Buka My Profile > API Tokens > Create Token. Gunakan template "Edit Cloudflare Workers". Simpan Account ID dan API Token kamu.

๐Ÿ—๏ธ Tahap 3: Otomatisasi (GitHub Secrets)

1. Bersihkan Konten Lama ๐Ÿงน

Hapus semua file contoh bawaan agar situsmu bersih: hapus isi folder artikel/ dan img/.

2. Pasang Kunci Rahasia

Agar GitHub bisa mengirim file ke Cloudflare secara otomatis:

  1. Buka tab Settings > Secrets and variables > Actions pada repository GitHub-mu.
  2. Klik New repository secret dan tambahkan:
    • CF_API_TOKEN: (Isi dengan token API Cloudflare-mu).
    • CF_ACCOUNT_ID: (Isi dengan ID akun Cloudflare-mu).

โœ๏ธ Tahap 4: Mulai Menulis dan Produksi

Di sinilah keajaiban terjadi. Ikuti alur "dapur" ini:

  1. Buat file HTML artikel barumu.
  2. Masukkan file tersebut ke dalam folder artikelx/ (perhatikan akhiran 'x').
  3. Lakukan git commit dan git push.
  4. Biarkan Action Bekerja: Sistem otomatis akan mendeteksi file baru, memprosesnya, dan memindahkannya ke etalase utama yang siap tayang!

๐ŸŽ‰ Selesai! Halaman pertamamu sudah terbit ke seluruh penjuru dunia.

๐ŸŽจ Tahap 5: Personalisasi Identitas & Konfigurasi

Konfigurasi Inti (Wajib Diubah)

  • wrangler.toml: Ganti name = "layarkosong" menjadi nama proyek Cloudflare-mu.
  • artikel.json: Nyawa mesin pencari blogmu, biarkan sistem yang mengupdatenya otomatis.
  • Folder ext/: Sesuaikan URL dan nama domain pada seluruh file konfigurasi di dalamnya.

Halaman Root (Sesuaikan Identitasmu)

Edit file-file berikut yang ada di halaman utama (root): index.html, search.html, 404.html, robots.txt, sitemap.html, hingga favicon dan thumbnail bawaan.

๐Ÿ™ Checklist Pra-Peluncuran

  • Ganti semua URL dari dalam.web.id ke domain kamu.
  • Update informasi kontak dan metadata.
  • Sesuaikan warna, logo, dan branding.
  • Test semua link internal.

๐ŸŒ Tahap 6: Domain Custom (Opsional)

Jika kamu punya domain sendiri:

  1. Tambahkan file CNAME di root repository.
  2. Isi dengan nama domain kamu (contoh: example.com).
  3. Atur DNS di provider domain kamu (tambahkan record A ke IP GitHub Pages atau atur langsung via dashboard Cloudflare Pages).

๐Ÿ’ฌ Butuh Bantuan?

Jika workflow macet atau bingung set-up Cloudflare, langsung saja meluncur ke ruang diskusi.

๐Ÿ‘‰ Diskusi di Repository LayarKosong

Keep coding and stay awesome! โœŒ๏ธ