[Solved]-Django Pipeline, Heroku, and SASS

9👍

OK, here’s how I got this working using Compass to compile my SASS files.

  • Use multiple Heroku buildpacks – Heroku Buildpack Multi
  • Put the following in your .buildpacks file

    https://github.com/heroku/heroku-buildpack-ruby.git
    https://github.com/heroku/heroku-buildpack-nodejs
    https://github.com/heroku/heroku-buildpack-python.git
    
  • Create a Gemfile with compass and any other requirements you have. Here’s mine:

    source 'https://rubygems.org'
    
    ruby '1.9.3'
    
    gem 'bootstrap-sass'
    gem 'compass'
    
  • Create a config.rb file. Here’s mine. As you can see it, requires the bootstrap-sass that I included in my Gemfile:

    # Require any additional compass plugins here.
    require 'bootstrap-sass'
    
    # Set this to the root of your project when deployed:
    http_path = "/"
    css_dir = "app_folder/static/css"
    sass_dir = "app_folder/static/sass"
    images_dir = "app_folder/static/images"
    
    output_style = :compact
    

    more details on config.rb can be found here

  • Install node packages (django-pipeline wants yuglify). You’ll need a package.json file:

    {
      "dependencies": {
        "yuglify": "0.1.4"
      },
      "engines": {
        "node": "0.10.x",
        "npm": "1.3.x"
      },
      "repository": {
        "type": "git",
        "url": "your repo url"
      }
    }
    
  • almost ready…
  • when Heroku runs the ruby buildpack, it will look for a rake task called assets:precompile. So now you’ll need to add a Rakefile with the following:

    namespace 'assets' do
      desc 'Updates the stylesheets generated by Sass/Compass'
      task :precompile do
        print %x(compass compile --time)
      end
    end
    

    this will put compile your stylesheets. You need to make sure you set the output (back in config.rb) to the place that django-pipeline is looking for CSS files (shown in the original question).

  • You should get rid of this part in the original question as django-pipeline isn’t compiling your SASS for you:

    PIPELINE_COMPILERS = (
      'pipeline.compilers.sass.SASSCompiler',
    )
    
  • That should be it! Deploys should just work now, and it didn’t really add a significant amount of time to my deploy process.

All in all, it amounts to a lot of setup, but for me it was well worth it as I no longer have to commit compiled files into the repository, which was causing a lot of merge conflicts when working with branches and pull requests.

I would like to figure out how to do this using only two buildpacks (obviously only one would be ideal but I don’t know if it’s possible). The problem is trying to find binary paths so that pipeline can do it’s thing when it doesn’t find the defaults. I’m not sure if the reason I can’t do this is because of how Heroku is installing things, or because there is a bug in django-pipeline, but right now this is good enough for me.

If you try this and it doesn’t work for you, let me know, if I missed something I’m happy to make updates.

6👍

I don’t want to take away from your excellent solution, but I tried this today and found a few differences that made things simpler for me – likely due to updates in django-pipeline and/or Heroku. My full solution is below, in case anyone else comes looking.

Add the 3 buildpacks to Heroku:

heroku buildpacks:set https://github.com/heroku/heroku-buildpack-ruby.git
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-nodejs
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-python.git

Add django-pipeline and django-pipeline-compass to requirements.txt:

django-pipeline==1.5.2
django-pipeline-compass==0.1.5

Create a Gemfile to install Sass:

source 'https://rubygems.org'
ruby '2.1.5'
gem 'bootstrap-sass'

Create a package.json file to install Yuglify:

{
  "dependencies": {
    "yuglify": "0.1.4"
  },
  "engines": {
    "node": "0.10.x",
    "npm": "1.4.x"
  }
}

I did not need a Rakefile or config.rb.

For reference, here are relevant settings from my settings.py:

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, '_generated_media')
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'pipeline.finders.PipelineFinder',
)

PIPELINE_COMPILERS = (
    'pipeline_compass.compiler.CompassCompiler',
)

PIPELINE_YUGLIFY_BINARY = os.path.join(BASE_DIR, 'node_modules', '.bin', 'yuglify')

And I also had to add this entry to urls.py:

url(r'^static/(?P<path>.*)$', serve, kwargs={'document_root': settings.STATIC_ROOT})

Hope it helps someone!

👤Andrew

0👍

You may need to set PIPELINE_SASS_BINARY so that django-pipeline can find your SASS compiler.

👤Chris

0👍

You can use the libsass compiler for django-pipeline that uses Sass packaged as a Python package:

pip install libsasscompiler

Update your config:

PIPELINE['COMPILERS'] = (
  'libsasscompiler.LibSassCompiler',
)

The default Yuglify compressor is also a problem on Heroku, which you can temporarily overcome by disabling it. This is my config for enabling Sass on Django for example:

PIPELINE = {
    'COMPILERS': (
        'libsasscompiler.LibSassCompiler',
    ),
    'STYLESHEETS': {
        'main': {
            'source_filenames': (
              'styles/main.scss',
            ),
            'output_filename': 'css/main.css'
        },
    },
    # disable the default Yuglify compressor not available on Heroku
    'CSS_COMPRESSOR': 'pipeline.compressors.NoopCompressor',
    'JS_COMPRESSOR': 'pipeline.compressors.NoopCompressor'
}

The longer-term solution would be to move towards a JS-only build toolchain (as most projects are doing). Rails integrates pretty nicely with Webpack for example and is maintained by the same team. Until that happens in Django (if ever) and trickles into the Heroku Python builpack, you can use Heroku’s multiple buildpacks and add an official Node buildpack step that runs npm install; npm run build for you.

Leave a comment