diff --git a/README.md b/README.md index ba118f4..40f2dc0 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ A plugin for [PostCSS](https://github.com/ai/postcss) that generates viewport units (vw, vh, vmin, vmax) from pixel units. +## Install +``` +$ npm install postcss-px-to-viewport --save-dev +``` + ## Usage If your project involves a fixed width, this script will help to convert pixels into viewport units. @@ -95,8 +100,9 @@ Default: fontViewportUnit: 'vw', // vmin is more suitable. selectorBlackList: [], minPixelValue: 1, + mediaQuery: false, replace: true, - mediaQuery: false + exclude: [] // ignore some files } ``` - `unitToConvert` (String) unit to convert, by default, it is px. @@ -113,9 +119,12 @@ Default: - `minPixelValue` (Number) Set the minimum pixel value to replace. - `mediaQuery` (Boolean) Allow px to be converted in media queries. - `replace` (Boolean) replaces rules containing rems instead of adding fallbacks. +- `exclude` (Array or Regexp) Ignore some files like 'node_modules' + - If value is regexp, will ignore the matches files. + - If value is array, the elements of the array are regexp. ### Use with gulp-postcss - +add to your gulp config: ```js var gulp = require('gulp'); var postcss = require('gulp-postcss'); @@ -135,3 +144,15 @@ gulp.task('css', function () { .pipe(gulp.dest('build/css')); }); ``` +### Use with Postcss configuration file +add to postcss.config.js +```js +module.exports = { + plugins: { + ... + 'postcss-px-to-viewport': { + // options + } + } +} +``` diff --git a/index.js b/index.js index d2bb878..9dfb5f0 100755 --- a/index.js +++ b/index.js @@ -27,11 +27,25 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { // Not anything inside url() // Any digit followed by px // !singlequotes|!doublequotes|!url()|pixelunit - var pxRegex = new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + opts.unitToConvert, 'ig') + var pxRegex = new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + opts.unitToConvert, 'g') return function (css) { - + css.walkDecls(function (decl, i) { + + // Add exlclude option to ignore some files like 'node_modules' + if (opts.exclude && decl.source.input.file) { + if (Object.prototype.toString.call(opts.exclude) === '[object RegExp]') { + if (!handleExclude(opts.exclude, decl.source.input.file)) return; + } else if (Object.prototype.toString.call(opts.exclude) === '[object Array]') { + for (let i = 0; i < opts.exclude.length; ++i) { + if (!handleExclude(opts.exclude[i], decl.source.input.file)) return; + } + } else { + throw new Error('options.exclude should be RegExp or Array!'); + } + } + // This should be the fastest test and will remove most declarations if (decl.value.indexOf(opts.unitToConvert) === -1) return; @@ -59,6 +73,14 @@ module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { }; }); +function handleExclude (reg, file) { + if (Object.prototype.toString.call(reg) !== '[object RegExp]') { + throw new Error('options.exclude should be RegExp!'); + } + if (file.match(reg) !== null) return false; + return true; +} + function getUnit(prop, opts) { return prop.indexOf('font') === -1 ? opts.viewportUnit : opts.fontViewportUnit; } @@ -68,7 +90,8 @@ function createPxReplace(viewportSize, minPixelValue, unitPrecision, viewportUni if (!$1) return m; var pixels = parseFloat($1); if (pixels <= minPixelValue) return m; - return toFixed((pixels / viewportSize * 100), unitPrecision) + viewportUnit; + var parsedVal = toFixed((pixels / viewportSize * 100), unitPrecision); + return parsedVal === 0 ? '0' : parsedVal + viewportUnit; }; } diff --git a/spec/px-to-viewport.spec.js b/spec/px-to-viewport.spec.js index f530ac5..d530061 100644 --- a/spec/px-to-viewport.spec.js +++ b/spec/px-to-viewport.spec.js @@ -37,6 +37,13 @@ describe('px-to-viewport', function() { expect(processed).toBe(expected); }); + it('should remain unitless if 0', function () { + var expected = '.rule { font-size: 0px; font-size: 0; }'; + var processed = postcss(pxToViewport()).process(expected).css; + + expect(processed).toBe(expected); + }); + it('should not add properties that already exist', function () { var expected = '.rule { font-size: 16px; font-size: 5vw; }'; var processed = postcss(pxToViewport()).process(expected).css; @@ -64,6 +71,14 @@ describe('value parsing', function() { expect(processed).toBe(expected); }); + + it('should not replace values with an uppercase P or X', function () { + var rules = '.rule { margin: 12px calc(100% - 14PX); height: calc(100% - 20px); font-size: 12Px; line-height: 16px; }'; + var expected = '.rule { margin: 3.75vw calc(100% - 14PX); height: calc(100% - 6.25vw); font-size: 12Px; line-height: 5vw; }'; + var processed = postcss(pxToViewport()).process(rules).css; + + expect(processed).toBe(expected); + }); }); describe('unitToConvert', function() { @@ -204,14 +219,62 @@ describe('minPixelValue', function () { }); }); +describe('exclude', function () { + var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'; + var covered = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }' + it('when using regex at the time, the style should not be overwritten.', function () { + var options = { + exclude: /node_modules/ + } + var processed = postcss(pxToViewport(options)).process(rules, { + from: '/node_modules/main.css' + }).css; + + expect(processed).toBe(rules); + }); + + it('when using regex at the time, the style should be overwritten.', function () { + var options = { + exclude: /node_modules/ + } + var processed = postcss(pxToViewport(options)).process(rules, { + from: '/example/main.css' + }).css; + + expect(processed).toBe(covered); + }); + + it('when using array at the time, the style should not be overwritten.', function () { + var options = { + exclude: [/node_modules/, /exclude/] + } + var processed = postcss(pxToViewport(options)).process(rules, { + from: '/exclude/main.css' + }).css; + + expect(processed).toBe(rules); + }); + + it('when using array at the time, the style should be overwritten.', function () { + var options = { + exclude: [/node_modules/, /exclude/] + } + var processed = postcss(pxToViewport(options)).process(rules, { + from: '/example/main.css' + }).css; + + expect(processed).toBe(covered); + }); +}); + describe('replace', function () { it('should leave fallback pixel unit with root em value', function () { - var options = { - replace: false - }; - var processed = postcss(pxToViewport(options)).process(basicCSS).css; - var expected = '.rule { font-size: 15px; font-size: 4.6875vw }'; + var options = { + replace: false + }; + var processed = postcss(pxToViewport(options)).process(basicCSS).css; + var expected = '.rule { font-size: 15px; font-size: 4.6875vw }'; - expect(processed).toBe(expected); + expect(processed).toBe(expected); }); -}); \ No newline at end of file +});