Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Importmap Laravel Laravel Package

tonysm/importmap-laravel

Importmap Laravel brings native ES module import maps to Laravel, letting you use modern JavaScript packages without a bundler. Pin dependencies from CDNs, manage vendor modules, and skip complex build steps while keeping Blade and Laravel integration simple.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require tonysm/importmap-laravel
php artisan importmap:install

The installer scaffolds three things you should open immediately, in this order:

  1. config/importmap.php — the single source of truth. Entries are "pins": either a path into your own tree, a url to a CDN, or a package downloaded into vendor/javascript. Each pin can carry preload and download flags.
  2. resources/js/application.js — the default entry point. This is plain ESM, imported directly by the browser.
  3. Your layout Blade file — the installer adds two directives. Get their order right:
<head>
    @importmap          {{-- <script type="importmap"> — must precede every module --}}
    @importmap_entry_point {{-- <script type="module" src="...application.js"> --}}
</head>

First use case: pin a CDN library and consume it with a bare specifier.

php artisan importmap:pin chart.js --preload
// resources/js/application.js
import Chart from "chart.js"
new Chart(document.querySelector("canvas"), { /* ... */ })

Refresh the page. No npm run dev, no watcher, no manifest. That absence of a loop is the feature — your mental model shifts from "build output" to "URLs the browser fetches."

If you're unsure of a command's options, php artisan importmap:pin --help, importmap:update --help, and importmap:outdated are the fastest way to learn the surface.

Implementation Patterns

CDN pins for speed, downloaded pins for stability. importmap:pin foo resolves the dependency graph via jspm.io and writes transitive pins into config/importmap.php. Add --download to vendor the files into vendor/javascript and pin them locally — commit that directory. A pragmatic split: CDN with preload for public marketing pages, downloaded pins for anything on a critical path or behind a compliance requirement.

Local modules by relative path, shared code by directory pins. Anything under resources/js is reachable as import "./components/modal.js". When sibling modules need a stable name (e.g. import { formatMoney } from "utils"), pin the directory instead of littering the map:

'utils' => ['path' => 'resources/js/utils/index.js', 'preload' => true],

Multiple entry points per layout. The entry point is just a pin. Keep application.js for the public site and add admin.js as a second entry point rendered only in the admin layout — one import map, several <script type="module"> tags. Don't try to share one entry point across layouts with conditionals inside JS.

Programmatic pinning in a service provider. For packages that must be pinned identically across many apps (an internal design system, say), pin in AppServiceProvider::boot() with the facade rather than hand-editing config. This keeps the config file diffable and lets you derive URLs from an env var.

Preload what blocks first paint. @importmap_preload emits <link rel="modulepreload"> for flagged pins. Mark the two or three modules your entry point imports synchronously; over-preloading is worse than none because it competes with your CSS.

Hotwire/Stimulus pairing. This package is the intended sibling of tonysm/turbo-laravel and the Stimulus controllers package. The idiom is: controllers registered by eager-importing a controllers/ directory, Turbo driving navigation, and the import map only ever changing when you add a library. If you're adopting Turbo, adopt all three at once.

CI guardrails. Run importmap:audit in CI — it fails when code imports a bare specifier that isn't pinned, which is otherwise a silent runtime TypeError in the browser that never shows up in PHP tests. Pair with importmap:outdated on a schedule; importmap:update rewrites pins in place.

CSS is not this package's job. Keep Vite (or the Tailwind CLI) for stylesheets and let it emit one static CSS file. Trying to route CSS through the import map is a dead end — import maps are for JS modules only.

Gotchas and Tips

  • The import map must appear before any module script. @importmap in the body after a <script type="module"> silently loses. Also avoid putting it behind a deferred partial or a Turbo frame.
  • Inline JSON vs. CSP. @importmap emits an inline <script type="importmap">, so a strict script-src without 'unsafe-inline' will block it. Confirm how the package's nonce hooks interact with your CSP package before shipping; this is the most common first-deploy breakage.
  • Config caching in production. The artisan commands rewrite config/importmap.php. In a deploy that runs config:cache, the new pins won't take effect until the cache is rebuilt — put php artisan config:cache after any pin-changing step, and never run importmap:* at runtime in prod.
  • No transpilation means no TypeScript, no JSX, no decorators. Also no import of extensionless relative files — browsers need the literal .js in the URL. Code that worked under webpack will 404 here.
  • Transitive pins are only free if the packager did the work. A manually added url pin does not include its dependencies; you must pin those too or the browser throws an unresolved-specifier error. importmap:pin handles this because jspm resolves the whole graph.
  • Subpath imports need their own pin. import "lodash" and import "lodash/merge" are two different map entries. Audit catches the missing one.
  • Windows: use forward slashes in path pins. Backslashes produce URLs the browser won't resolve and the error message is unhelpful.
  • Browser floor: import maps are baseline (Chrome 89+, Firefox 108+, Safari 16.4+). If you still support older Safari, this package is not the tool — stay on Vite.
  • Cache busting rides on the pin digest. Editing a local module changes its URL query, so you don't need manual versioning — but a CDN-pinned package pinned without a version will silently drift. Use importmap:outdated to catch it.
  • Debugging tip: view source and read the emitted <script type="importmap"> JSON directly. Nine out of ten "module not found" issues are visible as a missing or misnamed key in that blob, not in your JS.
  • Extension point: the Importmap facade is the seam — wrap it in your own service or Blade component if you need tenant-specific or feature-flagged pin sets, rather than branching inside config/importmap.php.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager