diff --git a/packages/cssnano/package.json b/packages/cssnano/package.json
index e552cbb7c..9dbeb2f35 100644
--- a/packages/cssnano/package.json
+++ b/packages/cssnano/package.json
@@ -24,7 +24,8 @@
],
"license": "MIT",
"dependencies": {
- "cosmiconfig": "^7.0.0",
+ "lilconfig": "^2.0.3",
+ "yaml": "^1.10.2",
"cssnano-preset-default": "^5.1.3",
"is-resolvable": "^1.1.0"
},
diff --git a/packages/cssnano/src/__tests__/config_loading/.cssnanorc.json b/packages/cssnano/src/__tests__/config_loading/.cssnanorc.json
new file mode 100644
index 000000000..2495f19bd
--- /dev/null
+++ b/packages/cssnano/src/__tests__/config_loading/.cssnanorc.json
@@ -0,0 +1,3 @@
+{
+ "preset": "lite"
+}
diff --git a/packages/cssnano/src/__tests__/config_loading/config-loading.js b/packages/cssnano/src/__tests__/config_loading/config-loading.js
new file mode 100644
index 000000000..b238ad41e
--- /dev/null
+++ b/packages/cssnano/src/__tests__/config_loading/config-loading.js
@@ -0,0 +1,22 @@
+import process from 'process';
+import postcss from 'postcss';
+import litePreset from 'cssnano-preset-lite';
+import defaultPreset from 'cssnano-preset-default';
+import cssnano from '../..';
+
+/* The configuration is loaded relative to the current working directory,
+ when running the repository tests, the working directory is
+ the repostiory root, so we need to change it to avoid having to place
+ the configuration file for this test in the repo root */
+const spy = jest.spyOn(process, 'cwd');
+spy.mockReturnValue(__dirname);
+
+test('should read the cssnano configuration file', () => {
+ const processor = postcss([cssnano]);
+ expect(processor.plugins.length).toBe(litePreset().plugins.length);
+});
+
+test('PostCSS config should override the cssnano config', () => {
+ const processor = postcss([cssnano({ preset: 'default' })]);
+ expect(processor.plugins.length).toBe(defaultPreset().plugins.length);
+});
diff --git a/packages/cssnano/src/index.js b/packages/cssnano/src/index.js
index 69674c234..4e3558adf 100644
--- a/packages/cssnano/src/index.js
+++ b/packages/cssnano/src/index.js
@@ -1,6 +1,7 @@
import path from 'path';
import postcss from 'postcss';
-import { cosmiconfigSync } from 'cosmiconfig';
+import yaml from 'yaml';
+import { lilconfigSync } from 'lilconfig';
import isResolvable from 'is-resolvable';
const cssnano = 'cssnano';
@@ -59,7 +60,7 @@ function resolvePreset(preset) {
/*
* cssnano will look for configuration firstly as options passed
- * directly to it, and failing this it will use cosmiconfig to
+ * directly to it, and failing this it will use lilconfig to
* load an external file.
*/
@@ -76,7 +77,21 @@ function resolveConfig(options) {
configPath = path.resolve(process.cwd(), options.configFile);
}
- const configExplorer = cosmiconfigSync(cssnano);
+ const configExplorer = lilconfigSync(cssnano, {
+ searchPlaces: [
+ 'package.json',
+ '.cssnanorc',
+ '.cssnanorc.json',
+ '.cssnanorc.yaml',
+ '.cssnanorc.yml',
+ '.cssnanorc.js',
+ 'cssnano.config.js',
+ ],
+ loaders: {
+ '.yaml': (filepath, content) => yaml.parse(content),
+ '.yml': (filepath, content) => yaml.parse(content),
+ },
+ });
const config = configPath
? configExplorer.load(configPath)
: configExplorer.search(searchPath);
diff --git a/site/docs/config-file.mdx b/site/docs/config-file.mdx
index 0a6a6d34f..ea021f151 100644
--- a/site/docs/config-file.mdx
+++ b/site/docs/config-file.mdx
@@ -21,10 +21,31 @@ export const ExampleChart = () => {
-## `cssnano` config files
+You can configure cssnano either in the PostCSS configuration file or in a dedicated cssnano configuration file. The PostCSS configuration file takes precedence over the dedicated cssnano configuration.
+If you don't pass any configuration, cssnano runs with the `default` preset.
+
+
+## Configure through PostCSS configuration files
+
+In the [PostCSS configuration file](https://github.com/postcss/postcss#usage), you can pass both the `preset` and `plugins` options when you add `cssnano` to the PostCSS plugins. For example, if you use PostCSS programmatically, the following uses cssnano with the `lite` preset and adds autoprefixer.
+
+```js
+import postcss from 'postcss';
+import cssnano from 'cssnano';
+import litePreset from 'cssnano-preset-lite';
+import autoprefixer from 'autoprefixer';
+const preset = litePreset({ discardComments: false });
+
+postcss([cssnano({ preset, plugins: [autoprefixer] })]).process("/* Your CSS here */")
+```
+
+## Configure through dedicated `cssnano` configuration
+
+If you cannot configure cssnano in the PostCSS configuration file, you can configure cssnano with a cssnano configuration option in `package.json` or with a dedicated configuration file. This file can be in different formats.
+
+* `.cssnanorc.config.json` and `.cssnanorc` must contain a JSON object
+* `cssnano.config.js` must export the configuration as a JavaScript object
-We use configuration for `cssnano` using file name as `cssnano.config.js` , `cssnano` property in your `package.json`, using `cssnano.config.json` and `.cssnanorc` as well.
-We are using `cosmiconfig` in order to load cssnano config. Please read [here](https://github.com/davidtheclark/cosmiconfig) for more details
## Options
@@ -32,35 +53,52 @@ We are using `cosmiconfig` in order to load cssnano config. Please read [here](h
- **Type:** `string` | `function` | `[string, Objects]` | `[function(preset options here)]`
-> For `string`, the name should be of type `cssnano-preset-` and you need to use `name` alone eg : `preset : ['default', {}]`
+Pass a preset to choose a pre-configured set of optimizations. You can either import the preset package or use the preset name as a string.
-Contains lists of `postcss` plugins where each plugin does their own minification.
+With the preset as import:
-- **Example:**
-
- ```js
- // cssnano.config.js
- module.exports = {
- preset: [require('cssnano-preset-default')]
-
- // or
- preset: require('cssnano-preset-default')
-
- // or
- preset: ['advanced', { discardComments: false }]
+```js
+cssnano({ preset: require('cssnano-preset-default') })
+```
+
+Using a string is useful if you use a configuration file in the JSON format.
+When you use a string, if the preset is called `cssnano-preset-`, use `name` alone:
+
+```js
+cssnano({ preset: 'default' })
+```
+
+Presets themselves can take options.
+Pass options to the preset by using an array where the first element is the preset and the second is an object with the preset options.
+You can specify a preset with the preset name as a string or by passing the result of importing the preset package.
+
+```js
+// cssnano.config.js
+module.exports = {
+ preset: [ require('cssnano-preset-default'), { discardComments: false } ]
+};
+```
+
+
+You can also pass preset options when you use the preset name as a string:
+For example, here's how to deactivate the `discardComments` plugin when using the `advanced` preset:
+
+```js
+cssnano({ preset: ['advanced', { discardComments: false }] })
+```
- // or
- preset: [require('cssnano-preset-default'), {discardComments: false}]
- }
- ```
### `plugins`
- **Type:** `Array<'string' | 'function' | ['string' | 'function', Object]>`
-> If you want to pass config to the plugin, you need to use Array's of array for the plugins i.e `plugins: [ ['autoprefixer', {}] ]`
+In addition to the preset, you can pass a list of plugins to cssnano.
+This is equivalent to adding the plugins after cssnano in the PostCSS plugins array.
+If you want to configure the individual plugins, use an array of arrays:
-These plugins will run after once all presets operations are complete.
+```js
+cssnano({ plugins: [['autoprefixer', {}]] })
+```
- **Example:**
@@ -84,8 +122,3 @@ These plugins will run after once all presets operations are complete.
]
}
```
-
-## Alternatives
-
-You can use the `postcss` config file and both `preset` and `plugins` will be passed as the options for `cssnano`.
-Refer [here](https://github.com/postcss/postcss#usage) for more details.
diff --git a/yarn.lock b/yarn.lock
index 37d9b0dd0..702c7a50b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6325,6 +6325,11 @@ libnpmpublish@^4.0.0:
semver "^7.1.3"
ssri "^8.0.1"
+lilconfig@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd"
+ integrity sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==
+
lines-and-columns@^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
@@ -7942,12 +7947,13 @@ postcss-font-magician@^3.0.0:
google-fonts-complete "^2.1.1"
postcss-load-config@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.0.1.tgz#d214bf9cfec1608ffaf0f4161b3ba20664ab64b9"
- integrity sha512-/pDHe30UYZUD11IeG8GWx9lNtu1ToyTsZHnyy45B4Mrwr/Kb6NgYl7k753+05CJNKnjbwh4975amoPJ+TEjHNQ==
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.0.tgz#d39c47091c4aec37f50272373a6a648ef5e97829"
+ integrity sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==
dependencies:
- cosmiconfig "^7.0.0"
import-cwd "^3.0.0"
+ lilconfig "^2.0.3"
+ yaml "^1.10.2"
postcss-reporter@^1.3.0:
version "1.4.1"
@@ -10270,7 +10276,7 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-yaml@^1.10.0:
+yaml@^1.10.0, yaml@^1.10.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==