├── test ├── colors.less ├── nonsense.less ├── styles.css ├── app │ ├── debug.js │ ├── package.json │ └── test.html ├── styles.less ├── error.js ├── test.html └── test.js ├── .travis.yml ├── .gitignore ├── package.json ├── LICENSE ├── index.js └── README.md /test/colors.less: -------------------------------------------------------------------------------- 1 | @verypaleyellow: #FFD; -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "7" 5 | - "8" 6 | notifications: 7 | email: false -------------------------------------------------------------------------------- /test/nonsense.less: -------------------------------------------------------------------------------- 1 | .css_region { 2 | font-framily: something 3 | } 4 | 5 | .css_region em { 6 | background-color: #CFF; 7 | 8 | -------------------------------------------------------------------------------- /test/styles.css: -------------------------------------------------------------------------------- 1 | .css_region { 2 | font-family: "Courier New", serif; 3 | } 4 | 5 | .css_region em { 6 | background-color: #CFF; 7 | } 8 | -------------------------------------------------------------------------------- /test/app/debug.js: -------------------------------------------------------------------------------- 1 | var css = require("../styles.css"); 2 | var less = require("../styles.less"); 3 | 4 | console.log(css); 5 | console.log(less); -------------------------------------------------------------------------------- /test/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lessify-test", 3 | "browserify": { 4 | "transform-options": { 5 | "node-lessify": "textMode" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | .DS_Store 11 | 12 | pids 13 | logs 14 | results 15 | 16 | npm-debug.log 17 | node_modules 18 | 19 | test/bundle.js 20 | test/app/script.js -------------------------------------------------------------------------------- /test/app/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |10 | This paragraph is styled with styles.less, compiled into a script by node-lessify 11 |
12 |13 | This paragraph is styled with styles.css, also compiled into a script by node-lessify 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require("fs"); 4 | var browserify = require('browserify'); 5 | var lessify = require("../index"); 6 | var assert = require("assert"); 7 | 8 | var sampleLESS = __dirname + "/styles.less"; 9 | var sampleCSS = __dirname + "/styles.css"; 10 | 11 | var LessPluginAutoPrefix = require('less-plugin-autoprefix'); 12 | var autoprefix= new LessPluginAutoPrefix({ browsers: ["last 2 versions"] }); 13 | 14 | var b = browserify(sampleLESS); 15 | //b.add(sampleLESS); 16 | //b.add(sampleCSS); 17 | b.transform(lessify, {plugins: [autoprefix] }); 18 | 19 | b.bundle(function (err, src) { 20 | if (err) { 21 | console.error(err); 22 | assert.fail(err); 23 | } 24 | assert.ok(src); 25 | fs.writeFileSync(__dirname + "/bundle.js", src.toString()); 26 | }); 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-lessify", 3 | "version": "0.2.0", 4 | "description": "LESS precompiler and CSS plugin for Browserify", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "test/test.js && cd test/app && browserify -t ../../index debug.js > script.js", 8 | "error": "test/error.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/wilson428/node-lessify" 13 | }, 14 | "keywords": [ 15 | "less", 16 | "css", 17 | "browserify", 18 | "browserify-transform" 19 | ], 20 | "author": { 21 | "name": "David Canas", 22 | "email": "david@learningequality.org" 23 | }, 24 | "license": "MIT", 25 | "dependencies": { 26 | "less": "^3.12.2", 27 | "object-assign": "^4.0.1", 28 | "through2": "^2.0.1" 29 | }, 30 | "engines": { 31 | "node": ">=6" 32 | }, 33 | "devDependencies": { 34 | "browserify": "^13.0.0", 35 | "less-plugin-autoprefix": "*" 36 | }, 37 | "bugs": { 38 | "url": "https://github.com/wilson428/node-lessify/issues" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Chris Wilson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // v0.0.9a 2 | 3 | var path = require("path"); 4 | var through = require('through2'); 5 | var less = require('less'); 6 | var assign = require('object-assign'); 7 | 8 | var func_start = "(function() { var head = document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css';", 9 | func_end = "if (style.styleSheet){ style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style);}())"; 10 | 11 | var defaultOptions = { 12 | compileOptions: { 13 | compress: true 14 | } 15 | }; 16 | 17 | /* 18 | you can pass options to the transform from your package.json file like so: 19 | 20 | "browserify": { 21 | "transform-options": { 22 | "node-lessify": "textMode" 23 | } 24 | } 25 | 26 | NOTE: This is deprecated since it is now possible to do this like so: 27 | 28 | "browserify": { 29 | "transform": [ 30 | [ "node-lessify", { "textMode": true } ] 31 | ] 32 | } 33 | */ 34 | 35 | var currentWorkingDir = process.cwd(); 36 | var packageConfig; 37 | try { 38 | packageConfig = require(currentWorkingDir + "/package.json"); 39 | } catch (e) { 40 | packageConfig = undefined; 41 | } 42 | 43 | /* 44 | textMode simply compiles the LESS into a single string of CSS and passes it back without adding the 45 | code that automatically appends that CSS to the page 46 | */ 47 | 48 | var packagePluginOptions = packageConfig && 49 | packageConfig.browserify && 50 | packageConfig.browserify["transform-packageConfig"] && 51 | packageConfig.browserify["transform-packageConfig"]["node-lessify"]; 52 | 53 | 54 | module.exports = function (file, transformOptions) { 55 | if (!/\.css$|\.less$/.test(file)) { 56 | return through(); 57 | } 58 | 59 | // set the curTransformOptions using the given plugin options 60 | var curTransformOptions = assign({}, defaultOptions, packagePluginOptions || {}, transformOptions || {}); 61 | curTransformOptions._flags = undefined; // clear out the _flag property 62 | 63 | 64 | var buffer = "", 65 | myDirName = path.dirname(file); 66 | 67 | var compileOptions = assign({}, curTransformOptions.compileOptions || {}); 68 | compileOptions.paths = [].concat(compileOptions.paths || [], [".", myDirName]); 69 | 70 | return through(write, end); 71 | 72 | function write(chunk, enc, next) { 73 | buffer += chunk.toString(); 74 | next(); 75 | } 76 | 77 | function end(done) { 78 | var self = this; 79 | 80 | // CSS is LESS so no need to check extension 81 | less.render(buffer, compileOptions).then( 82 | function(output) { 83 | // small hack to output the file path of the LESS source file 84 | // so that we can differentiate 85 | var compiled = JSON.stringify( 86 | output.css + 87 | (curTransformOptions.appendLessSourceUrl ? 88 | '/*# sourceURL=' + path.relative(currentWorkingDir, file).replace(/\\/g, '/') + ' */' : '') 89 | ); 90 | 91 | if (curTransformOptions.textMode) { 92 | compiled = "module.exports = " + compiled + ";"; 93 | } else { 94 | compiled = func_start + "var css = " + compiled + ";" + func_end; 95 | } 96 | 97 | self.push(compiled); 98 | self.push(null); 99 | 100 | // emit change event for watchers 101 | output.imports.forEach(function (f) { 102 | self.emit('file', f); 103 | }); 104 | 105 | done(); 106 | }, 107 | function (err, output) { 108 | if (err) { 109 | var msg = err.message; 110 | if (err.line) { 111 | msg += " on " + err.line; 112 | } 113 | if (err.column) { 114 | msg += ":" + err.column; 115 | } 116 | if (err.extract) { 117 | msg += "\n" + err.extract + "\n"; 118 | } 119 | 120 | done(new Error(msg, file, err.line)); 121 | self.emit('file', err.filename); 122 | } 123 | 124 | 125 | }); 126 | } 127 | }; 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-lessify 2 | ============ 3 | Version 0.2.0 4 | 5 | [](https://travis-ci.org/wilson428/node-lessify) 6 | [](https://david-dm.org/wilson428/node-lessify) 7 | [](https://david-dm.org/wilson428/node-lessify#info=devDependencies) 8 | 9 | LESS 3.12 precompiler and CSS plugin for Browserify. Inspired by [node-underscorify](https://github.com/maxparm/node-underscorify). Originally developed for TIME Magazine's [interactive deployment framework](https://github.com/TimeMagazine/time-interactive). 10 | 11 | When bundling an app using [Browserify](http://browserify.org/), it's often convenient to be able to include your CSS as a script that appends the style declarations to the head. This is particularly relevant for self-assembling apps that attach themselves to a page but otherwise have reserved real-estate on the DOM. 12 | 13 | This small script allows you to `require()` your CSS or LESS files as you would any other script. 14 | 15 | ## Installation 16 | 17 | ``` 18 | npm install node-lessify 19 | ``` 20 | 21 | ## Usage 22 | Write your LESS or CSS files as you normally would, and put them somewhere where your script can find it. 23 | 24 | Then simply require them as you might anything else: 25 | 26 | ``` 27 | require('./styles.less'); 28 | require('./mysite.css'); 29 | ``` 30 | 31 | To compile the stylesheets, pass this module to browserify as a transformation on the command line. 32 | 33 | ``` 34 | browserify -t node-lessify script.js > bundle.js 35 | ``` 36 | 37 | ## How it works 38 | 39 | The stylesheets are compiled (in the case of LESS), minified, and bundle into a function that creates a new `