UNPKG

gulp-css2js

Version:

Convert CSS into JavaScript. Works with buffers and streams.

207 lines (176 loc) 6.31 kB
/** * Embed CSS into JavaScript * * This will take your CSS and convert it into JavaScript. When executed, * the resulting code will generate a <script> element and put the CSS text * into it. Instead of having an external file for your necessary styles, * they are embedded into your library. * * As an exercise and possibly as an example for other Gulp developers, * this plugin supports both buffers and streams. */ (function () { 'use strict'; var defaultOptions, through2, defaultWrapper, PluginError, replaceExt; /** * @typedef {Object} gulpCss2js~options * @property {string} remainder Leftover newlines from last write * @property {string} [prefix] * @property {boolean} [splitOnNewline=true] * @property {string} [suffix] * @property {boolean} [trimSpacesBeforeNewline=true] * @property {boolean} [trimTrailingNewline=false] */ /** * Get an options object * * @param {?Object} options * @return {gulpCss2js~options} */ function getOptions(options) { var result; options = options || {}; result = { remainder: '', remainderEncoding: 'utf8' }; Object.keys(defaultOptions).forEach(function (key) { if (options[key] === undefined) { result[key] = defaultOptions[key]; } else { result[key] = options[key]; } }); return result; } /** * Escapes content to be used in the middle of a JavaScript string. * This string will be surrounded by double quotes elsewhere, but this * is important because we need to escape double quotes in the buffers. * * @param {Buffer} bufferIn * @param {string} encoding * @param {gulpCss2js~options} options * @return {Buffer} */ function escapeBuffer(bufferIn, encoding, options) { var lastLine, str; try { str = bufferIn.toString(encoding); } catch (e) { str = bufferIn.toString(); encoding = 'utf8'; } /* If there was a chunk left over from a previous write, add it back. * This portion of code should only get executed when: * a stream is being processed * a chunk ends in a newline * another chunk comes after it */ if (options.remainder) { str = options.remainder + str; options.remainder = ''; } // Escape backslashes and double quotes str = str.replace(/\\/g, '\\\\'); str = str.replace(/"/g, '\\"'); // Newline conversion str = str.replace(/(\r?\n|\r)/g, '\n'); // Remove spaces before newlines if (options.trimSpacesBeforeNewline) { str = str.replace(/[\t ]*\n/g, '\n'); } /* We grab the last line of content and all following newlines * and put it into options.remainder. This is necessary for * processing streams. */ lastLine = str.match(/[^\n]+\n*$/); options.remainderEncoding = encoding; if (lastLine && lastLine[0]) { options.remainder = lastLine[0]; str = str.replace(/[^\n]+\n*$/, ''); } else { options.remainder = str; str = ''; } // Break on newlines if (options.splitOnNewline) { str = str.replace(/\n/g, '\\n" +\n"'); } else { str = str.replace(/\n/g, '\\n'); } return new Buffer(str, encoding); } function getRemainder(options) { var newlines, str; str = options.remainder; options.remainder = ''; // Trim the last newlines if (options.trimTrailingNewline) { newlines = str.match(/\n*$/); if (newlines && newlines[0]) { options.remainder = newlines[0]; str = str.replace(/\n*$/, ''); } } // Break on newlines if (options.splitOnNewline) { /* Prevent the last line from looking like this when encoded: * ".css { display: block }\n" + * "" */ str = str.replace(/\n$/, '\\n'); str = str.replace(/\n/g, '\\n" +\n"'); } else { str = str.replace(/\n/g, '\\n'); } return new Buffer(str, options.remainderEncoding); } /** * Uses Through2 to create a stream translation that converts CSS * into JavaScript. * * @param {gulpCss2js~options} options * @return {Stream} */ function convertStream(options) { var outStream; outStream = through2(function (chunk, encoding, callback) { this.push(escapeBuffer(chunk, encoding, options)); callback(); }, function (callback) { this.push(getRemainder(options)); this.push(new Buffer(options.suffix, 'utf8')); callback(); }); outStream.push(new Buffer(options.prefix, 'utf8')); return outStream; } PluginError = require('plugin-error'); replaceExt = require('replace-ext'); through2 = require('through2'); module.exports = function (options) { options = getOptions(options); return through2.obj(function (file, encoding, callback) { if (file.isBuffer()) { file.contents = Buffer.concat([new Buffer(options.prefix, 'utf8'), escapeBuffer(file.contents, encoding, options), getRemainder(options), new Buffer(options.suffix, 'utf8')]); file.path = replaceExt(file.path, ".js"); } else if (file.isStream()) { file.contents = file.contents.pipe(convertStream(options)); file.path = replaceExt(file.path, ".js"); } else if (!file.isNull()) { // Not sure what this could be, but future-proofing the code. this.emit('error', new PluginError('gulp-css2js', 'Unhandled file source type.')); return callback(); } this.push(file); return callback(); }); }; /* The following `preval` expression is evaluated and replaced at build-time. * (For more on that, see https://github.com/kentcdodds/babel-plugin-preval) * See assets/defaultWrapper.js for the unminified version of `defaultWrapper`. */ defaultWrapper = ["\"undefined\"!=typeof document&&function(e,t){var n=e.createElement(\"style\");if(e.getElementsByTagName(\"head\")[0].appendChild(n),n.styleSheet)n.styleSheet.disabled||(n.styleSheet.cssText=t);else try{n.innerHTML=t}catch(e){n.innerText=t}}(document,\"", "\");"]; module.exports.defaultOptions = defaultOptions = { prefix: defaultWrapper[0], suffix: defaultWrapper[1], splitOnNewline: true, trimSpacesBeforeNewline: true, trimTrailingNewline: true }; })();