# 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
```crystal
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/jquery@3.7.1/dist/jquery.min.js")
import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/lodash@4.17.21/+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:
```crystal
# Preload essential libraries
import_map.add_import(
"@hotwired/stimulus",
"https://cdn.jsdelivr.net/npm/@hotwired/stimulus@3.2.2/+esm",
preload: true
)
import_map.add_import(
"chart.js",
"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/+esm",
preload: true
)
```
Generated HTML includes preload hints:
```html
```
## Multiple Import Maps
Create different import maps for different sections of your application:
```crystal
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/stimulus@3.2.2/+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/stimulus@3.2.2/+esm", preload: true)
admin_map.add_import("chart.js", "https://cdn.jsdelivr.net/npm/chart.js@4.4.0/+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:
```crystal
import_map = front_loader.get_import_map
# Global imports
import_map.add_import("@hotwired/stimulus", "https://cdn.jsdelivr.net/npm/@hotwired/stimulus@3.2.2/+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
```crystal
# ESM format (recommended)
import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm")
import_map.add_import("axios", "https://cdn.jsdelivr.net/npm/axios@1.6.0/+esm")
```
### unpkg
```crystal
import_map.add_import("alpinejs", "https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js")
import_map.add_import("vue", "https://unpkg.com/vue@3/dist/vue.esm-browser.js")
```
### esm.sh
```crystal
# 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
```crystal
# Stimulus (official Hotwire)
import_map.add_import("@hotwired/stimulus", "https://cdn.jsdelivr.net/npm/@hotwired/stimulus@3.2.2/+esm")
# jQuery
import_map.add_import("jquery", "https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js")
# Chart.js
import_map.add_import("chart.js", "https://cdn.jsdelivr.net/npm/chart.js@4.4.0/+esm")
# Lodash (ESM)
import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/+esm")
# Day.js
import_map.add_import("dayjs", "https://cdn.jsdelivr.net/npm/dayjs@1.11.10/+esm")
# Axios
import_map.add_import("axios", "https://cdn.jsdelivr.net/npm/axios@1.6.0/+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
```crystal
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
```crystal
# In your layout
puts front_loader.render_import_map_tag
```
Output:
```html
```
### With Initialization Script
```crystal
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
```crystal
environment = ENV["AMBER_ENV"]? || "development"
import_map.add_import("@hotwired/stimulus", "https://cdn.jsdelivr.net/npm/@hotwired/stimulus@3.2.2/+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
```crystal
# 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
```crystal
# Good: ESM version
import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/+esm")
# Avoid: CommonJS version (may not work)
# import_map.add_import("lodash", "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.js")
```
### 3. Pin Versions
```crystal
# Good: Pinned version
import_map.add_import("chart.js", "https://cdn.jsdelivr.net/npm/chart.js@4.4.0/+esm")
# Avoid: Latest (unpredictable)
# import_map.add_import("chart.js", "https://cdn.jsdelivr.net/npm/chart.js@latest/+esm")
```