Skip to content

RetailMeNotSandbox/roux-sass-importer

Repository files navigation

@retailmenot/roux-sass-importer

A node-sass custom importer for ingredients in the [Roux][Roux ecosystem].

Build Status Coverage Status

Installation

npm install @retailmenot/roux-sass-importer

Usage

This importer makes it possible to import Sass from an ingredient by specifying the pantry and ingredient name only:

@import "@namespace/pantry/an-ingredient";
@import "another-pantry/another-ingredient";

Create an importer and pass it to node-sass as follows:

var sass = require('node-sass');
var rouxSassImporter = require('@retailmenot/roux-sass-importer');

var importer = rouxSassImporter(sass.NULL, {
  pantries: {
    '@namespace/pantry': somePantryInstance,
    // This will be initialized and cached across calls to the
    // importer
    '@namespace/pantry2': '/path/to/pantry2'
  },
  pantrySearchPaths: [
    path.resolve('node_modules'),
    path.resolve('some/other/path')
  ]
});

sass.render({
  file: 'path/to/your/file.scss',
  importer: importer
},
function(err, result){
  console.log(result && result.css.toString());
});

If passing only a path, and you have nested the pantry entry, please ensure that you have correctly noted that in your package.json, per the roux README.

Relative @import paths

An important note regarding how relative @import paths are resolved:

If the import path can be parsed by roux.parseIngredientPath, then the importer will try to look up the corresponding Sass entry point for that ingredient by instantiating the pantry with roux.initialize. If successful, the import path is resolved to the entry point, otherwise an error is returned. This means that relative file system paths which look like ingredient paths will not work.

Ideally, if we couldn't find the pantry in any of the pantrySearchPaths, we would not return an error, but instead tell node-sass to resolve the import path in the default manner. Unfortunately, this is not possible due to a bug in either node-sass or libsass.

The upshot of this is that relative paths should begin with ./ or ../. These will never be parseable as ingredient paths, so they will be handed off to node-sass to resolve.

CSS De-duplicating

An important note on deduping output in the CSS:

The importer will keep track of which ingredient files have already been imported. It will do so for imports matching an ingredient's entrypoint, as well as relative imports from within any sass file inside of a known pantry. Whenever an import for the same file is encountered, the importer will return empty file contents to prevent duplicate CSS from showing up in the compiled output.

API

This module exports a function that accepts an optional config object and returns a node-sass custom importer. The importer only handles import paths matching the following patterns:

  • @<namespace>/<pantry>/<ingredient>
  • <pantry>/<ingredient>

If the import path matches one of the above, the importer attempts to look up the Sass entry point for the named pantry and ingredient. If successful, an absolute path to the entry point is returned (possibly asynchronously).

If the pantry is not found, an Error is returned. If the pantry is found but does not contain the named ingredient, an Error is returned. If both the pantry and ingredient are found but the ingredient does not have a Sass entry point, an Error is returned.

The importer maintains a cache of pantries it looks up. The cache can be primed by means of the optional config.pantries parameter. If the named pantry is cached, the above process completes synchronously. If not cached, the pantry is looked up in the locations named by config.pantrySearchPaths. The first matching pantry found is cached and the above process performed.

  • NODE_SASS_NULL - The object to return when node-sass should do its thing. You should pass require('node-sass').NULL from your webpack config in the repo that's consuming this module.
  • config - optional config object for the importer
  • config.pantries - optional primed cache of pantries, defaults to {}
  • config.pantrySearchPaths - optional array of paths to search for pantries not found in the cache, defaults to ['$CWD/node_modules']