sass-thematic

2.0.4 • Public • Published

SassThematic

A parser for generating dynamic theme stylesheets from Sass.

The Problem:

We're building a site that gets themed with customizable colors, fonts, sizes, etc. So, we set up a base stylesheet for the site, and then maintain a separate theme stylesheet for custom style overrides.

This works, but makes updates difficult. All changes in the base stylesheet must be mirrored in the theme-specific overrides. Keeping these stylesheets synchronized is tedious and error-prone. It would be great if we could just automate the generation of these theme overrides from the base source... or, just generate a CSS template to be rendered by our application with theme variables at runtime.

This is SassThematic.

Workflows

SassThematic accomodates two unique workflows for generating CSS themes – each takes a different approach to the problem. A process overview for each workflow is available on the wiki:

Install

Install the NPM package:

npm install sass-thematic --save-dev

Upgrading to v2.x

The v2.x API has changed significantly to better support selecting a workflow. Breaking changes:

  • Smaller API, tailored via options. Tree pruning no longer happens by default.
  • Webpack integration removed. Webpack plugins should independently wrap this module.

API

SassThematic provides the following API. All methods take similar options, which are fully outlined below.

parseAST

  • thematic.parseAST( options, callback )
  • thematic.parseASTSync( options )

Parses and returns a raw abstract syntax tree of your deeply-nested Sass source. The returned object is a gonzales-pe node tree with all @import statements replaced by the imported stylesheet nodes. Use this complete source tree to make your own modifications.

var thematic = require('sass-thematic');
 
// Async
thematic.parseAST({
  file: './styles/main.scss',
  includePaths: ['./lib/']
}, function(err, ast) {
   console.log(ast);
});
 
// Sync
var ast = thematic.parseASTSync({ ...options... });

parseSass

  • thematic.parseSass( options, callback )
  • thematic.parseSassSync( options )

Parses and returns a raw Sass string of your deeply-nested Sass source with optional transformations applied. This raw Sass may be run through the Sass compiler. Options:

  • varsFile or varsData: required to identify relevant theme variables.
  • treeRemoval: optionally removes Sass rules that do not implement theme variables.
  • varsRemoval: optionally removes theme variable imports.
  • template: optionally transforms theme variables into template identifiers.
var thematic = require('sass-thematic');
 
// Async
thematic.parseSass({
  file: './styles/main.scss',
  varsFile: './styles/_theme.scss',
  includePaths: ['./lib/'],
  treeRemoval: true,
  varsRemoval: true,
  template: true
}, function(err, sassString) {
   console.log(sassString);
});
 
// Sync
var sassString = thematic.parseSassSync({ ...options... });

renderCSS

  • thematic.renderCSS( options, callback )
  • thematic.renderCSSSync( options )

Renders a CSS string from your Sass source. Sass is parsed with optional transformations applied, then custom theme variables are prepended, and lastly this custom themed Sass is run through the Sass compiler. Options:

  • varsFile or varsData: required to identify relevant theme variables.
  • themeFile or themeData: required to provide variables for the themed CSS rendering.
  • treeRemoval: optionally removes Sass rules that do not implement theme variables.
  • varsRemoval: optionally removes theme variable imports.
  • sassOptions: options object passed to the Node-Sass compiler.
var thematic = require('sass-thematic');
 
// Async
thematic.renderCSS({
  file: './styles/main.scss',
  varsFile: './styles/_theme.scss',
  themeData: '$color1: red; $color2: green;',
  includePaths: ['./lib/']
}, function(err, cssString) {
   console.log(cssString);
});
 
// Sync
var cssString = thematic.renderCSSSync({ ...options... });

renderTemplate

  • thematic.renderTemplate( options, callback )
  • thematic.renderTemplateSync( options )

Renders a CSS template string from your Sass source. Sass is parsed with theme variables preserved as identifiers (and other optional transformations applied), then CSS is compiled from the transformed source, and lastly field identifiers are filled back in with template interpolation fields. Options:

  • varsFile or varsData: required to identify relevant theme variables.
  • treeRemoval: optionally removes Sass rules that do not implement theme variables.
  • varsRemoval: optionally removes theme variable imports.
  • templateOpen: token used to open template interpolation fields (ie: <%=).
  • templateClose: token used to close template interpolation fields (ie: %>).
  • templateSnakeCase: formats all variable names as snake_case (lowercase with underscores).
  • sassOptions: options object passed to the Node-Sass compiler.

Note: theme variable names must pass through the Sass compiler as literal string identifiers, therefore restrictions apply on how theme variables may be used in pre-rendered Sass contexts.

var thematic = require('sass-thematic');
 
// Async
thematic.renderTemplate({
  file: './styles/main.scss',
  varsFile: './styles/_theme.scss',
  includePaths: ['./lib/'],
  templateOpen: '<%=',
  templateClose: '%>'
}, function(err, templateString) {
   console.log(templateString);
});
 
// Sync
var templateString = thematic.renderTemplateSync({ ...options... });

Parser API

The primary API above is designed to accomodate common use-cases. However, custom build tools may want to take advantage of the underlying parser API, documented on the wiki.

Full API Options

Required for all methods, one or both:

  • file: String. Path to the main Sass file to load and parse. This may be an absolute path, or else a relative path from cwd.

  • data: String. A raw Sass string to parse. You may still provide a file option as filepath context for mapping imports.

Required for Sass parsing methods, one of:

  • varsFile: String. Path to a file containing all theme variables. This may be an absolute path, or else a relative path from cwd. This file must contain all theme variable definitions, and nothing else. Variables may be formatted as Sass or JSON.

  • varsData: String. Data containing variable definitions for all theme variables. Should be formatted as Sass ($color1: red; $color2: black;) or JSON ({"color1": "red", "color2": "black"}).

Required for CSS rendering methods, one of:

  • themeFile: String. Path to a file containing all theme variables to render CSS with. This may be an absolute path, or else a relative path from cwd.

  • themeData: String. Data containing Sass variable definitions for all theme variables rendered into CSS. Should be formatted as Sass ($color1: red; $color2: black;) or JSON ({"color1": "red", "color2": "black"}).

Optional options:

  • includePaths: Array. List of base paths to search while performing file lookups. These should be absolute directory paths, or else relative to cwd. This operates just like the node-sass option of the same name.

  • cwd: String. Path of the directory to resolve file, varsFile, themeFile, and includePaths references from. Uses process.cwd() by default.

  • treeRemoval: Boolean. Enables the removal of tree nodes that do not implement theme variables.

  • varsRemoval: Boolean. Enables the removal of theme variable imports. Be sure to use the Sass !default flag when leaving theme variable imports in the source tree.

  • templateOpen: String. The opening token for template interpolation fields. Uses ERB-style <%= by default.

  • templateClose: String. The closing token for template interpolation fields. Uses ERB-style %> by default.

  • templateSnakeCase: Boolean. Enables the transformation of template variable names into snake_case (lowercase with underscores).

  • fieldOpen: String. The opening token wrapping field literals that get sent through the Sass compiler. Uses ____ (four underscores) by default.

  • fieldClose: String. The closing token wrapping field literals that get sent through the Sass compiler. Uses ____ (four underscores) by default.

  • sassOptions: Object. For rendering methods, this options object is passed through to the Sass compiler. See node-sass docs for possible values.

Webpack Builders

As of v2.x, Webpack integration has been broken out into wrapper modules. Build objectives vary, therefore SassThematic remains unopinionated about how it hooks into a build pipeline. The following Webpack wrappers exist:

  • sass-theme-template-loader: compiles CSS templates with theme variables as interpolation fields.
  • sass-thematic-override-plugin: a live-compiler for theme overrides included in SassThematic v1.3. No longer supported, but available if anyone wants to spin it into a community project.

Gulp Pipe

It's pretty simple to setup a Gulp pipe that hooks multiple Sass entry point files into SassThematic. Use the following as a basic template:

var gulp = require('gulp');
var vinyl = require('vinyl');
var through2 = require('through2');
var thematic = require('sass-thematic');
 
// SassThematic Gulp pipe:
function sassTheme(opts) {
  var output = '';
  return through2.obj(function(file, enc, done) {
      opts.file = file.path;
      opts.data = file.contents.toString('utf-8');
 
      thematic.parseSass(opts, function(err, result) {
        output += result;
        done();
      });
    },
    function(done) {
      this.push(new vinyl({
        path: 'theme.scss',
        contents: new Buffer(output)
      }));
      done();
    });
}
 
// Then use it...
gulp.task('theme', function() {
  return gulp.src('components/**/index.scss')
    .pipe(sassTheme({ ... opts ...}))
    .pipe(gulp.dest('/path/to/output/dir'));
});

Credit

This toolkit would be impossible without the hard work of @tonyganch on the gonzales-pe lexer, which provides the framework for intelligently dismantling Sass. Serious kudos.

Brought to you by Vox Media.

Dependencies (1)

Dev Dependencies (1)

Package Sidebar

Install

npm i sass-thematic

Weekly Downloads

67

Version

2.0.4

License

MIT

Last publish

Collaborators

  • gmacwilliam