1. Pengenalan Clerk
Clerk adalah platform autentikasi dan user management yang menyediakan solusi lengkap untuk login, registrasi, manajemen profil, dan kontrol akses β tanpa perlu membangun semuanya dari nol. Clerk memberikan komponen UI siap pakai, SDK yang kaya, dan dashboard admin yang powerful.
Clerk mendukung berbagai metode autentikasi: email/password, social login (Google, GitHub, Apple, dll.), passwordless (magic link, OTP), multi-factor authentication (MFA), dan SSO (SAML).
Mengapa Menggunakan Clerk?
| Keunggulan | Penjelasan |
|---|---|
| Drop-in UI Components | Komponen login, signup, profil siap pakai β tinggal render |
| Multi-Framework | Next.js, React, Remix, Astro, Express, dan banyak lagi |
| Social Login | Google, GitHub, Apple, Facebook, Microsoft, dan 20+ lainnya |
| Organizations | Multi-tenancy, team management, role-based access control |
| Webhooks | Real-time events untuk sinkronisasi dengan database Anda |
| User Management | Dashboard admin untuk mengelola semua user |
Clerk vs Alternatif Lain
| Aspek | Clerk | NextAuth.js | Firebase Auth | Auth0 |
|---|---|---|---|---|
| UI Components | β Built-in | β Manual | π‘ Widget | π‘ Universal Login |
| Setup Time | β‘ 5 menit | π‘ 30 menit | π‘ 15 menit | π΄ 1 jam |
| Organizations | β Built-in | β Manual | β Tidak ada | β Built-in |
| Free Tier | 10.000 MAU | Gratis (self-host) | 50.000 MAU | 7.500 MAU |
| Self-hosted | β Tidak | β Ya | β Tidak | β Tidak |
| Learning Curve | π’ Mudah | π‘ Sedang | π’ Mudah | π΄ Curam |
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β CLERK ARCHITECTURE β β β β ββββββββββββββββββββββββ ββββββββββββββββββββββββ β β β Your Application β β Clerk Dashboard β β β β β β (clerk.com) β β β β ββββββββββββββββββ β β β β β β β Clerk Provider β β β β’ App Settings β β β β βββββββββ¬βββββββββ β β β’ User Management β β β β β β β β’ Appearance Config β β β β βββββββββΌβββββββββ β β β’ Social Connectionsβ β β β β UI Components β β β β’ Webhooks Config β β β β β <SignIn /> β β β β’ Organizations β β β β β <SignUp /> β β ββββββββββββββββββββββββ β β β β <UserButton /> β β β β β βββββββββ¬βββββββββ β β β β β β β β β βββββββββΌβββββββββ β β β β β useAuth() β β β β β β useUser() β β β β β β auth() β β β Server-side β β β βββββββββ¬βββββββββ β β β ββββββββββββΌββββββββββββ β β β β β ββββββββββββΌββββββββββββββββββββββββββββββββββββ β β β CLERK API β β β β β’ Session Management β β β β β’ JWT Tokens β β β β β’ User CRUD β β β β β’ OAuth Flows β β β β β’ MFA Verification β β β ββββββββββββββββββββββββββββββββββββββββββββββββ β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Setup dan Instalasi
Langkah 1: Buat Akun Clerk
1. Buka https://clerk.com dan daftar akun (bisa pakai GitHub) 2. Buat aplikasi baru di dashboard 3. Pilih metode autentikasi yang diinginkan: - Email / Password - Google Sign-In - GitHub Sign-In - Magic Link (passwordless) 4. Catat API Keys yang diberikan: - NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... - CLERK_SECRET_KEY=sk_test_...
Langkah 2: Install Package
# Untuk Next.js App Router npm install @clerk/nextjs # Untuk React (standalone) npm install @clerk/react # Untuk Remix npm install @clerk/remix # Untuk Express/Node.js backend npm install @clerk/express # Untuk Astro npm install @clerk/astro
Langkah 3: Environment Variables
# .env.local β JANGAN commit ke git! # Ambil dari Clerk Dashboard β API Keys NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_aWQtZm9v... CLERK_SECRET_KEY=sk_test_abc123xyz... # URL configuration NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/dashboard # Webhook secret (untuk verifikasi webhook) CLERK_WEBHOOK_SECRET=whsec_...
Langkah 4: ClerkProvider
// app/layout.tsx β Root Layout dengan ClerkProvider
import { ClerkProvider } from '@clerk/nextjs';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata = {
title: 'BeebaneLabs',
description: 'Tutorial web development modern'
};
export default function RootLayout({
children
}: {
children: React.ReactNode
}) {
return (
<ClerkProvider>
<html lang="id">
<body className={inter.className}>
{children}
</body>
</html>
</ClerkProvider>
);
}
ClerkProvider harus membungkus seluruh aplikasi. Di Next.js App Router, taruh di app/layout.tsx. Di Pages Router, taruh di pages/_app.tsx. Pastikan environment variables diawali dengan NEXT_PUBLIC_ untuk yang bisa diakses di client-side.
3. Komponen UI Clerk
Clerk menyediakan komponen UI siap pakai yang bisa langsung digunakan. Komponen-komponen ini sudah mendukung dark mode, responsive, dan bisa dikustomisasi.
SignIn dan SignUp
// app/sign-in/[[...sign-in]]/page.tsx
// Catch-all route untuk Clerk sign-in flow
import { SignIn } from '@clerk/nextjs';
export default function SignInPage() {
return (
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100vh'
}}>
<SignIn
path="/sign-in"
routing="path"
signUpUrl="/sign-up"
appearance={{
elements: {
rootBox: 'mx-auto',
card: 'shadow-xl rounded-2xl'
}
}}
/>
</div>
);
}
// app/sign-up/[[...sign-up]]/page.tsx
import { SignUp } from '@clerk/nextjs';
export default function SignUpPage() {
return (
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '100vh'
}}>
<SignUp
path="/sign-up"
routing="path"
signInUrl="/sign-in"
/>
</div>
);
}
UserButton β Profil Dropdown
// components/Header.tsx
import {
SignedIn,
SignedOut,
SignInButton,
SignUpButton,
UserButton
} from '@clerk/nextjs';
export default function Header() {
return (
<header className="header">
<nav>
<a href="/">BeebaneLabs</a>
<div className="nav-right">
{/*
SignedIn: hanya render saat user sudah login
SignedOut: hanya render saat user belum login
*/}
<SignedOut>
<SignInButton mode="modal">
<button className="btn-secondary">Masuk</button>
</SignInButton>
<SignUpButton mode="modal">
<button className="btn-primary">Daftar</button>
</SignUpButton>
</SignedOut>
<SignedIn>
<UserButton
afterSignOutUrl="/"
appearance={{
elements: {
avatarBox: 'w-10 h-10'
}
}}
/>
</SignedIn>
</div>
</nav>
</header>
);
}
Semua Komponen UI Clerk
| Komponen | Fungsi |
|---|---|
<SignIn /> | Halaman login lengkap (email, social, passwordless) |
<SignUp /> | Halaman registrasi lengkap |
<UserButton /> | Avatar profil dengan dropdown menu |
<UserProfile /> | Halaman pengaturan profil lengkap |
<OrganizationSwitcher /> | Switch antar organization |
<OrganizationList /> | Daftar organizations |
<OrganizationProfile /> | Profil dan settings organization |
<CreateOrganization /> | Form buat organization baru |
<SignInButton /> | Tombol trigger sign-in (modal/redirect) |
<SignUpButton /> | Tombol trigger sign-up |
<SignOutButton /> | Tombol sign-out |
<SignedIn /> | Wrapper β render hanya saat authenticated |
<SignedOut /> | Wrapper β render hanya saat unauthenticated |
<Protect /> | Render berdasarkan permission/role |
4. User Management
Mengakses User Data di Client
// components/UserProfile.tsx
'use client';
import { useUser, useAuth } from '@clerk/nextjs';
export default function UserProfile() {
const { user, isLoaded, isSignedIn } = useUser();
const { userId, sessionId, getToken } = useAuth();
// Loading state
if (!isLoaded) {
return <div>Loading...</div>;
}
// Not signed in
if (!isSignedIn) {
return <div>Silakan login terlebih dahulu</div>;
}
return (
<div className="profile-card">
{/* Avatar */}
<img
src={user.imageUrl}
alt={user.fullName || 'User'}
className="avatar"
/>
{/* Informasi dasar */}
<h2>{user.fullName}</h2>
<p>{user.primaryEmailAddress?.emailAddress}</p>
{/* Metadata */}
<div className="meta">
<span>ID: {user.id}</span>
<span>Session: {sessionId}</span>
<span>
Bergabung: {user.createdAt?.toLocaleDateString('id-ID')}
</span>
</div>
{/* Verifikasi email */}
<div className="verifications">
{user.emailAddresses.map((email) => (
<div key={email.id}>
{email.emailAddress}
{email.verification?.status === 'verified'
? ' β
'
: ' β Belum verifikasi'}
</div>
))}
</div>
{/* Public metadata */}
<div className="metadata">
<p>Role: {user.publicMetadata.role as string || 'user'}</p>
</div>
</div>
);
}
Mengakses User Data di Server
// app/dashboard/page.tsx β Server Component
import { auth, currentUser } from '@clerk/nextjs/server';
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
// auth() β mendapatkan userId dan sessionId di server
const { userId, sessionId } = auth();
// Redirect jika belum login
if (!userId) {
redirect('/sign-in');
}
// currentUser() β mendapatkan data lengkap user
const user = await currentUser();
return (
<div className="dashboard">
<h1>Dashboard</h1>
<p>Selamat datang, {user?.firstName}!</p>
<div className="stats">
<div className="stat">
<span className="label">User ID</span>
<span className="value">{userId}</span>
</div>
<div className="stat">
<span className="label">Email</span>
<span className="value">
{user?.primaryEmailAddress?.emailAddress}
</span>
</div>
<div className="stat">
<span className="label">Role</span>
<span className="value">
{(user?.publicMetadata?.role as string) || 'user'}
</span>
</div>
</div>
</div>
);
}
Updating User Metadata
// app/api/set-role/route.ts
import { auth, clerkClient } from '@clerk/nextjs/server';
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
const { userId } = auth();
if (!userId) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
const { role } = await request.json();
// Update public metadata (bisa diakses di client)
await clerkClient.users.updateUserMetadata(userId, {
publicMetadata: {
role: role, // 'admin', 'editor', 'user'
}
});
return NextResponse.json({ success: true, role });
}
// Tipe metadata:
// publicMetadata β bisa diakses di client (useUser)
// privateMetadata β hanya di server (clerkClient)
// unsafeMetadata β user bisa update sendiri
5. Middleware dan Proteksi Route
Clerk Middleware
// middleware.ts β di root proyek (bukan di app/)
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
// Definisikan route yang membutuhkan autentikasi
const isProtectedRoute = createRouteMatcher([
'/dashboard(.*)', // Semua route di /dashboard
'/settings(.*)', // Semua route di /settings
'/api/protected(.*)', // API routes yang dilindungi
]);
// Definisikan route yang hanya untuk admin
const isAdminRoute = createRouteMatcher([
'/admin(.*)',
]);
export default clerkMiddleware((auth, req) => {
// Proteksi route yang membutuhkan login
if (isProtectedRoute(req)) {
auth().protect();
}
// Proteksi route admin β butuh role 'admin'
if (isAdminRoute(req)) {
auth().protect({
unauthorizedUrl: '/sign-in',
forbiddenUrl: '/not-authorized'
});
}
});
export const config = {
// Matcher: route mana yang diproses middleware
matcher: [
// Skip internal Next.js dan static files
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Selalu jalankan untuk API routes
'/(api|trpc)(.*)',
],
};
Route Protection dengan Protect Component
// app/admin/page.tsx β Protect berdasarkan role
import { Protect } from '@clerk/nextjs';
export default function AdminPage() {
return (
<div>
<h1>Admin Panel</h1>
{/*
Protect component β render berdasarkan permission/role
Jika user tidak punya role 'admin', tampilkan fallback
*/}
<Protect
role="admin"
fallback={
<div className="error">
<h2>Akses Ditolak</h2>
<p>Anda tidak memiliki izin untuk mengakses halaman ini.</p>
</div>
}
>
<div className="admin-content">
<h2>Manajemen User</h2>
<p>Konten khusus admin yang hanya bisa dilihat oleh admin.</p>
{/* Admin content here */}
</div>
</Protect>
</div>
);
}
6. Webhooks
Clerk mengirim webhook events setiap kali terjadi perubahan pada user, organization, atau session. Ini sangat penting untuk sinkronisasi data dengan database Anda sendiri.
Setup Webhook di Clerk Dashboard
1. Buka Clerk Dashboard β Webhooks 2. Klik "Add Endpoint" 3. Masukkan URL endpoint Anda: https://your-domain.com/api/webhooks/clerk 4. Pilih events yang ingin di-subscribe: β user.created β user.updated β user.deleted β organization.created β organizationMembership.created 5. Simpan β catat "Signing Secret" (whsec_...) 6. Tambahkan ke .env.local: CLERK_WEBHOOK_SECRET=whsec_...
Webhook Handler
// app/api/webhooks/clerk/route.ts
import { Webhook } from 'svix';
import { headers } from 'next/headers';
import { WebhookEvent } from '@clerk/nextjs/server';
import { db } from '@/lib/db';
export async function POST(request: Request) {
// 1. Verifikasi webhook signature
const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET;
if (!WEBHOOK_SECRET) {
throw new Error('CLERK_WEBHOOK_SECRET not set');
}
const headerPayload = headers();
const svixId = headerPayload.get('svix-id');
const svixTimestamp = headerPayload.get('svix-timestamp');
const svixSignature = headerPayload.get('svix-signature');
if (!svixId || !svixTimestamp || !svixSignature) {
return new Response('Missing svix headers', { status: 400 });
}
const payload = await request.json();
const body = JSON.stringify(payload);
const wh = new Webhook(WEBHOOK_SECRET);
let evt: WebhookEvent;
try {
evt = wh.verify(body, {
'svix-id': svixId,
'svix-timestamp': svixTimestamp,
'svix-signature': svixSignature,
}) as WebhookEvent;
} catch (err) {
console.error('Webhook verification failed:', err);
return new Response('Verification failed', { status: 400 });
}
// 2. Handle berbagai event types
const eventType = evt.type;
switch (eventType) {
case 'user.created': {
const { id, email_addresses, first_name, last_name, image_url } = evt.data;
console.log('User created:', id);
// Simpan user ke database lokal
await db.user.create({
data: {
clerkId: id,
email: email_addresses[0]?.email_address || '',
name: `${first_name || ''} ${last_name || ''}`.trim(),
avatar: image_url,
createdAt: new Date()
}
});
break;
}
case 'user.updated': {
const { id, email_addresses, first_name, last_name, image_url } = evt.data;
console.log('User updated:', id);
await db.user.update({
where: { clerkId: id },
data: {
email: email_addresses[0]?.email_address || '',
name: `${first_name || ''} ${last_name || ''}`.trim(),
avatar: image_url,
}
});
break;
}
case 'user.deleted': {
const { id } = evt.data;
console.log('User deleted:', id);
await db.user.delete({
where: { clerkId: id! }
});
break;
}
default:
console.log('Unhandled event type:', eventType);
}
return new Response('Webhook processed', { status: 200 });
}
Webhook Events yang Tersedia
| Event | Trigger |
|---|---|
user.created | User baru mendaftar |
user.updated | User mengupdate profil |
user.deleted | User dihapus dari Clerk |
session.created | User login (session baru) |
session.ended | User logout |
organization.created | Organization baru dibuat |
organization.updated | Organization diupdate |
organizationMembership.created | User ditambahkan ke org |
organizationMembership.deleted | User dihapus dari org |
Selalu verifikasi signature webhook menggunakan svix library! Tanpa verifikasi, siapapun bisa mengirim fake webhook ke endpoint Anda. Tanda tangan digital memastikan webhook benar-benar berasal dari Clerk.
7. Organizations
Organizations memungkinkan Anda membuat fitur multi-tenancy β satu user bisa menjadi anggota beberapa organization, masing-masing dengan role dan permission berbeda.
Organization Components
// app/organizations/page.tsx
import {
OrganizationSwitcher,
OrganizationList,
CreateOrganization
} from '@clerk/nextjs';
export default function OrganizationsPage() {
return (
<div className="org-page">
<h1>Organizations</h1>
{/*
OrganizationSwitcher β dropdown untuk switch org
Menampilkan org saat ini dan memungkinkan switch
*/}
<OrganizationSwitcher
afterCreateOrganizationUrl="/organization/:slug"
afterSelectOrganizationUrl="/organization/:slug"
appearance={{
elements: {
rootBox: 'mb-8'
}
}}
/>
{/*
OrganizationList β daftar semua org yang user ikuti
Plus tombol untuk membuat org baru
*/}
<OrganizationList
hidePersonal={false}
afterSelectOrganizationUrl="/organization/:slug"
afterCreateOrganizationUrl="/organization/:slug"
/>
</div>
);
}
Organization Roles dan Permissions
// app/api/organizations/[orgId]/route.ts
import { auth, clerkClient } from '@clerk/nextjs/server';
import { NextResponse } from 'next/server';
export async function GET(
request: Request,
{ params }: { params: { orgId: string } }
) {
const { userId, orgId } = auth();
if (!userId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Mendapatkan data organization
const organization = await clerkClient.organizations.getOrganization({
organizationId: params.orgId
});
// Mendapatkan daftar member
const members = await clerkClient.organizations.getOrganizationMembershipList({
organizationId: params.orgId
});
return NextResponse.json({
organization,
members: members.data.map(m => ({
id: m.id,
role: m.role,
user: {
id: m.publicUserData?.userId,
name: m.publicUserData?.firstName + ' ' + m.publicUserData?.lastName,
avatar: m.publicUserData?.imageUrl
}
}))
});
}
8. Kustomisasi dan Theming
Appearance API
// app/layout.tsx β Kustomisasi global Clerk
import { ClerkProvider } from '@clerk/nextjs';
// Definisikan tema global
const clerkAppearance = {
variables: {
// Warna
colorPrimary: '#3b82f6',
colorBackground: '#0f172a',
colorInputBackground: '#1e293b',
colorInputText: '#e2e8f0',
colorText: '#e2e8f0',
colorTextSecondary: '#94a3b8',
colorDanger: '#ef4444',
colorSuccess: '#22c55e',
// Typography
fontFamily: 'Inter, system-ui, sans-serif',
fontSize: '0.875rem',
fontWeight: {
normal: 400,
medium: 500,
bold: 700
},
// Border
borderRadius: '0.75rem',
// Spacing
spacingUnit: '1rem'
},
elements: {
// Card styling
card: {
boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.5)',
border: '1px solid rgba(255, 255, 255, 0.1)',
},
// Button styling
formButtonPrimary: {
backgroundColor: '#3b82f6',
'&:hover': {
backgroundColor: '#2563eb'
}
},
// Input styling
formFieldInput: {
border: '1px solid rgba(255, 255, 255, 0.2)',
'&:focus': {
borderColor: '#3b82f6',
boxShadow: '0 0 0 3px rgba(59, 130, 246, 0.3)'
}
},
// Avatar
avatarBox: {
width: '3rem',
height: '3rem'
},
// Footer
footerActionLink: {
color: '#3b82f6',
'&:hover': {
color: '#60a5fa'
}
}
}
};
export default function RootLayout({
children
}: {
children: React.ReactNode
}) {
return (
<ClerkProvider appearance={clerkAppearance}>
<html lang="id">
<body>{children}</body>
</html>
</ClerkProvider>
);
}
Path Aliases
// tsconfig.json β TypeScript path aliases
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@utils/*": ["./src/utils/*"],
"@hooks/*": ["./src/hooks/*"],
"@styles/*": ["./src/styles/*"],
"@types/*": ["./src/types/*"]
}
}
}
// next.config.js β Turbopack aliases (opsional)
// Turbopack bisa membaca langsung dari tsconfig.json
module.exports = {
turbopack: {
resolveAlias: {
// Tambahkan alias yang tidak ada di tsconfig
'@lib': './src/lib',
'@config': './config'
}
}
};
// Penggunaan di kode:
import Button from '@components/Button';
import { formatRupiah } from '@utils/format';
import useAuth from '@hooks/useAuth';
8. CSS dan Asset Handling
CSS Modules
/* components/Button.module.css */
/* CSS Modules β class names di-scope secara otomatis */
.button {
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
.primary {
background: #3b82f6;
color: white;
border: none;
}
.primary:hover {
background: #2563eb;
transform: translateY(-1px);
}
.secondary {
background: transparent;
color: #3b82f6;
border: 2px solid #3b82f6;
}
.secondary:hover {
background: #3b82f6;
color: white;
}
/* Output: class names menjadi unik */
/* .Button_button__x7d2k { ... } */
/* .Button_primary__a3f9m { ... } */
// components/Button.tsx
import styles from './Button.module.css';
interface ButtonProps {
variant?: 'primary' | 'secondary';
children: React.ReactNode;
onClick?: () => void;
}
export default function Button({
variant = 'primary',
children,
onClick
}: ButtonProps) {
return (
<button
className={`${styles.button} ${styles[variant]}`}
onClick={onClick}
>
{children}
</button>
);
}
// Penggunaan:
// <Button variant="primary">Simpan</Button>
// <Button variant="secondary">Batal</Button>
9. Komparasi dengan Bundler Lain
Turbopack vs Webpack vs Vite vs esbuild
| Aspek | Turbopack | Webpack | Vite | esbuild |
|---|---|---|---|---|
| Bahasa | Rust | JavaScript | JS + esbuild | Go |
| Dev Speed | β‘ Tercepat | π Lambat | π Cepat | π Cepat |
| HMR | β‘ <100ms | 1-10s | 50-200ms | N/A (no HMR) |
| Prod Build | π‘ Berkembang | β Mature | β (Rollup) | β‘ Tercepat |
| Code Splitting | β Automatic | β Manual/Optimal | β (Rollup) | π‘ Basic |
| CSS Support | β Full | β Full | β Full | π‘ Basic |
| Ekosistem | π‘ Growing | β Massive | β Large | π‘ Growing |
| Framework | Next.js | Semua | Semua | Semua |
| Best For | Next.js apps | Legacy/Large | Modern SPA | Libraries |
Kapan Harus Menggunakan Turbopack?
β GUNAKAN Turbopack jika: - Anda menggunakan Next.js 15+ - Proyek sangat besar (10.000+ files) - HMR lambat dengan bundler saat ini - Development speed adalah prioritas utama - Proyek baru yang belum punya custom build config β JANGAN GUNAKAN Turbopack jika: - Menggunakan framework selain Next.js (misal: Nuxt, SvelteKit) - Membutuhkan plugin Webpack yang kompleks - Membutuhkan production build optimization (belum matang) - Proyek sangat bergantung pada custom webpack config - Stabilitas lebih penting daripada speed (gunakan Webpack/Vite)
10. Masa Depan Turbopack
Turbopack masih dalam pengembangan aktif. Berikut roadmap yang diumumkan oleh tim Vercel:
Roadmap Turbopack
2024 (SELESAI): β Turbopack Dev β stable di Next.js 15 β CSS Modules, PostCSS, Tailwind support β HMR yang sangat cepat β Server Components support 2025-2026 (DALAM PENGEMBANGAN): π Turbopack Build β production bundling π Improved caching (persistent disk cache) π Module Federation support π Broader framework support (beyond Next.js) FUTURE (PLANNED): π Turbopack as standalone tool π Custom plugin API π Better bundle analysis tools π Parallel compilation improvements π Support untuk library bundling GOAL AKHIR: β Turbopack menjadi bundler default untuk semua proyek β Menggantikan Webpack di ekosistem JavaScript β Menggabungkan kecepatan esbuild + fitur Webpack
Saat ini Turbopack paling optimal digunakan untuk development di Next.js. Untuk production build, Next.js masih menggunakan Webpack/Rollup secara default. Namun seiring Turbopack Build stabil, ini akan berubah.
11. Quiz Pemahaman
1. Bahasa apa yang digunakan untuk membangun Turbopack?
2. Apa konsep kunci yang membuat Turbopack sangat cepat?
3. Bagaimana cara mengaktifkan Turbopack di Next.js?
4. Siapa yang mengembangkan Turbopack?
5. Apa status Turbopack untuk production build saat ini?
Dalam tutorial ini, Anda telah mempelajari:
- Pengenalan Turbopack dan motivasi pembuatannya
- Arsitektur incremental computation dengan Turbo Engine
- Performa dan benchmark dibanding Webpack dan Vite
- Integrasi dengan Next.js dan cara mengaktifkannya
- Konfigurasi loaders, aliases, dan environment variables
- Migrasi dari Webpack ke Turbopack
- CSS Modules dan asset handling
- Komparasi dengan bundler lain
- Roadmap dan masa depan Turbopack