importmap.cr
importmap.cr
A Crystal port of the core of importmap-rails 2.2.3 (the Rails 8.1 companion gem) — the JS module pinning DSL plus importmap tag helpers. Namespace Importmap mirrors the original 1:1. Output is byte-identical to the gem (oracle recorded with real importmap-rails 2.2.3 + actionview 8.1.4; the path_to_asset resolver stubbed to /javascripts/<path>, i.e. Rails behavior without sprockets/propshaft).
⚠️ EXPERIMENTAL FRAMEWORK, DO NOT USE IN PRODUCTION YET.
Installation
dependencies:
importmap_cr:
github: OrelSokolov/importmap.cr
shards install
Depends on action_view.cr (TagHelper / compute_asset_path, SafeString).
Usage
Importmap.map.draw do |map|
map.pin "application", preload: true
map.pin "chart", to: "chart.js"
map.pin_all_from "app/javascript/controllers", under: "controllers"
end
<%= javascript_importmap_tags %> <!-- inline importmap + modulepreload + import -->
Integration with railties: helpers are included into ActionController::Base, CRails::Middleware::Static serves /javascripts/* from app/javascript, and crails new generates a layout with javascript_importmap_tags, a config/importmap.cr and app/javascript/application.js.
Feature comparison vs importmap-rails 2.2.3
| Feature | Original (importmap-rails) | Port (importmap.cr) | Status |
|---|---|---|---|
pin (to:, preload: Bool|String entrypoint) |
✅ | Same | ✅ |
pin_all_from (under:, to:) |
✅ | Same; relative dir resolved from Importmap::Map.root (railties sets it to CRails.root) |
✅ |
draw DSL |
draw(path) reads a Ruby config via instance_eval |
Block DSL only: Importmap.map.draw do |map| ... end |
🔶 |
to_json (pretty, like Ruby JSON.pretty_generate) |
✅ | Same | ✅ |
preloaded_module_paths (+ entry-point filter) |
✅ | Same, incl. the gem quirk: default cache_key ignores entry_point changes (helpers pass cache_key: entry_point, as the gem does) |
✅ |
digest (SHA1), cache_as / clear_cache |
✅ | Same | ✅ |
javascript_importmap_tags, javascript_inline_importmap_tag, javascript_import_module_tag, javascript_importmap_module_preload_tags, javascript_module_preload_tag |
✅ | Same, byte-identical output | ✅ |
Asset resolution (path_to_asset → compute_asset_path) |
✅ (sprockets/propshaft) | /javascripts/x.js, URLs pass through; does not fail on missing files (no manifest) |
🔶 |
SRI integrity (enable_integrity!, integrity:) |
✅ | P2 — omitted (no asset pipeline with integrity support) | ⬜ |
Packager (bin/importmap pin/unpin/update, jsDelivr/npm) |
✅ | P2 (needs an HTTP client) | ⬜ |
Reloader (EventedFileUpdateChecker) |
✅ | Not needed (compile-time) | — |
| CSP nonce in tags | ✅ | Omitted (no CSP layer; nonce always nil — matches the nil-request oracle) | ❌ (equivalent: none, until a CSP layer exists) |
preloaded_module_packages |
✅ | Omitted — preloaded_module_paths suffices without integrity |
❌ |
Glob quirk: **/*.js{,m} pins .js/.jsm but not .mjs |
✅ (quirk) | Preserved 1:1 (oracle-confirmed) | ✅ |
Testing
crystal spec # 17 examples, 0 failures; output byte-for-byte
Oracle: oracle/importmap_cases.rb → oracle/importmap_expected.yml (21 cases). Benchmarks: bench/importmap_bench.{cr,rb} against the real gem — ~11.6× faster on tag rendering (bench/results/204-importmap.md).
importmap.cr
- 0
- 0
- 0
- 1
- 0
- 2 days ago
- October 12, 2026
Mon, 12 Oct 2026 05:24:01 GMT