├── .gitignore ├── tests ├── util │ ├── _vars.scss │ ├── indented.sass │ ├── basic.scss │ ├── imports-old.scss │ ├── imports.scss │ ├── mock-importer-factory.js │ ├── mock-importer.js │ └── integration.js ├── settings.js ├── indented.js ├── import-events.js ├── style-tag.js └── custom-importers.js ├── .travis.yml ├── .github ├── ISSUE_TEMPLATE.md └── workflows │ └── run-test.yml ├── LICENSE ├── lib ├── browser.js └── index.js ├── package.json ├── README.md └── history.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /tests/util/_vars.scss: -------------------------------------------------------------------------------- 1 | $color: red; 2 | $background: blue; 3 | -------------------------------------------------------------------------------- /tests/util/indented.sass: -------------------------------------------------------------------------------- 1 | body 2 | color: red 3 | background: blue 4 | -------------------------------------------------------------------------------- /tests/util/basic.scss: -------------------------------------------------------------------------------- 1 | body { 2 | color: red; 3 | background: blue; 4 | columns: 300px 2; 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "7" 5 | - "8" 6 | notifications: 7 | email: false 8 | -------------------------------------------------------------------------------- /tests/util/imports-old.scss: -------------------------------------------------------------------------------- 1 | @import 'vars'; 2 | 3 | body { 4 | color: $color; 5 | background: $background; 6 | } 7 | -------------------------------------------------------------------------------- /tests/util/imports.scss: -------------------------------------------------------------------------------- 1 | @import 'resolve-to-vars'; 2 | 3 | body { 4 | color: $color; 5 | background: $background; 6 | } 7 | -------------------------------------------------------------------------------- /tests/util/mock-importer-factory.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const mockImporter = require('./mock-importer') 3 | module.exports = function () { 4 | module.exports.count++ 5 | return mockImporter 6 | } 7 | 8 | module.exports.count = 0 9 | 10 | -------------------------------------------------------------------------------- /tests/util/mock-importer.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const importedFiles = new Set() 3 | module.exports = function (file) { 4 | importedFiles.add(file) 5 | if (file === 'resolve-to-vars') 6 | return {file: 'tests/util/_vars.scss'} 7 | return null 8 | } 9 | 10 | // Expose for assertions 11 | module.exports.importedFiles = importedFiles 12 | -------------------------------------------------------------------------------- /tests/settings.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /* eslint-env mocha */ 3 | const assert = require('assert') 4 | const integration = require('./util/integration') 5 | 6 | it('settings', integration(__dirname + '/util/basic.scss', { 7 | autoInject: false, 8 | sass: { 9 | outputStyle: 'expanded' 10 | }, 11 | postcss: { 12 | autoprefixer: {} 13 | } 14 | }, function (context, done) { 15 | let css = context.exports 16 | assert.equal(typeof css, 'string', 'exported raw css') 17 | assert.notEqual(css.indexOf('-moz'), -1, 'postcss plugins ran') 18 | done() 19 | })) 20 | -------------------------------------------------------------------------------- /tests/indented.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /* eslint-env mocha */ 3 | const assert = require('assert') 4 | const integration = require('./util/integration') 5 | 6 | it('supports indented syntax (.sass)', integration(__dirname + '/util/indented.sass', { 7 | // empty 8 | }, function (context, done) { 9 | let applied = context.window.getComputedStyle(context.document.body) 10 | assert.equal(context.exports.tagName, 'STYLE', 'created tag and add it to the document head 7 | * @param {string} cssText 8 | * @param {object?} options 9 | * @return {Element} 10 | */ 11 | createStyle: function (cssText, options) { 12 | var container = document.head || document.getElementsByTagName('head')[0] 13 | var style = document.createElement('style') 14 | options = options || {} 15 | style.type = 'text/css' 16 | if (options.href) { 17 | style.setAttribute('data-href', options.href) 18 | } 19 | if (style.sheet) { // for jsdom and IE9+ 20 | style.innerHTML = cssText 21 | style.sheet.cssText = cssText 22 | } 23 | else if (style.styleSheet) { // for IE8 and below 24 | style.styleSheet.cssText = cssText 25 | } 26 | else { // for Chrome, Firefox, and Safari 27 | style.appendChild(document.createTextNode(cssText)) 28 | } 29 | if (options.prepend) { 30 | container.insertBefore(style, container.childNodes[0]); 31 | } else { 32 | container.appendChild(style); 33 | } 34 | return style 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scssify", 3 | "version": "4.0.0", 4 | "description": "Sass browserify transformer", 5 | "repository": "cody-greene/scssify", 6 | "main": "./lib/index.js", 7 | "browser": "./lib/browser.js", 8 | "files": [ 9 | "lib/" 10 | ], 11 | "scripts": { 12 | "watch": "mocha tests/*.js -bwR min", 13 | "test": "mocha tests/*.js -bR tap" 14 | }, 15 | "keywords": [ 16 | "browserify", 17 | "browserify-transform", 18 | "css", 19 | "postcss-runner", 20 | "sass", 21 | "scss", 22 | "transform" 23 | ], 24 | "author": "Chris Hoage", 25 | "license": "MIT", 26 | "engines": { 27 | "node": ">=14" 28 | }, 29 | "eslintConfig": { 30 | "root": true, 31 | "extends": "./node_modules/@cody-greene/eslint-config/strict.yml", 32 | "env": { 33 | "node": true, 34 | "es6": true 35 | } 36 | }, 37 | "devDependencies": { 38 | "@cody-greene/eslint-config": "3.3.3", 39 | "autoprefixer": "^10.4.0", 40 | "jsdom": "^21.1.0", 41 | "mocha": "^10.2.0", 42 | "postcss": "^8.4.0" 43 | }, 44 | "dependencies": { 45 | "resolve": "^1.1.6", 46 | "sass": "^1.59.2" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/custom-importers.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /* eslint-env mocha */ 3 | const assert = require('assert') 4 | const integration = require('./util/integration') 5 | const importSpy = require('./util/mock-importer').importedFiles 6 | const factory = require('./util/mock-importer-factory') 7 | 8 | before(function setup() { 9 | importSpy.clear() 10 | }) 11 | 12 | it('loads custom importer files', integration(__dirname + '/util/imports.scss', { 13 | autoInject: false, 14 | sass: { 15 | importer: 'tests/util/mock-importer.js' 16 | } 17 | }, function (context, done) { 18 | const [firstFile] = Array.from(importSpy) 19 | assert.equal(firstFile, 'resolve-to-vars', 'import spy was loaded') 20 | done() 21 | })) 22 | 23 | it('loads importer from factory function every time it runs', function (done) { 24 | // this mimics browserify + factor-bundle calling the transform several times in a single process 25 | let file = __dirname + '/util/imports.scss' 26 | let config = { 27 | autoInject: false, 28 | sass: { 29 | importerFactory: 'tests/util/mock-importer-factory.js' 30 | } 31 | } 32 | integration(file, config, function (context, done) { 33 | integration(file, config, function (context, done) { 34 | let count = factory.count 35 | assert.equal(count, 2, 'factory not called expected number of times') 36 | done() 37 | })(done) 38 | })(done) 39 | }) 40 | -------------------------------------------------------------------------------- /tests/util/integration.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const scssify = require('../../lib') 3 | const JSDOM = require('jsdom').JSDOM 4 | const fs = require('fs') 5 | const vm = require('vm') 6 | const CLIENT_HELPER_CODE = fs.readFileSync('lib/browser.js', 'utf8') 7 | 8 | /** 9 | * @param {string} src Absolute path to a scss file 10 | * @param {object} config scssify parameters 11 | * @param {function} callback(context, assert) 12 | * @param {function?} prepare(context) 13 | * @return {function} Pass this to tape('test-name', fn) 14 | */ 15 | function createIntegrationTest(src, config, callback, prepare) { 16 | if (!config._flags) config._flags = {} 17 | return function (done) { 18 | fs.createReadStream(src) 19 | .on('error', done) 20 | .pipe(scssify(src, config)) 21 | .on('error', done) 22 | .once('data', function (transformed) { 23 | let doc = new JSDOM(null, {runScripts: 'dangerously'}) 24 | let helperModule = {exports: {}} 25 | let cssModule = {exports: {}} 26 | vm.runInNewContext(CLIENT_HELPER_CODE, { 27 | window: doc.window, 28 | document: doc.window.document, 29 | module: helperModule 30 | }) 31 | if (prepare) prepare({ 32 | window: doc.window, 33 | document: doc.window.document, 34 | exports: cssModule.exports 35 | }) 36 | vm.runInNewContext(transformed.toString(), { 37 | window: doc.window, 38 | document: doc.window.document, 39 | module: cssModule, 40 | require: function (req) { 41 | if (req === 'scssify') return helperModule.exports 42 | throw new Error('sandboxed module: unexpected require(...)') 43 | } 44 | }) 45 | callback({ 46 | window: doc.window, 47 | document: doc.window.document, 48 | exports: cssModule.exports 49 | }, done) 50 | }) 51 | } 52 | } 53 | 54 | module.exports = createIntegrationTest 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### scssify 2 | Browserify transfomer to compile [sass][] stylesheets. Features: 3 | - Inject a `