cssnano 8.0.5 → 9.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,17 +1,16 @@
1
1
  {
2
2
  "name": "cssnano",
3
- "version": "8.0.5",
4
- "description": "A modular minifier, built on top of the PostCSS ecosystem.",
3
+ "version": "9.0.3",
4
+ "description": "A modular CSS minifier, built on top of the PostCSS ecosystem.",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./types/index.d.ts",
8
8
  "default": "./src/index.js"
9
9
  },
10
- "./src": "./src/index.js",
11
- "./src/index": "./src/index.js",
12
- "./src/index.js": "./src/index.js",
13
10
  "./package.json": "./package.json"
14
11
  },
12
+ "main": "./src/index.js",
13
+ "types": "./types/index.d.ts",
15
14
  "funding": {
16
15
  "type": "opencollective",
17
16
  "url": "https://opencollective.com/cssnano"
@@ -27,8 +26,7 @@
27
26
  ],
28
27
  "license": "MIT",
29
28
  "dependencies": {
30
- "lilconfig": "^3.1.3",
31
- "cssnano-preset-default": "^8.0.5"
29
+ "cssnano-preset-default": "^9.0.3"
32
30
  },
33
31
  "homepage": "https://github.com/cssnano/cssnano",
34
32
  "author": {
@@ -38,7 +36,7 @@
38
36
  },
39
37
  "repository": {
40
38
  "type": "git",
41
- "url": "cssnano/cssnano"
39
+ "url": "git+https://github.com/cssnano/cssnano.git"
42
40
  },
43
41
  "files": [
44
42
  "src",
@@ -49,18 +47,19 @@
49
47
  "url": "https://github.com/cssnano/cssnano/issues"
50
48
  },
51
49
  "engines": {
52
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
50
+ "node": "^22.22.3 || ^24.15.0 || >=26.0"
53
51
  },
54
52
  "devDependencies": {
55
- "autoprefixer": "^10.5.4",
56
- "postcss": "^8.5.26",
57
- "postcss-font-magician": "^4.0.0",
58
- "cssnano-preset-advanced": "^8.0.5",
59
- "cssnano-preset-lite": "^5.0.3"
53
+ "autoprefixer": "^10.5.5",
54
+ "cssnano-preset-advanced": "^9.0.3",
55
+ "cssnano-preset-lite": "^6.0.2",
56
+ "postcss": "^8.5.28",
57
+ "postcss-font-magician": "^4.0.0"
60
58
  },
61
59
  "peerDependencies": {
62
- "postcss": "^8.5.26"
60
+ "postcss": "^8.5.28"
63
61
  },
62
+ "type": "module",
64
63
  "scripts": {
65
64
  "test": "node --test"
66
65
  }
package/src/index.js CHANGED
@@ -1,13 +1,20 @@
1
- 'use strict';
2
- const path = require('node:path');
3
- /** @type {any} */
4
- const postcss = require('postcss');
5
- const { lilconfigSync } = require('lilconfig');
6
- const defaultPreset = require('cssnano-preset-default');
7
-
8
- const cssnano = 'cssnano';
9
-
10
- /** @typedef {{preset?: any, plugins?: any[], configFile?: string}} Options */
1
+ import { createRequire } from 'node:module';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import postcss from 'postcss';
5
+ import defaultPreset from 'cssnano-preset-default';
6
+
7
+ const require = createRequire(import.meta.url);
8
+
9
+ const configFileNames = ['.cssnanorc.json', 'cssnano.config.js'];
10
+
11
+ /** @typedef {boolean | { exclude?: boolean } | void | undefined} PluginOptions */
12
+ /** @typedef {import('postcss').PluginCreator<any>} PluginCreator */
13
+ /** @typedef {[PluginCreator, PluginOptions]} PresetPlugin */
14
+ /** @typedef {(options?: any) => { plugins: PresetPlugin[] }} PresetFactory */
15
+ /** @typedef {string | PresetFactory | [string | PresetFactory, object] | { plugins: PresetPlugin[] }} PresetSpec */
16
+ /** @typedef {string | PluginCreator | [string | PluginCreator, object?]} PluginSpec */
17
+ /** @typedef {{ preset?: PresetSpec, plugins?: PluginSpec[], configFile?: string }} Options */
11
18
  /**
12
19
  * @param {string} moduleId
13
20
  * @returns {boolean}
@@ -28,8 +35,8 @@ function isResolvable(moduleId) {
28
35
  * preset = function <- to be invoked
29
36
  * preset = {plugins: []} <- already invoked function
30
37
  *
31
- * @param {any} preset
32
- * @return {[import('postcss').PluginCreator<any>, boolean | Record<string, any> | undefined][]}}
38
+ * @param {unknown} preset
39
+ * @return {PresetPlugin[]}
33
40
  */
34
41
  function resolvePreset(preset) {
35
42
  let fn, options;
@@ -43,7 +50,7 @@ function resolvePreset(preset) {
43
50
  }
44
51
 
45
52
  // For JS setups where we invoked the preset already
46
- if (fn.plugins) {
53
+ if (typeof fn === 'object' && fn !== null && 'plugins' in fn) {
47
54
  return fn.plugins;
48
55
  }
49
56
 
@@ -62,11 +69,13 @@ function resolvePreset(preset) {
62
69
  return require(fn)(options).plugins;
63
70
  }
64
71
 
65
- const sugar = `cssnano-preset-${fn}`;
66
-
67
- // Try loading a preset from node_modules (sugar)
68
- if (isResolvable(sugar)) {
69
- return require(sugar)(options).plugins;
72
+ // Only the built-in preset names support shorthand resolution. Other
73
+ // strings must be passed to the module resolver unchanged.
74
+ if (fn === 'lite' || fn === 'advanced') {
75
+ const sugar = `cssnano-preset-${fn}`;
76
+ if (isResolvable(sugar)) {
77
+ return require(sugar)(options).plugins;
78
+ }
70
79
  }
71
80
 
72
81
  // If all else fails, we probably have a typo in the config somewhere
@@ -76,89 +85,100 @@ function resolvePreset(preset) {
76
85
  }
77
86
 
78
87
  /**
79
- * cssnano will look for configuration firstly as options passed
80
- * directly to it, and failing this it will use lilconfig to
81
- * load an external file.
82
-
83
- * @param {Options} options
88
+ * @param {string} filePath
89
+ * @returns {unknown}
84
90
  */
85
- function resolveConfig(options) {
86
- if (options.preset) {
87
- return resolvePreset(options.preset);
91
+ function loadConfigFile(filePath) {
92
+ if (filePath.endsWith('.json')) {
93
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
88
94
  }
89
-
90
- /** @type {string | undefined} */
91
- let searchPath = process.cwd();
92
- let configPath = undefined;
93
-
94
- if (options.configFile) {
95
- searchPath = undefined;
96
- configPath = path.resolve(process.cwd(), options.configFile);
95
+ const config = createRequire(filePath)(filePath);
96
+ if (
97
+ config !== null &&
98
+ typeof config === 'object' &&
99
+ Object.prototype.toString.call(config) === '[object Module]' &&
100
+ 'default' in config
101
+ ) {
102
+ return config.default;
97
103
  }
104
+ return config;
105
+ }
98
106
 
99
- const configExplorer = lilconfigSync(cssnano, {
100
- searchPlaces: [
101
- 'package.json',
102
- '.cssnanorc',
103
- '.cssnanorc.json',
104
- '.cssnanorc.js',
105
- 'cssnano.config.js',
106
- ],
107
- });
108
- const config = configPath
109
- ? configExplorer.load(configPath)
110
- : configExplorer.search(searchPath);
111
-
112
- if (config === null) {
113
- return resolvePreset('default');
107
+ /**
108
+ * @param {string} [configFile]
109
+ * @returns {unknown | null}
110
+ */
111
+ function loadDiscoveredConfig(configFile) {
112
+ if (configFile) {
113
+ const configPath = path.resolve(process.cwd(), configFile);
114
+ if (!fs.existsSync(configPath)) {
115
+ throw new Error(
116
+ `Cannot find cssnano configuration file "${configFile}".`
117
+ );
118
+ }
119
+ return loadConfigFile(configPath);
114
120
  }
115
121
 
116
- return resolvePreset(config.config.preset || config.config);
122
+ for (const fileName of configFileNames) {
123
+ const configPath = path.join(process.cwd(), fileName);
124
+ if (!fs.existsSync(configPath)) continue;
125
+ return loadConfigFile(configPath);
126
+ }
127
+ return null;
117
128
  }
118
129
 
119
130
  /**
120
- * @type {import('postcss').PluginCreator<Options>}
121
- * @param {Options=} options
122
- * @return {import('postcss').Processor}
131
+ * @param {Options} options
132
+ * @returns {PresetPlugin[]}
123
133
  */
124
- function cssnanoPlugin(options = {}) {
125
- if (Array.isArray(/** @type {Options} */ (options).plugins)) {
134
+ function resolveConfig(options) {
135
+ if (options.preset) {
126
136
  if (
127
- !(/** @type {Options} */ (options).preset) ||
128
- !(/** @type {Options} */ (options).preset.plugins)
137
+ Array.isArray(options.preset) &&
138
+ /** @type {unknown[]} */ (options.preset).length === 0
129
139
  ) {
130
- /** @type {Options} */ (options).preset = { plugins: [] };
140
+ return [];
131
141
  }
142
+ return resolvePreset(options.preset);
143
+ }
144
+ if (Array.isArray(options.plugins)) return [];
145
+
146
+ const config = loadDiscoveredConfig(options.configFile);
147
+ const preset =
148
+ config !== null && typeof config === 'object' && 'preset' in config
149
+ ? config.preset
150
+ : config;
151
+ return resolvePreset(config === null ? 'default' : preset);
152
+ }
132
153
 
133
- const inputPlugins = /** @type {any[]} */ (
134
- /** @type {Options} */ (options).plugins
135
- );
154
+ /**
155
+ * @param {Options=} options
156
+ * @return {import('postcss').Processor}
157
+ */
158
+ function cssnanoPlugin(options = {}) {
159
+ let nanoPlugins = resolveConfig(options);
160
+ if (Array.isArray(options.plugins)) {
161
+ nanoPlugins = nanoPlugins.slice();
162
+ const inputPlugins = options.plugins;
136
163
  for (const plugin of inputPlugins) {
137
164
  if (Array.isArray(plugin)) {
138
165
  const [pluginDef, opts = {}] = plugin;
139
166
  if (typeof pluginDef === 'string' && isResolvable(pluginDef)) {
140
- /** @type {Options} */ (options).preset.plugins.push([
141
- require(pluginDef),
167
+ nanoPlugins.push([
168
+ /** @type {PluginCreator} */ (require(pluginDef)),
142
169
  opts,
143
170
  ]);
144
171
  } else {
145
- /** @type {Options} */ (options).preset.plugins.push([
146
- pluginDef,
147
- opts,
148
- ]);
172
+ nanoPlugins.push([/** @type {PluginCreator} */ (pluginDef), opts]);
149
173
  }
150
174
  } else if (typeof plugin === 'string' && isResolvable(plugin)) {
151
- /** @type {Options} */ (options).preset.plugins.push([
152
- require(plugin),
153
- {},
154
- ]);
175
+ nanoPlugins.push([/** @type {PluginCreator} */ (require(plugin)), {}]);
155
176
  } else {
156
- /** @type {Options} */ (options).preset.plugins.push([plugin, {}]);
177
+ nanoPlugins.push([/** @type {PluginCreator} */ (plugin), {}]);
157
178
  }
158
179
  }
159
180
  }
160
181
  const plugins = [];
161
- const nanoPlugins = resolveConfig(options);
162
182
  for (const nanoPlugin of nanoPlugins) {
163
183
  if (Array.isArray(nanoPlugin)) {
164
184
  const [processor, opts] = nanoPlugin;
@@ -176,5 +196,7 @@ function cssnanoPlugin(options = {}) {
176
196
  return postcss(plugins);
177
197
  }
178
198
 
199
+ /** @type {true} */
179
200
  cssnanoPlugin.postcss = true;
180
- module.exports = cssnanoPlugin;
201
+
202
+ export { cssnanoPlugin as default, cssnanoPlugin as 'module.exports' };
package/types/index.d.ts CHANGED
@@ -1,13 +1,28 @@
1
- export = cssnanoPlugin;
1
+ export type PluginOptions = boolean | {
2
+ exclude?: boolean;
3
+ } | void | undefined;
4
+ export type PluginCreator = import('postcss').PluginCreator<any>;
5
+ export type PresetPlugin = [PluginCreator, PluginOptions];
6
+ export type PresetFactory = (options?: any) => {
7
+ plugins: PresetPlugin[];
8
+ };
9
+ export type PresetSpec = string | PresetFactory | [string | PresetFactory, object] | {
10
+ plugins: PresetPlugin[];
11
+ };
12
+ export type PluginSpec = string | PluginCreator | [string | PluginCreator, object?];
2
13
  export type Options = {
3
- preset?: any;
4
- plugins?: any[];
14
+ preset?: PresetSpec;
15
+ plugins?: PluginSpec[];
5
16
  configFile?: string;
6
17
  };
7
18
  /**
8
- * @type {import('postcss').PluginCreator<Options>}
9
19
  * @param {Options=} options
10
20
  * @return {import('postcss').Processor}
11
21
  */
12
- declare function cssnanoPlugin(options?: {}): any;
22
+ declare function cssnanoPlugin(options?: Options | undefined): import('postcss').Processor;
23
+ declare namespace cssnanoPlugin {
24
+ var _a: true;
25
+ export { _a as postcss };
26
+ }
27
+ export { cssnanoPlugin as default, cssnanoPlugin as 'module.exports' };
13
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"SAmLiB,aAAa;AA1K1B,YAAgE,OAAO,GAA7D;IAAC,MAAM,CAAC,EAAE,GAAG,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAC,CAAS;AA6G3E;;;;GAIG;AACH,iBAAS,aAAa,CAAC,OAAO,KAAK,OAqDlC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAUI,YAA8D,aAAa,GAAjE,OAAO,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAe;AAC3E,YAAgD,aAAa,GAAnD,OAAO,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAe;AAC7D,YAA0C,YAAY,GAA5C,CAAC,aAAa,EAAE,aAAa,CAAC,CAAc;AACtD,YAA0D,aAAa,GAA7D,CAAC,OAAO,CAAC,EAAE,GAAG,KAAK;IAAE,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,CAAe;AACvE,YAAmG,UAAU,GAAnG,MAAM,GAAG,aAAa,GAAG,CAAC,MAAM,GAAG,aAAa,EAAE,MAAM,CAAC,GAAG;IAAE,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,CAAY;AAC7G,YAAsE,UAAU,GAAtE,MAAM,GAAG,aAAa,GAAG,CAAC,MAAM,GAAG,aAAa,EAAE,MAAM,CAAC,CAAC,CAAY;AAChF,YAAgF,OAAO,GAA7E;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAS;AAyI3F;;;GAGG;AACH,iBAAS,aAAa,CAAC,OAAO,AAH3B,CACA,EADQ,OAAO,YAGiB,GAFvB,OAAO,SAAS,EAAE,SAAS,CAyCtC;kBAvCQ,aAAa;YAyCX,IAAI;;;AAGf,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}