ninjs-sass
Version:
.scss to .css build
115 lines (93 loc) • 3.77 kB
JavaScript
/**
* Sass Build
* sass build plugin for building/optimizing/converting .scss to .css
* - scss build using node-sass
* - parses parallel optimization results and returns SassResultModel.toJSON
*/
const _ = require('ninjs-lodash')
const sass = require('node-sass')
const autoprefixer = require('autoprefixer')
const postcss = require('postcss')
// const Backbone = require('backbone')
// const ba = require('backbone-associations')
const AUTOP_OPTS = _.$('sass.autoprefixer')
const OPTIONS = _.$('sass.defaults')
const OUTPUT_STYLES = _.$('sass.defaults.output_style_options')
const OUTPUT_STYLES_MAP = _.$('sass.defaults.file_suffix_map')
const prefixer = postcss([autoprefixer(AUTOP_OPTS)])
exports = module.exports = {
render: render,
renderApp: renderApp,
renderHeadings: renderHeadings
}
// returns css string after running sass optimizer
function render(options, callback) {
let params = _.mcopy(OPTIONS, options)
let { enabled=true, dest='', outputStyle='expanded', xform=undefined } = params
let isExpanded = _.toLower(outputStyle) === 'expanded'
if(!enabled) return _.fail('not enabled', callback)
if(!dest) return _.fail('invalid dest', callback)
sass.render(params, (err, result) => {
if (err) return _.fail(err, callback)
let { css, map, stats } = result
let { entry, duration, includedFiles } = stats
// map = map ? JSON.stringify(map) : ''
prefixer.process(css)
.then((prefixed) => {
let prefixedCss = _.get(prefixed, 'css') || ''
console.log(prefixedCss)
_.outputFile(dest, prefixedCss, (err) => {
if (err) return _.fail(err, callback)
let stat = _.statSync(dest)
let bytes = _.get(stat, 'size') || 0
_.done({ path: dest, files: includedFiles, duration: duration, bytes: bytes, size: _.bytes(bytes) }, callback)
})
})
.catch((err) => { return _.fail(err, callback) })
})
}
function renderApp(options, callback) {
let { file='', dest='' } = options
if(!file) return _.fail('Invalid file', callback)
if(!dest) return _.fail('Invalid dest', callback)
let start = _.now()
let dir = _.path.dir(dest)
let res = { file: file, dest: dest, duration: 0, bytes: 0, size: '', files: [], results: {} }
let tasks = _.reduce(OUTPUT_STYLES, (result, v) => {
let mapped = _.get(OUTPUT_STYLES_MAP, v) || ''
let styleName = mapped ? `styles.${mapped}.css` : `styles.css`
result[v] = _.async.apply(render, _.mcopy(options, { outputStyle: v, dest: _.path.join(dir, styleName) }))
res.results[v] = { path: "", duration: 0, bytes: 0, size: "" }
return result
}, {})
return _.async.parallel(tasks, (err, result) => {
if(err) return _.fail(err, callback)
_.each(OUTPUT_STYLES, (v) => {
let oResult = _.get(result, v)
res.files = _.get(oResult, 'files') || []
res.results[v] = _.omit(oResult, ['files'])
})
_.each(res.files, (file) => {
let bytes = _.get(_.statSync(file), 'size') || 0
res.bytes = res.bytes + bytes
})
_.assign(res, { size: _.bytes(res.bytes), duration: _.nowDiff(start) })
return _.done(res, callback)
})
}
function renderHeadings(options, callback) {
options = _.mcopy(options, {
data: '#{headings(2,5)} { color: #08c }',
functions: {
'headings($from: 0, $to: 6)': (from, to) => {
let i, f = from.getValue()
let t = to.getValue()
let list = new sass.types.List(t - f + 1)
for (i = f; i <= t; i++) list.setValue(i - f, new sass.types.String('h' + i))
return list
}
}
})
return render(options, callback)
}