Importmap and css

What is considered the best practice Rails Way™ to handle JS dependencies that come with their own stylesheets or other non-js assets for applications using importmap? I’ve struggled with this poorly documented issue since starting to use importmap and currently I have several NPM modules installed using importmaps where I have manually added the relevant stylesheets to /vendor/css/ and imported it in my application’s stylesheet, but of course this kinda defeats the purpose of using a tool like bin/importmap to install dependencies since I cannot get updates to these stylesheets and they will get left behind if I unpin the relevant module JS.

What are large-scale production apps doing for this? Is there some way to manage JS and CSS dependencies together without actually using NPM seperately to manage dependencies and then linking them through importmaps or something?

1 Like

Can you explain what you mean by that?

importmaps only handles JavaScript, and it only vendors JavaScript.

If you’re installing npm packages into node_modules, you can add node_modules to your sprocket paths and then import any css/sass in the node_modules into your CSS pipeline.

Does that help? I can be more specific or help alternatively with propshaft/cssbundling/etc.

No content in node_modules, I mean JS dependencies installed using the bin/importmap tool. For example, on a project right now I have dropzone and just-extend installed by running:

bin/importmap pin dropzone

This installs both dependencies into /vendor/javascript/ as expected, but since dropzone ships with CSS (and as you say, importmap is JS-only), I have to manually bring in the relevant CSS elsewhere in my app. This is a very common pattern, as a lot of dependencies have additional non-JS assets, and the crux of this question is what the recommended way to manage these dependencies is. Importmap states in it’s description that the goal is to free users from dependency on NPM, Yarn, Webpack, etc (a goal I very much support), but since it is common to need non-JS assets from NPM installs, clearly anyone using importmap in place of NPM (rather than in addition to it) needs to handle these assets somehow.

What are the preferred methods of doing this in modern Rails apps that are moving away from using NPM or Yarn? Are there projects that are using Importmap and manually adding all the other assets? Or is there a workflow I’m missing that is commonly used?

(To be clear, this isn’t a technical question about how to use importmap, I’m looking for feedback from other people working on larger Rails codebases than I am as to what their standard workflows are with the new tools available.)

I think the raison for importmaps is if your javascript needs are simple, not a general purpose “in the future no apps will need npm”.

Are there projects that are using Importmap and manually adding all the other assets? Or is there a workflow I’m missing that is commonly used?

There is not a workflow. You probably saw this issue.

My experience is handling it manually (usually writing a script like this) until it becomes unwieldy and then bring in a build tool (I like Vite Ruby). The “no build” story is very nice for small apps, but it’s easy to outgrow.

There isn’t a css functionality of importmaps that defines the list CSS files and then automatically adds them to the html head. You can see that Propshaft is itself barebones in what options it offers too (not even a :vendor option), which means that, in practice, you have to enumerate everything if you want to go the no-build route. No large applications go the no-build route.

If you take the most complex app I can think of going this no-build route, 37 Signals own Fizzy, it simply loads everything in app/assets/stylesheets:

Yeah, that issue has informed how I’ve used importmap since I first tried it out a year or two ago. Given the major improvements to Rails tooling (starting from a fairly good place already!) in recent years, spinning up greenfield projects with kamal, importmap, and hotwire out of the box is a great experience. As a major advocate for getting away from the current state of JS frontend and moving towards tools like hotwire, importmap is a great lightweight utility, and the fact that it can, in theory, download and link dependencies without an NPM step holds so much promise for shedding the overhead of NPM, package.json, and node_modules, so I’ve been holding out hope that someone had cracked a better workflow than I had to avoid a whole separate non-ruby dependency chain for NPM/yarn/whatever. DHH has even said elsewhere that importmap is supposed to be an alternative to package.json! So it’s so disappointing to then have to maintain a package.json anyway just to use any dependency that isn’t pure JS. Obviously manually adding the associated assets does match the principle of vendoring dependencies with the app, but now that stuff gets out of sync if importmap is used to update the version of an installed dependency or can easily be missed and left behind if something is removed from importmap. I appreciate the idea of very simple tools that do a single task well, but in the context of modern JS dependencies, it feels like a tool missing major features to download something when asked, but only part of it.