Flask Static Files: CSS, JavaScript, dan Asset
Aplikasi Flask tidak hanya mengirim HTML. Setelah browser menerima sebuah halaman, biasanya ia membuat request tambahan untuk CSS, JavaScript, gambar, font, dan favicon yang di-link-kan di dalam HTML. File-file inilah yang disebut static files karena Flask tidak perlu memprosesnya sebagai template.
Secara default, Flask menyajikan asset dari folder static/. Kita tetap bisa membuat subfolder di dalamnya supaya CSS, JavaScript, dan gambar tidak bercampur.
Susun Asset Berdasarkan Jenisnya
Tambahkan folder static di sebelah app.py dan templates:
flask-first-route/
├── app.py
├── templates/
│ └── home.html
└── static/
├── css/
│ └── app.css
├── js/
│ └── app.js
└── images/
└── logo.png
Struktur ini bukan aturan mutlak, tetapi nama folder yang konsisten membuat asset lebih mudah dicari saat project mulai bertambah besar.
Hubungkan Asset dari Template
Gunakan url_for("static", filename="...") untuk membentuk URL asset. Nilai filename dihitung relatif dari folder static, jadi tidak perlu menyertakan kata static dua kali.
<!-- File: templates/home.html -->
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Flask Notes</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}">
<script src="{{ url_for('static', filename='js/app.js') }}" defer></script>
</head>
<body>
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Flask Notes">
<h1>Flask Notes</h1>
<button id="theme-button" type="button">Ganti tema</button>
</body>
</html>
Flask akan menghasilkan URL seperti /static/css/app.css. Menulis URL melalui url_for membuat template tidak terikat pada path hardcoded dan tetap bekerja jika konfigurasi static URL berubah.
Tambahkan CSS dan JavaScript
/* File: static/css/app.css */
body {
font-family: system-ui, sans-serif;
margin: 2rem;
background: #ffffff;
color: #172033;
}
body.dark {
background: #172033;
color: #ffffff;
}
JavaScript-nya cukup menambahkan atau menghapus class dark pada <body>:
// File: static/js/app.js
const themeButton = document.querySelector("#theme-button");
themeButton.addEventListener("click", () => {
document.body.classList.toggle("dark");
});
Atribut defer pada tag <script> meminta browser menjalankan JavaScript setelah HTML selesai diparsing. Karena itu, tombol sudah tersedia ketika querySelector() dipanggil.
Satu Halaman, Beberapa Request
Ketika / dibuka, Flask lebih dulu mengirim hasil render home.html. Browser membaca HTML tersebut, menemukan tiga URL asset, lalu meminta CSS, JavaScript, dan gambar secara terpisah. Jadi satu tampilan halaman hampir selalu melibatkan beberapa request.
Kamu bisa melihat prosesnya melalui tab Network di browser DevTools. Status 200 berarti file berhasil diambil, sedangkan 404 biasanya menunjukkan nama file atau path yang tidak cocok.
Saat Perubahan CSS Belum Terlihat
Browser menyimpan static files di cache agar halaman berikutnya lebih cepat. Akibatnya, perubahan CSS kadang belum langsung terlihat meskipun file sudah benar. Coba lakukan hard refresh atau nonaktifkan cache sementara dari DevTools saat development.
Masalah lain yang cukup sering muncul adalah perbedaan huruf besar dan kecil. Logo.png dan logo.png dapat dianggap file berbeda di Linux. Pastikan nama pada filename sama persis dengan file aslinya.
Untuk latihan, tambahkan class pada <h1>, ganti warna tombol dari CSS, dan tampilkan gambar lain dari static/images. Setelah itu pindahkan salah satu file dengan sengaja dan lihat bagaimana request 404 muncul di tab Network. Cara ini membuat hubungan antara path template dan lokasi asset jauh lebih mudah dipahami.
Folder static cocok untuk file publik yang memang boleh diminta oleh browser. Jangan menaruh secret, file konfigurasi, dump database, atau upload privat di sana karena siapa pun yang mengetahui URL-nya dapat mencoba mengakses file tersebut dan mengetahui konten sensitif seperti password dsb.
Artikel Terkait
Lanjutkan membaca topik yang masih satu konteks.
Flask Authentication: Login, Session, dan Logout
Buat authentication Flask dengan password hash, login session, current user, protected route, dan logout tanpa menyimpan password mentah.
Flask CRUD SQLAlchemy: Create, Read, Update, Delete
Bangun CRUD Flask dan SQLAlchemy untuk membuat, membaca, mengubah, serta menghapus note lengkap dengan validasi, form, dan redirect.
Flask SQLAlchemy: Koneksi Database dan Model
Hubungkan Flask ke SQLite dengan Flask-SQLAlchemy, buat model dan tabel, lalu pahami proses add, commit, serta query data.
Struktur Project Flask: Blueprint, Template, dan Config
Rapikan struktur project Flask dengan application factory, Blueprint, folder route, template, static files, dan config yang terpisah.