Command-line argument as var in Sass, for hardcoded CDN URL's on compile
Asked Answered
V

1

2

For local HTML/Sass/Css developement we use libsass (via Grunt) to compile our Sass files to Css. The Css background-image URL's are root relative.

Sass

$dir-img: /img;

.header {
    background-image: url(#{$dir-img}/header.jpg);
}

We'd like to change the URL to use a CDN when compiling for production server:

background-image: url(http://media.website.com/img/header.jpg);

Is there some solution to pass-in a command-line argument TO Sass so Sass can use a Sass @IF to switch the root-relative URL's to hard-coded CDN like URL's. Something like:

Command-line:

grunt sass:dist --cdnurl="http://media.website.com/img/"

Sass

Then Sass checks if the command-line argument was given:

@if using CDN {
    $dir-img: cdnurl;
@else {
    $dir-img: /img;
}

And then all IMG url's would use the CDN URL.

Veinstone answered 9/7, 2015 at 14:58 Comment(1)
Are you tied to using a command line argument like that? Assuming libsass has the same command line options as the Ruby version, you could get the behavior similar to what you're looking for, but it won't look like that.Metallurgy
V
3

I couldn't find anything on libass command-line options to pass said vars. to Sass.

But eventually came up with a working version of my own! Have Grunt write a Sass config partial.

Pretty simple actually if your already using Grunt and Sass. We'd already had NodeJS and Grunt-cli installed on our staging (test) -server.

Sass setup

In Sass we already used a (larger) Sass config file which holds a few vars like:

_config.scss

$dir-font: '/assets/assets/fonts';
$dir-htc: '/assets/htc';
$dir-img: '/assets/images';

This config file holds much more config settings but I've updated these vars. in this config file to:

@import "_sourcepaths";
$dir-font: '/assets/fonts' !default;
$dir-htc: '/assets/htc' !default;
$dir-img: '/assets/images' !default;

Note the @import partial of _sourcepaths.scss. This smaller partial file is generated by Grunt. The Sass !default; is used as fallback vars. or you might not even need these anymore (are overwritten by Grunt).

Grunt setup

On the Grunt side I added a custom task that is only executed on our staging (or test) -server (for example during a build process). On our local machine we keep using root-relative paths for local development.

Grunt custom target configuration

module.exports = function(grunt) {
    grunt.initConfig({
        writeSassConfig: {
            options: {
                scss: './assets/scss/partials/_sourcepaths.scss',
                dirFont: '/assets/fonts',
                dirHtc: '/assets/htc',
                dirImg: '/assets/images'
            },
            cdn: {
                //pathprefix: 'http://cdn.website.com'
                pathprefix: grunt.option('pathprefix') || ''
            }
        }
    }
});

Example cdn Grunt target with hardcoded (http://cdn.website.com) or dynamic (via grunt.option command-line argument) pathprefix. See below at 'Running the Grunt task' how to run this. It also has a fallback || '' to empty, which actually resets the paths in the Sass config file to root-relative URL's.

Grunt custom task

Then the required Grunt task (for configuration above). This Grunt task writes the Sass partial to disk.

grunt.registerMultiTask('writeSassConfig', 'Write Sass config file to change source paths', function(){
    grunt.config.requires(
        this.name + '.options.scss',
        this.name + '.options.dirFont',
        this.name + '.options.dirHtc',
        this.name + '.options.dirImg',
    );

    // Create Sass vars
    var _thisOptions = this.options(),
        pathprefix = this.data.pathprefix || '',
        contents = "// Generated by Grunt for dynamic paths like a CDN server\n";
        contents += "$dir-font: '" + pathprefix + _thisOptions.dirFont + "';\n";
        contents += "$dir-htc: '" + pathprefix + _thisOptions.dirHtc + "';\n";
        contents += "$dir-img: '" + pathprefix + _thisOptions.dirImg + "';\n";

    grunt.file.write(_thisOptions.scss, contents);
});

Grunt aliased task

This creates a custom chained workflow of two tasks running after each other. The sass:dist is a regular Grunt task and target via grunt-sass (libsass) plugin. You are probably already using this.

grunt.registerTask('build-sasscdn', 'Generate Sass config for different Sass paths like a CDN server path', function(){
    grunt.task.run(
        'writeSassConfig',
        'sass:dist'
    );          
});

Running the custom Grunt task

The pathprefix var., via grunt.option('pathprefix'), in above Grunt custom target is provided via grunt command-line argument:

grunt build-sasscdn --pathprefix="https://cdn.website.com"

This domainname can be changed by the staging (test) -server server-side-scripting language (like .NET/PHP/Ruby). The Sass config file _sourcepaths.scss is now changed by Grunt to:

_sourcepaths.scss

$dir-font: 'https://cdn.website.com/assets/fonts';
$dir-htc: 'https://cdn.website.com/assets/htc';
$dir-img: 'https://cdn.website.com/assets/images';

Remember that _sourcepaths.scss is imported by Sass. The Grunt alias task then runs the usual sass:dist target, which just re-compiles the Sass (on the staging / test server) WITH updated hard-coded CDN domain name paths in the Css.

Veinstone answered 14/7, 2015 at 12:7 Comment(1)
This worked beautifully. Thanks for sharing. My setup was a little bit more complex, because grunt is called from gradle. But it was really easy to combine your approach with gradle properties.Herbertherbicide

© 2022 - 2024 — McMap. All rights reserved.