Rails Stimulus dan Importmaps 2026: JavaScript Modern Tanpa Build Tools

Stimulus dan Importmaps di Rails 8.1 memungkinkan penulisan JavaScript modern tanpa bundler. Tutorial ini membahas controller, action, target, dan package npm.

Rails Stimulus dan Importmaps 2026: JavaScript Modern Tanpa Build Tools

Rails Stimulus dan Importmaps menghilangkan kebutuhan webpack, esbuild, atau langkah build JavaScript apapun. Rails 8.1 hadir dengan importmap-rails dan stimulus-rails secara default, memungkinkan pengembang menambahkan perilaku interaktif ke HTML yang di-render server tanpa mengelola node_modules atau konfigurasi bundler yang kompleks.

Tidak Perlu Build Step

Importmaps menggunakan ES modules browser native. Menjalankan bin/importmap pin chart.js mengambil package dari CDN dan mendaftarkannya di config/importmap.rb. Tidak perlu npm install, tidak ada kompilasi, tidak perlu menunggu.

Bagaimana Importmaps Menggantikan Bundler Tradisional

Importmaps memanfaatkan dukungan ES module native browser untuk memuat file JavaScript secara langsung. Alih-alih menggabungkan semua dependency menjadi satu file, browser mengambil setiap module sesuai kebutuhan. JSPM CDN menyelesaikan package npm ke URL yang kompatibel dengan browser.

File config/importmap.rb berfungsi sebagai manifest:

ruby
# config/importmap.rb
pin "application"
pin "@hotwired/turbo-rails", to: "turbo.min.js"
pin "@hotwired/stimulus", to: "stimulus.min.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
pin_all_from "app/javascript/controllers", under: "controllers"

Konfigurasi ini memberi tahu browser di mana menemukan setiap module. Direktif pin_all_from secara otomatis mendaftarkan semua controller Stimulus dari direktori yang ditentukan.

Browser yang mendukung importmaps termasuk Chrome 89+, Edge 89+, Firefox 108+, dan Safari 16.4+. Untuk browser lama, Rails menyuntikkan polyfill es-module-shims secara otomatis.

Membuat Controller Stimulus untuk UI Interaktif

Controller Stimulus menghubungkan perilaku JavaScript ke elemen HTML melalui atribut data. Setiap controller adalah class yang meng-extend Controller dari @hotwired/stimulus.

app/javascript/controllers/dropdown_controller.jsjavascript
import { Controller } from "@hotwired/stimulus"

// Mengelola visibilitas dropdown dengan dukungan keyboard
export default class extends Controller {
  static targets = ["menu", "button"]
  static values = { open: Boolean }

  // Toggle dropdown saat tombol diklik
  toggle() {
    this.openValue = !this.openValue
  }

  // Tutup saat mengklik di luar dropdown
  clickOutside(event) {
    if (!this.element.contains(event.target)) {
      this.openValue = false
    }
  }

  // Dipanggil otomatis saat openValue berubah
  openValueChanged() {
    this.menuTarget.classList.toggle("hidden", !this.openValue)
    this.buttonTarget.setAttribute("aria-expanded", this.openValue)
  }

  // Connect lifecycle callback
  connect() {
    document.addEventListener("click", this.clickOutside.bind(this))
  }

  // Disconnect lifecycle callback - pembersihan
  disconnect() {
    document.removeEventListener("click", this.clickOutside.bind(this))
  }
}

HTML yang sesuai menggunakan atribut data untuk menghubungkan controller:

erb
<%# app/views/components/_dropdown.html.erb %>
<div data-controller="dropdown" data-dropdown-open-value="false">
  <button data-dropdown-target="button"
          data-action="click->dropdown#toggle"
          aria-haspopup="true">
    Opsi
  </button>
  <ul data-dropdown-target="menu" class="hidden">
    <li>Edit</li>
    <li>Hapus</li>
  </ul>
</div>

Stimulus 3.2.2 memperkenalkan Outlets API dan keyboard event modifiers. Fitur-fitur ini mengurangi boilerplate saat mengkoordinasikan antar controller atau memfilter keystroke.

Menambahkan Package npm dengan Importmaps

Menambahkan library JavaScript hanya memerlukan satu perintah:

bash
# Pin chart.js dari JSPM CDN
bin/importmap pin chart.js

Ini menambahkan entri ke config/importmap.rb:

ruby
# config/importmap.rb
pin "chart.js", to: "https://ga.jspm.io/npm:chart.js@4.4.1/dist/chart.js"

Library kemudian dapat diimpor di controller manapun:

app/javascript/controllers/chart_controller.jsjavascript
import { Controller } from "@hotwired/stimulus"
import { Chart, registerables } from "chart.js"

Chart.register(...registerables)

export default class extends Controller {
  static targets = ["canvas"]
  static values = {
    type: { type: String, default: "bar" },
    data: Object
  }

  connect() {
    this.chart = new Chart(this.canvasTarget, {
      type: this.typeValue,
      data: this.dataValue,
      options: { responsive: true }
    })
  }

  disconnect() {
    this.chart.destroy()
  }
}

Dokumentasi importmap-rails membahas vendoring package secara lokal untuk pengembangan offline atau ketika akses CDN dibatasi.

Menangani Dependency Package

Beberapa package npm memiliki dependency tree yang dalam. Gunakan bin/importmap pin package-name --download untuk vendor semua dependency secara lokal. Pendekatan ini lebih baik untuk package dengan banyak transitive imports.

Action Parameters dan Event Modifiers

Stimulus 3.x memperkenalkan action parameters, memungkinkan nilai diteruskan langsung dari HTML ke method controller:

erb
<%# Meneruskan parameter via atribut data %>
<button data-controller="item"
        data-action="click->item#delete"
        data-item-id-param="42"
        data-item-confirm-param="true">
  Hapus
</button>
app/javascript/controllers/item_controller.jsjavascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  delete(event) {
    const { id, confirm } = event.params
    
    if (confirm && !window.confirm("Hapus item ini?")) {
      return
    }
    
    // Lanjutkan penghapusan menggunakan parameter id
    fetch(`/items/${id}`, { method: "DELETE" })
  }
}

Keyboard event modifiers memfilter tombol mana yang memicu action:

erb
<%# Hanya trigger pada tombol Enter %>
<input type="text"
       data-controller="search"
       data-action="keydown.enter->search#submit">

<%# Kombinasikan beberapa modifier %>
<input type="text"
       data-controller="shortcuts"
       data-action="keydown.ctrl+s->shortcuts#save:prevent">

Modifier :prevent memanggil event.preventDefault(), dan :stop memanggil event.stopPropagation(). Ini menggantikan penanganan event manual di method controller.

Siap menguasai wawancara Ruby on Rails Anda?

Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.

Target Lifecycle Callbacks dan Default Values

Stimulus memanggil method lifecycle saat target muncul atau menghilang dari DOM:

app/javascript/controllers/tabs_controller.jsjavascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["panel"]
  static values = {
    index: { type: Number, default: 0 }
  }

  // Dipanggil saat target panel baru ditambahkan ke DOM
  panelTargetConnected(element) {
    element.hidden = this.panelTargets.indexOf(element) !== this.indexValue
  }

  // Dipanggil saat target panel dihapus dari DOM
  panelTargetDisconnected(element) {
    // Pembersihan jika diperlukan
  }

  select(event) {
    this.indexValue = event.params.index
  }

  indexValueChanged() {
    this.panelTargets.forEach((panel, index) => {
      panel.hidden = index !== this.indexValue
    })
  }
}

Default values menghilangkan null checks. Opsi default dalam definisi value memastikan value selalu ada, bahkan ketika atribut data tidak ada di HTML.

Mengkoordinasikan Controller dengan Outlets API

Outlets API, diperkenalkan di Stimulus 3.2, memungkinkan controller mereferensikan controller lain di halaman:

app/javascript/controllers/form_controller.jsjavascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static outlets = ["validation"]

  submit(event) {
    // Akses semua instance validation controller
    const allValid = this.validationOutlets.every(v => v.isValid())
    
    if (!allValid) {
      event.preventDefault()
    }
  }
}
app/javascript/controllers/validation_controller.jsjavascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["input", "error"]
  static values = { pattern: String }

  isValid() {
    const valid = new RegExp(this.patternValue).test(this.inputTarget.value)
    this.errorTarget.hidden = valid
    return valid
  }
}
erb
<%# Hubungkan outlets di HTML %>
<form data-controller="form"
      data-form-validation-outlet=".validation-field">
  <div class="validation-field"
       data-controller="validation"
       data-validation-pattern-value="^\S+@\S+$">
    <input type="email" data-validation-target="input">
    <span data-validation-target="error" hidden>Email tidak valid</span>
  </div>
  <button data-action="click->form#submit">Kirim</button>
</form>

Outlets menyediakan alternatif yang lebih bersih daripada dispatching custom events ketika controller perlu berkomunikasi langsung.

Outlets Memerlukan Kehadiran DOM

Referensi outlet diselesaikan saat controller terhubung. Jika elemen target ditambahkan secara dinamis, referensi outlet tidak akan diperbarui secara otomatis. Gunakan callback outletConnected dan outletDisconnected untuk menangani skenario dinamis.

Pertanyaan Interview Teknis tentang Arsitektur Frontend Rails

Pewawancara sering bertanya tentang pendekatan Rails terhadap JavaScript untuk menilai pemahaman arsitektur:

Mengapa memilih Importmaps daripada bundler tradisional?

Importmaps mengurangi kompleksitas untuk aplikasi di mana JavaScript bersifat tambahan, bukan utama. Trade-off-nya: tree-shaking dan optimisasi lanjutan tidak tersedia, dan package dengan distribusi CommonJS-only memerlukan konversi manual atau vendoring. Untuk aplikasi yang berat JavaScript, jsbundling-rails dengan esbuild tetap menjadi pilihan valid.

Bagaimana Stimulus berbeda dari React atau Vue?

Stimulus memperkaya HTML yang sudah ada daripada menghasilkannya. Markup yang di-render server tetap menjadi sumber kebenaran, dengan Stimulus menambahkan perilaku melalui atribut data. Model ini bekerja baik dengan Turbo dan siklus request-response tradisional Rails. Kurva pembelajarannya lebih rendah, tetapi manajemen state sisi klien yang kompleks lebih sulit diimplementasikan.

Apa yang terjadi saat controller Stimulus terhubung?

Callback connect() dipicu setelah Stimulus mengidentifikasi atribut data-controller pada elemen. Target dan value sudah diselesaikan pada titik ini. Controller tetap aktif sampai elemen dihapus dari DOM, di mana disconnect() dipanggil.

Memahami konsep-konsep ini menandakan keakraban dengan filosofi Hotwire dan strategi frontend Rails.

Debugging Controller Stimulus dalam Development

Stimulus menyediakan mode debug yang mencatat event lifecycle controller ke console:

app/javascript/application.jsjavascript
import { Application } from "@hotwired/stimulus"

const application = Application.start()

// Aktifkan mode debug di development
if (process.env.NODE_ENV === "development") {
  application.debug = true
}

export { application }

Dengan mode debug diaktifkan, console menunjukkan kapan controller terhubung, terputus, dan kapan value berubah. Output ini membantu melacak masalah dengan atribut data atau selector target.

Untuk debugging yang lebih kompleks, ekstensi browser Stimulus Devtools menampilkan semua controller aktif dan state mereka saat ini.

Mengintegrasikan Stimulus dengan Rails Modern Asset Pipeline

Rails 8.1 menggunakan Propshaft sebagai asset pipeline default, menggantikan Sprockets. Propshaft menangani aset statis seperti gambar dan CSS, sementara Importmaps mengelola JavaScript secara independen. Pelajari lebih lanjut tentang pendekatan asset pipeline Rails di modul khusus.

Pemisahan ini bersih: Propshaft mengompilasi dan menambahkan fingerprint file CSS, Importmaps menyelesaikan module JavaScript saat runtime. Tidak ada langkah kompilasi untuk JavaScript, mengurangi waktu deployment dan menghilangkan node_modules dari production image.

ruby
# Gemfile - Setup default Rails 8.1
gem "propshaft"
gem "importmap-rails"
gem "stimulus-rails"
gem "turbo-rails"

Stack ini mewakili jawaban Rails yang opinionated untuk pengembangan frontend: HTML yang di-render server diperkaya dengan JavaScript tertarget, dikirimkan tanpa kompleksitas build-time.

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Poin-Poin Utama untuk Pengembangan JavaScript Rails

  • Importmaps memuat package npm via CDN tanpa bundling. Gunakan bin/importmap pin package-name untuk menambahkan dependency. Versi 2.2.2 importmap-rails adalah rilis terkini.
  • Controller Stimulus menghubungkan JavaScript ke HTML melalui atribut data-controller, data-action, dan data-target. Framework menangani manajemen lifecycle secara otomatis.
  • Action parameters meneruskan data dari HTML ke method controller via atribut data-*-param, mengurangi kebutuhan untuk query DOM.
  • Outlets API mengkoordinasikan beberapa controller di halaman tanpa custom events atau global state.
  • Mode debug (application.debug = true) mencatat semua aktivitas controller ke console selama development.
  • Propshaft menangani CSS dan aset statis, sementara Importmaps menangani JavaScript. Kedua sistem beroperasi secara independen.
  • Untuk aplikasi yang berat JavaScript, jsbundling-rails menyediakan jalan keluar ke esbuild atau webpack sambil mempertahankan konvensi Rails.
Tantangan harian

Bisakah kamu menemukan bug di Ruby on Rails?

Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Anthony Fillion-Maillet

Ditulis oleh

Anthony Fillion-Maillet

Pendiri SharpSkill

Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.

Diperbarui 29 Agustus 2026

Bagikan

Artikel terkait