how to get webpacker to load css if extract_css is false - ruby-on-rails

I have the following pack file:
// app/javascript/packs/styles.js
import 'bootstrap/dist/css/bootstrap'
Unless I set extract_css: true in config/webpack.yml I do not see how to get these styles to load.
If I set extract_css: true and include <%= stylesheet_pack_tag 'styles' %> in the layout everything seems to work.
But then what is the point of extract_css: false why would you ever NOT want this? Because its the default webpacker configuration I feel as if I am missing something important.

With extract_css: false, the styles are provided by the webpack js runtime as blob urls and injected into the document <head> inline (assuming you have a corresponding javascript_pack_tag).
One use case for this approach in development is to better support hot module reloading for CSS.

I'm not 100% sure, but I think if you extract the css, webpack will generate that standalone css file so you can link it. If you don't extract it, the CSS is bundled insde the js file and webpack will process it when the page loads and inserts the CSS in a style tag in the head tag of the document.
To extract the CSS from the js file it uses the mini-css-extract plugin.
https://webpack.js.org/guides/asset-management/#loading-css
In some cases you may want to keep the css on the bundle if you want to have all the js and css with only one request.

Related

When to use stylesheet_pack_tag instead stylesheet_link_tag with Rails 6

When creating a new rails project with Rails 6, it creates an application.html.erb with stylesheet_link_tag to load CSS and javascript_pack_tag for javascript files.
Now, rails 6 also provide a stylesheet_pack_tag, so my question is, when to use it? And if we use it, do we need to add all CSS files in app/javascript folder?
What is the best practice to load css, images with rails 6 and webpacker?
You should use stylesheet_pack_tag if you are importing any CSS in Webpack AND if you have enabled extract_css: true for any environment in config/webpacker.yml.
Given the following directory structure:
app/
javascript/
packs/
application.js
styles/
site.css
And the following code in application.js:
import '../styles/site.css'
You would use <%= stylesheet_pack_tag 'application' %> in your view, i.e., the name of the stylesheet matches the name of the "pack".
At this point, I also recommend renaming app/javascript to something like app/frontend. So, the key changes in config/webpacker.yml:
source_path: app/frontend
extract_css: true
app/
frontend/
packs/
application.js
styles/
site.css
Just to try to clarify this a little. This is based on my current understanding, which seems to work well enough but still might not be fully accurate.
CSS processed by the asset pipeline gets a css_link_tag and css that is imported via a Webpacker javascript bundle is referenced with css_pack_tag.
Asset pipeline css is in app/assets/stylesheets. Webpack css is in app/javascripts/wherever_you_want.
So in webpack, all of the css imported into a javascript bundle is eventually extracted to a servable file that can be referenced via the same name as the js bundle.
So if in app/javascripts/application.js you have:
import 'app/javascripts/css/one.css'
import 'app/javascripts/css/two.css'
import 'app/javascripts/css/three.css'
These will be referenced with
css_pack_tag 'application'
This comes out looking like this in my deploy logs
Entrypoints:
application (430 KiB)
css/application-9d82d487.css
js/application-9f45d7ff735a7a203f28.js
It also bears noting, as was mentioned above that this behavior is affected by the extract_css setting.
Presumably this is false in development by default and true in production. One big GOTCHA with this is that, at least in my case, the css_pack_tag wasn't actually "required" in development, in the sense that removing it had no effect because it wasn't extracted locally. It still "worked" because the css was loaded in the javascript and seemed to be applied somehow that way. So I removed these tags thinking they were unnecessary before my understanding improved. Unfortunately when I deployed to production on heroku some time later, none of my css was working and it took me a while to figure out why and remember that I had removed these css_pack_tag lines.

How to inline CSS in Rails Header with Webpacker assets

I would like to inline some CSS within my html. I have done this in the past with Sprockets putting something like that in my layouts/application.html.erb
<style>
<%= Rails.application.assets["application.css"].to_s.html_safe %>
</style>
Now I would like to do the same but with CSS assets bundled by Webpacker.
I am able to get the path of the file with Webpacker.manifest.lookup("application.css"), but I am missing the latest part to get the content and embed it into the layout
The rationale behind this:
To improve page speed I want to embed my critical CSS into the header of the HTML. Using Webpack and PostCss tools (PurgeCss). I am able to get a very compact very of my CSS for the above the fold of my home page.
The rest of the CSS is loading asynchronously with the usual packs helpers
Update 1
Here is the link to the article I wrote thanks to the answer.
https://dev.to/adrienpoly/critical-css-with-rails-and-webpacker-sprocketsless-part-1-2bck
Let's consider having a line in app/javascript/packs/application.js
import `../css/application.css'
and a file app/javascript/css/application.css with some useful content.
Then you spell
<style>
<%= File.read(File.join(Rails.root, 'public', Webpacker.manifest.lookup('application.css'))).html_safe %>
</style>
and it simply works.
Don't forget:
To set extract_css: true in config/webpacker.yml
Exec rake webpacker:compile after changing these .css and/or .js files. Or use webpack-dev-server for a things like Hot Module Replacement
Turn on (though this is default setting for development) config.public_file_server.enabled = true (as #Adrien mentioned in comments) for serving .js resources by puma

Dynamic (S)CSS in rails 3.1

I'm trying to allow the user to customize my application using YML files.
When the user updates certain things the CSS needs to be updated as well.
I'd like to solve this problem using dynamic CSS instead. The way I was planning on doing this is to have a settings SCSS file which the other css files import and use.
Here is what I have so far:
settings.scss.erb:
$width: <%= Rails.application.config.width %>px;
main.css.scss:
//= require settings
#import "settings";
#main {
width: $width;
}
But I get this error:
Invalid CSS after "$width: ": expected expression (e.g. 1px, bold), was "<%= Rails.appli..."`
So It seems that the settings are not being passed through the erb parser before being handed off to the SCSS parser, is there any way to solve this.
I'd rather not put everything in .erb files since my text editor doesn't support (syntax highlighting and commands) when having scss in erb files
Side stepping the problem where ERB is not being parsed, you are not going to be able to customize the CSS dynamically (I think the main file may require an erb extension). The asset pipeline is designed to serve assets in a way that tells browsers that the are static and are not going to change.
Assuming the erb parsing was working, the width would be rendered during the precompile phase, or on the first request. If you are using Sprockets far-future headers are set to tell the remote clients to cache the content for 1 year. And Sprockets only picks up changes if the timestamp of the file changes, so would never get any new values.
You could force Sprockets to dynamically serve every request, and to not send any headers, but it is not really designed for this and there are significant performance risks in doing so.

Javascript and CSS specific files, how to include them by convention ? Rails 3.1

How can I include specific JS or CSS files (by convention ?) with Ruby Rails 3.1 ?
I have a view :
views/project/index.html.erb
And I want to include a specific javascript file for this page. I put it in
assets/javascripts/project/index.js
Same for another view :
home/index.html
Thanks
In the application.css and application.js file, be sure to remove the line \\= require tree.
Then, manually list all the css/js files you want included in each manifest file, for example:
// application.js
//= global.js
//= everywhere.js
Then, I would setup a yield in your header or your closing body tag for your application layout file, for instance (in haml)
%head
%title Some Page
= stylesheet_link_tag 'application'
= yield :stylesheets
Then in your particular view, say _example_partial.html.haml, do this:
- content_for :stylesheets do
= stylesheet_link_tag 'example_partial'
-# the rest of your view goes here
You do the exact same thing with Javascript files, just using javascript_include_tag instead of stylesheet_link_tag.
This will let you quickly and easily assemble view-specific javascript / css payloads. There may be a more sophisticated way to handle this using the asset pipeline, but I would suggest that if the asset pipeline is already minifying and merging you major stylesheets that this kind of +1 css / js file per view is not going to cause a major performance hit. Just try to make sure you don't overdo it with dozens of separate files loading into a single view.

How do I use CSS with a ruby on rails application?

How do I use CSS with RoR? When I link externally, I'm never able to see the files. I cp'd the .css file to every folder I could think of...views, controller, template, and nothing seems to work.
What do I need to do to enable external CSS files with a rails application? I'm new to rails, so forgive me if this is basic.
Put the CSS files in public/stylesheets and then use:
<%= stylesheet_link_tag "filename" %>
to link to the stylesheet in your layouts or erb files in your views.
Similarly you put images in public/images and javascript files in public/javascripts.
If you are using rails > 3 version, then there is a concept called asset pipeline. You could add your CSS to
app/assets/stylesheets
then it will automatically be picked up by the app. (this is useful as rails will automatically compress the CSS files)
read more here about the asset pipeline
Use the rails style sheet tag to link your main.css like this
<%= stylesheet_link_tag "main" %>
Go to
config/initializers/assets.rb
Once inside the assets.rb add the following code snippet just below the Rails.application.config.assets.version = '1.0'
Rails.application.config.assets.version = '1.0'
Rails.application.config.assets.precompile += %w( main.css )
Restart your server.
I did the following...
place your css file in the app/assets/stylesheets folder.
Add the stylesheet link <%= stylesheet_link_tag "filename" %> in your default layouts file (most likely application.html.erb)
I recommend this over using your public folder. You can also reference the stylesheet inline, such as in your index page.
The original post might have been true back in 2009, but now it is actually incorrect now, and no linking is even required for the stylesheet as I see mentioned in some of the other responses. Rails will now do this for you by default.
Place any new sheet .css (or other) in app/assets/stylesheets
Test your server with rails-root/scripts/rails server and you'll see the link is added by rails itself.
You can test this with a path in your browser like testserverpath:3000/assets/filename_to_test.css?body=1
To add to the above, the most obvious place to add stylesheet_link_tag is in your global application layout - application.html.erb.
With Rails 6.0.0, create your "stylesheet.css" stylesheet at app/assets/stylesheets.
Have you tried putting it in your public folder? Whenever I have images or the like that I need to reference externally, I put it all there.

Resources