Skip to main content
Last updated: 22 Jul 2024

Migrate to Dart Sass from LibSass

What is Dart Sass?

Dart Sass is the primary implementation of Sass, which means it gets new features before any other implementation.

Why migrate from LibSass?

LibSass is now deprecated.

Prerequisites

Applications which use GOV.UK Publishing Components should bundle version 37.1.1 or above.

Installation

  1. Update your Gemfile to replace sassc-rails with dartsass-rails and run bundle install (or with Docker: govuk-docker-run bundle install)
+ gem "dartsass-rails"
- gem "sassc-rails"

Note, some dependencies of sassc-rails might be needed in your application. For example, tilt or sprockets-rails in which case you should manually add these dependencies to your Gemfile.

Configuration

Create a builds folder

Create a builds folder: app/assets/builds and add a file named .keep in the corresponding folder.

Ignoring files

Update .gitignore to ignore all files in the builds folder , but not .keep.

+ /app/assets/builds/*
+ !/app/assets/builds/.keep

Update the manifest file

Delete references to your application CSS files from the Sprockets manifest file: app/assets/config/manifest.js.

- //= link application.css
- //= link components/_component-1.css
- //= link components/_component-2.css
- //= link components/_component-3.css
- //= link components/_component-4.css
- //= link views/_view-1.css
- //= link views/_view-2.css
- //= link views/_view-3.css
- //= link views/_view-4.css
  ...

Note, do not delete references to vendor CSS files (stylesheets placed in the vendor/assets folder) to ensure they are processed by Sprockets.

Add a link_tree directive to link all files in all subdirectories of the builds folder.

+ //= link_tree ../builds

Add an initializer

If your stylesheets are not individually loaded, or if your application serves only one stylesheet, there’s no need to add a builds initializer since by default, app/assets/stylesheets/application.scss will be compiled.

Otherwise, create an initializer: config/initializers/dartsass.rb. This file will include all Sass entry points and build options.

Rails.application.config.dartsass.builds = {
  "application.scss" => "application.css",
  "components/_component-1.scss" => "components/_component-1.css",
  "components/_component-2.scss" => "components/_component-2.css",
  "views/_view-1.scss" => "views/_view-1.css",
  "views/_view-2.scss" => "views/_view-2.css",
}

The hash key is the relative path to a Sass file in app/assets/stylesheets/ and the hash value will be the name of the file output to app/assets/builds/.

Note, if your application uses GOV.UK Publishing Components, and the stylesheets are individually loaded, you will need to merge all entry points, including those from your application and those from GOV.UK Publishing Components.

APP_STYLESHEETS = {
  "application.scss" => "application.css",
  "components/_component-1.scss" => "components/_component-1.css",
  "components/_component-2.scss" => "components/_component-2.css",
  "views/_view-1.scss" => "views/_view-1.css",
  "views/_view-2.scss" => "views/_view-2.css",
}.freeze

all_stylesheets = APP_STYLESHEETS.merge(GovukPublishingComponents::Config.all_stylesheets)
Rails.application.config.dartsass.builds = all_stylesheets

Also, the initializer should configure build options, incorporating the --quiet-deps option which tells Sass to suppress dependency deprecation warnings.

Rails.application.config.dartsass.build_options << " --quiet-deps"

Delete unused Sass configuration

Delete Sass configuration previously added for sassc-rails. Update config/environments/production.rb to delete

- config.sass.style = :compressed
- config.sass.line_comments = false
  ...

Builds

dartsass:build is linked to assets:precompile. When assets:precompile is run, it triggers the compilation of Sass files, which are generated in the /app/assets/builds directory. They are then processed by Sprockets.

Configuring build options

See configuring build options and Dart Sass Command-Line Interface

Watch mode

When you’re developing your application, you can run Sass in watch mode, so stylesheets are continuously updated when Sass files are changed.

  1. Add bin/dev
#!/usr/bin/env sh
if ! gem list foreman -i --silent; then
  echo "Installing foreman..."
  gem install foreman
fi
exec foreman start -f Procfile.dev "$@"
  1. Add (or update) procfile.dev
web: bin/rails server -p 3070
css: bin/rails dartsass:watch

Note, the port number should match the one previously specified, in startup.sh and or docker-compose.yml, for running your Rails server.

  1. Update startup.sh
if [[ $1 == "--live" ]] ; then
  GOVUK_APP_DOMAIN=www.gov.uk \
  GOVUK_WEBSITE_ROOT=https://www.gov.uk \
  GOVUK_PROXY_STATIC_ENABLED=true \
  PLEK_SERVICE_CONTENT_STORE_URI=${PLEK_SERVICE_CONTENT_STORE_URI-https://www.gov.uk/api} \
  PLEK_SERVICE_STATIC_URI=${PLEK_SERVICE_STATIC_URI-https://assets.publishing.service.gov.uk} \
  PLEK_SERVICE_SEARCH_API_URI=${PLEK_SERVICE_SEARCH_API_URI-https://www.gov.uk/api} \
- bundle exec rails s -p 3070
+ ./bin/dev
else
  ...
  1. In Docker, update docker-compose.yml
  expose:
-  - "3000"
- command: bin/rails s --restart
+  - "3070"
+ command: ./bin/dev
  ...

Note, you might see a ‘permission denied’ error when executing startup.sh. If this occurs, you’ll need to modify the permissions for bin/dev. Navigate to the directory where the bin/dev script is located. Once you’ve identified the script, use the chmod command to modify its permissions. For instance, to grant execute permission for the owner, you can use chmod u+x bin/dev.

Digests

To see the latest stylesheet changes when developing your application, if running Sass in watch mode, you’ll have to turn off digests. Update config/environments/development.rb to add

config.assets.digest = false

See 3.2 Turning Digests Off - The Asset Pipeline — Ruby on Rails Guides.

Troubleshooting

If you see LoadError: cannot load such file -- sassc (e.g. when attempting to run tests), try running:

govuk-docker-run rails assets:precompile

If that doesn’t work, read the rails/dartsass-rails troubleshooting guide.

Other issues

Globs

Any form of pattern matching added for importing Sass files will not work. Sass files needs to be imported individually.

- @import "modules/*";
+ @import "modules/module-1";
+ @import "modules/module-2";
+ @import "modules/module-3";
+ @import "modules/module-4";
  ...

Asset helpers

Asset helpers no longer work in dartsass-rails. Replace occurrences of the image-url and asset-url helpers with the url() CSS function. See asset_url helpers don’t work - issue #18 - rails/dartsass-rails.

.my-image {
- background-image: image-url("path/to/my/image.svg");
+ background-image: url("path/to/my/image.svg");
  background-color: transparent;
  ...
}

Asset paths

If you are using GOV.UK Frontend in your application you might need to add asset handlers to ensure fonts and images are correctly referenced. See if you have your own folder structure.

@function app-image-url($filename) {
  @return url("#{$filename}");
}

$govuk-image-url-function: "app-image-url";

Pull requests