Giter Site home page Giter Site logo

rails / importmap-rails Goto Github PK

View Code? Open in Web Editor NEW
1.0K 37.0 110.0 832 KB

Use ESM with importmap to manage modern JavaScript in Rails without transpiling or bundling.

License: MIT License

Ruby 90.68% JavaScript 0.59% Shell 0.71% CSS 0.93% HTML 7.09%

importmap-rails's Introduction

Importmap for Rails

Import maps let you import JavaScript modules using logical names that map to versioned/digested files โ€“ directly from the browser. So you can build modern JavaScript applications using JavaScript libraries made for ES modules (ESM) without the need for transpiling or bundling. This frees you from needing Webpack, Yarn, npm, or any other part of the JavaScript toolchain. All you need is the asset pipeline that's already included in Rails.

With this approach you'll ship many small JavaScript files instead of one big JavaScript file. Thanks to HTTP/2 that no longer carries a material performance penalty during the initial transport, and in fact offers substantial benefits over the long run due to better caching dynamics. Whereas before any change to any JavaScript file included in your big bundle would invalidate the cache for the whole bundle, now only the cache for that single file is invalidated.

Import maps are supported natively in all major, modern browsers. If you need to work with legacy browsers without native support, you can explore using the shim available.

Installation

Importmap for Rails is automatically included in Rails 7+ for new applications, but you can also install it manually in existing applications:

  1. Run ./bin/bundle add importmap-rails
  2. Run ./bin/rails importmap:install

Note: In order to use JavaScript from Rails frameworks like Action Cable, Action Text, and Active Storage, you must be running Rails 7.0+. This was the first version that shipped with ESM compatible builds of these libraries.

You can pin those libraries manually by relying on the compiled versions included in Rails like this:

pin "@rails/actioncable", to: "actioncable.esm.js"
pin "@rails/activestorage", to: "activestorage.esm.js"
pin "@rails/actiontext", to: "actiontext.esm.js"
pin "trix"

How do importmaps work?

At their core, importmaps are essentially a string substitution for what are referred to as "bare module specifiers". A "bare module specifier" looks like this: import React from "react". This is not compatible with the ES Module loader spec. Instead, to be ESM compatible, you must provide 1 of the 3 following types of specifiers:

  • Absolute path:
import React from "/Users/DHH/projects/basecamp/node_modules/react"
  • Relative path:
import React from "./node_modules/react"
  • HTTP path:
import React from "https://ga.jspm.io/npm:[email protected]/index.js"

Importmap-rails provides a clean API for mapping "bare module specifiers" like "react" to 1 of the 3 viable ways of loading ES Module javascript packages.

For example:

# config/importmap.rb
pin "react", to: "https://ga.jspm.io/npm:[email protected]/index.js"

means "everytime you see import React from "react" change it to import React from "https://ga.jspm.io/npm:[email protected]/index.js""

import React from "react" 
// => import React from "https://ga.jspm.io/npm:[email protected]/index.js"

Usage

The import map is setup through Rails.application.importmap via the configuration in config/importmap.rb. This file is automatically reloaded in development upon changes, but note that you must restart the server if you remove pins and need them gone from the rendered importmap or list of preloads.

This import map is inlined in the <head> of your application layout using <%= javascript_importmap_tags %>, which will setup the JSON configuration inside a <script type="importmap"> tag. Then the application entrypoint is imported via <script type="module">import "application"</script>. That logical entrypoint, application, is mapped in the importmap script tag to the file app/javascript/application.js.

It's in app/javascript/application.js you setup your application by importing any of the modules that have been defined in the import map. You can use the full ESM functionality of importing any particular export of the modules or everything.

It makes sense to use logical names that match the package names used by npm, such that if you later want to start transpiling or bundling your code, you won't have to change any module imports.

Local modules

If you want to import local js module files from app/javascript/src or other sub-folders of app/javascript (such as channels), you must pin these to be able to import them. You can use pin_all_from to pick all files in a specific folder, so you don't have to pin each module individually.

# config/importmap.rb
pin_all_from 'app/javascript/src', under: 'src', to: 'src'

The :to parameter is only required if you want to change the destination logical import name. If you drop the :to option, you must place the :under option directly after the first parameter.

Allows you to:

// app/javascript/application.js
import { ExampleFunction } from 'src/example_function'

Which imports the function from app/javascript/src/example_function.js.

Note: Sprockets used to serve assets (albeit without filename digests) it couldn't find from the app/javascripts folder with logical relative paths, meaning pinning local files wasn't needed. Propshaft doesn't have this fallback, so when you use Propshaft you have to pin your local modules.

Using npm packages via JavaScript CDNs

Importmap for Rails downloads and vendors your npm package dependencies via JavaScript CDNs that provide pre-compiled distribution versions.

You can use the ./bin/importmap command that's added as part of the install to pin, unpin, or update npm packages in your import map. This command uses an API from JSPM.org to resolve your package dependencies efficiently, and then add the pins to your config/importmap.rb file. It can resolve these dependencies from JSPM itself, but also from other CDNs, like unpkg.com and jsdelivr.com.

./bin/importmap pin react
Pinning "react" to vendor/react.js via download from https://ga.jspm.io/npm:[email protected]/index.js
Pinning "object-assign" to vendor/object-assign.js via download from https://ga.jspm.io/npm:[email protected]/index.js

This will produce pins in your config/importmap.rb like so:

pin "react" # https://ga.jspm.io/npm:[email protected]/index.js
pin "object-assign" # https://ga.jspm.io/npm:[email protected]/index.js

The packages are downloaded to vendor/javascript, which you can check into your source control, and they'll be available through your application's own asset pipeline serving.

If you later wish to remove a downloaded pin:

./bin/importmap unpin react
Unpinning and removing "react"
Unpinning and removing "object-assign"

Preloading pinned modules

To avoid the waterfall effect where the browser has to load one file after another before it can get to the deepest nested import, importmap-rails uses modulepreload links by default. If you don't want to preload a dependency, because you want to load it on-demand for efficiency, append preload: false to the pin.

Example:

# config/importmap.rb
pin "@github/hotkey", to: "@github--hotkey.js" # file lives in vendor/javascript/@github--hotkey.js
pin "md5", preload: false # file lives in vendor/javascript/md5.js

# app/views/layouts/application.html.erb
<%= javascript_importmap_tags %>

# will include the following link before the importmap is setup:
<link rel="modulepreload" href="/assets/javascript/@github--hotkey.js">
...

Composing import maps

By default, Rails loads import map definition from the application's config/importmap.rb to the Importmap::Map object available at Rails.application.importmap.

You can combine multiple import maps by adding paths to additional import map configs to Rails.application.config.importmap.paths. For example, appending import maps defined in Rails engines:

# my_engine/lib/my_engine/engine.rb

module MyEngine
  class Engine < ::Rails::Engine
    # ...
    initializer "my-engine.importmap", before: "importmap" do |app|
      app.config.importmap.paths << Engine.root.join("config/importmap.rb")
      # ...
    end
  end
end

And pinning JavaScript modules from the engine:

# my_engine/config/importmap.rb

pin_all_from File.expand_path("../app/assets/javascripts", __dir__)

Selectively importing modules

You can selectively import your javascript modules on specific pages.

Create your javascript in app/javascript:

// /app/javascript/checkout.js
// some checkout specific js

Pin your js file:

# config/importmap.rb
# ... other pins...
pin "checkout", preload: false

Import your module on the specific page. Note: you'll likely want to use a content_for block on the specifc page/partial, then yield it in your layout.

<% content_for :head do %>
  <%= javascript_import_module_tag "checkout" %>
<% end %>

Important: The javascript_import_module_tag should come after your javascript_importmap_tags

<%= javascript_importmap_tags %>
<%= yield(:head) %>

Include a digest of the import map in your ETag

If you're using ETags generated by Rails helpers like stale? or fresh_when, you need to include the digest of the import map into this calculation. Otherwise your application will return 302 cache responses even when your JavaScript assets have changed. You can avoid this with something like:

class ApplicationController < ActionController::Base
  etag { Rails.application.importmap.digest(resolver: helpers) if request.format&.html? }
end

Sweeping the cache in development and test

Generating the import map json and modulepreloads may require resolving hundreds of assets. This can take a while, so these operations are cached, but in development and test, we watch for changes to both config/importmap.rb and files in app/javascript to clear this cache. This feature can be controlled in an environment configuration file via the boolean config.importmap.sweep_cache.

If you're pinning local files from outside of app/javascript, you'll need to add them to the cache sweeper configuration or restart your development server upon changes to those external files. For example, here's how you can do it for Rails engine:

# my_engine/lib/my_engine/engine.rb

module MyEngine
  class Engine < ::Rails::Engine
    # ...
    initializer "my-engine.importmap", before: "importmap" do |app|
      # ...
      app.config.importmap.cache_sweepers << Engine.root.join("app/assets/javascripts")
    end
  end
end

Checking for outdated or vulnerable packages

Importmap for Rails provides two commands to check your pinned packages:

  • ./bin/importmap outdated checks the NPM registry for new versions
  • ./bin/importmap audit checks the NPM registry for known security issues

Supporting legacy browsers such as Safari on iOS 15

If you want to support legacy browsers that do not support import maps such as iOS 15.8.1 released on 22 Jan 2024, insert es-module-shims before javascript_importmap_tags as below.

<script async src="https://ga.jspm.io/npm:[email protected]/dist/es-module-shims.js" data-turbo-track="reload"></script>
<%= javascript_importmap_tags %>

License

Importmap for Rails is released under the MIT License.

importmap-rails's People

Contributors

akiomik avatar andystabler avatar botandrose avatar byroot avatar caleb-t-owens avatar cover avatar dhh avatar elia avatar faqndo97 avatar guybedford avatar jonathanhefner avatar jsntv200 avatar kaiquekandykoga avatar kirillplatonov avatar konnorrogers avatar matthewd avatar mohamedbechirmejri avatar npezza93 avatar ollie-nye avatar petergoldstein avatar qichunren avatar rafaelfranca avatar rmacklin avatar rotario avatar skipkayhil avatar tenderlove avatar tomasc avatar uwekubosch avatar vietqhoang avatar websebdev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

importmap-rails's Issues

Rails new application starting issue.

While creating new application i am facing issue with importmap can anyone please explain how to resolve this issue please check below error

Bundle complete! 15 Gemfile dependencies, 70 gems now installed.
Use bundle info [gemname] to see where a bundled gem is installed.
run bundle binstubs bundler
rails importmap:install
rails aborted!
TZInfo::DataSourceNotFound: tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install
C:/Users/nittr/desktop/Ruby/newBlog/config/environment.rb:5:in `

'

Caused by:
TZInfo::DataSources::ZoneinfoDirectoryNotFound: None of the paths included in TZInfo::DataSources::ZoneinfoDataSource.search_path are valid zoneinfo directories.
C:/Users/nittr/desktop/Ruby/newBlog/config/environment.rb:5:in `

'
Tasks: TOP => app:template => environment
(See full trace by running task with --trace)
rails turbo:install stimulus:install
You must either be running with node (package.json) or importmap-rails (config/importmap.rb) to use this gem.
You must either be running with node (package.json) or importmap-rails (config/importmap.rb) to use this gem.

Deprecation warning if missing a command

% ./bin/importmap plyr
Could not find command "plyr".
Deprecation warning: Thor exit with status 0 on errors. To keep this behavior, you must define `exit_on_failure?` in `Importmap::Commands`
You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.

The correct command would be ./bin/importmap pin plyr, but just noting the deprecation warning :)

Unpredictable order in javascript_importmap_tags output with pin_all_from

What's the issue?

We have a situation where Turbo is sometimes invalidating the page and reloading after a form submission returns with 422 status (because of model validation errors). Like all the best bugs, this is only happening in production ๐Ÿ˜†. The impact is that instead of seeing the validation output around the form inputs, the data entered in the form is wiped when the form is refreshed.

rails (7.0.1)
turbo-rails (1.0.0)
importmap-rails (1.0.1)
Ruby 2.7.5

Why is this related to importmap-rails?

Tracking the times it reloads the page vs when it successfully does a Turbo Drive page view, the only difference (aside from the CSRF tags) seems to be the content of the importmap script tag. Specifically, the order of the imports that use pin_all_from to load a whole directory.
Screenshot 2022-03-02 at 17 31 21

What should happen instead?

I believe the pin_all_from in the importmap should sort the results it gets from globbing the directory so that javascript_importmap_tags generates a consistent result.

I haven't actually been able to reproduce this in development. It seems to give a predictable ordering on my macbook, but not on heroku. I'm raising the issue now, because regardless of the specifics of our issue, making this output predictable seems like a good idea.

I'm open to submitting a PR if necessary here. I've already had a quick look at the code, but haven't cloned it to edit/run tests etc yet.


Everything below here is background information, so if you agree with the above, you probably don't have to read it!

How do we know this is what's happening?

The Chrome DevTools show that the trigger for the reload is that Turbo is calling invalidate while rendering the 422 response.
image

I poked around, and it looks like indeed the Turbo.session.snapshot.headSnapshot.trackedElementSignature is just a string with all of this in it. If this changes, then the page will reload.
Screenshot 2022-03-02 at 17 41 14

I think it's not noticeable if the page occasionally reloads when navigating, but it's very noticeable when submitting a form, because it wipes the form content.

Relevant bits of Turbo code showing that a change in this signature will reload the page.

https://github.com/hotwired/turbo/blob/56bfa462d598d6750386891efbbbfff7ebacb989/src/core/view.ts#L72

async render(renderer: R) {
  const { isPreview, shouldRender, newSnapshot: snapshot } = renderer

  if (shouldRender) {
	...
  } else {
	this.invalidate()
  }

https://github.com/hotwired/turbo/blob/539b249d82f44f5a4fd6bd245fe1e45718b31508/src/core/drive/page_renderer.ts#L5

export class PageRenderer extends Renderer<HTMLBodyElement, PageSnapshot> {
  get shouldRender() {
    return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical
  }

https://github.com/hotwired/turbo/blob/539b249d82f44f5a4fd6bd245fe1e45718b31508/src/core/drive/page_renderer.ts#L52

  get trackedElementsAreIdentical() {
    return this.currentHeadSnapshot.trackedElementSignature == this.newHeadSnapshot.trackedElementSignature
  }

Our code

in layouts/admin_section.erb:

 <%= javascript_importmap_tags "admin_section" %>

in importmap.rb

pin "admin_section", preload: true
pin_all_from "app/javascript/admin", under: "admin"
pin_all_from "app/javascript/shared", under: "shared"

pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true

pin "jquery", to: "https://ga.jspm.io/npm:[email protected]/dist/jquery.js"
pin "jquery-ujs", to: "https://ga.jspm.io/npm:[email protected]/src/rails.js"

pin "jquery-ui", to: "jquery-ui.js"
pin "autocomplete-rails", to: "autocomplete-rails.js"
pin "bootstrap3", to: "https://ga.jspm.io/npm:[email protected]/dist/js/npm.js"
pin "bootstrap-tokenfield", to: "https://ga.jspm.io/npm:[email protected]/dist/bootstrap-tokenfield.js"

pin "cocoon"

in admin_section.js

// Activate Turbo:
import "@hotwired/turbo-rails";

// This shim imports jquery and puts it in the global scope
import "shared/jquery-shim";
// These modules depend on jQuery being in the global scope
import "jquery-ujs";
import "jquery-ui";
import "autocomplete-rails";
import "bootstrap3";
import "bootstrap-tokenfield";
import "cocoon";

import "admin/schedule";
import "shared/counter";
import "shared/autocompleteMap";
import "admin/booking_url";
import "admin/display_name";
import "admin/activity";
import "admin/venues";
import "shared/tag-token-picker";
import "shared/activate-tooltip";

console.log("Loaded admin_section.js");

v 0.5.3 - es-module-shim script still blocked by Content Security Policy

Thanks for adding the content security policy nonce awareness to the importmap_tags_helpers. Adding es-module-shim, however, is generating this script in the header:

<script type="esms-options">{"nonce":"PvInLekGVYkMB8sUJCUZ8fg/1q+UWuNyJlI="}</script>

This fails csp with:

Refused to load the script 'http://localhost:3000/assets/es-module-shims-a1fc5fe40f250a03bc2e7a9b90c68adb1ee2c1b40d1a87f2554941d0c5232a11.js' because it violates the following Content Security Policy directive: "script-src 'self' https: 'strict-dynamic'...

Importmaps-rails 0.5.3
Rails 7.0.0.alpha2
Ruby 3.0.2

Javascript errors after running rails importmap:install on fresh Rails app.

After adding the importmap-rails gem to a freshly generated Rails app's Gemfile and running rails importmap:install, I'm seeing the following javascript console error messages:

An import map is added after module script load was triggered.

Uncaught TypeError: Failed to resolve module specifier "application". Relative references must start with either "/", "./", or "../".

I have tested this with fresh Rails 6.1 and 7.0a apps in Chrome and Safari.

What is the recommended way to import css bundled in js libraries

When trying to use glide.js with importmap.
Glide.js provides a js and a css file.

importmap-rails provides a way to vendor the js.

โžœ bin/importmap pin @glidejs/glide --download
Pinning "@glidejs/glide" to vendor/javascript/@glidejs/glide.js via download from https://ga.jspm.io/npm:@glidejs/[email protected]/dist/glide.esm.js

We don't know what is the best way to include the css.
We found a way to include the css by using the package.json.
The problem is that the glide.js dependency version is in 2 places that must be kept in sync.

Downloading vendor files from the JavaScript CDN
package.json

{
  "name": "app",
  "private": "true",
  "dependencies": {
    "@glidejs/glide": "^3.5.2",
  }
}

I'm wondering if it could be useful to automatically/optionnaly vendor the css when downloading the js ?

bin/importmap pin @glidejs/glide --download --download-css

Intentions for integrating with Propshaft?

I know development on this stuff is still very much in progress, but is it correct to assume that we'll want this gem to work with Propshaft (i.e. in apps that use an alternative asset pipeline to Sprockets)? From what I've seen so far, it doesn't seem like the gem needs any of the more complex Sprockets-specific stuff.

But I noticed the gem currently has a direct reference to a Sprockets constant here:

rescue Sprockets::Rails::Helper::AssetNotFound

Would we want to generalize it such that we only reference that constant when Sprockets has been loaded (after checking if defined?(Sprockets::Rails) or something similar)?

Different modules for, say, admin namespace

Hi,
I tried javascript_importmap_tags "admin" in a separate layout.
But in both cases all the modules were included (application one includes admin as well and vice versa).

Is it possible? I don't need all the stuff for, say, public part (except turbo).

Thanks!

Should importmap include /vendor/assets by default?

With the initial release of Hotwire, I put ESM versions of javascript libraries like SortableJS into /app/assets/javascripts/libraries which was generated by the stimulus gem (if I remember correctly).

With import maps, it seems like I need to update all import statements to be relative to the javascripts folder, such that in my sortable controller I need import Sortable from "libraries/sortable".

But more importantly, this libraries folder is no longer generated in a new install, which prompted me to go back to the Asset Pipeline guide and review the meaning of the vendor folder.

Should this gem automatically be mapping /vendor/assets/javascripts or should I add those assets manually to /config/initializers/assets.rb?

Filtering import maps

As far as I can tell, importmap-rails has the same issue that I brought up over on rails/webpacker#2876. To summarize, the importmap always exposes to the client the existence of all javascript in the application.

For reference, my use case is a Rails monolith that is serving multiple apps/audiences. While nothing exactly secret is contained in any of the JS, some of it (e.g. fetch calls revealing URLs that are not available to all users) would still be better left out.

While this library is still new, I'd like to suggest that adding some way of filtering the import map. The simplest way I can think of is providing an optional glob pattern to the view helpers. For example, writing <%= javascript_importmap_tags(exclude: 'admin/**/*') %> would ensure that nothing from app/assets/javascript/admin is included in the resulting import map.

What do you think?

Are there proposals for importmap-rails to work in rails 7 engines?

A new engine with Rails 7 alpha 2, generated usingrails plugin new custom_page --mountable --fullgenerates a new engine that includes the importmap-rails gem in the bundled gems but there is no ability to use it. Adding spec.add_dependency 'importmap-rails' to gemspec makes no difference. there is no importmap executable in the bin directory.
A call to bundle info importmap-rails
Produces

* importmap-rails (0.8.1)
	Summary: Use ESM with importmap to manage modern JavaScript in Rails without transpiling or bundling.
	Homepage: https://github.com/rails/importmap-rails
	Source Code: https://github.com/rails/importmap-rails
	Path: /home/jamie/.rvm/gems/ruby-3.0.0@custom_page/gems/importmap-rails-0.8.1

A call to rails --tasks lists
rails app:importmap:install # Setup Importmap for the app
I was expecting to see the same without app: prefix
A call to this task resolves to a template error
rails app:importmap:install

Don't know how to build task 'app:template' (See the list of available tasks with `rails --tasks`)
Did you mean?  app:tmp:create

Hope this is a clear enough question for you. If there is a workaround solution to this I'd be grateful to hear it and I'm sure others will too. The reason for me wanting this is that I totally failed to introduced webpacker in a rails 6.1.4 engine and I was hoping this was going to be my, much improved, solution
Cheers
James

Idiomatic Sass processing in Rails 7

I'm confused about the idiomatic way to process Sass in Rails 7.

The README.md for this repo says:

This frees you from needing Webpack, Yarn, npm, or any other part of the JavaScript toolchain. All you need is the asset pipeline that's already included in Rails.

and The Rails Guide to The Asset Pipeline states that:

Rails [7] can easily work with Sass by adding the sassc-rails gem to your Gemfile, which is used by Sprockets for Sass compilation

But in October 2020 we learned that LibSass is Deprecated, and that we should be using Dart Sass instead.

The sassc-rails gem is based on LibSass.

Hence should we be using something else to process Sass? And if so is the documentation on the Rails 7 asset pipeline misleading?

I'm relatively new to Rails and my naive reading of The README.md and The Asset Pipeline Guide led me to think that we should be using "the asset pipeline that's already included in Rails" to compile Sass and did not need "Yarn, npm, or any other part of the JavaScript toolchain".

What is the Rails 7 idiomatic way to process Sass?

Unable to pin selectize

Hi, trying to taste new instrument and stucked with the problem while pinning selectize.js

Here is what I found:

./bin/importmap pin selectize           
Couldn't find any packages in ["selectize"] on jspm

But real response (which I spied with mitmproxy) from api.jspm.io is:

{
    "error": "Error: Unable to resolve package npm:jquery to \"1.7.0, ^2, ^3\" imported from
https://ga.jspm.io/npm:[email protected]/dist/js/selectize.js"
}

May be it would be good to display full error response?

By the way if you could help me with correct command I will be pleasuered. But this question is offtop :)

Confusion between the `:to` and `:under` options of `pin_all_from`

I was testing the pin_all_from method and found what might be a potential issue. pin_all_from requires both the :to and :under options to be passed for this test case to pass:

test "directory pin under custom asset path" do
assert_match %r|assets/spina/controllers/another_controller-.*\.js|, generate_importmap_json["imports"]["controllers/spina/another_controller"]
assert_match %r|assets/spina/controllers/deeper/again_controller-.*\.js|, generate_importmap_json["imports"]["controllers/spina/deeper/again_controller"]
end

This is also apparent by removing the line:

pin_all_from "app/javascript/spina/controllers", under: "controllers/spina", preload: true

from the setup and noticing that the tests still pass. I also verified it by creating a new Rails 7 app and adding both the lines:

pin_all_from "app/javascript/spina/controllers", under: "controllers/spina", preload: true
pin_all_from "app/javascript/spina/controllers", under: "controllers/spina", to: "spina/controllers", preload: true

to config/importmap.rb and running bin/importmap json. Commenting out the second line doesn't generate any imports but commenting out the first line does.

Popper.js not working when --download is used

I apologize in advance if this is not a importmap problem, I am still learning to use it.

I have problem with bootstrap configuration through importmaps, for some reason when I run bin/importmap pin bootstrap --download I am getting these errors in chrome console (jsdelivr, unpkg) cdn providers

GET http://localhost:3000/assets/modifiers/index.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-ce872054c46039b8d5939756969a7a008e8d1ab3907e72b141e9e4650641b9ea.js:1 GET http://localhost:3000/assets/enums.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-ce872054c46039b8d5939756969a7a008e8d1ab3907e72b141e9e4650641b9ea.js:6 GET http://localhost:3000/assets/popper.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-ce872054c46039b8d5939756969a7a008e8d1ab3907e72b141e9e4650641b9ea.js:8 GET http://localhost:3000/assets/popper-lite.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-ce872054c46039b8d5939756969a7a008e8d1ab3907e72b141e9e4650641b9ea.js:4 GET http://localhost:3000/assets/createPopper.js net::ERR_ABORTED 404 (Not Found)

when I use command without download option like this bin/importmap pin bootstrap it works properly...not sure what is the problem in both commands it uses same cdn link

errors below are from JSPM cdn provider

GET http://localhost:3000/_/40866a73.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/enums.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/index.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/eventListeners.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/popperOffsets.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/offset.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/applyStyles.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/flip.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/preventOverflow.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/arrow.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/hide.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/popper-lite.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/detectOverflow.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getBoundingClientRect.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getCompositeRect.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getNodeScroll.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getWindowScroll.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getWindow.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/instanceOf.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getHTMLElementScroll.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getNodeName.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getWindowScrollBarX.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getDocumentElement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/isScrollParent.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getComputedStyle.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getLayoutRect.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/listScrollParents.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getParentNode.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getOffsetParent.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/08d18af5.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/03a0b0f1.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/5328de10.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/getMainAxisFromPlacement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/8937ec25.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/getOppositePlacement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/computeAutoPlacement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/utils/getOppositeVariationPlacement.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/ea19fa71.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/8d8f2f4c.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/c591086d.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/_/6e98d37c.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/modifiers/computeStyles.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getDocumentRect.js net::ERR_ABORTED 404 (Not Found)
@popperjs--core-139c8b1356b983f829b396b480ea4fa4e5205f8045a1c02bccb5024bda4fded6.js:1 GET http://localhost:3000/assets/dom-utils/getViewportRect.js 404 (Not Found)

javascript/application.js

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"

import "@popperjs/core"
import "bootstrap"

config/importmap.rb

# Pin npm packages by running ./bin/importmap

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.js"
pin "@hotwired/stimulus", to: "stimulus.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
pin_all_from "app/javascript/controllers", under: "controllers"
pin "bootstrap" # @5.1.3
pin "@popperjs/core", to: "@popperjs--core.js" # @2.10.2

Overriding asset_host results in incorrect asset paths

When the Rails app is configured with an asset_host the urls for the importmap look good until you override the asset_host in the controller. Eg:

config/environments/production.rb

config.asset_host = "https://cdn.example.com"

app/controllers/admin_controller.rb

class AdminController < ApplicationController
  self.asset_host = "https://cdn-admin.example.com"
end

The html output in the admin view has the wrong asset host. It has cdn.example.com instead of cdn-admin.example.com.

<script type="importmap" data-turbo-track="reload" nonce="">{
  "imports": {
    "application": "https://cdn.example.com/assets/application-11b28290a99e06bbb97f89de85099237219c655f.js",
    "admin": "https://cdn.example.com/assets/admin-c574738f5c1adffd9b7a877bf36ca6320be01a06.js",
    "@hotwired/turbo-rails": "https://cdn.example.com/assets/turbo-b993120d6c7ae1a4f86fc1faf67a6d7d462fa2f0.js",
    "@hotwired/stimulus": "https://cdn.example.com/assets/stimulus-33b5690d111cc0620be9dd1b12e236dacf03a024.js",
    "@hotwired/stimulus-loading": "https://cdn.example.com/assets/stimulus-loading-e6cc58d8195016dd774d85da7a37d34620facbfd.js",
    "controllers/hello_controller": "https://cdn.example.com/assets/controllers/hello_controller-8404a78da18e60f56632427531b2407db4f7f75e.js"
  }
}</script>
<link rel="modulepreload" href="https://cdn.example.com/assets/application-11b28290a99e06bbb97f89de85099237219c655f.js" nonce="">
<link rel="modulepreload" href="https://cdn.example.com/assets/admin-c574738f5c1adffd9b7a877bf36ca6320be01a06.js" nonce="">
<script src="https://cdn-admin.example.com/assets/es-module-shims.min-6e2591c8c15bae03d37b0f75efe46d7c609ef6e4.js" async="async" data-turbo-track="reload" nonce=""></script>

Love the work you guys are doing! โค

Duplication with package.json?

I'm very new to the concept of importmaps, but I've gone through the readme and tried this gem out. A question I have is how this library works with package.json and node_modules. Doesn't config/importmap.rb duplicate information that is already stored in package.json?

Or is the end-goal that we wouldn't need package.json at all? If the goal is to replace package.json and npm altogether, wouldn't this library end up being a full-fledged package manager?

Not allowed to load local resource: blob://null/

I'm not sure if it is the right place to report this issue.

I'm seeing those errors under safari :

[Error] Not allowed to load local resource: blob://null/assets/turbo.min.js-12ab1481b54e9f84d4561ac0e6e5328811dc5b233b7cba05444fcdee85912e46.map
[Error] Not allowed to request resource
[Error] Cannot load blob://null/assets/turbo.min.js-12ab1481b54e9f84d4561ac0e6e5328811dc5b233b7cba05444fcdee85912e46.map due to access control checks.
[Error] Not allowed to load local resource: blob://null/assets/stimulus.min.js-5cdf38f474c7d64a568a43e5de78b4313515aa0e4bd3d13fac297fffeba809f0.map
[Error] Not allowed to request resource
[Error] Cannot load blob://null/assets/stimulus.min.js-5cdf38f474c7d64a568a43e5de78b4313515aa0e4bd3d13fac297fffeba809f0.map due to access control checks.

where does that null is coming from ?

Uncaught TypeError: Error resolving module specifier โ€œapplicationโ€ on Rails 7 in Firefox

I see the following 2 console warnings in FireFox after creating a rails 7 app.


The first warning:

Uncaught TypeError: Error resolving module specifier โ€œapplicationโ€. Relative module specifiers must start with โ€œ./โ€, โ€œ../โ€ or โ€œ/โ€.

The warning points to the following line of code:

<script type="module">import "application"</script>

Any javascript I place in application.js appears to work as expected. Turbolinks and Trix work correctly too.


The second warning:

asm.js type error: Disabled because no suitable wasm compiler is available

The above warning points to the es shim js file.


These warnings only appear in Firefox.

Screen Shot 2021-10-02 at 2 15 53 AM


To reproduce:

  • rails new internetwebsite
  • rails g scaffold posts title
  • rails db:migrate
  • rails s
  • open localhost:3000/posts

Additional info:

  • Using Ruby 3.0.2
  • Not using yarn/node/esbuild etc
  • Happens with both the alpha gems
  • Happens when pulling rails directly from github
  • No warnings in Chrome or Safari
  • MacOs Big Sur 11.6
  • FireFox 92.0.1

Add reloadable importmap.rb

Convert only-loaded-on-boot config/initializers/importmap.rb into reloaded-on-change config/importmap.rb. Just like routes.rb or i18n translations.

Bad Import Statement in Stimulus Controller Doesn't Raise an Error

In Webpacker, if I made a mistake in an import statement within a Stimulus controller like:

import { Controller } from 'bad_name_here'

Then I'd get an error in the JavaScript console or when compiling that would show:

Module not found: Error: Can't resolve 'bad_name_here' in ...

If I make a mistake in an import statement in a Stimulus controller when I'm using importmap-rails, then I don't get any error. The JavaScript for that controller just doesn't run. Could this be changed so that we continue to get a warning for import mistakes?

I can see that if I have a bad import statement up in my application.js file that I do get an error like this which is good:

Uncaught TypeError: Failed to resolve module specifier "bad_name_here" ...

Pin_all_from in subdirectories

When using pin_all_from, it's currently impossible to have a module name that's on a different folder level than the module_path.

Example:
My gem contains namespaced Stimulus controllers in app/assets/javascripts/spina/controllers. I want those to be available with the module_name controllers/[some-stimulus-controller].js, pointing to /assets/spina/controllers/[some-stimulus-controller].js so that stimulus-autoloader picks them up.

I've currently worked around this by adding a prepend_path attribute to the method (and MappedDir) and simply prepending it to the path in expand_directories_into(paths):

Spina.config.importmap.draw do
  pin "@spina/spina", to: "spina.js"
  pin_all_from Spina::Engine.root.join("app/assets/javascripts/spina"), prepend_path: "spina"
end
def pin_all_from(path, under: nil, preload: false, prepend_path: nil)
  @directories[path] = MappedDir.new(path: path, under: under, preload: preload, prepend_path: prepend_path)
end
MappedDir  = Struct.new(:path, :under, :preload, :prepend_path, keyword_init: true)
if mapping.prepend_path
  module_path = File.join(mapping.prepend_path, module_path).to_s
end

Is there a better way to fix this? My other two options would be to either a) pin every file separately (don't want to do that) or b) create my own stimulus-autoloader, specifically for Spina's Stimulus controllers.

NoMethodError: private method `importmap=' called

I'm updating importmap-rails from 0.6.1 to 0.7.6 and I get the following error:

NoMethodError: private method `importmap=' called for #<XXXX::Application:0x000056001ecded98>
/home/runner/work/xxxx/xxxx/vendor/bundle/ruby/2.6.0/gems/importmap-rails-0.7.6/lib/importmap/engine.rb:14:in `block in <class:Engine>'
  • importmap-rails 0.7.6
  • stimulus-rails 0.6.0
  • turbo-rails 0.8.1
  • rails 6.1.4.1
# config/importmap.rb

pin 'bootstrap', to: 'https://cdn.skypack.dev/bootstrap'
pin '@hotwired/turbo-rails', to: 'turbo.js'
pin '@hotwired/stimulus', to: 'stimulus.js'
pin '@hotwired/stimulus-autoloader', to: 'stimulus-autoloader.js'
pin '@hotwired/stimulus-importmap-autoloader', to: 'stimulus-importmap-autoloader.js'
pin '@rails/activestorage', to: 'https://cdn.skypack.dev/@rails/activestorage'
pin '@rails/actioncable', to: 'https://cdn.skypack.dev/@rails/actioncable'
pin 'trix', to: 'https://cdn.skypack.dev/trix'
pin '@rails/actiontext', to: 'https://cdn.skypack.dev/@rails/actiontext'

pin_all_from 'app/assets/javascripts/channels', under: 'channels'
pin_all_from 'app/assets/javascripts/controllers', under: 'controllers'

pin 'application'

Unable to complete installation on existing rails 6 app

The command ./bin/rails importmap:install is always giving me an error

NoMethodError: undefined method paths' for #<Importmap::Map:0x000055db94454028 @files={}, @directories={}>`

on the rails initialization process. I've tried many versions of the gems to no avail. Maybe there is something missing on the documentation?

My rails version is 6.1.3.2

Many thanks

Best Practice for Environment Variables

With webpacker, we were able to define environment variables in process.env. We used it to store things like RAILS_ENV or keys for Stripe integration.

Is there are recommended way to achieve the same result with importmap? My first thought is to define a meta tag, but is there another approach?

importmap json does not include a package in package.json

Hi,

I am using "face-api.js" package (https://github.com/justadudewhohacks/face-api.js).

When I use "./bin/importmap pin face-api.js", there are packages added to config/importmap.rb and I have a problem with tslib because it does not provide default export. It seems that this is common issue with ES6 tslib.

So that I want to use package.json to manage this lib.
yarn add face-api.js

Then, I "pin" this inside config/importmap.rb
pin 'face-api.js'

Add it to application.js
import "face-api.js";

And, use it in my js component
import * as faceapi from "face-api.js";

After restart rails server, i got this error
---- error on my browser's console ----
Uncaught TypeError: Failed to resolve module specifier "face-api.js". Relative references must start with either "/", "./", or "../".

Rails server reports some more warning in console
---- rails server ----
Rendered logins/index.html.erb within layouts/application (Duration: 7.4ms | Allocations: 2177)
Importmap skipped missing path: face-api.js.js

I tried to change "face-api.js" to "face-api", but it does not work.

Using "importmap json" does not show this package in my import map

I am not sure what is missing. Could you please give a support ?

Thanks,

Switch --download makes error

Hi,

I got error when using "--download" switch.

Ex: "./bin/importmap pin react --download" command generates error
Couldn't find any packages in ["react", "--download"] on

Rails: 7.0.0.alpha2
Importmap-rails: 0.7.6

Could you please take look ?

Thanks,

Possible issue shim not honoring config.assets.prefix

As i'm bumbling around on development i'm trying to get the most verbose and most production-like set up so i can better understand the working parts i'm running bin/rails assets:precompile with config.assets.prefix = "/dev-assets"

On page load i'm getting a bad route

devlog        | ActionController::RoutingError (No route matches [GET] "/assets/es-module-shims.js-2cdffbe3452e6a89e4b5e919cfb60b544a5ef6d45f21d93df54c4af2a76890bc.map"):

Sprockets did write it to public/dev-assets/es-module-shims.js-2cdffbe3452e6a89e4b5e919cfb60b544a5ef6d45f21d93df54c4af2a76890bc.map so

The actual mappings look good

// bin/importmap json
{
  "imports": {
    "application": "/dev-assets/application-93ee4e955b86e96387d3aa9cc90658c164fefd765c992f79d37b72fdd09c1d0f.js",
    "@hotwired/turbo-rails": "/dev-assets/turbo.min-2e35750e215200b3e20412a6fa49c166604997c83c17a063885c0e06c5c5c0fe.js",
    "@hotwired/stimulus": "/dev-assets/stimulus.min-471bff773ecece7e73ba136dfdf213f54a5b6ef32de7df8863280be2bfc7c0c4.js",
    "@hotwired/stimulus-loading": "/dev-assets/stimulus-loading-c1cc576b2c58baf36b1e1f81e8f4265e3023b9b322711c18f26d270f6bdf26b0.js",
    "firebase/app": "https://www.gstatic.com/firebasejs/9.6.1/firebase-app.js",
    "firebase/auth": "https://www.gstatic.com/firebasejs/9.6.1/firebase-auth.js",
    "firebase/analytics": "https://www.gstatic.com/firebasejs/9.6.1/firebase-analytics.js",
    "firebase/app-check": "https://www.gstatic.com/firebasejs/9.6.1/firebase-app-check.js",
    "@fortawesome/fontawesome-free": "https://ga.jspm.io/npm:@fortawesome/[email protected]/js/fontawesome.js",
    "@fortawesome/fontawesome-svg-core": "https://ga.jspm.io/npm:@fortawesome/[email protected]/index.es.js",
    // [clipped]
}

Couldn't find any packages in ["any package"] on jspm

Not sure what is up but I can't pin anything from ga.jspm.io.

bin/importmap pin @rails/request.js
#> Couldn't find any packages in ["@rails/request.js"] on jspm

bin/importmap pin video.js
#> Couldn't find any packages in ["video.js"] on jspm

bin/importmap pin el-transition
#> Couldn't find any packages in ["el-transition"] on jspm

bin/importmap pin stimulus-use
#> Couldn't find any packages in ["stimulus-use"] on jspm

I just checked another project that run the same setup and run into the exact same thing so opening a bug report because I have the same issue in multiple projects.

json command returns null when using importmap-rails > 0.6.3

Using importmap-rails version 0.6.3 and running ./bin/importmap json works as expected (i.e. it returns the importmap JSON:

$ ./bin/importmap json
{
  "imports": {
    "application": "/assets/application-37f365cbecf1fa2810a8303f4b6571676fa1f9c56c248528bc14ddb857531b95.js",
    "@hotwired/turbo-rails": "/assets/turbo-7c5e418c7a4d154780d11e54c0fbd17ca23ba401e915c299c4166410c90db9df.js",
    "@hotwired/stimulus": "/assets/stimulus-24c1fe138493d69738cc137a0b8412877d0ffac33385b62d153012a3e7a13db5.js",
    "@hotwired/stimulus-importmap-autoloader": "/assets/stimulus-importmap-autoloader-7366d931317007a1e7e62c8dd8198dbc6d6b438207ff8d8539d06019597bf2f7.js",
    "controllers": "/assets/controllers/index-f6aa019eef4d0e13975a27efdf6d17ba2c6446417bfcb3139efd889f948a5dfc.js",
    "controllers/application": "/assets/controllers/application-0a88d7da94dddbd4b5db3a7e58aba83c761c0de29f578c197e4e41a3a79d014f.js",
    "controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js"
  }
}

However, on later versions (such as 0.7.4, the latest release) it returns null:

$ ./bin/importmap json
null

This appears to have been broken by this change: 75f312b#diff-5dac3d58ec92e0c2cba54981b8ff708a46dd3650b323dcfd9edccb25aac48ff1, which moved the construction of the Importmap::Map instance into an initializer (previously it was constructed at class-evaluation-time of Importmap::Engine). Thus, the importmap is no longer available after requiring config/application.rb since that doesn't run the initializers.

Need some common migration examples in Wiki

It would be very helpful if there were examples of how to get commonly used packages to be migrated to use this. For instance:

  • jQuery
  • TailwindCSS
  • Bulma
  • AnimateJS
  • ApexCharts
  • ChartKick
  • FontAwesome

Having such a guide would help developers adopt this new technology.

Minimized es-module-shims + @hotwired/stimulus-loading in Safari

Upgrading to importmap-rails v0.9.0 results in issues with eager- or lazyLoad of Stimulus controllers (using @hotwired/stimulus-loading).

= javascript_importmap_tags

JS console:

Failed to autoload controller: modulor--view-components--grid--component
Error: Unable to resolve specifier 'controllers/modulor/view_components/grid/component_controller' from http://127.0.0.1:3010/assets/stimulus-loading-685d40a0b68f785d3cdbab1c0f3575320497462e335c4a63b8de40a355d883c0.js
throwUnresolved โ€” es-module-shims.min.source.js:2
(anonymous function) โ€” es-module-shims.min.source.js:2
asyncFunctionResume
(anonymous function)
promiseReactionJobWithoutPromise

I was able to find out that switching to non-minified version of es-module-shims resolves the issue

= javascript_importmap_tags shim: false
= javascript_importmap_shim_tag minimized: false

test fails on NoMethodError content_security_policy_nonce

Perhaps a require "action_dispatch/http/content_security_policy" or something, somewhere?

Importmap::ImportmapTagsHelperTest#test_javascript_inline_importmap_tag:
NameError: undefined local variable or method `content_security_policy_nonce' for #<Importmap::ImportmapTagsHelperTest:0x000055fa425cbda8>
    /home/runner/work/importmap-rails/importmap-rails/vendor/bundle/ruby/2.7.0/gems/actionpack-6.1.3.1/lib/action_dispatch/testing/assertions/routing.rb:187:in `method_missing'
    /home/runner/work/importmap-rails/importmap-rails/vendor/bundle/ruby/2.7.0/gems/actionview-6.1.3.1/lib/action_view/test_case.rb:273:in `method_missing'
    /home/runner/work/importmap-rails/importmap-rails/app/helpers/importmap/importmap_tags_helper.rb:16:in `javascript_inline_importmap_tag'
    /home/runner/work/importmap-rails/importmap-rails/test/importmap_tags_helper_test.rb:7:in `block in <class:ImportmapTagsHelperTest>'

rails test /home/runner/work/importmap-rails/importmap-rails/test/importmap_tags_helper_test.rb:4

Allow to pin modules with .jsm extension

The .jsm extension can be used to refer to javascript modules, and allows to distinguish javascript files from those that are used as modules. In some circumstances, it can be useful to make this distinction.

My use case : I use a source bundler (esbuild) and I want to register some imports as external so the bundled code can make a reference to another javascript module in the browser. It allows for lighter bundles and also allows to import dynamic modules. I planned to use the .jsm extension for that.

importmap should allow to pin .jsm modules. Proposed syntax:

pin "extra", extname: ".jsm", preload: true

The extname keyword is already in use in sprockets to refer to assets by name in order to have sprockets compute the correct asset path.

Also, .jsm should be a registered mime type by default.

rails importmap:install creates app/javascript/application.js

Running rails importmap:install creates the entrypoint file in app/javascript/application.js instead of app/assets/javascripts/application.js.

If I delete it and add app/assets/javascripts/application.js manually and install Stimulus, it can't find my controllers:

Failed to autoload controller: chart Error: Unable to resolve specifier 'chart_controller' from <path>

Before switching to importmap-rails I had webpacker installed - can it have something to do with that? Although I uninstalled webpacker and deleted all files before installing importmap-rails.

Conventional differences between `pin` and `pin_all_from`?

Great job on this gem! I was testing the pin and pin_all_from methods and was looking into how they generate the Import Map. The way pin works is we specify the "name under which we want a file inside JS modules to be referred as" as the first parameter, and the :to option accepts the "file inside public/assets which the name will resolve to". That is:

# config/importmap.rb

pin "foobar", to: "foobar.js"

generates:

{
  "foobar": "/assets/foobar-06d932.js"
}

This same convention might not be followed for pin_all_from, since the first parameter accepts the "path to the folder (excluding the app/javascript part) inside public/assets that we want to resolve", and :under option accepts the "name(s) under which we want all those files to be accessed as". That is:

# config/importmap.rb

pin_all_from "app/javascript/controllers", under: "controllers"

generates:

{
  "controllers/hello_controller": "/assets/controllers/hello_controller-074c78.js",
  "controllers": "/assets/controllers/index-9f08c7.js"
}

Also, in the pin_all_from's case, we have to specify the file path relative to the project's root, whereas in the case of pin, it auto-resolves.

I feel that there's an ideal difference between pin_all_from and pin. The arguments to pin rely on app/assets/config/manifest.js to make sure that the processed files are put properly inside the public/assets folder. But the arguments to pin_all_from feel like they care about the folder/files themselves and don't rely on the manifest file.

This might not be an issue as such and that I'm assuming/understanding things incorrectly. So please feel free to disagree with an explanation of where I might be wrong. Cause that would be helpful if someone else has the same doubts.

Import Map doesn't support CDN based directories

It seems that Import Map only supports the happy case of having to use a single file from a REPO for example:

pin "quill", to: "https://ga.jspm.io/npm:[email protected]/dist/quill.js"

In reality though, in order write custom plugins you tend to have to extend some existing classes. It would be nice to be able to say something like

pin_all_from "https://unpkg.com/[email protected]/", under: "quill"

and then be able to access different files via import "quill/dist/quill.js" Or at least have a "Download all files" option to vendor it. Otherwise if you need 10 files youd probably have to do:

pin "quill", to: "https://ga.jspm.io/npm:[email protected]/dist/quill.js"
pin "Bold", to: "https://ga.jspm.io/npm:[email protected]/fonts/bold.js"
pin "Italtic", to: "https://ga.jspm.io/npm:[email protected]/fonts/italtic.js"
etc, etc.

Impormap raises error when we have another module on page

I have this script on my page that is not in my importmap.

    <script type="module">
      import githubAutoCompleteElement from 'https://cdn.skypack.dev/@github/auto-complete-element';
    </script>

When the page runs I see this error:

Uncaught SyntaxError: unexpected token: 'from'
    processScript es-module-shims.js:750
    processScriptsAndPreloads es-module-shims.js:667
    <anonymous> es-module-shims.js:705
    async* es-module-shims.js:700
    <anonymous> es-module-shims.js:2

The asset "actioncable.esm.js" is not present in the asset pipeline.

Thank you so much for this gem and really shaping up Hotwire!

I'm upgrading an asset pipeline only Hotwire app on Rails 6.1.4.

I assume these will be available automatically in Rails 7,
but how should we go about getting the three javascript files added to assets.rb by the installer?

Uncaught SyntaxError: The requested module 'tslib' does not provide an export named 'default'

Trying to use package @shopify/polaris using importmap, failed to load the component and found the following messgae in the console.

Uncaught SyntaxError: The requested module 'tslib' does not provide an export named 'default'

Steps to reproduce the error:

  1. Install packages using importmap
bin/importmap pin @shopify/polaris htm/react react-dom
  1. Load a simple react component
import ReactDOM from "react-dom"
import { html } from "htm/react"

import {AppProvider} from '@shopify/polaris'

const app = html`
  <${AppProvider}>
    Hello world
  <//>
`

ReactDOM.render(app, document.getElementById("root"))

Tried to search around, vitejs/vite#1583 it looks like the suggestion is to use tslib.es6.js, however, according to the importmap list, it is already using the tslib.es6.js

pin "tslib", to: "https://ga.jspm.io/npm:[email protected]/tslib.es6.js"

Also, what's more interesting is that removing the line above doesn't change anything. I will still receive the same error message. Tried to bump the tslib version, but doesn't work as well.

Pretty confused with this error. Does anyone have a clue here?

JavaScript for different environments?

In the Rails app we are using where I work we have multiple per-environment files:

- config
   |- webpack
      |- development.js
      |- environment.js
      |- production.js
      |- staging.js
      |- test.js

One of the reasons we do this is that there are libraries that are useful for development that we don't want to be part of production. Another is to have environment-specific versions of a library used for that environment.

Is there a way to do this with importmap-rails that I have missed?

It might be nice to have groupings like Gemfiles, e.g.

# bin/importmap pin react --env development --group development
# bin/importmap pin react --group production

# importmap.rb

group :development do
  pin "react", to: "https://ga.jspm.io/npm:[email protected]/dev.index.js"
end

group :production do
  pin "react", to: "https://ga.jspm.io/npm:[email protected]/index.js"
end

Importmap validation error

Using the default javascript_importmap_tags method helper, will generate the following output sequence

<script type="importmap" data-turbo-track="reload">{
  "imports": {
    "leaflet": "https://ga.jspm.io/npm:[email protected]/dist/leaflet-src.js",
  }
}
</script>

Validating the HTML output of a page using: https://validator.w3.org/nu/#textarea will yield a validation error like :

image

In order to avoid that, it is recommended to set the script type to application/importmap+json .

Faliling validation
<!DOCTYPE html>
<html  lang="en">
    <title>Koelpin-Macejkovic</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="importmap" data-turbo-track="reload">
{
  "imports": {
    "./resources/log.js?pipe=sub&name=A": "./resources/log.js?pipe=sub&name=B"
  }
}
</script>
<script>
const log = [];
promise_test(() => {
  return import("./resources/log.js?pipe=sub&name=A")
    .then(() => import("./resources/log.js?pipe=sub&name=B"))
    .then(() => assert_array_equals(log, ["log:B"]))
  },
  "Module map's key is the URL after import map resolution");
</script>
Passing validation
<!DOCTYPE html>
<html  lang="en">
    <title>Koelpin-Macejkovic</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="application/importmap+json" data-turbo-track="reload">
{
  "imports": {
    "./resources/log.js?pipe=sub&name=A": "./resources/log.js?pipe=sub&name=B"
  }
}
</script>
<script>
const log = [];
promise_test(() => {
  return import("./resources/log.js?pipe=sub&name=A")
    .then(() => import("./resources/log.js?pipe=sub&name=B"))
    .then(() => assert_array_equals(log, ["log:B"]))
  },
  "Module map's key is the URL after import map resolution");
</script>

Importing local files from app/javascript folder

I tried to migrate from webpacker to importmap-rails and managed to port everything, including migrating from turbolinks to turbo-rails. Everything worked well in development mode, but broke as soon as I deployed the application. Specifically, a JavaScript file i loaded from application.js was not found. Here's my setup:

app/javascript/application.js

import "@hotwired/turbo-rails"
import { Filter } from './src/Filter.js';

/* some more js code skipped for brevity */

app/javascript/src/filter.js

class Filter {
  /* some more js code skipped for brevity */
}

As soon as I run the application in production mode, I get the following browser error when loading the page: Uncaught Error: 404 Not Found https://example.com/assets/src/Filter.js

I tried the following mitigations and many possible combinations:

  • Adding pin_all_from "app/javascript/src", under: "src" to config/importmap.rb
  • Moving the filter.js file to app/assets/javascripts/src, and adding //= link_tree ../../../app/assets/javascripts/src .jsto app/assets/config/manifest.js, as well as adding pin_all_from "app/assets/javascripts/src", under: "src" to config/importmap.rb
  • Adding Rails.application.config.assets.precompile += %w( src/*.js ) to config/initializers/assets.rb

I noticed that I can get the asset pipeline to compile filter.js (I do get a digested version in public/assets/src), but when the JS code is run in production, it always tries to load the non-digested version.

How can I import files that are available locally using importmaps?

I can provide a minimal example if the issue is unknown and if that helps.

version 0.4.1 causes NoMethod Error undefined method `error' for nil:NilClass

I have been successfully learning turbo-rails gem with importmap-rails and Rails 7 alpha. Update of import-map from 0.3.4 to 0.4.1 causes the following error when trying to start the rails server:

/Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/map.rb:16:in `rescue in draw': undefined method `error' for nil:NilClass (NoMethodError)
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/map.rb:13:in `draw'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/engine.rb:5:in `<class:Engine>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/engine.rb:4:in `<module:Importmap>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/engine.rb:3:in `<main>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/zeitwerk-2.5.0.beta2/lib/zeitwerk/kernel.rb:35:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap-rails.rb:6:in `<main>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/zeitwerk-2.5.0.beta2/lib/zeitwerk/kernel.rb:35:in `require'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:60:in `block (2 levels) in require'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:55:in `each'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:55:in `block in require'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:44:in `each'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:44:in `require'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler.rb:174:in `require'
	from /Users/charlie/sites/defluris_engine/defluris/config/application.rb:12:in `<main>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/zeitwerk-2.5.0.beta2/lib/zeitwerk/kernel.rb:35:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/commands/server/server_command.rb:137:in `block in perform'
	from <internal:kernel>:90:in `tap'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/commands/server/server_command.rb:134:in `perform'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/command/base.rb:87:in `perform'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/command.rb:48:in `invoke'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/commands.rb:18:in `<main>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from bin/rails:9:in `<main>'
/Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/map.rb:14:in `read': No such file or directory @ rb_sysopen - config/importmap.rb (Errno::ENOENT)
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/map.rb:14:in `draw'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/engine.rb:5:in `<class:Engine>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/engine.rb:4:in `<module:Importmap>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap/engine.rb:3:in `<main>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/zeitwerk-2.5.0.beta2/lib/zeitwerk/kernel.rb:35:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/importmap-rails-0.4.1/lib/importmap-rails.rb:6:in `<main>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/zeitwerk-2.5.0.beta2/lib/zeitwerk/kernel.rb:35:in `require'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:60:in `block (2 levels) in require'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:55:in `each'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:55:in `block in require'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:44:in `each'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler/runtime.rb:44:in `require'
	from /Users/charlie/.rvm/rubies/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/bundler.rb:174:in `require'
	from /Users/charlie/sites/defluris_engine/defluris/config/application.rb:12:in `<main>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/zeitwerk-2.5.0.beta2/lib/zeitwerk/kernel.rb:35:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/commands/server/server_command.rb:137:in `block in perform'
	from <internal:kernel>:90:in `tap'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/commands/server/server_command.rb:134:in `perform'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/command/base.rb:87:in `perform'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/command.rb:48:in `invoke'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/bundler/gems/rails-b4ccee7a8a57/railties/lib/rails/commands.rb:18:in `<main>'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/charlie/.rvm/gems/ruby-3.0.2@ruby3rails7/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from bin/rails:9:in `<main>'

If I go back to importmap-rails 0.3.4, the rails server loads properly.

Reloader and pin_all_from not picking up assets transformed by the asset pipeline

Currently, importmaps don't work properly with JS assets which have their filename extension transformed by the Rails asset pipeline from something other than .js to .js:

  • pin_all_from only matches .js(m) files
  • The cache sweeper file watcher only watches for .js files

Use cases for other filename extensions include:

  • the default Sprockets functionality of transforming .js.erb to .js
  • transformations for framework-specific file formats like .vue and .jsx

For example, we are using the jass-vue-sfc gem to transform .vue components into ES modules, which are then loaded by import maps. The same can be achieved for JSX files with jass-react-jsx.

In PR #57 I'm proposing adding config.importmap.accept which would allow importmaps to pin other filename extensions than .js, while staying agnostic to the asset pipeline used.

/bin/importmap outdated

Given the new bin command to pin and unpin dependencies, what do you think about adding a new outdated command to check what needs to be updated (like bundler / yarn / etc) in order to make it easier and not having to check each single dependency (given that integrations like dependabot wouldn't support that... at least initially, maybe at some point?)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.