How to get Rails 6 working with PureCSS and WebPacker

554 views Asked by At

I am trying to upgrade a Rails 5 app that used PureCSS for stylesheets to Rails 6 with Webpacker and nothing I do can make this work other than a brute force approach.

I have these lines in application.html.erb

  <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

I have had to download all of the PureCSS and place the files in app/assets/stylesheets

I have then had to list each file as an import in application.js as shown

    import "../../assets/stylesheets/base.css"
    import "../../assets/stylesheets/buttons.css"
    import "../../assets/stylesheets/buttons-core.css"
    import "../../assets/stylesheets/forms.css"
    import "../../assets/stylesheets/forms-r.css"`
    import "../../assets/stylesheets/menus-core.css"
    import "../../assets/stylesheets/menus-dropdown.css"
    import "../../assets/stylesheets/menus-horizontal.css"
    import "../../assets/stylesheets/menus-scrollable.css"
    import "../../assets/stylesheets/menus-skin.css"
    import "../../assets/stylesheets/tables.css"

I tried to tidy this up by moving the imports into app/assets/stylesheets/application.css

...
 *= require_tree .
 *= require_self
 */

@import "base.css";
@import "buttons.css";
@import "buttons-core.css";
...

but this doesnt work whether I try to require or import application.css into application.js as either

import "../../assets/stylesheets/application.css"

or

require("../../assets/stylesheets/application.css")

Really I would have liked the purecss-sass gem to just carry on working and I dont really understand why it doesnt?

Surely there has to be a better way?

1

There are 1 answers

1
max On BEST ANSWER

There is a lot to unpack here so please bear with me.

Surely there has to be a better way?

Not really. In Webpack you can use webpack-import-glob-loader to load all the files in a directory with a glob pattern. In Sprockets the require_tree directive pulls an entire directory. The old sass-rails gem for the depreciated Ruby SASS compiler can take globs for @import (but its use was always discouraged).

However the problem with all these approaches is that they give you no control over the load order. Since CSS is a language where rules have priority in the order the are declared this is a recipe for disaster.

If you don't want to make your application.js insanely long then split it up into a separate pure_css.js file and import the sub-files from there. You really want to get purecss from Yarn instead of relying on a "sprockets asset gem".

Webpack vs Sprockets

Assets in Rails 6 are very confusing as the community has not really found a set of best practices and the docs have not caught up.

According to David Heinemeier Hansson (DHH) Webpack and Sprockets are intended to coexist with Webpack used for JavaScript and Sprockets delivering images, CSS and JavaScript "sprinkles" (whatever that is).

While Webpack can actually do images and css its awkward (according to DHH). Others are not as sold on the idea of two different toolchains to do largely the same thing. Especially since Sprockets really always has relied on the community to create gem that wrap front end packages and really who wants to do that when we all know the future is NPM/Yarn?

See Why does Rails 6 include both Webpacker and Sprockets?

Sprockets directives

/*
*= require_tree .
*= require_self
*/

Will only actually work if the file is processed by Sprockets. require_tree . will require all the files in the current directory and its subfiles.

However since you are importing the file through Webpack its not being pulled through Sprockets and that comment is just a plain old comment that does absolutely nothing.

If you want to use Sprockets instead of Webpack for css you need the sprockets-rails gem and you want to use:

<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

Using Sprockets should allow you to continue using the purecss-sass gem if its gemspec is compatible with Rails 6. However this approach might not be very future proof.

CSS @import

In CSS the @import at-rule can be used to link style sheets together. You need to use @import with a URL and the stylesheet is loaded in the client through a separate HTTP request - which means that its use should be generally avoided for performance reasons.

@import "base.css"; won't actually work as the browser will attempt to load http://example.com/base.css.

SASS @import

@import "base.css"; looks like you copy pasted SASS.

In SASS @import tells the SASS compiler to pull the rules, variables, mixins and functions defined in the other file into the current file. Unlike the CSS equivalent this is done server side and will not cause additional HTTP requests. @import has always been quite problematic and is replaced by @use in Dart SASS.

If you want to use SASS and avoid the deprechiated libsass and Ruby compilers you want to use Webpack instead of Sprockets.