Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Using SCSS in a Django project

Hi, is there an official or most recommended way to compile SCSS in a Django project?

I was surprised it didn't ship with one out of the box, considering it's a batteries-included framework, and thought I was missing something.

On github I found django-libsass (last updated 2 years ago) and django-static-precompiler (7 months ago), both with a surprisingly low number or stars, which made me wary.

What do you guys use?

1 Answer

Hi Fernando,

As Django is a backend web framework, and SCSS is a front-end style sheet language they are not very connected. This is why it doesn't work "out of the box". In order to compile SCSS you need a task runner. The two most popular task runners are Gulp and Grunt. I personally prefer Gulp.

Here is a course on TreeHouse: https://teamtreehouse.com/library/gulp-basics

Yeah, eventually I settled with Gulp as well. Here is my script, by the way, in case it helps anyone who faces the sames issues:

'use-strict';

const gulp = require('gulp');
const concat = require('gulp-concat');
const uglify = require('gulp-terser');
const rename = require('gulp-rename');
const sass = require('gulp-sass');
const maps = require('gulp-sourcemaps');
const del = require('del');
const gzip = require('gulp-gzip');
const util = require('gulp-util');
const exec = require('child_process').exec;

const Paths = {
    THIS: './',
    APP_DIST: 'build/APP_NAME/',
    APP_JS: 'assets/js/',
    APP_SCSS: 'assets/scss/',
};

const app_js_files = [
    Paths.APP_JS + MY_JS_FILES,
    // Page-specific JS
    'APP_NAME/static/APP_NAME/js/*.js'
]

var config = {
    production: !!util.env.production
};

const gzip_options = {
    threshold: '1kb',
    gzipOptions: {
        level: 9
    }
};

/*--------------------*/
/* Clean build folder */
/*--------------------*/
// All but admin folder
gulp.task('clean', function () {
    return del('build/**/*');
});

/*--------------*/
/* Compile Scss */
/*--------------*/
// One App
gulp.task('compileAppScss', function () {
    return gulp.src(Paths.APP_SCSS + "main.scss")
        .pipe(config.production ? util.noop() : maps.init())
        .pipe(sass())
        .pipe(config.production ? util.noop() : maps.write(Paths.THIS))
        .pipe(gulp.dest(Paths.APP_DIST + '/css'))
        .pipe(config.production ? gzip(gzip_options) : util.noop())
        .pipe(config.production ? gulp.dest(Paths.APP_DIST + '/css') : util.noop());
});
// Other App
gulp.task('compilePagesScss', function () {
    .....
});
// Project
gulp.task('compileScss',
    gulp.parallel('compileAppScss', 'compilePagesScss')
);

/*----------------*/
/* Concatenate JS */
/*----------------*/
// App
gulp.task('concatAppJs', function () {
    return gulp.src(app_js_files)
        .pipe(config.production ? util.noop() : maps.init())
        .pipe(concat('main.js'))
        .pipe(config.production ? util.noop() : maps.write(Paths.THIS))
        .pipe(gulp.dest(Paths.APP_DIST + 'js'));
});
// Other App
gulp.task('concatPagesJs', function () {
     ....
});
// Project
gulp.task('concatJs',
    gulp.parallel('concatAppJs', 'concatPagesJs')
);


/*----------*/
/* Minify JS*/
/*----------*/
// App
gulp.task('minifyAppJs', gulp.series(
    'concatAppJs',
    function () {
        return gulp.src(Paths.APP_DIST + 'js/main.js')
            .pipe(uglify())
            .pipe(rename('main.min.js'))
            .pipe(gulp.dest(Paths.APP_DIST + 'js'))
            .pipe(config.production ? gzip(gzip_options) : util.noop())
            .pipe(config.production ? gulp.dest(Paths.APP_DIST + 'js') : util.noop());
    }
));
// Other app
gulp.task('minifyPagesJs', gulp.series(
    'concatPagesJs',
    ...
    }
));
// Project
gulp.task('minifyJs',
    gulp.parallel('minifyAppJs', 'minifyPagesJs')
);


/*-------------------------*/
/* Watch Files For Changes */
/*-------------------------*/
gulp.task('watchFiles', function () {
    gulp.watch(
        [Paths.APP_JS + '**/*.js', 'app/static/**/*.js'],
        gulp.series('concatAppJs'));
    gulp.watch(
        Paths.OTHER_APP_JS + '**/*.js',
        gulp.series('concatPagesJs'));
    gulp.watch(
        [Paths.APP_SCSS + '**/*.scss', 'app/static/**/*.scss'],
        gulp.series('compileAppScss'));
    gulp.watch(
        Paths.OTHER_APP_SCSS + '**/*.scss',
        gulp.series('compilePagesScss'));
});

/*---------------*/
/* Build project */
/*---------------*/
gulp.task(
    'build',
    gulp.series(
        'clean',
        gulp.parallel(
            'compileScss',
            config.production ? 'minifyJs' : 'concatJs'
        )
    )
);

/*------------------*/
/* Run local server */
/*------------------*/
gulp.task('runserver', function () {
    var proc = exec('python manage.py runserver')
    console.log('Starting development server at http://127.0.0.1:8000/');
    console.log('Quit the server with CTRL-C.');
})

/* DEFAULT TASK */
gulp.task('default', gulp.series(
    'build', gulp.parallel('watchFiles', 'runserver')
));

But before I settled with Gulp, I wasted about 3 weeks going in circles. First I used django-pipelines, which never fully worked. Then I used django-compressor. This fared much, much better, but I hit a point in development I could really use a source map to debug the scss and I couldn't make it work with django-compressor.

The only downside of Gulp is the node_modules overhead. 20Mb of codes and dependencies is madness!

Even if it's a backend web framework, it makes no sense for a framework that claims to be 'batteries-included' not to include such a vital aspect of web development. It's an ugly problem to have and to be forced to rely on Node.js, specially when you consider Rails has introduced a very elegant solution with asset pipeline 7 years ago.

Kyle Hartigan , that course could really use an update! Gulp 4 is very different from Gulp 3 and it fills your code with gulp.series and gulp-parallel tasks!