• Stars
    star
    118
  • Rank 299,923 (Top 6 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 9 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A parser for generating dynamic theme stylesheets from Sass.

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.

More Repositories

1

backbone.epoxy

Declarative data binding and computed models for Backbone
JavaScript
614
star
2

schema-stitching-handbook

Guided examples exploring GraphQL Tools v6+ Schema Stitching
JavaScript
349
star
3

technical-interview

Resources for Technical Interview prep session
HTML
91
star
4

gemoji-parser

The missing helper methods for GitHub's gemoji gem.
Ruby
72
star
5

graphql-stitching-ruby

GraphQL Schema Stitching for Ruby
Ruby
33
star
6

professional-javascript

Curriculum for Professional JavaScript classroom workshop.
HTML
31
star
7

sidekiq-heroku-autoscale

Dynamically start, stop, and scale Sidekiq dynos on Heroku based on queued jobs.
Ruby
24
star
8

backbone.containerview

A fast and efficient subview renderer and lifecycle manager.
JavaScript
22
star
9

constellation-js

A grid geometry toolkit for A* pathfinding and 2D sprite motion.
JavaScript
21
star
10

pods.js

Tiny managers for module definition and dependency management.
JavaScript
20
star
11

graphql-ruby-schema-directives

Generic implementation of schema directives for GraphQL Ruby
Ruby
6
star
12

federation-to-stitching-sdl

Format Federation SDL documents for use in a Schema Stitching gateway.
JavaScript
4
star
13

series-stats

Numeric series statistics algorithms and utility methods.
JavaScript
3
star
14

FishingGame

Canvas-based fishing game from "What Makes You Tick: A Stitch in Time"
JavaScript
2
star
15

graphql-asia-demo

Countries API + UNESCO World Heritage site data for GraphQL Asia demo
JavaScript
2
star
16

lassie-rails

Lassie game engine on Rails
JavaScript
1
star
17

lassie-js

JavaScript
1
star
18

muppets-api

Ruby
1
star
19

mtginfo

JavaScript
1
star
20

happenstance

JavaScript
1
star
21

bubblechart.js

An animated time-based bubble chart (scatter plot) with JavaScript and SVG/HTML graphics.
JavaScript
1
star