diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8b23445 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6ce4292 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# postcss-combine-media-query + +If you are used to write the media queries of your components within those components (what you should do instead of maintaining a large global media query file) you might end up with CSS that contains the same media query rule multiple times. + +```css +.foo { color: red; } +@media (min-width: 1024px) { + .foo { color: green; } +} +.bar { font-size: 1rem; } +@media (min-width: 1024px) { + .bar { font-size: 2rem; } +} +``` + +While this is totally fine in development (and supports a modular structure in particular when using [Sass](https://sass-lang.com/)) it's not that good for production where you wanna keep your CSS as small as possible. + +That's the use case this plugin is built for! +It looks for equal media query rules and appends them combined. + +```css +.foo { color: red; } +.bar { font-size: 1rem; } +@media (min-width: 1024px) { + .foo { color: green; } + .bar { font-size: 2rem; } +} +``` + +## Installation + +- npm +```bash +npm install postcss-combine-media-query --save-dev +``` + +- yarn +```bash +yarn add postcss-combine-media-query --dev +``` + +## Usage + +Simply add the plugin to your PostCSS config. +That's all – easy as pie :wink: (there are no options) + +If you're not familiar with using PostCSS you should read the official [PostCSS documentation](https://github.com/postcss/postcss#usage) first. + +## Side Effects + +Since this plugin moves all media queries to end of the file it may introduce bugs if your CSS is not well structured. So keep that in mind! + +Let's say you've got the following code which results in `.foo` being yellow on desktop. + +```css +.foo { color: red; } +@media (min-width: 1024px) { + .foo { color: green; } +} +.foo { color: yellow; } +``` + +Once you use this plugin it will change into `green` because the media query has been moved. + +```css +.foo { color: red; } +.foo { color: yellow; } +@media (min-width: 1024px) { + .foo { color: green; } +} +``` + +Therefore it's recommended to use this plugin in development as well to detect such side effects sooner. + +## Credits + +If this plugin is helpful to you it'll be great when you give me a star on github and share it. Keeps me motivated to continue the development. diff --git a/index.js b/index.js new file mode 100644 index 0000000..08346c4 --- /dev/null +++ b/index.js @@ -0,0 +1,31 @@ + +const postcss = require('postcss'); + +module.exports = postcss.plugin('postcss-combine-media-query', opts => { + + const atRules = {}; + + function addToAtRules(atRule) { + const key = atRule.params; + + if (!atRules[key]) { + atRules[key] = postcss.atRule({ name: atRule.name, params: atRule.params }); + } + atRule.nodes.forEach(node => { + atRules[key].append(node.clone()); + }); + + atRule.remove(); + } + + return root => { + + root.walkAtRules('media', atRule => { + addToAtRules(atRule); + }); + + Object.keys(atRules).forEach(key => { + root.append(atRules[key]); + }); + }; +}); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..9a23824 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "postcss-combine-media-query", + "version": "1.0.0", + "description": "PostCSS plugin to combine equal media query rules.", + "author": "Kai Falkowski", + "license": "MIT", + "main": "index.js", + "scripts": {}, + "keywords": [ + "postcss", + "plugin", + "postcss-plugin", + "css", + "mediaquery", + "mq", + "combine", + "optimization" + ], + "peerDependencies": { + "postcss": "^7.0.21" + }, + "devDependencies": {}, + "repository": { + "type": "git", + "url": "https://github.com/SassNinja/postcss-combine-media-query.git" + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..aff7d76 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,69 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +postcss@^7.0.21: + version "7.0.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" + integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0"