Frank Koehl
Frank Koehl

Reputation: 3186

File locations Javascript vs Stylesheet in Rails 7

In a new default Rails 7 application using the import maps functionality, Javascript is stored in app/javascript, while CSS is located in app/assets/stylesheets. Not only are they located at different hierarchy levels, but javascript is singular, while stylesheets is plural.

I'm looking for sources that explain these divergent locations and pluralization decisions. Searches through Rails Guides and API documentation have turned up nothing, but support talk on the Rails repo suggests that docs are still being actively updated.

On the surface this seems really shortsighted, but I want to make sure I'm not missing something before I go messing with the defaults.

Upvotes: 5

Views: 1375

Answers (1)

Alex
Alex

Reputation: 29994

app/assets is used by sprockets. This is rails asset pipeline. Preprocessing, minification, compilation etc. app/assets/javascripts was a thing before javascript took over the world and had to be given its own separate directory.

app/javascript was used by webpacker to avoid mixing it with sprockets processing. This is javascript pipeline that does what sprockets does, process, compile, minify etc. A way to bring javascript build tools into rails. Singular "javascript" is referring to Javascript language, not "javascripts" as in collection of js files.

Both of these directories can have css and js assets, just processed and compiled by different tools.

In rails 7, app/javascript is used by jsbundling-rails which integrates a few js build tools with rails: esbuild, webpack, and rollup.js. After javascript has done its job, bundles go into app/assets/builds where sprockets treats it as any other js or css file.

With import-maps there is no processing but app/javascript is the logical place for it. All files in app/javascript have to be precompiled by sprockets for use in production:

// app/assets/config/manifest.js

//= ../../javascript .js

and app/javascript has to be in Rails.application.config.assets.paths:

config.assets.paths << Rails.root.join("app/javascript")

This is what importmap-rails does, among other things. Note that because app/javascript is added to config.assets.paths, it is part of sprockets pipeline from the start.

Here is a short overview of who lives where:

app/
├─ assets/          # used by sprockets-rails, propshaft, everything else hooks into it
│  ├─ build/        # compiled assets (jsbundling-rails, cssbundling-rails, tailwindcss-rails)
│  ├─ config/       # precompile `build/` if any of these three ^ are used
│  │                #  and precompile `app/javascript/` if importmap-rails is used
│  ├─ stylesheets/  # used by cssbundling-rails, tailwindcss-rails
│  └─ javascripts/  # not used in rails 7 by default, but any directory can be added to `app/assets/`,
│                   #  just add it to config/manifest.js as well 
└─ javascript/      # used by jsbundling-rails, importmap-rails and anything node related
   └─ controllers/  # used by stimulus-rails   

Also, rails gems themselves use app/assets/javascripts to ship any js files so that you have access to them via asset url and tag helpers.

Upvotes: 9

Related Questions