imported css files are not compiled into application.css file - ruby-on-rails

I have a style.scss file where i have imported bunch of other files like
#import url(asset-path('bootstrap/css/bootstrap.min.scss'));
#import url(asset-path('ionicons/css/ionicons.min.scss'));
#import url(asset-path('slick-carousel/slick/slick.scss'));
#import url(asset-path('slick-carousel/slick/slick-theme.scss'));
#import url(asset-path('owl-carousel/assets/owl.carousel.min.scss'));
#import url(asset-path('owl-carousel/assets/owl.theme.default.scss'));
#import url(asset-path('owl-carousel/assets/carousel.min.scss'));
#import url(asset-path('bxslider/jquery.bxslider.min.scss'));
#import url(asset-path('magicsuggest/magicsuggest-min.scss'));
these files are located under vendor/ directory.
Looking at the network tab in production mode, the server makes request to each an every of those imported files from the scss files instead of compiling them under on file.
I am also using sass rails gem. Is there anything I am not understanding about the rails assets pipeline?

The confusion comes from the fact that SASS overrides the #import directive in a way.
In your case the pure CSS' #import directive is used since your are passing url(.., which as you noticed makes HTTP request for every file.
In order to use the SASS' version of #import (which will import and combine the contents), you need to pass the files in quotes:
...
#import 'slick-carousel/slick/slick.scss';
...
Here's a detailed explanation about SASS' #import

Your master css file is done through app/assets/stylesheets/application.css file.
For example :
*= require navbars.css.scss
*= require footer.css.scss
*= require cookiewarning.css.scss
*= require_self
The above code will include in the application.css master file all of the mentionned css files, whether they are located in app/assets app/lib or app\vendor.
You master file is called in views/layouts/application.html.erb
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= yield(:headcss) %>
<%= stylesheet_link_tag params[:controller], media: 'all' %>
As you can see I have a separate file for the current controller. And also a yield tag for extra CSS I would like to add when needed.
Also one note about your files: SASS is a preprocessor of CSS. It is better to name your files whatever.css.scss than whatever.scss. I got some problems getting the SASS helpers work properly because of this: Sass rails seems to generate a different logical path than in manifest

Related

Importing CSS with webpacker in Rails 6

I use webpacker with Rails and am installing taildwindcss right now. Their installation guide says to use an #import method if I'm using postcss-import. I must say I get confused whenever I have to import CSS to Rails with webpacker, so I have a few questions:
1) The #import method from the docs - is it a JavaScript or CSS import method?
2) If it's a CSS method, why do I have to paste it inside javascript folder (e.g. javascript/stylesheets? I tried to put it inside the application.css file and it doesn't work. I assume it is somehow related to the fact that it's using PostCSS and package was installed via yarn?
3) If the above is true, does it mean that I have to import every CSS package that way if it's installed via yarn?
You will likely want to actually want to import into the CSS and javascript!
The typically setup will have app/javascript/styles/application.css for example which will bootstrap your global css:
#import "tailwindcss/base";
#import "tailwindcss/components";
#import "components/buttons"; // custom components that map to path app/javascript/styles/components/buttons.css for example
#import "tailwindcss/utilities";
In your app/javascript/packs/application.js you will import this:
// other js
import('styles/application.css');
// other js
In your layout you will add <%= stylesheet_pack_tag 'application' %> to add the css from application.js and <%= javascript_pack_tag 'application' %> to add the javascript from application.js.
The reason for this setup is that webpack is going to process application.js and it will handle the CSS and JS separately. Think of javascript/pack/application.js more of a bootstrap/dependencies file than a running javascript file. It's saying here's a list of stuff I need to work. In this case, one of the things is app/javascript/styles/xyz.css, and by the way, use post-css to manage how it is processed.

How do I organize SCSS in rails?

I just bootstrapped a new rails project and I was trying to reference from an open sourced rails project on how they architect their app.
Link to the open sourced project
I noticed they have multiple layouts e.g. admin, application, home ..etc. And each may load in different stylesheets via stylesheet_link_tag.
For example in focus_home.html.erb:
<!-- Load styles -->
<%= stylesheet_link_tag 'focus_home' %>
<%= stylesheet_link_tag 'app/components/modal' %>
And in their app/assets/stylesheets directory, they have focus_home.scss
I try to follow their architecture where I have multiple css files and I call different stylesheets with different layout.
I created my home.scss to be used by home.html.slim
when I started my rails server and try to load the home page, the following error occurs
Asset filtered out and will not be served: add
`Rails.application.config.assets.precompile += %w( home.css )` to
`config/initializers/assets.rb` and restart your server
Basically it asked me to tell rails to precompile home.scss. However, when I browse through the open source project's code base. It doesn't seem to have this line of code. The precompilation just seem to happen like magic.
So I am wondering what I am missing ?
==============
Edit: Further explain the case
In their project they DO NOT have an application.css file like normal rails project.
/* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. *
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any styles * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * *= require_tree . *= require_self */
Instead, in their application.scss, it goes like
#charset "utf-8";
#import "vars/base";
#import "constants";
// Libraries
#import 'bootstrap';
#import 'app/mixins/*';
#import 'basscss';
#import '_deprecated/basspluss';
#import '_deprecated/utility';
#import '_deprecated/nocss_vars';
#import '_deprecated/nocss';
#import '_deprecated/nocss_mq';
#import "app/main";
#import "base/*";
#import "utilities/*";
#import "app/components/*";
#import "components/*";
#import "app/slop";
#import 'libs/owl.carousel';
#import 'libs/owl.transitions';
#import 'libs/owl.theme';
#import 'c3/c3'
So I wonder how they actually do their precompilation??
You don't need to use Sprockets comments in your application.scss and must only use #import CSS rules.
From rails-sass documentation:
Sprockets provides some directives that are placed inside of comments
called require, require_tree, and require_self. DO NOT USE THEM IN
YOUR SASS/SCSS FILES. They are very primitive and do not work well
with Sass files. Instead, use Sass's native #import directive which
sass-rails has customized to integrate with the conventions of your
Rails projects.
Then, if you have any other .scss that needs to be precompiled, you will have to explicitly add them using the Rails.Application.config.assets.precompile directive, then the sprockets railtie will do the rest of the job!
To answer your original question, the reason why the open source project do not need to specify assets to precompile is because they are using config.assets.compile = true in the config/environment/production.rb file. This is obviously a very bad practice and I don't recommend you to switch this directive to true in a production environment... you will end up with a slow code making a lot of requests and there a slow page load.

How should I go about managing sass code when using bootstrap-sass?

The documentation says:
Import Bootstrap styles in app/assets/stylesheets/application.scss:
// "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables"
#import "bootstrap-sprockets";
#import "bootstrap";
bootstrap-sprockets must be imported before bootstrap for the icon fonts to work.
Make sure the file has .scss extension (or .sass for Sass syntax). If you have just generated a new Rails app, it may come with a .css file instead. If this file exists, it will be served instead of Sass, so rename it:
$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
Then, remove all the //= require and //= require_tree statements from the file. Instead, use #import to import Sass files.
Do not use //= require in Sass or your other stylesheets will not be able to access the Bootstrap mixins or variables.
But if I do as they say, my other stylesheets won't be included automatically, as they did before that. Should I include every stylesheet explicitly in layout? AFAIU, that would also make me have separate stylesheets in production environment, instead of one as it would have been without bootstrap-sass.
There are several things here. First, by default each stylesheet is served in separate http request in development, and in one request in production (they are precompiled into one file). If we follow the docs, we'll end up having one request in development as well, which would negate performance benefit of compiling only the file that has changed. If we don't, we might end up having bootstrap several times in our stylesheets. In case we need some variables or mixins in several stylesheets.
So I suggest having it this way:
application.sass (do note that I put require_self before require_tree .):
/*
*= require_self
*= require_tree .
*/
// import bootstrap once
#import "bootstrap-sprockets"
#import "bootstrap"
.d1
text-align: center
welcome.sass:
// in other files import only some particular partials
#import "bootstrap/variables"
#import "bootstrap/mixins"
.d2
text-align: right
But if I do as they say, my other stylesheets won't be included automatically, as they did before that.
Yes, you a right.
1) You shouldn't remove your require directives from application.scss. They don't want to use require directives because in this case you don't have ability to use SASS variables and mixins inside of included files.
2) Just rename application.css to application.scss. They want it because in this case you will have ability to use #import directives inside application.scss file. This is mean that you will have ability to use SASS variables and mixins inside of included files.
Should I include every stylesheet explicitly from layout?
No, just leave them in application.scss
AFAIU, that would also make me have separate stylesheets in production environment, instead of one as it would have been without bootstrap-sass.
No, you will use one application.scss in different environments.

How can I get Compass to automatically import all stylesheets in app/assets/stylesheets?

I'm trying to add Compass to my Rails 3.2 app, using compass-rails. How can I get it to automatically import all of the stylesheets in app/assets/stylesheets? At the moment I have to manually do #import 'filename'; in application.css.scss for each one.
Put all your scss files (except application.css.scss) in a different folder:
/application.css.scss
/all/hello.css.scss
/all/hi.css.scss
application.css.scss file like below will work.
#import "compass";
#import "all/*";
For bundling stylesheets, use the asset pipeline
If you're using the asset pipeline, this should happen automagically with:
/*
* In application.css
*= require_tree .
*/
Docs: http://guides.rubyonrails.org/asset_pipeline.html#manifest-files-and-directives
The important caveat is "Using Sprockets directives all Sass files exist within their own scope, making variables or mixins only available within the document they were defined in."
For mixins & vars, have your imports in one place, then import once
If you're heavy on the functions, try having a file like app/assets/stylesheets/base.css.scss that contains #import directives (wildcard or not) for all your mixin and var files. Then you only need to #import "base" once for every stylesheet and can still bundle your css using sprockets directives.

How can I configure SASS to compile specific stylesheets into a separate desktop and mobile version

I'm running Rails 3.1 along with Sass. I now need to segment my stylesheets into a mobile version as well as a desktop version. By default sass-rails is compressing every .scss file in my assets/stylesheets/ path into one application.css file.
I would like, instead, to explicitly tell Sass to compiled scss file X into mobile.css and files Y & Z into desktop.css
Is this accomplished via a config.sass value? I really appreciate the help on this one.
Normally you <%= stylesheet_link_tag :application %>
And application.scss looks like:
*= require_self
*= require_tree
Instead of sprocket's manifest for require files, use sass's includes. To still use application.scss, remove the line *= require_tree
So <%= stylesheet_link_tag :mobile %>
/app/assets/stylesheets/mobile.scss
#import "bootstrap/bootstrap.scss";
#import "typography.scss";
body {
padding-top: 60px;
}
And you'd do the same for desktop.scss. Note: you'll have to manually add each file you want to import.
Use response design instead of server side checks! More progressive/better approach. Plus, your http requests will thank you!
http://css-tricks.com/snippets/css/media-queries-for-standard-devices/
Or write a method that checks user agent (which I assume you already did) and conditionalize' the loading of your style

Resources