This repository demonstrates two different approaches for integrating Stimulus JavaScript controllers in Rails engines, each with distinct trade-offs and use cases.
| Engine | Strategy | Best For |
|---|---|---|
| blogh_isolate | Isolated Setup | Independent modules, microservices, reusable components |
| blogh_main_app_layout | Main App Integration | Feature extensions, admin panels, content management |
engine_stimulus/
βββ blogh_isolate/ # π Isolated Stimulus engine
β βββ app/javascript/blogh/ # Engine-specific JS structure
β βββ config/importmap.rb # Custom importmap configuration
β βββ app/helpers/ # Custom importmap helper
β
βββ blogh_main_app_layout/ # π Main app integrated engine
β βββ app/javascript/controllers/blogh/ # Main app JS structure
β βββ app/views/ # Uses main app layout
β
βββ README.md # This file
A completely self-contained Rails engine with its own Stimulus setup, importmap, and JavaScript bundle.
- β Own importmap configuration
- β
Custom
blogh_importmap_tagshelper - β Independent asset compilation
- β Engine-specific layout
- β No main app JavaScript dependencies
// Engine creates its own Stimulus application
import { Application } from "@hotwired/stimulus"
const application = Application.start()
// Controllers loaded from engine namespace
eagerLoadControllersFrom("controllers", application)- π― Microservice Architecture: Engine can be deployed independently
- π― Reusable Components: Same engine used across multiple apps
- π― Version Independence: Engine JS updates don't affect main app
- π― Team Isolation: Different teams work on engine vs main app
- π― Complex UI: Engine has sophisticated JavaScript requirements
- β Complete isolation - no conflicts with main app
- β Independent deployment - can be distributed as gem
- β Clear boundaries - easy to understand ownership
- β More setup complexity - custom importmap configuration required
- β Larger bundle size - duplicate dependencies
- β Manual integration - requires custom helper usage
A lightweight Rails engine that leverages the main application's existing Stimulus setup and layout.
- β Uses main app's importmap
- β Shares main app's Stimulus instance
- β Inherits main app styling
- β Automatic controller discovery
- β Single asset bundle
// Controllers automatically discovered by main app
// app/javascript/controllers/blogh/blogh_controller.js
// Registered as "blogh" controller in main app's Stimulus- π― Feature Extensions: Adding functionality to existing app
- π― Admin Panels: Management interfaces for main app
- π― Content Management: Editorial tools within main app
- π― Consistent UX: Want engine to match main app exactly
- π― Simple Integration: Quick setup with minimal configuration
- β Simple setup - no custom JavaScript configuration
- β Consistent UX - automatically matches main app
- β Shared dependencies - smaller overall bundle size
- β Automatic integration - works with main app's importmap
- β Coupled to main app - cannot function independently
- β Shared fate - main app JS changes affect engine
- β Less isolation - potential for conflicts
Use this matrix to choose the right approach:
| Requirement | Isolated | Main App |
|---|---|---|
| Independent deployment | β | β |
| Quick setup | β | β |
| Consistent styling | β | β |
| Version independence | β | β |
| Reusable across apps | β | β |
| Small bundle size | β | β |
| Team isolation | β | β |
| Simple maintenance | β | β |
cd blogh_isolate
bundle install
cd test/dummy
rails server
# Visit http://localhost:3000/bloghcd blogh_main_app_layout
bundle install
cd test/dummy
rails server
# Visit http://localhost:3000/blogh# config/importmap.rb
pin_all_from Blogh::Engine.root.join("app/javascript/blogh/controllers"),
under: "controllers",
to: "blogh/controllers"
# Custom helper
def blogh_importmap_tags(entry_point = "blogh/application")
importmap = Blogh.configuration.importmap
# Generate engine-specific importmap...
end# Main app's config/importmap.rb automatically includes:
pin_all_from "app/javascript/controllers", under: "controllers"
# This picks up controllers/blogh/ directory from engine
# Engine controller naming:
# controllers/blogh/post_controller.js β "blogh--post" - Develop engine in isolation
- Test with dummy app
- Package as gem
- Install in main app
- Use
blogh_importmap_tagshelper
- Develop engine alongside main app
- Controllers automatically discovered
- Test integration continuously
- Deploy together
- E-commerce Engine: Product catalog with advanced filtering
- CMS Engine: Content management with rich editor
- Analytics Dashboard: Complex data visualization
- Chat Engine: Real-time messaging with WebSocket
- Admin Interface: User management for main app
- Blog Module: Simple blog functionality
- Comment System: User comments on main app content
- Settings Panel: Application configuration interface
- Create engine importmap configuration
- Set up isolated JavaScript structure
- Implement custom importmap helper
- Create engine-specific layout
- Update controller references
- Move controllers to main app structure
- Remove custom importmap configuration
- Update layout to use main app's
- Remove custom helper usage
- Update controller naming
- Isolated Engine README - Deep dive into isolated setup
- Main App Integration README - Integration approach details
- Rails Engines Guide - Official Rails documentation
- Stimulus Handbook - Stimulus framework documentation
- Importmap Rails - Import mapping for Rails
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
This project is available as open source under the terms of the MIT License.
Choose your approach and start building! Both examples provide complete, working implementations you can learn from and adapt to your needs.