Import Maps
Preview ecosystem guide: Asset Pipeline is not part of the Amber 2.0.0-beta.2 core web-app release gate. Its package version, API, and platform support may change independently. Do not add a personal fork as a default dependency.
Import maps allow you to control how JavaScript module specifiers are resolved by the browser, enabling you to use bare module names like import _ from "lodash" without a bundler.
Basic Usage
Creating Import Maps
front_loader = AssetPipeline::FrontLoader.new
import_map = front_loader.get_import_map
# Add dependencies from CDN
import_map.add_import("jquery", "https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js")
import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
# Add local modules
import_map.add_import("utils", "/javascript/utils.js")
import_map.add_import("UserService", "/javascript/services/user_service.js")
Preloading Critical Modules
Mark critical modules for preloading to improve page load performance:
# Preload essential libraries
import_map.add_import(
"@hotwired/stimulus",
"https://cdn.jsdelivr.net/npm/@hotwired/[email protected]/+esm",
preload: true
)
import_map.add_import(
"chart.js",
"https://cdn.jsdelivr.net/npm/[email protected]/+esm",
preload: true
)
Generated HTML includes preload hints:
<script type="importmap">{"imports": {...}}</script>
<link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/@hotwired/[email protected]/+esm">
<link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/[email protected]/+esm">
Multiple Import Maps
Create different import maps for different sections of your application:
front_loader = AssetPipeline::FrontLoader.new do |import_maps|
# Main application
app_map = AssetPipeline::ImportMap.new("application")
app_map.add_import("@hotwired/stimulus", "https://cdn.jsdelivr.net/npm/@hotwired/[email protected]/+esm", preload: true)
app_map.add_import("UserController", "user_controller.js")
import_maps << app_map
# Admin-specific
admin_map = AssetPipeline::ImportMap.new("admin")
admin_map.add_import("@hotwired/stimulus", "https://cdn.jsdelivr.net/npm/@hotwired/[email protected]/+esm", preload: true)
admin_map.add_import("chart.js", "https://cdn.jsdelivr.net/npm/[email protected]/+esm", preload: true)
admin_map.add_import("AdminController", "admin_controller.js")
import_maps << admin_map
end
# Render different maps for different pages
front_loader.render_import_map_tag("application") # Main pages
front_loader.render_import_map_tag("admin") # Admin pages
Scoped Imports
Define path-specific module resolution:
import_map = front_loader.get_import_map
# Global imports
import_map.add_import("@hotwired/stimulus", "https://cdn.jsdelivr.net/npm/@hotwired/[email protected]/+esm")
# Scoped imports for specific paths
import_map.add_scope("/admin/users", "UserManagementController", "admin/user_management_controller.js")
import_map.add_scope("/admin/analytics", "AnalyticsController", "admin/analytics_controller.js")
Common CDN Sources
jsdelivr
# ESM format (recommended)
import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
import_map.add_import("axios", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
unpkg
import_map.add_import("alpinejs", "https://unpkg.com/[email protected]/dist/cdn.min.js")
import_map.add_import("vue", "https://unpkg.com/vue@3/dist/vue.esm-browser.js")
esm.sh
# React from esm.sh
import_map.add_import("react", "https://esm.sh/react@18")
import_map.add_import("react-dom", "https://esm.sh/react-dom@18")
Popular Libraries
# Stimulus (official Hotwire)
import_map.add_import("@hotwired/stimulus", "https://cdn.jsdelivr.net/npm/@hotwired/[email protected]/+esm")
# jQuery
import_map.add_import("jquery", "https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js")
# Chart.js
import_map.add_import("chart.js", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
# Lodash (ESM)
import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
# Day.js
import_map.add_import("dayjs", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
# Axios
import_map.add_import("axios", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
Local Modules
Organizing Local JavaScript
src/javascript/
├── controllers/
│ ├── application_controller.js
│ ├── dropdown_controller.js
│ └── modal_controller.js
├── services/
│ ├── api_service.js
│ └── storage_service.js
└── utils/
├── formatting.js
└── validation.js
Mapping Local Modules
import_map = AssetPipeline::ImportMap.new("application", Path["/javascript"])
# Controllers (auto-detected as Stimulus controllers)
import_map.add_import("DropdownController", "controllers/dropdown_controller.js")
import_map.add_import("ModalController", "controllers/modal_controller.js")
# Services and utilities
import_map.add_import("ApiService", "services/api_service.js")
import_map.add_import("formatters", "utils/formatting.js")
Rendering Import Maps
Basic Rendering
# In your layout
puts front_loader.render_import_map_tag
Output:
<script type="importmap">
{
"imports": {
"@hotwired/stimulus": "https://cdn.jsdelivr.net/npm/@hotwired/[email protected]/+esm",
"lodash": "https://cdn.jsdelivr.net/npm/[email protected]/+esm",
"DropdownController": "/javascript/controllers/dropdown_controller.js"
}
}
</script>
With Initialization Script
custom_js = <<-JS
console.log('Application initialized');
document.addEventListener('DOMContentLoaded', () => {
// Initialization code
});
JS
puts front_loader.render_import_map_tag
puts front_loader.render_initialization_script(custom_js)
Environment Configuration
environment = ENV["AMBER_ENV"]? || "development"
import_map.add_import("@hotwired/stimulus", "https://cdn.jsdelivr.net/npm/@hotwired/[email protected]/+esm", preload: true)
case environment
when "development"
# Development tools
import_map.add_import("DebugController", "debug_controller.js")
when "production"
# Production analytics
import_map.add_import("AnalyticsController", "analytics_controller.js")
end
Best Practices
1. Organize by Priority
# Core framework first (preload)
import_map.add_import("@hotwired/stimulus", "...", preload: true)
# Essential libraries (preload if critical)
import_map.add_import("jquery", "...", preload: true)
# Utility libraries (load on demand)
import_map.add_import("lodash", "...")
import_map.add_import("dayjs", "...")
# Application controllers
import_map.add_import("NavigationController", "...")
2. Use ESM Versions
# Good: ESM version
import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
# Avoid: CommonJS version (may not work)
# import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/[email protected]/lodash.js")
3. Pin Versions
# Good: Pinned version
import_map.add_import("chart.js", "https://cdn.jsdelivr.net/npm/[email protected]/+esm")
# Avoid: Latest (unpredictable)
# import_map.add_import("chart.js", "https://cdn.jsdelivr.net/npm/chart.js@latest/+esm")