Release 1.9
Rails 7. Start Kit
. Assets and Asset Pipelines
Install and Run Ruby on Rails
now!
Copy & Paste in your terminal
git clone https://github.com/the-teacher/rails7-startkit.git && \
cd rails7-startkit && \
bin/setup
I want to use Bootstrap. What next?
I just want to install Bootstrap. What should I do?
Option 1
Oldish "rails way" with installing a gem like "bootstrap-rails". Right? Maybe it still even works. Who knows.
Bootstrap is a front-end solution. I'm sure It has to be managed with a typical front-end approach. I mean node
, npm
or yarn
.
Wrapping a front-end solution with a ruby code in 2023 is a very weird approach. Not my way!
Option 2
I heard something about ImportMap
. Ok. Maybe it may help somehow. For sure, partially, because it is about JS code only. I should investigate what I can do with that.
Option 3
I can (even I have to) use a typical Front-end way with using yarn
and compiling Bootstrap
assets with a processor or processors. I'm going to use this way.
A Direction to Go
Before I continue, I should clearly understand what asset management approaches Rails provides out of the box (or recommends) and how to use them for my goals.
Let's do a quick overview first.
Sprockets
What is that? A way to deliver CSS/JS assets of a web page.
What does it do? It merges all assets described in a manifest in the only bundle-file.
What types of assets? It can work with CSS / JS.
Something else? It can minify a js/css bundle file and provide for a bundle a hashed name to provide caching.
Best Match For precompiled assets that you want to merge in the only bundle file and deliver in a typical Rails way.
ImportMap
What is that? A way to deliver JS assets of a web page.
What does it do? It emulates a modern way to import JS modules in an entryPoint.js
file
What types of assets? Only JS files without any compilation or processing.
Something else? It can minify a js/css bundle file and provide for a bundle a hashed name to provide caching.
Best Match For small JS scripts and modules to make alive some of your elements on a page.
NPM/YARN and node_modules
What is that? A typical way to work with any Front-end assets and tools.
What does it do? It does everything what any FE developer needs, because it is FE eco system.
What types of assets? Any types.
Something else? Can be difficult to setup and use with Rails.
Best Match For front-end developers who are going to work with Rails and for heavy and big FE solutions for Rails apps.
What a Plan?
I want to use in my Application all possible approaches. I will use.
yarn
+ESBuild
+SASS
to build Bootstrap Assets.importMap
to deliver on a page my own small JS scripts that I do not need to compile.Sprockets
to deliver precompiled assets on a page in a typical Rails way.
Yes, my friend! The party is going to be hard.
Naming is everything!
To avoid mixing different things the first thing that I'm going to do is renaming.
Having only application.js
or application.css
in the project may confuse when you use different approaches at the same time.
Let's isolate importmap
and sprockets
and place them in different folders (read scopes)
<%= javascript_importmap_tags("importmap/application") %>
<%= stylesheet_link_tag "sprockets/application", "data-turbo-track": "reload" %>
<%= javascript_include_tag "sprockets/application", "data-turbo-track": "reload", defer: true %>
app/javascript/
├── importmap
│ ├── application.js
│ ├── articlesIndex.js
│ └── theSearchHighlight.js
└── sprockets
└── application.js
app/assets/stylesheets/
├── demo
│ ├── articles.css
│ ├── demo.css
│ ├── devise.css
│ ├── main.css
│ └── users.css
└── sprockets
└── application.css
ImportMap
In my project I'm going to use ImportMap
for delivering on the page my own simple JS scripts. It is a cheap and interesting way which I never used before. Why not? It just works and does not intersect with other things in the project.
app/javascript/importmap/
├── application.js
├── articlesIndex.js
└── theSearchHighlight.js
app/javascript/importmap/application.js
import ArticlesIndex from 'importmap/articlesIndex'
import TheSearchHighlight from 'importmap/theSearchHighlight'
console.log("Hello World! This is `importmap` entry point")
ArticlesIndex.init()
TheSearchHighlight.init('.the-search-highlight')
My config/importmap.rb
looks so:
# Pin npm packages by running ./bin/importmap
pin "importmap/articlesIndex", preload: true
pin "importmap/theSearchHighlight", preload: true
pin "importmap/application", preload: true
And together with
javascript_importmap_tags("importmap/application")
It produces the following code:
<script type="importmap" data-turbo-track="reload">
{ "imports": {
"importmap/articlesIndex": "/assets/importmap/articlesIndex-69e4089.js",
"importmap/theSearchHighlight": "/assets/importmap/theSearchHighlight-c58f503.js",
"importmap/application": "/assets/importmap/application-acea523.js"
}}
</script>
<link rel="modulepreload" href="/assets/importmap/articlesIndex-69e4089.js">
<link rel="modulepreload" href="/assets/importmap/theSearchHighlight-c58f503.js">
<link rel="modulepreload" href="/assets/importmap/application-acea525.js">
<script src="/assets/es-module-shims.min-d89e732.js" async="async" data-turbo-track="reload"></script>
<script type="module">import "importmap/application"</script>
Potentially you can even to install and use additional packages with using something like ./bin/importmap pin react react-dom
or even ./bin/importmap pin react react-dom --download
.
I would like to recommend you to avoid it. Because installing any front-end packages with this way will contradict with a regular way to install packages with using node
.
As you can see -- all ImportMap
assets have hashed tails to provide a correct caching. It is because ImportMap
is integrated with sprockets and rails asset pipeline. Not sure if I name things correctly. But you can see it here
Rails.application.config.assets.paths
ImportMap. Conclusion
ImportMap
is a simple way to use simple modular JS scripts that do not need any compilation. You can use this approach even if you use something more difficult. No need to remove it if you are going to use something else, like esbuild
or typical sprockets
.
Node + Bootstrap + ESBuild + SASS
- I'm going to install Bootstrap in my project.
- Bootstrap is a pure Front-end solution
- I'm going to use only FE ecosystem solutions. No rails gems or something like that!
Node and Yarn
$ node -v
v18.12.1
$ yarn -v
3.4.1
{
"name": "rails7startkit",
"scripts": {
"start": "yarn build:js:watch & yarn build:sass:watch",
"build": "yarn build:js & yarn build:sass",
"build:sass": "sass ./app/assets/stylesheets/sass/application.scss:./app/assets/builds/sass/application.css --verbose --no-source-map --load-path=node_modules",
"build:sass:watch": "yarn build:sass --watch",
"build:js": "esbuild app/javascript/esbuild/application.js --outdir=app/assets/builds/esbuild --bundle --sourcemap --public-path=assets",
"build:js:watch": "yarn build:js --watch"
},
"dependencies": {
"@popperjs/core": "2.11.6",
"bootstrap": "5.2.3",
"bootstrap-icons": "1.10.3",
"esbuild": "0.17.10",
"sass": "^1.58.3"
},
"packageManager": "yarn@3.4.1"
}
Now let's install required things
yan install
Let's add some things in our JS, SASS entry points.
app/javascript/esbuild/application.js
import 'bootstrap'
import * as Popper from '@popperjs/core'
app/assets/stylesheets/sass/application.scss
@import 'bootstrap/scss/bootstrap';
@import 'bootstrap-icons/font/bootstrap-icons';
yarn build
lucky@bb2cd8bf2c41:~/app$ yarn build
[1]
[1] app/assets/builds/esbuild/application.js 186.8kb
[1] app/assets/builds/esbuild/application.js.map 356.9kb
[1]
[1] ⚡ Done in 66ms
Job [1], 'yarn build:js' has ended
Now we have some precompiled files
app/assets/builds/
├── esbuild
│ ├── application.js
│ └── application.js.map
└── sass
└── application.css
Node and Yarn. Conclusion
Installation front-end packages with using Node
and Yarn
and compiling them is a typical way in front-end ecosystem. Use it for your front-end solutions. It may improve your development experience and will work correctly in a chain with Rails' Sprockets.
Sprockets
Now, when we have Bootstrap and precompiled bootstrap assets, we can use them as a typical local assets for sprockets
We will just use existed precompiled sass
and js
assets and use them in a sprocket's manifests.
app/javascript/sprockets/application.js
//= require esbuild/application.js
console.log("Hello from `sprockets/application.js`")
app/assets/stylesheets/sprockets/application.css
/*
*= require "demo/main"
*= require "demo/demo"
*= require "demo/articles"
*= require "demo/devise"
*= require "demo/users"
*= require "sass/application"
*/
To make things work property do not forget to edit manifest.js
app/assets/config/manifest.js
//= link_tree ../builds
//= link_tree ../images
//
//= link_directory ../stylesheets/sprockets
//
//= link_directory ../../../vendor/javascript
//= link_directory ../../javascript/importmap
//
//= link sprockets/application.js
Now, in development mode sprockets will merge all possible JS and CSS assets in bundles like that.
In production mode everything will be managed during assets:precompile
Conclusion
- I've successfully and simultaneously used in my project 3 different types to work with assets
- Careful naming and placing files in the system opens comfortable ways to use approaches together
- I better understood advantages and boundaries different approaches to work with assets in Rails
- Sprockets can be easily used with tools like
eslint
andsass
and be a good addition for them - To work with FE tools in Rails you do not need and additional gems like
jsbundling-rails
Personal recommendations
- Use
ImportMap
to manage simple modular scripts for your page. - Avoid installing any assets or packages with
ImportMap
. It is not a best way that you can use. Avoid a mess in a project. - Use
node
,npm
,yarn
as a main way to install and compile any FE solutions. With FE solutions better to work in FE way. - You precompiled assets can be used by
Sprockets
and extend a typical Rails approach to manage assets.
That is it!
👉 Subscribe to the project to know about most recent updates.
Happy coding with Rails 7. Start Kit