// unified CSS creation module. used for prod and dev/watch tasks. // writes files to `static/target/stylesheets` i.e. has side-effects // exports a function which takes: // 1. glob for files in static/src/stylesheets // 2. options object offering `remify` (boolean) and `browsers` (browserlist) const fs = require('fs'); const path = require('path'); const mkdirp = require('mkdirp'); const glob = require('glob'); const pify = require('pify'); const sass = require('node-sass'); const postcss = require('postcss'); const autoprefixer = require('autoprefixer'); const pxtorem = require('postcss-pxtorem'); const sassRenderP = pify(sass.render); const writeFileP = pify(fs.writeFile); const { src, target } = require('./__tasks__/config').paths; const sassDir = path.resolve(src, 'stylesheets'); const SASS_SETTINGS = { outputStyle: 'compressed', sourceMap: true, precision: 5, }; const BROWSERS_LIST = [ 'Firefox >= 26', 'Explorer >= 10', 'Safari >= 5', 'Chrome >= 36', 'iOS >= 5', 'Android >= 2', 'BlackBerry >= 6', 'ExplorerMobile >= 7', '> 2% in US', '> 2% in AU', '> 2% in GB', ]; const REMIFICATIONS = { replace: true, root_value: 16, unit_precision: 5, propList: ['*'], }; const getFiles = sassGlob => glob.sync(path.resolve(sassDir, sassGlob)); module.exports = ( sassGlob, { remify = true, browsers = BROWSERS_LIST } = {} ) => { if (typeof sassGlob !== 'string') { return Promise.reject(new Error('No glob provided.')); } return Promise.all( getFiles(sassGlob).map(filePath => { const dest = path.resolve( target, 'stylesheets', path.relative(sassDir, filePath).replace('scss', 'css') ); const sassOptions = Object.assign( { file: filePath, outFile: dest, sourceMapContents: true, includePaths: ['node_modules'], }, SASS_SETTINGS ); const postcssPlugins = [autoprefixer({ browsers })]; if (remify) { postcssPlugins.push(pxtorem(REMIFICATIONS)); } mkdirp.sync(path.parse(dest).dir); return sassRenderP(sassOptions) .then(result => postcss(postcssPlugins).process(result.css.toString(), { from: filePath, to: dest, map: { inline: false, prev: result.map.toString(), }, }) ) .then(result => Promise.all([ writeFileP(dest, result.css), writeFileP(`${dest}.map`, result.map), ]) ); }) ); };