Rails 6 is full of fun awesome new features and some new ways of compiling our assets. Heroku is one of the easiest way to deploy your rails application but things between development and production can get a little hairy if you’re not careful with a couple of gotchas that exist with the way we compile and use assets in production making your site look weird by having missing pictures or css that just don’t load. Throw in two ways off compiling assets now with Webpacker and Sprockets and things getting even more complicated.
The first thing you need to do with any asset your you want to use like images that are in your assets folder is to use the asset_path helper or asset_url helper instead of a hardcode link to the path.
So image tag that might look like this in your erb file:
<img src="/assets/my_image.png">
Needs to change to look like this:
<img src=<%=asset_path("my_image.png")%>
If you have rule sets in you scss files that require an image in your assets image folder you will have to use the asset-url helper. A background image property in your application.scss file will need to be changed from this:
body {
background-image: url("/assets/cool_image.png");
}
Will need to be changed to this:
body {
background-image: asset-url("cool_image.png");
}
Not doing the above will probably work fine on your local development environment but will break on your production environment. This is because your local environment doesn’t have the compiled images with their hashed named.
Therefore /asset/cool_image.png
will be in its location locally but might look like this in in your production environment /asset/cool_image123h53jh2358uigjeru894lasen49.png
One thing you want to do is stick to just one place for your scss.
Your css can live in /app/assets/stylesheets
directory
.OR. in your /app/javascript/ folder you want to create a new folder and call it src or stylesheets or whatever you want.
DO NOT put styles in both places unless you want to have a bad time. If you do you will have to use two links in your layouts application folder which will give you many hours of frustration trying to make it all work.
I recommend sticking your css files in /app/asset since the Webpacker documentation clearly states that you probably should unless your working with component based javascript (like React, Vue, Angular etc…) From the WebPacker Docs:
It[WebPacker] coexists with the asset pipeline, as the primary purpose for webpack is app-like JavaScript, not images, CSS, or even JavaScript Sprinkles (that all continues to live in app/assets).
The easy and recommended way keep it in assets
If you decide to to put your scss in your /app/assets/stylesheets
directory then you must make sure that in your /app/views/layouts/application.html.erb
you have the stylesheet being linked like this
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
That is the default way that the css stylesheet will be loaded when you create your app so no need to change anything there. However if you installed other things using Webpacker like Bootstrap or Fontawesome and did not use sprockets and the asset pipeline you will have to also use the the stylesheet_pack_tag.
Below I will go over how to use SCSS / CSS with webpacker and properly import your stylesheets. The difficult and NOT recommended way (by me atleast)
If you want to put your scss files in your /app/javascript/whatever_folder then you must change the /app/views/layouts/application.html.erb to the following:
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
Notice the difference in between the methods, this time around its pack_tag where before it was link_tag. Now you must tell Webpack yourself what you want to import.
In /app/javascript/packs/application.js
Let’s say you want to import your scss files that you created above from whatever folder you created.
So if you have a scss file in /app/javascript/packs/stylesheets/my_stylesheet.scss
then you must have
import "./stylesheets/my_styleshees.scss"
in your application.js file. In your application.js file is also where you would load up anything else that you wanted to load using WebPack instead of using the asset pipeline.