Next.js 15 untuk Pemula: Konsep Dasar hingga Deployment Sederhana

Selamat datang para calon web developer dan juga Anda yang mungkin sudah familiar dengan dunia React, tapi penasaran dengan "sesuatu" yang lebih canggih! Pernahkah Anda merasa ketika membangun aplikasi web dengan React, ada kalanya kita ingin lebih? Lebih cepat, lebih SEO-friendly, lebih efisien dalam mengelola data dari server? Nah, di sinilah Next.js hadir sebagai "penolong" kita.


Bayangkan Next.js ini seperti sebuah superhero bagi React. React itu pondasi rumah yang kokoh, tapi Next.js ini adalah arsitek dan kontraktor yang lengkap, yang akan membangun seluruh rumah impian Anda dengan fondasi React tadi. Ia menambahkan kekuatan super seperti kemampuan untuk membuat halaman web yang bisa langsung di-render di server (jadi lebih cepat tampil di browser dan lebih disukai Google), sampai fitur-fitur keren lainnya yang bikin pengembangan web jadi jauh lebih menyenangkan dan powerful. Next.js itu ibaratnya, kalau React adalah "mesin" aplikasi Anda, maka Next.js adalah "mobil balap" lengkap dengan fitur navigasi, lampu sein, dan bahkan turbo charger-nya!


Nah, sekrang kita bicara tentang bintang utama kita: Next.js 15. Kenapa versi ini begituu penting dan layak Anda perhatikan? Next.js itu selalu berevolusi, dan versi 15 ini membawa banyak pembaruan menarik yang akan membuat pengalaman ngoding Anda makin asyik dan efisien. Ada banyak peningkatan di balik layar yang membuatnya lebih cepat dan stabil, serta beberapa penyempurnaan pada fitur andalannya, App Router, yang akan kita jelajahi bersama. Ini bukan cuma update nomor versi, tapi lompatan yang signifikan dalam bagaimana kita membangun aplikasi web modern.


Jadi, untuk siapa panduan komprehensif ini dibuat? Jangan khawatir, kalau Anda adalah seorang pemula di dunia Next.js, bahkan yang baru kenalan dengan React, Anda sudah berada di tempat yang tepat! Kami akan membawa Anda dari nol, benar-benar dari dasar, menjelaskan setiap konsep penting dengan bahasa yang mudah dicerna. Tidak ada istilah teknis yang bikin kening berkerut tanpa penjelasan. Tujuan kami adalah agar setelah membaca dan mempraktikkan panduan ini, Anda tidak hanya paham konsep Next.js, tapi juga bisa langsung membangun aplikasi sederhana Anda sendiri, bahkan sampai tahap deployment alias "mengirim" aplikasi Anda ke internet agar bisa diakses banyak orang!


Dalam perjalanan kita ini, kita akan membahas banyak hal. Mulai dari konsep dasar rendering di Next.js (SSR, SSG, CSR, ISR... jangan pusing dulu, kita akan kupas tuntas!), bagaimana cara memulai proyek Next.js 15 dari awal, seluk beluk App Router yang kini jadi tulang punggung Next.js terbaru, cara styling aplikasi Anda agar terlihat menarik, hingga langkah-langkah mudah untuk me-deploy aplikasi Anda. Jadi, siapkan secangkir kopi (atau teh, atau minuman favorit Anda), dan mari kita mulai petualangan seru ini bersama Next.js 15!

Bagian 1: Memahami Next.js — Konsep Dasar

Oke, setelah kita tahu kenapa Next.js ini keren, sekarang mari kita menyelami fondasinya. Apa sih yang membuat Next.js begitu istimewa dan berbeda dari sekadar React biasa?

Filosofi Next.js: React yang Bisa Jadi "Full-Stack"

Next.js hadir dengan sebuah misi: membuat React tidak hanya jago di frontend (bagian yang dilihat dan diinteraksi pengguna), tapi juga punya kekuatan di backend (bagian server yang mengelola data dan logika). Makanya, sering disebut "framework React untuk produksi" atau "React yang full-stack".

Bayangkan Anda ingin membangun restoran. React itu ibarat dapur Anda yang canggih, tempat Anda meracik semua hidangan (komponen UI). Nah, Next.js ini bukan cuma dapur, tapi juga termasuk ruang makan, kasir, bahkan sistem pemesanan. Jadi, Anda bisa mengurus semuanya dalam satu ekosistem yang rapi. Ini berarti Next.js memungkinkan Anda menulis kode yang berjalan di sisi server (misalnya untuk mengambil data aman dari database) dan juga kode yang berjalan di sisi klien (untuk interaksi tombol, animasi, dll.) dalam satu proyek yang sama. Praktis, kan?

Jenis-jenis Rendering: Seni Membangun Halaman Web

Salah satu kekuatan super Next.js yang paling mencolok adalah fleksibilitasnya dalam "merender" atau "membentuk" halaman web. Next.js punya beberapa cara, dan Anda bisa memilih yang paling cocok untuk setiap bagian aplikasi Anda:

  1. Server-Side Rendering (SSR): Si Koki yang Cepat Saji Ini seperti Anda memesan makanan di restoran, dan koki (server) langsung memasak dan menyajikan hidangan lengkap di piring (halaman HTML jadi) untuk Anda. Begitu hidangan sampai di meja Anda (browser), Anda bisa langsung menikmati (melihat dan membaca).
    • Apa itu? Halaman web dibangun sepenuhnya di sisi server untuk setiap permintaan (setiap kali pengguna mengakses URL).
    • Kapan digunakan? Cocok untuk halaman yang datanya sering berubah, seperti feed berita terkini, profil pengguna, atau daftar produk di e-commerce. Ini sangat baik untuk SEO (Search Engine Optimization) karena bot pencarian (seperti Google) akan langsung melihat konten lengkap.
  2. Static Site Generation (SSG): Hidangan Siap Saji di Kulkas Metode ini seperti Anda sudah menyiapkan semua hidangan favorit dari jauh-jauh hari dan menyimpannya di kulkas (sudah jadi file HTML, CSS, JavaScript statis) sebelum ada pengunjung datang. Begitu ada yang lapar (pengguna mengakses URL), Anda tinggal mengambilnya dari kulkas dan menyajikan. Super cepat!
    • Apa itu? Halaman web dibangun sekali pada saat proses build (ketika Anda menyiapkan aplikasi untuk deployment). Hasilnya adalah file HTML statis yang bisa disajikan dengan sangat cepat.
    • Kapan digunakan? Ideal untuk konten yang jarang berubah, seperti blog posts, halaman "Tentang Kami", atau dokumentasi. Karena sudah statis, performanya luar biasa cepat dan aman.
  3. Incremental Static Regeneration (ISR): Upgrade Hidangan Siap Saji Ini adalah perpaduan unik antara SSG dan SSR. Seperti hidangan siap saji, tapi Anda bisa mengatur agar koki memeriksa setiap beberapa waktu (misalnya, setiap 5 menit) apakah ada bahan baru atau resep yang di-update. Kalau ada, koki akan "memperbarui" hidangan di kulkas tanpa perlu memasak ulang semua hidangan dari awal.
    • Apa itu?? Memungkinkan Anda untuk memperbarui halaman SSG setelah deployment tanpa harus membangun ulang seluruh aplikasi. Ini menjaga kecepatan SSG tapi tetap memungkinkan konten untuk selalu segar.
    • Kapan digunakan? Cocok untuk blog yang sering ada update tapi tidak setiap detik, atau daftar produk yang update setiap jam.
  4. Client-Side Rendering (CSR): Anda yang Memasak Sendiri Ini adalah cara React biasa bekerja. Anda dikasih bahan mentah (bundle JavaScript), dan Anda (browser) yang meracik semua hidangan (merender UI) di dapur Anda sendiri.
    • Apa itu? Halaman awalnya kosong atau minim konten, lalu JavaScript di browser akan mengunduh data dan merender konten setelah halaman dimuat.
    • Perannya di Next.js: Meskipun Next.js menawarkan SSR/SSG/ISR, CSR masih digunakan untuk bagian-bagian aplikasi yang sangat interaktif atau yang membutuhkan data real-time setelah halaman awal dimuat (misalnya, form yang dinamis, peta interaktif, atau chat). Next.js bisa memadukan berbagai strategi rendering ini dalam satu aplikasi!

File System Routing: Jalan Pintas Navigasi

Di Next.js, navigasi atau routing itu super intuitif. Anda tidak perlu menulis baris kode panjang untuk mendefinisikan URL. Cukup buat folder dan file di dalam direktori app (atau pages di versi lama), dan Next.js akan otomatis membuat URL yang sesuai.

Misalnya:

  • app/page.tsx akan jadi / (halaman utama)
  • app/tentang/page.tsx akan jadi /tentang
  • app/blog/[slug]/page.tsx akan jadi /blog/nama-artikel-anda (ini namanya dynamic route, kita akan bahas nanti!)

Sangat rapi dan mudah diorganisir, kan?


Components: Fondasi React yang Lebih Cerdas dan Terstruktur dengan TypeScript

Tentu saja, karena Next.js dibangun di atas React, Anda akan tetap menggunakan komponen React yang sudah Anda kenal. Setiap bagian UI adalah komponen: tombol, card, navigasi bar, dll. Namun, di Next.js 15 dengan App Router, ada sedikit "kecerdasan" tambahan pada komponen. Ditambah lagi, dengan TypeScript, komponen kita jadi lebih powerful dan aman karena kita bisa mendefinisikan tipe data untuk props dan state.


  • Server Components: Ini komponen yang di-render di server. Mereka cepat, efisien, dan bisa langsung mengakses data dari backend. Mereka tidak punya state atau lifecycle hooks seperti di React biasa. Dengan TypeScript, kita bisa memastikan data yang diambil dan digunakan di Server Components memiliki struktur yang benar. File-file ini biasanya berekstensi .tsx.
  • Client Components: Ini komponen React yang biasa Anda kenal, di-render di browser. Mereka bisa punya state, menerima input pengguna, dan berinteraksi dengan browser API. TypeScript sangat membantu di sini untuk mendefinisikan interface atau type untuk props dan state, sehingga mengurangi bug dan membuat kode lebih mudah dipelihara. File-file ini juga berekstensi .tsx.

Jangan khawatir kalau ini terdengar agak rumit sekarang. Kita akan membahas perbedaan dan penggunaan kedua jenis komponen ini secara mendalam di Bagian 3, ketika kita menyelami App Router. Anggap ini sebagai pengantar awal saja, bahwa komponen di Next.js sekarang punya "kekuatan" yang berbeda tergantung di mana mereka dijalankan, dan TypeScript akan menjadi teman setia kita dalam membangunnya dengan lebih kokoh!

Bagian 2: Memulai Proyek Next.js 15

Setelah kita memahami dasar-dasar kekuatan Next.js, sekarang saatnya "mengotori tangan" dan mulai membangun! Bagian ini akan memandu Anda langkah demi langkah untuk membuat proyek Next.js 15 pertama Anda. Jangan khawatir, prosesnya jauh lebih mudah dari yang Anda bayangkan.

Prasyarat: Modal Awal Anda

Sebelum kita ngebut, ada beberapa "modal" atau alat yang perlu Anda siapkan di komputer Anda. Anggap saja ini seperti bahan-bahan dasar sebelum mulai memasak:

Node.js
Node.js
  • Node.js (Versi yang Direkomendasikan): Ini adalah runtime environment yang memungkinkan JavaScript berjalan di luar browser, jadi kita bisa menjalankan Next.js di komputer kita. Pastikan Anda sudah menginstalnya. Next.js biasanya membutuhkan versi Node.js yang relatif baru. Anda bisa cek versi Node.js Anda dengan mengetik node -v di terminal. Jika belum ada atau versi lama, silakan unduh dan instal dari website resmi Node.js.
React.js
React.js
  • Pengetahuan Dasar React dan JavaScript/TypeScript ES6: Next.js dibangun di atas React. Jadi, pemahaman dasar tentang komponen React, props, state, dan sintaks JavaScript ES6 (seperti const, let, arrow functions, destructuring), ditambah dasar-dasar TypeScript, akan sangat membantu. Jika Anda masih sangat baru di React atau TypeScript, mungkin ada baiknya luangkan sedikit waktu untuk memahami dasarnya terlebih dahulu.
NPM
NPM
  • Pemahaman Dasar tentang NPM/Yarn: Ini adalah package manager untuk JavaScript. Kita akan menggunakannya untuk menginstal library yang dibutuhkan Next.js dan juga untuk menjalankan perintah-perintah proyek. Anda bisa cek versi dengan npm -v atau yarn -v. Biasanya, Node.js sudah otomatis menginstal NPM.

Sudah siap semua? Oke, mari kita mulai!

Instalasi Next.js 15: Membuat Proyek Pertama

Saatnya membangun rumah impian kita! Next.js punya alat yang super praktis untuk membuat proyek baru bernama create-next-app. Ini seperti kontraktor yang sudah menyiapkan semua fondasi dan struktur awal untuk Anda.

Buka terminal atau command prompt Anda, lalu ketik perintah berikut:

npx create-next-app@latest

Setelah Anda menekan Enter, create-next-app akan mengajukan beberapa pertanyaan untuk mengonfigurasi proyek Anda. Untuk panduan ini, kita akan menggunakan TypeScript, yang sangat direkomendasikan untuk proyek Next.js yang lebih besar dan terstruktur. Jawab saja seperti ini (atau sesuaikan jika Anda punya preferensi lain):

What is your project named? my-next-app       (Anda bisa ganti sesuai nama proyek Anda)
Would you like to use TypeScript? Yes         (PENTING! Pilih 'Yes' untuk menggunakan TypeScript)
Would you like to use ESLint? Yes             (Ini bagus untuk menjaga kualitas kode)
Would you like to use Tailwind CSS? Yes       (Sangat direkomendasikan untuk styling cepat dan modern!)
Would you like to use `src/` directory? No    (Pilih 'Yes' jika Anda suka struktur 'src' terpisah)
Would you like to use App Router? (recommended) Yes  (INI PENTING! Pastikan pilih 'Yes' untuk Next.js 15)
Would you like to use Turbopack for `next dev`? Yes
Would you like to customize the default import alias (@/*)? No

Tunggu sebentar sampai semua file diunduh dan diinstal. Setelah selesai, Anda akan melihat pesan sukses! 🎉

Sekarang, masuk ke direktori proyek yang baru dibuat:

cd my-next-app-blog

Dan untuk melihat aplikasi Anda berjalan di browser, jalankan perintah ini:

npm run dev
# atau jika Anda menggunakan Yarn:
# yarn dev

Anda akan melihat pesan seperti ready - started server on 0.0.0.0:3000, url: http://localhost:3000. Buka http://localhost:3000 di browser Anda, dan... voila! Anda akan melihat halaman awal Next.js yang indah. Selamat, proyek Next.js 15 pertama Anda sudah hidup!


Struktur Proyek Next.js 15: Mengenal Isi Rumah Anda

Setelah proyek tercipta, mari kita intip isi "rumah" kita. Meskipun create-next-app sudah menyiapkan banyak hal, ada beberapa direktori dan file penting yang perlu Anda kenali:

  • app/: Ini adalah "jantung" dari proyek Next.js Anda ketika menggunakan App Router. Semua route (halaman web) dan layout aplikasi Anda akan berada di sini. Setiap folder di dalamnya akan merepresentasikan sebuah URL, dan file page.tsx di dalam folder tersebut adalah halaman yang akan ditampilkan (perhatikan ekstensi .tsx untuk TypeScript React Component).
    • Misalnya, app/page.tsx adalah halaman utama (/).
    • app/dashboard/page.tsx akan menjadi halaman /dashboard.
    • app/layout.tsx adalah layout utama yang membungkus semua halaman (seperti kerangka rumah).
  • public/: Folder ini adalah tempat Anda menyimpan aset statis seperti gambar, font, atau file lainnya yang ingin Anda akses langsung melalui URL publik (misalnya /gambar-saya.png).
  • components/ (opsional, tapi umum): Ini bukan folder bawaan Next.js, tapi sangat umum dan direkomendasikan untuk Anda buat sendiri. Di sinilah Anda akan menyimpan komponen React yang bisa digunakan kembali di berbagai halaman atau bagian aplikasi Anda (misalnya Button.tsx, Navbar.tsx).
  • package.json: File ini berisi metadata proyek Anda, daftar dependency (library yang Anda gunakan), dan script yang bisa Anda jalankan (seperti dev, build, start).
  • next.config.ts: Ini adalah file konfigurasi Next.js. Di sinilah Anda bisa menambahkan pengaturan khusus untuk proyek Anda, seperti mengoptimalkan gambar, mengelola variabel lingkungan, atau mengubah behavior Next.js lainnya.
  • tsconfig.json: File ini adalah konfigurasi untuk TypeScript. Next.js akan otomatis membuatnya jika Anda memilih TypeScript saat instalasi.

Memahami struktur dasar ini akan memudahkan Anda menavigasi dan mengembangkan aplikasi Next.js Anda. Selanjutnya, kita akan menyelam lebih dalam ke fitur paling canggih di Next.js 15: App Router!


Bagian 3: Menguasai App Router Next.js 15

Selamat datang di bagian yang paling seru dan mungkin paling "Next.js 15" dari panduan ini: App Router! Jika Anda sebelumnya pernah menggunakan Next.js versi lama (dengan folder pages/), App Router ini akan terasa seperti evolusi besar. Tapi jangan khawatir, jika Anda pemula, ini adalah cara terbaik untuk belajar karena ini adalah future dari Next.js.

Mengapa App Router? Kekuatan di Balik Perubahan

App Router bukan sekadar cara baru untuk mengatur route. Ini adalah perubahan fundamental yang dirancang untuk:

  • Performa Lebih Baik: Dengan mengoptimalkan rendering di sisi server dan memungkinkan Server Components, App Router secara signifikan mengurangi jumlah JavaScript yang dikirim ke browser, membuat aplikasi Anda jauh lebih cepat dimuat dan lebih responsif. Ini seperti mobil balap yang bobotnya dikurangi sehingga bisa melaju lebih kencang!
  • Pengalaman Developer yang Lebih Baik: Struktur yang lebih terorganisir (dengan layouts, loading states, error boundaries) membuat pengembangan lebih intuitif, terutama untuk aplikasi berskala besar.
  • Arsitektur yang Lebih Fleksibel: Memungkinkan developer untuk memadukan Server Components dan Client Components dengan mulus, memberikan kontrol penuh di mana dan bagaimana kode dijalankan.

App Router vs. Pages Router: Perbandingan Singkat

Sebelum App Router, Next.js menggunakan Pages Router (berbasis folder pages/). Mari kita lihat perbedaannya:

  1. Lokasi File
    • Pages Router: Menggunakan folder pages/ Contoh: pages/about.js
    • App Router: Menggunakan folder app/ Contoh: app/about/page.tsx
  2. Rendering
    • Pages Router:
      • Default: CSR (Client-Side Rendering)
      • Bisa SSR/SSG menggunakan getServerSideProps atau getStaticProps
    • App Router:
      • Default: Server Components (otomatis SSR/SSG)
      • Bisa CSR dengan menambahkan "use client"
  3. Tata Letak (Layouts)
    • Pages Router:
      • Membutuhkan custom logic di _app.js untuk layout bersama
    • App Router:
      • Menggunakan layout.tsx di setiap route segment untuk layout bersama
  4. Data Fetching
    • Pages Router:
      • Menggunakan getServerSideProps, getStaticProps, atau useEffect
    • App Router:
      • Menggunakan fetch() langsung di Server Components (lebih fleksibel)
  5. Error & Loading
    • Pages Router:
      • Menggunakan _error.js untuk error page
    • App Router:
      • Menggunakan error.tsx dan loading.tsx di setiap route segment
  6. Komponen
    • Pages Router: Semua komponen secara default adalah Client Components
    • App Router:
      • Default adalah Server Components
      • Bisa dijadikan Client Components dengan "use client"
  7. Ekstensi File
    • Pages Router: Mendukung .js, .jsx, .ts, dan .tsx
    • App Router: Sama seperti Pages Router, mendukung .tsx, .ts, .js, dan .jsx

Kapan menggunakan App Router? Hampir selalu! Next.js 15 sangat mendorong penggunaan App Router karena semua inovasi terbaru dan peningkatan performa ada di sini. Jika Anda memulai proyek baru, gunakan App Router.

Server Components vs. Client Components (Detail): Pasangan Serasi

Ini adalah konsep kunci di App Router yang akan sering Anda temui:

  1. Server Components:
    • Apa itu? Ini adalah komponen React yang hanya di-render di sisi server. Mereka tidak pernah mencapai browser dalam bentuk JavaScript. Yang dikirim ke browser adalah hasil renderingnya dalam bentuk HTML.
    • Kapan menggunakannya? Ideal untuk:
      • Mengambil data (Data Fetching): Anda bisa langsung mengakses database atau API private di sini tanpa perlu API endpoint terpisah. Ini lebih cepat dan aman!
      • Logika Bisnis yang Berat: Melakukan komputasi yang intensif tanpa membebani browser pengguna.
      • Menyembunyikan Kredensial: Kunci API atau informasi sensitif lainnya tetap aman di server.
    • Keterbatasan: Karena mereka tidak berjalan di browser, Server Components:
      • Tidak bisa menggunakan hooks React seperti useState, useEffect, useContext.
      • Tidak bisa menggunakan event listeners seperti onClick, onChange (karena tidak ada interaksi di browser).
      • Tidak bisa menggunakan window atau document (karena itu API browser).
    • File Extension: Biasanya .tsx atau .ts (untuk TypeScript).
  2. Client Components:
    • Apa itu? Ini adalah komponen React yang kita kenal dan cintai. Mereka di-render di browser dan menyediakan semua interaktivitas yang kita harapkan dari aplikasi web modern.
    • Kapan menggunakannya? Gunakan Client Components untuk:
      • Interaktivitas: Tombol yang berubah warna saat di-klik, form dengan validasi real-time, animasi, dll.
      • Menggunakan hooks: useState, useEffect, useRef, useContext, dan custom hooks.
      • Akses API Browser: Seperti localStorage, navigator, atau manipulasi DOM langsung (jika diperlukan).
    • Directive "use client": Untuk menandakan bahwa sebuah file adalah Client Component, Anda wajib menambahkan "use client"; di baris paling atas file tersebut.
    • File Extension: Biasanya .tsx atau .ts (untuk TypeScript).

Bagaimana mereka bekerja sama? Bayangkan Server Components membuat "kerangka" atau "konten statis" halaman Anda dengan data yang sudah siap, lalu di dalam kerangka itu, Anda "menempelkan" Client Components untuk bagian yang interaktif. Server Components bisa meng-import dan menggunakan Client Components sebagai children, dan Next.js akan tahu bagaimana meng-"hydrate" mereka di browser.


Data Fetching di App Router: Mengambil Data dengan Cerdas

Salah satu fitur paling keren di App Router adalah cara pengambilan data. Next.js telah meningkatkan API fetch() bawaan JavaScript agar lebih cerdas:

  • fetch() yang Diperluas: Di Next.js, setiap panggilan fetch() secara otomatis di-cache dan di-deduplicate (dihilangkan duplikasinya) untuk permintaan yang sama, bahkan di antara request yang berbeda. Ini artinya, jika Anda melakukan fetch() data yang sama di beberapa komponen, Next.js hanya akan mengambilnya sekali.
  • Mengambil Data di Server Components: Ini adalah cara yang direkomendasikan untuk mengambil data di Next.js 15. Anda bisa langsung memanggil fetch() di Server Component Anda.
// app/blog/page.tsx (Ini adalah Server Component secara default)
interface Post {
  id: number;
  title: string;
  body: string;
}

async function getPosts(): Promise<Post[]> {
  const res = await fetch('<https://jsonplaceholder.typicode.com/posts>');
  // Otomatis di-cache. Anda bisa mengatur revalidate timing.
  if (!res.ok) {
    throw new Error('Failed to fetch posts');
  }
  return res.json();
}

export default async function BlogPage() {
  const posts = await getPosts(); // Mengambil data langsung di server

  return (
    <main>
      <h1>Latest Blog Posts</h1>
      <ul className="flex flex-col gap-4">
        {posts.map((post) => (
          <li key={post.id}>
            <h2>{post.title}</h2>
            <p>{post.body.substring(0, 100)}...</p>
          </li>
        ))}
      </ul>
    </main>
  );
}

Perhatikan penggunaan async/await langsung di dalam komponen atau fungsi getPosts. Next.js akan menunggu data ini siap sebelum merender HTML di server.

Halaman Blog: localhost:3000/blo
Halaman Blog: localhost:3000/blo

  • Mengambil Data di Client Components: Untuk data yang hanya dibutuhkan di sisi klien atau yang perlu diperbarui secara real-time berdasarkan interaksi pengguna, Anda tetap bisa menggunakan useEffect dan useState seperti di React biasa, tetapi pastikan komponen tersebut ditandai dengan "use client".
// components/InteractiveSearch.tsx
"use client"; // Ini adalah Client Component

import React, { useState, useEffect } from 'react';

interface SearchResult {
  id: number;
  name: string;
}

export default function InteractiveSearch() {
  const [query, setQuery] = useState<string>('');
  const [results, setResults] = useState<SearchResult[]>([]);
  const [loading, setLoading] = useState<boolean>(false);

  useEffect(() => {
    if (query.length < 3) {
      setResults([]);
      return;
    }

    const fetchResults = async () => {
      setLoading(true);
      try {
        const res = await fetch(`/api/search?q=${query}`); // Contoh API di Next.js
        const data: SearchResult[] = await res.json();
        setResults(data);
      } catch (error) {
        console.error("Failed to fetch search results", error);
        setResults([]);
      } finally {
        setLoading(false);
      }
    };

    const handler = setTimeout(() => {
      fetchResults();
    }, 500); // Debounce search

    return () => clearTimeout(handler);
  }, [query]);

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
        className="border p-2 rounded-md"
      />
      {loading && <p>Loading results...</p>}
      <ul>
        {results.map((result) => (
          <li key={result.id}>{result.name}</li>
        ))}
      </ul>
    </div>
  );
}

Routing Lanjutan dengan App Router: Fitur Tambahan yang Memudahkan

App Router tidak hanya tentang struktur dasar, tapi juga menyediakan fitur-fitur khusus untuk membuat aplikasi Anda lebih solid dan dinamis:

  • Dynamic Routes: Membuat route yang dinamis berdasarkan parameter di URL. Contoh: app/users/[userId]/page.tsx akan menampilkan halaman detail pengguna berdasarkan userId di URL (/users/123).
// app/users/[userId]/page.tsx
interface User {
  id: number;
  name: string;
  email: string;
}

interface UserPageProps {
  params: { userId: string };
}

async function getUser(userId: string): Promise<User> {
  const res = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
  if (!res.ok) {
    throw new Error('Failed to fetch user');
  }
  return res.json();
}

export default async function UserPage({ params }: UserPageProps) {
  const user = await getUser(params.userId);

  return (
    <main>
      <h1>User Profile: {user.name}</h1>
      <p>Email: {user.email}</p>
    </main>
  );
}
Dynamic Route: localhost:3000/users/[USER_ID]
Dynamic Route: localhost:3000/users/[USER_ID]

  • Loading States (loading.tsx): Menampilkan UI loading otomatis saat data sedang diambil atau route sedang di-load. Cukup buat file loading.tsx di dalam folder route yang Anda inginkan.
// app/blog/loading.tsx
export default function BlogLoading() {
  return <p>Loading blog posts... please wait!</p>;
}
Loading State
Loading State

  • Error Handling (error.tsx): Menangkap dan menampilkan error secara spesifik untuk bagian route tertentu. Ini melindungi aplikasi Anda dari crash total jika ada masalah di salah satu bagian.
// app/blog/error.tsx
"use client"; // Error boundaries harus Client Component

import { useEffect } from 'react';

interface ErrorPageProps {
  error: Error;
  reset: () => void;
}

export default function BlogError({ error, reset }: ErrorPageProps) {
  useEffect(() => {
    // Log error ke layanan pelacakan error
    console.error(error);
  }, [error]);

  return (
    <div>
      <h2>Something went wrong with the blog!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  );
}
Error State
Error State

  • Route Groups ((folderName)): Mengelompokkan route tanpa memengaruhi URL. Berguna untuk mengorganisir route yang memiliki layout atau tujuan yang sama, tapi tidak ingin nama foldernya muncul di URL. Contoh: app/(auth)/login/page.tsx.
  • Layouts (layout.tsx): Berbagi UI antar route yang berbeda. Misalnya, header dan footer yang sama di semua halaman. layout.tsx membungkus page.tsx atau layout.tsx lainnya di dalamnya.
// app/dashboard/layout.tsx
import React from 'react';

export default function DashboardLayout({
  children, // prop children akan menjadi `page.tsx` atau `layout.tsx` di bawahnya
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <nav>
          {/* Ini adalah navigasi khusus untuk dashboard */}
          Dashboard Nav
        </nav>
        <main>{children}</main> {/* Konten halaman dashboard akan dirender di sini */}
      </body>
    </html>
  );
}
  • Templates (template.tsx): Mirip dengan layout, tetapi template akan me-mount ulang komponennya setiap kali route berubah. Berguna untuk animasi transisi atau untuk state yang perlu direset saat navigasi.
  • Metadata API: Mengelola SEO dan metadata halaman (seperti title, description, gambar OG) dengan mudah. Anda bisa mengekspor objek metadata atau fungsi generateMetadata dari layout.tsx atau page.tsx.
// app/blog/[slug]/page.tsx
import type { Metadata } from 'next';

// Definisikan interface untuk struktur data Post
interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

// Mendapatkan metadata secara dinamis
export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
  // Pastikan slug adalah angka jika API endpoint mengharapkannya
  const postId = params.slug;
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`);

  if (!res.ok) {
    // Handle case where post is not found for metadata
    return {
      title: 'Post Not Found',
      description: 'The requested blog post could not be found.',
    };
  }

  const post: Post = await res.json();

  return {
    title: post.title,
    description: post.body.substring(0, 150) + '...', // Tambahkan ellipsis
    // Anda bisa menambahkan lebih banyak metadata di sini, contoh:
    // openGraph: {
    //   images: [`/some-image-for-post-${postId}.jpg`],
    // },
  };
}

// Fungsi untuk mengambil data posting blog
async function getPost(slug: string): Promise<Post | null> {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${slug}`);

  if (!res.ok) {
    // Jika respons tidak OK, lempar error atau kembalikan null
    // Ini akan ditangkap oleh error.tsx jika ada
    return null;
  }

  return res.json();
}

// Komponen halaman Anda di bawah ini
interface BlogPostPageProps {
  params: { slug: string };
}

export default async function BlogPostPage({ params }: BlogPostPageProps) {
  const post = await getPost(params.slug);

  if (!post) {
    // Anda bisa mengarahkan ke halaman 404 atau menampilkan pesan not found
    // Untuk demo sederhana, kita tampilkan pesan
    return (
      <div className="container mx-auto p-4">
        <h1 className="text-4xl font-bold mb-4">Post Not Found</h1>
        <p className="text-lg">The blog post you are looking for does not exist.</p>
      </div>
    );
  }

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-4xl font-bold mb-4">{post.title}</h1>
      <p className="text-gray-600 mb-6">By User ID: {post.userId}</p>
      <div className="prose lg:prose-xl">
        <p>{post.body}</p>
      </div>
      {/* Contoh tombol kembali (Client Component) */}
      {/* <BackButton /> */}
    </div>
  );
}
Blog Page: localhost:3000/blog/1
Blog Page: localhost:3000/blog/1

Memahami dan memanfaatkan App Router dengan semua fitur ini akan membuka banyak potensi untuk membangun aplikasi Next.js 15 yang modern, cepat, dan mudah dipelihara. Selanjutnya, kita akan mulai membangun aplikasi sederhana kita!


Bagian 4: Styling dan Mengembangkan Aplikasi Sederhana

Setelah memahami arsitektur dan cara kerja App Router, saatnya membuat aplikasi kita terlihat cantik dan berfungsi. Bagian ini akan membahas bagaimana kita bisa memberikan "pakaian" pada aplikasi Next.js kita menggunakan berbagai metode styling, lalu kita akan mempraktikkan semua yang sudah kita pelajari dengan membangun aplikasi blog sederhana.

Styling di Next.js: Memberikan Tampilan Menarik

Ada beberapa cara populer untuk memberikan gaya pada komponen di Next.js, dan Anda bisa memilih yang paling nyaman atau paling cocok untuk proyek Anda:

CSS Modules: CSS yang Terisolasi dan Terorganisir Ini adalah cara yang direkomendasikan oleh Next.js untuk mengelola CSS. Dengan CSS Modules, setiap file CSS (.module.css) akan secara otomatis memiliki scope lokal, artinya class name yang Anda definisikan di satu file tidak akan bertabrakan dengan class name yang sama di file lain. Ini sangat bagus untuk menghindari konflik gaya dan menjaga kebersihan kode.

  • Kapan digunakan? Ketika Anda ingin menulis CSS "tradisional" namun dengan keuntungan isolasi scope.

Contoh:

/* styles/Home.module.css */
.container {
  padding: 2rem;
  background-color: #f0f0f0;
}

.title {
  color: #333;
  font-size: 2.5rem;
}
// app/page.tsx
import styles from "../styles/Home.module.css";

export default function HomePage() {
  return (
    <div className={styles.container}>
      <h1 className={styles.title}>Selamat Datang di Blog Saya!</h1>
    </div>
  );
}
CSS Modules
CSS Modules

Tailwind CSS: Utilitas Cepat untuk Desain Responsif (Sangat Direkomendasikan!) Jika Anda memilih "Yes" untuk Tailwind CSS saat membuat proyek, Anda sudah selangkah lebih maju! Tailwind CSS adalah framework CSS berbasis utilitas yang memungkinkan Anda mendesain UI langsung di dalam JSX/TSX Anda dengan class pra-desain. Ini super cepat untuk prototyping dan membangun antarmuka pengguna yang responsif tanpa harus menulis CSS kustom yang banyak.

  • Kapan digunakan? Hampir di semua proyek modern karena kecepatan pengembangan, kemudahan responsivitas, dan ukuran bundle yang optimal.

Contoh:

// app/page.tsx (Tailwind CSS terinstal)
export default function HomePage() {
  return (
    <div className="min-h-screen bg-gray-100 flex items-center justify-center p-4">
      <h1 className="text-5xl font-bold text-blue-600 text-center">
        Hello dari Next.js 15 dengan Tailwind!
      </h1>
    </div>
  );
}
TailwindCSS
TailwindCSS

  • Integrasinya di Next.js biasanya otomatis jika Anda memilihnya saat create-next-app.

Inline Styles dan Global CSS:

  • Inline Styles: Mirip dengan React biasa, Anda bisa menerapkan gaya langsung di elemen menggunakan objek JavaScript. Cocok untuk gaya yang sangat spesifik dan dinamis.
// app/page.tsx
export default function HomePage() {
  return (
    <div style={{ backgroundColor: 'lightblue', padding: '20px' }}>
      <p style={{ color: 'darkblue', fontSize: '18px' }}>Ini adalah inline style.</p>
    </div>
  );
}
Inline Style
Inline Style

  • Global CSS: Untuk gaya yang ingin Anda terapkan ke seluruh aplikasi (misalnya reset CSS atau font dasar). Anda bisa meng-import file CSS biasa (bukan module.css) di dalam app/layout.tsx.
/* app/globals.css */
body {
  margin: 0;
  font-family: 'Inter', sans-serif;
}
h1, h2 {
  color: #222;
}
// app/page.tsx
export default function HomePage() {
  return (
    <div>
      <h1>Heading 1</h1>
      <h2>Heading 2</h2>
    </div>
  );
}
Globals.css
Globals.css

Membangun Aplikasi Contoh: Blog Sederhana

Sekarang, mari kita terapkan semua yang sudah kita pelajari dengan membangun aplikasi blog sederhana. Tujuannya adalah menampilkan daftar artikel dan halaman detail untuk setiap artikel. Kita akan menggunakan Server Components untuk mengambil data dan App Router untuk navigasi.

Perencanaan Fitur:

  • Daftar Artikel (Halaman Utama Blog): Menampilkan judul dan ringkasan singkat dari semua artikel.
  • Detail Artikel: Menampilkan judul lengkap dan konten lengkap dari satu artikel yang dipilih.

Langkah demi Langkah Implementasi:

Kita akan menggunakan API publik JSONPlaceholder untuk mensimulasikan data blog.

Membuat Tata Letak Global (app/layout.tsx): Ini adalah tata letak dasar yang akan membungkus semua halaman kita. Kita akan tambahkan <html> dan <body> tags, serta import global CSS (jika ada, seperti globals.css yang otomatis dibuat oleh create-next-app).

// app/layout.tsx
import Link from "next/link";
import "./globals.css"; // Pastikan file global CSS Anda ada di sini
import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "Blog Sederhana Next.js 15",
  description:
    "Panduan komprehensif Next.js 15 untuk pemula: Konsep dasar hingga deployment sederhana.",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="id">
      <body className="bg-gray-50 text-gray-900">
        <header className="bg-blue-700 text-white p-4 shadow-md">
          <nav className="container mx-auto flex justify-between items-center">
            <Link
              href="/"
              className="text-2xl font-bold hover:text-blue-200 transition-colors"
            >
              NextBlog 🚀
            </Link>
            <ul className="flex space-x-4">
              <li>
                <Link
                  href="/blog"
                  className="hover:text-blue-200 transition-colors"
                >
                  Blog
                </Link>
              </li>
              <li>
                <Link
                  href="/about"
                  className="hover:text-blue-200 transition-colors"
                >
                  Tentang
                </Link>
              </li>
            </ul>
          </nav>
        </header>
        <main className="container mx-auto p-4 py-8 min-h-screen">
          {children}
        </main>
        <footer className="bg-gray-800 text-white p-4 text-center mt-8">
          <p>
            &copy; {new Date().getFullYear()} Panduan Next.js 15. Hak Cipta
            Dilindungi.
          </p>
        </footer>
      </body>
    </html>
  );
}

Pastikan Anda memiliki file app/globals.css (otomatis dibuat oleh create-next-app) dan menambahkan beberapa gaya dasar di sana, misalnya untuk body atau utilitas Tailwind jika Anda menggunakannya.

Membuat Halaman Daftar Artikel Blog (app/blog/page.tsx): Kita akan membuat folder blog di dalam app, dan di dalamnya akan ada page.tsx yang bertindak sebagai halaman daftar artikel. Komponen ini akan menjadi Server Component karena kita akan langsung mengambil data posting di dalamnya.

// app/blog/page.tsx
import type { Metadata } from "next";
import Link from "next/link";

interface Post {
  id: number;
  title: string;
  body: string;
  userId: number; // Tambahkan ini jika dibutuhkan
}

export const metadata: Metadata = {
  title: "Daftar Artikel Blog",
  description: "Temukan berbagai artikel menarik di blog Next.js kami.",
};

async function getPosts(): Promise<Post[]> {
  const res = await fetch("<https://jsonplaceholder.typicode.com/posts>");
  if (!res.ok) {
    // Ini akan memicu error.tsx jika ada
    throw new Error("Gagal mengambil data artikel");
  }
  return res.json();
}

export default async function BlogListPage() {
  const posts = await getPosts();

  return (
    <section>
      <h1 className="text-5xl font-extrabold text-center mb-10">
        Daftar Artikel Terbaru
      </h1>
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
        {posts.map((post) => (
          <article
            key={post.id}
            className="bg-white rounded-lg shadow-md hover:shadow-xl transition-shadow duration-300 overflow-hidden"
          >
            <div className="p-6">
              <h2 className="text-2xl font-bold text-gray-900 mb-3 leading-tight">
                <Link
                  href={`/blog/${post.id}`}
                  className="hover:text-blue-600 transition-colors"
                >
                  {post.title}
                </Link>
              </h2>
              <p className="text-gray-700 text-base mb-4 line-clamp-3">
                {post.body}
              </p>
              <Link
                href={`/blog/${post.id}`}
                className="text-blue-600 hover:text-blue-800 font-semibold inline-flex items-center"
              >
                Baca Selengkapnya
                <svg
                  className="ml-1 w-4 h-4"
                  fill="none"
                  stroke="currentColor"
                  viewBox="0 0 24 24"
                  xmlns="<http://www.w3.org/2000/svg>"
                >
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    strokeWidth="2"
                    d="M14 5l7 7m0 0l-7 7m7-7H3"
                  ></path>
                </svg>
              </Link>
            </div>
          </article>
        ))}
      </div>
    </section>
  );
}

Perhatikan penggunaan komponen Link dari next/link untuk navigasi antar halaman tanpa full-page reload.

Page localhost:3000/blog
Page localhost:3000/blog

Membuat Halaman Detail Artikel (app/blog/[slug]/page.tsx): Kita sudah membahas kode ini di Bagian 3, tapi saya akan menyertakannya lagi di sini sebagai bagian dari contoh lengkap. Folder [slug] menunjukkan bahwa ini adalah dynamic route.

// app/blog/[slug]/page.tsx
import type { Metadata } from 'next';
import Link from 'next/link';

// Definisikan interface untuk struktur data Post
interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

// Mendapatkan metadata secara dinamis
export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
  const postId = params.slug;
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`);

  if (!res.ok) {
    return {
      title: 'Artikel Tidak Ditemukan',
      description: 'Artikel yang Anda cari tidak ada.',
    };
  }

  const post: Post = await res.json();

  return {
    title: `${post.title} | Blog Sederhana`,
    description: post.body.substring(0, 150) + '...',
  };
}

// Fungsi untuk mengambil data posting blog
async function getPost(slug: string): Promise<Post | null> {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${slug}`);

  if (!res.ok) {
    return null; // Mengembalikan null untuk penanganan 404/not found
  }

  return res.json();
}

// Komponen halaman blog detail
interface BlogPostPageProps {
  params: { slug: string };
}

export default async function BlogPostPage({ params }: BlogPostPageProps) {
  const post = await getPost(params.slug);

  if (!post) {
    // Tampilkan pesan "Artikel Tidak Ditemukan"
    return (
      <div className="container mx-auto p-4 text-center">
        <h1 className="text-4xl font-bold mb-4 text-red-600">404 - Artikel Tidak Ditemukan</h1>
        <p className="text-lg text-gray-700">Maaf, artikel yang Anda cari tidak ada atau telah dihapus.</p>
        <Link href="/blog" className="mt-6 inline-block bg-blue-500 text-white px-6 py-3 rounded-md hover:bg-blue-600 transition-colors">
          Kembali ke Daftar Blog
        </Link>
      </div>
    );
  }

  return (
    <div className="container mx-auto p-4">
      <article className="bg-white shadow-lg rounded-lg p-6 mb-8">
        <h1 className="text-4xl font-extrabold text-gray-900 mb-4">{post.title}</h1>
        <p className="text-sm text-gray-500 mb-6">Ditulis oleh Pengguna #{post.userId}</p>
        <div className="prose lg:prose-xl text-gray-800 leading-relaxed">
          <p>{post.body}</p>
        </div>
      </article>
      <div className="flex justify-center">
        <Link href="/blog" className="inline-block bg-indigo-600 text-white px-6 py-3 rounded-md hover:bg-indigo-700 transition-colors duration-200">
          &larr; Kembali ke Daftar Artikel
        </Link>
      </div>
    </div>
  );
}

Page localhost:3000/blog/1
Page localhost:3000/blog/1

Menambahkan Interaktivitas Sederhana (Client Component - Opsional) Untuk menunjukkan bagaimana Client Components digunakan, kita bisa membuat tombol sederhana yang hanya berfungsi di browser. Misalnya, tombol "Bagikan" yang menyalin URL artikel. Kita akan membuat komponen ini di folder components/ dan menggunakannya di halaman detail blog.

// components/ShareButton.tsx
"use client"; // Ini wajib untuk Client Component!

import React from 'react';

interface ShareButtonProps {
  url: string;
  title: string;
}

export default function ShareButton({ url, title }: ShareButtonProps) {
  const handleShare = async () => {
    if (navigator.share) {
      try {
        await navigator.share({
          title: title,
          url: url,
        });
        console.log('Konten berhasil dibagikan');
      } catch (error) {
        console.error('Gagal membagikan konten:', error);
      }
    } else {
      // Fallback untuk browser yang tidak mendukung Web Share API
      // Menggunakan document.execCommand('copy') sebagai alternatif clipboard
      const tempInput = document.createElement('input');
      tempInput.value = url;
      document.body.appendChild(tempInput);
      tempInput.select();
      try {
        document.execCommand('copy');
        alert('Link berhasil disalin ke clipboard!');
      } catch (err) {
        console.error('Gagal menyalin link:', err);
        alert('Gagal menyalin link. Silakan salin secara manual: ' + url);
      }
      document.body.removeChild(tempInput);
    }
  };

  return (
    <button
      onClick={handleShare}
      className="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded-md transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-opacity-75"
    >
      Bagikan Artikel Ini
    </button>
  );
}

Kemudian, Anda bisa meng-import dan menggunakan ShareButton di app/blog/[slug]/page.tsx di bawah elemen <div className="prose ...">.

// app/blog/[slug]/page.tsx
import ShareButton from "@/components/ShareButton";
import type { Metadata } from "next";
import Link from "next/link";

// Definisikan interface untuk struktur data Post
interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

// Mendapatkan metadata secara dinamis
export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>;
}): Promise<Metadata> {
  const { slug } = await params;
  const postId = slug;
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${postId}`
  );

  if (!res.ok) {
    return {
      title: "Artikel Tidak Ditemukan",
      description: "Artikel yang Anda cari tidak ada.",
    };
  }

  const post: Post = await res.json();

  return {
    title: `${post.title} | Blog Sederhana`,
    description: post.body.substring(0, 150) + "...",
  };
}

// Fungsi untuk mengambil data posting blog
async function getPost(slug: string): Promise<Post | null> {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${slug}`);

  if (!res.ok) {
    return null; // Mengembalikan null untuk penanganan 404/not found
  }

  return res.json();
}

export default async function BlogPostPage({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const post = await getPost(slug);

  if (!post) {
    // Tampilkan pesan "Artikel Tidak Ditemukan"
    return (
      <div className="container mx-auto p-4 text-center">
        <h1 className="text-4xl font-bold mb-4 text-red-600">
          404 - Artikel Tidak Ditemukan
        </h1>
        <p className="text-lg text-gray-700">
          Maaf, artikel yang Anda cari tidak ada atau telah dihapus.
        </p>
        <Link
          href="/blog"
          className="mt-6 inline-block bg-blue-500 text-white px-6 py-3 rounded-md hover:bg-blue-600 transition-colors"
        >
          Kembali ke Daftar Blog
        </Link>
      </div>
    );
  }

  return (
    <div className="container mx-auto p-4">
      <article className="bg-white shadow-lg rounded-lg p-6 mb-8">
        <h1 className="text-4xl font-extrabold text-gray-900 mb-4">
          {post.title}
        </h1>
        <p className="text-sm text-gray-500 mb-6">
          Ditulis oleh Pengguna #{post.userId}
        </p>
        <div className="prose lg:prose-xl text-gray-800 leading-relaxed">
          <p>{post.body}</p>
        </div>
        <div className="mt-6 flex justify-center">
          {/* Menggunakan ShareButton sebagai Client Component */}
          <ShareButton url={`/blog/${post.id}`} title={post.title} />
        </div>
      </article>
      <div className="flex justify-center">
        <Link
          href="/blog"
          className="inline-block bg-indigo-600 text-white px-6 py-3 rounded-md hover:bg-indigo-700 transition-colors duration-200"
        >
          &larr; Kembali ke Daftar Artikel
        </Link>
      </div>
    </div>
  );
}
Share Button
Share Button

Dengan langkah-langkah di atas, Anda sekarang memiliki dasar aplikasi blog yang berfungsi penuh dengan Next.js 15, App Router, TypeScript, dan styling dasar! Jangan lupa untuk menjalankan npm run dev setelah membuat perubahan pada file Anda untuk melihat hasilnya di browser.


Bagian 5: Deployment Sederhana

Selamat! Jika Anda sudah mengikuti panduan ini sampai sini, berarti Anda sudah berhasil membangun aplikasi Next.js 15 yang fungsional. Tapi, aplikasi yang keren tentu saja ingin dilihat dan digunakan oleh banyak orang, bukan? Nah, di bagian ini, kita akan membahas "memamerkan" aplikasi Anda ke dunia maya, atau yang sering disebut dengan deployment.

Proses deployment ini adalah langkah mengubah aplikasi yang Anda buat di komputer lokal menjadi aplikasi yang bisa diakses oleh siapa saja melalui internet. Jangan khawatir, Next.js dirancang untuk deployment yang sangat mudah, terutama dengan bantuan platform modern.


Mempersiapkan Aplikasi untuk Produksi: Sesi Finalisasi Sebelum Launching

Sebelum "meluncurkan" aplikasi Anda, ada satu langkah penting yang harus dilakukan: membangun versi produksi dari aplikasi Anda. Saat Anda mengembangkan aplikasi dengan npm run dev, Next.js menjalankan mode pengembangan yang menyertakan banyak tool untuk membantu debugging dan hot reloading. Tapi, untuk produksi, kita butuh versi yang lebih ringkas, cepat, dan dioptimalkan.

Membangun Proyek (next build): Di terminal atau command prompt Anda, matikan server pengembangan (jika masih berjalan, tekan Ctrl + C), lalu jalankan perintah ini:

npm run build
# atau jika Anda menggunakan Yarn:
# yarn build

Next.js akan mulai mengoptimalkan aplikasi Anda. Ini termasuk:

  • Mengompilasi semua kode TypeScript/JavaScript.
  • Mengoptimalkan gambar dan font.
  • Meng-generate file HTML statis (untuk SSG).
  • Membuat bundle JavaScript yang seoptimal mungkin.
  • Mengidentifikasi rute-rute yang akan di-render di server atau sebagai halaman statis.

Proses ini mungkin memakan waktu beberapa saat tergantung pada ukuran proyek Anda.


Memahami Output Build: Setelah proses build selesai, Anda akan melihat output di terminal yang mirip dengan ini:

Next build
Next build
  • λ (Lambda): Menunjukkan rute ini akan di-render di server (Server-Side Rendering).
  • (Lingkaran): Menunjukkan rute ini di-generate sebagai HTML statis (Static Site Generation).
  • First Load JS: Jumlah JavaScript yang diunduh pertama kali oleh browser untuk setiap halaman. Semakin kecil, semakin cepat!

Anda juga akan melihat folder .next/ yang baru di root proyek Anda. Folder ini berisi semua file yang di-generate Next.js untuk produksi. Anda tidak perlu menyentuh folder ini secara manual; biarkan Next.js yang mengurusnya.

Untuk menguji versi produksi secara lokal (tanpa server pengembangan), Anda bisa menjalankan:

npm run start
# atau jika Anda menggunakan Yarn:
# yarn start

Ini akan menjalankan aplikasi Anda menggunakan build produksi.


Platform Deployment yang Umum: Rumah Baru untuk Aplikasi Anda

Ada banyak penyedia hosting yang mendukung Next.js, tetapi dua yang paling populer dan direkomendasikan adalah Vercel (dibuat oleh tim Next.js sendiri) dan Netlify. Keduanya menawarkan deployment yang sangat mudah dan fitur-fitur canggih.

Vercel: Pilihan Terbaik untuk Next.js Vercel adalah platform cloud yang dioptimalkan khusus untuk Next.js. Ini seperti rumah yang dirancang sempurna untuk aplikasi Next.js Anda, dengan semua fasilitas yang sudah terpasang.

  • Mengapa Vercel?
    • Integrasi Penuh: Dibuat oleh tim Next.js, jadi integrasinya paling mulus.
    • Deployment Otomatis: Otomatis deploy setiap kali Anda melakukan push ke repositori Git Anda (GitHub, GitLab, Bitbucket).
    • Optimasi Otomatis: Otomatis mengoptimalkan performa (CDN, edge functions, serverless).
    • Gratis untuk Proyek Pribadi: Anda bisa deploy banyak proyek secara gratis.
  • Langkah-langkah Deployment dengan Vercel:
    1. Daftar Akun Vercel: Kunjungi vercel.com dan daftar menggunakan akun GitHub/GitLab/Bitbucket Anda.
    2. Hubungkan Repositori Git: Setelah masuk, Anda akan diminta untuk mengimpor proyek Git. Pilih repositori proyek Next.js Anda.
    3. Konfigurasi Proyek: Vercel biasanya akan otomatis mendeteksi bahwa ini adalah proyek Next.js dan mengonfigurasi pengaturan build yang tepat. Anda hanya perlu memberikan nama proyek.
    4. Deploy! Klik tombol "Deploy". Vercel akan otomatis melakukan proses build dan meluncurkan aplikasi Anda. Setelah selesai, Anda akan mendapatkan URL publik untuk aplikasi Anda.
    Anda juga bisa menggunakan Vercel CLI (Command Line Interface):
    • Instal Vercel CLI: npm i -g vercel
    • Masuk: vercel login (akan membuka browser untuk otentikasi)
    • Deploy dari root proyek Anda: vercel (ikuti instruksi di terminal)
Deploy ke Vercel
Deploy ke Vercel
Deploy ke  Vercel
Deploy ke Vercel
Vercel
Vercel

Kesimpulan

Selamat! Anda telah mencapai akhir dari Panduan Komprehensif Next.js 15 untuk Pemula ini. Kita sudah melalui perjalanan yang cukup panjang, mulai dari memahami filosofi dasar Next.js sebagai framework React yang full-stack, berbagai strategi rendering seperti SSR, SSG, ISR, hingga menyelami jantung Next.js 15 yaitu App Router dengan konsep Server dan Client Components-nya yang revolusioner.

Kita juga sudah mencoba "mengotori tangan" dengan menyiapkan proyek baru berbasis TypeScript, memahami struktur proyeknya, dan bahkan membangun bagian-bagian inti dari aplikasi blog sederhana. Terakhir, kita baru saja membahas bagaimana cara membawa aplikasi Anda ke internet dengan langkah-langkah deployment yang sederhana menggunakan platform seperti Vercel dan Netlify.

Next.js 15 adalah alat yang sangat kuat di tangan Anda. Dengan pemahaman tentang App Router dan kemampuan untuk mengoptimalkan performa serta pengalaman developer, Anda kini memiliki fondasi yang kokoh untuk membangun aplikasi web modern yang cepat, aman, dan scalable.

Apa Selanjutnya? Teruslah Bereksplorasi!

Dunia pengembangan web selalu bergerak cepat, dan Next.js juga terus berevolusi. Jangan berhenti di sini!

  • Praktikkan: Cobalah membangun lebih banyak proyek, mulai dari yang sederhana hingga yang lebih kompleks. Semakin banyak Anda ngoding, semakin cepat Anda akan menguasai Next.js.
  • Eksplorasi Fitur Lanjutan: Next.js masih punya banyak fitur canggih lainnya (seperti Route Handlers untuk API, middleware, image optimization yang lebih mendalam, dll.) yang layak Anda pelajari seiring berjalannya waktu.
  • Bergabung dengan Komunitas: Ada banyak komunitas Next.js di Discord, forum, atau platform media sosial. Bertanya, berbagi, dan belajar dari orang lain adalah cara terbaik untuk terus berkembang.
  • Baca Dokumentasi Resmi: Dokumentasi Next.js (nextjs.org/docs) adalah sumber terbaik dan paling mutakhir untuk informasi.

Potensi Next.js untuk aplikasi skala besar dan kinerja tinggi sangatlah besar. Dengan dasar yang Anda peroleh dari panduan ini, Anda sudah siap untuk menjelajahi berbagai kemungkinan dan menciptakan pengalaman web yang luar biasa.

Terima kasih sudah mengikuti panduan ini. Selamat membangun dengan Next.js 15!