From 2ec7eefe6737525ea9dd7ae7f5e3a5c5cd8582d6 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sun, 8 Nov 2026 10:33:39 -0500 Subject: [PATCH] fix(css): migrate cssnano options to native minification --- .changeset/css-minimizer-options.md | 5 + .gitattributes | 1 + README.md | 2 +- codemods/css-plugins-to-native-css/README.md | 78 ++++- .../css-plugins-to-native-css/codemod.yaml | 2 +- .../css-plugins-to-native-css/package.json | 2 +- .../src/minification.ts | 283 ++++++++++++++++++ .../src/minimizer-options.ts | 234 +++++++++++++++ .../css-plugins-to-native-css/src/workflow.ts | 7 +- .../minimizer-comment-callback/expected.js | 3 + .../tests/minimizer-comment-callback/input.js | 3 + .../tests/minimizer-conflict/expected.js | 3 + .../tests/minimizer-conflict/input.js | 3 + .../tests/minimizer-crlf/expected.js | 6 + .../tests/minimizer-crlf/input.js | 7 + .../tests/minimizer-css-disabled/expected.js | 3 + .../tests/minimizer-css-disabled/input.js | 3 + .../tests/minimizer-custom-engine/expected.js | 3 + .../tests/minimizer-custom-engine/input.js | 3 + .../tests/minimizer-custom-preset/expected.js | 3 + .../tests/minimizer-custom-preset/input.js | 3 + .../tests/minimizer-default/expected.js | 6 + .../tests/minimizer-default/input.js | 7 + .../minimizer-duplicate-options/expected.js | 3 + .../minimizer-duplicate-options/input.js | 3 + .../minimizer-dynamic-cssnano/expected.js | 3 + .../tests/minimizer-dynamic-cssnano/input.js | 3 + .../expected.js | 3 + .../minimizer-dynamic-native-options/input.js | 3 + .../minimizer-dynamic-plugin/expected.js | 3 + .../tests/minimizer-dynamic-plugin/input.js | 3 + .../tests/minimizer-esm/expected.mjs | 6 + .../tests/minimizer-esm/input.mjs | 7 + .../minimizer-existing-options/expected.js | 1 + .../tests/minimizer-existing-options/input.js | 3 + .../minimizer-explicit-engine/expected.js | 1 + .../tests/minimizer-explicit-engine/input.js | 3 + .../minimizer-external-config/expected.js | 3 + .../tests/minimizer-external-config/input.js | 3 + .../tests/minimizer-filters/expected.js | 3 + .../tests/minimizer-filters/input.js | 3 + .../tests/minimizer-first-comment/expected.js | 3 + .../tests/minimizer-first-comment/input.js | 3 + .../minimizer-grouped-options/expected.js | 1 + .../tests/minimizer-grouped-options/input.js | 3 + .../tests/minimizer-guarded/expected.js | 3 + .../tests/minimizer-guarded/input.js | 3 + .../tests/minimizer-idempotent/expected.js | 1 + .../tests/minimizer-idempotent/input.js | 1 + .../expected.js | 3 + .../minimizer-inactive-other-options/input.js | 3 + .../minimizer-inline-shadowed/expected.js | 3 + .../tests/minimizer-inline-shadowed/input.js | 3 + .../tests/minimizer-inline/expected.js | 1 + .../tests/minimizer-inline/input.js | 1 + .../tests/minimizer-keep-binding/expected.js | 4 + .../tests/minimizer-keep-binding/input.js | 4 + .../minimizer-keep-shorthand/expected.js | 4 + .../tests/minimizer-keep-shorthand/input.js | 4 + .../tests/minimizer-multiconfig/expected.js | 4 + .../tests/minimizer-multiconfig/input.js | 6 + .../tests/minimizer-multiple/expected.js | 3 + .../tests/minimizer-multiple/input.js | 3 + .../tests/minimizer-namespace/expected.mjs | 1 + .../tests/minimizer-namespace/input.mjs | 3 + .../tests/minimizer-native-spread/expected.js | 3 + .../tests/minimizer-native-spread/input.js | 3 + .../minimizer-nested-options/expected.js | 3 + .../tests/minimizer-nested-options/input.js | 3 + .../tests/minimizer-only-css/expected.js | 1 + .../tests/minimizer-only-css/input.js | 3 + .../tests/minimizer-options/expected.js | 8 + .../tests/minimizer-options/input.js | 26 ++ .../minimizer-other-minimizer/expected.js | 1 + .../tests/minimizer-other-minimizer/input.js | 3 + .../tests/minimizer-parallel/expected.js | 3 + .../tests/minimizer-parallel/input.js | 3 + .../tests/minimizer-reassigned/expected.js | 3 + .../tests/minimizer-reassigned/input.js | 3 + .../expected.js | 1 + .../input.js | 3 + .../tests/minimizer-shadowed/expected.js | 5 + .../tests/minimizer-shadowed/input.js | 5 + .../tests/minimizer-shorthand/expected.js | 1 + .../tests/minimizer-shorthand/input.js | 3 + .../tests/minimizer-spread-array/expected.js | 3 + .../tests/minimizer-spread-array/input.js | 3 + .../tests/minimizer-spread-config/expected.js | 3 + .../tests/minimizer-spread-config/input.js | 3 + .../minimizer-spread-options/expected.js | 3 + .../tests/minimizer-spread-options/input.js | 3 + .../tests/minimizer-typescript/expected.ts | 8 + .../tests/minimizer-typescript/input.ts | 8 + .../minimizer-unknown-option/expected.js | 3 + .../tests/minimizer-unknown-option/input.js | 3 + .../tests/minimizer-unrelated/expected.js | 2 + .../tests/minimizer-unrelated/input.js | 2 + .../tests/minimizer-whitespace/expected.js | 3 + .../tests/minimizer-whitespace/input.js | 3 + .../tests/minimizer-with-loaders/expected.js | 7 + .../tests/minimizer-with-loaders/input.js | 8 + .../css-plugins-to-native-css/workflow.yaml | 3 +- 102 files changed, 941 insertions(+), 6 deletions(-) create mode 100644 .changeset/css-minimizer-options.md create mode 100644 codemods/css-plugins-to-native-css/src/minification.ts create mode 100644 codemods/css-plugins-to-native-css/src/minimizer-options.ts create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-comment-callback/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-comment-callback/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-conflict/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-conflict/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-crlf/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-crlf/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-css-disabled/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-css-disabled/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-custom-engine/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-custom-engine/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-custom-preset/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-custom-preset/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-default/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-default/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-duplicate-options/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-duplicate-options/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-dynamic-cssnano/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-dynamic-cssnano/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-dynamic-native-options/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-dynamic-native-options/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-dynamic-plugin/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-dynamic-plugin/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-esm/expected.mjs create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-esm/input.mjs create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-existing-options/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-existing-options/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-explicit-engine/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-explicit-engine/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-external-config/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-external-config/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-filters/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-filters/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-first-comment/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-first-comment/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-grouped-options/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-grouped-options/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-guarded/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-guarded/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-idempotent/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-idempotent/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-inactive-other-options/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-inactive-other-options/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-inline-shadowed/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-inline-shadowed/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-inline/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-inline/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-keep-binding/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-keep-binding/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-keep-shorthand/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-keep-shorthand/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-multiconfig/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-multiconfig/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-multiple/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-multiple/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-namespace/expected.mjs create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-namespace/input.mjs create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-native-spread/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-native-spread/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-nested-options/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-nested-options/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-only-css/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-only-css/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-options/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-options/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-other-minimizer/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-other-minimizer/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-parallel/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-parallel/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-reassigned/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-reassigned/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-separate-options-precedence/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-separate-options-precedence/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-shadowed/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-shadowed/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-shorthand/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-shorthand/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-spread-array/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-spread-array/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-spread-config/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-spread-config/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-spread-options/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-spread-options/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-typescript/expected.ts create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-typescript/input.ts create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-unknown-option/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-unknown-option/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-unrelated/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-unrelated/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-whitespace/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-whitespace/input.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-with-loaders/expected.js create mode 100644 codemods/css-plugins-to-native-css/tests/minimizer-with-loaders/input.js diff --git a/.changeset/css-minimizer-options.md b/.changeset/css-minimizer-options.md new file mode 100644 index 0000000..275627e --- /dev/null +++ b/.changeset/css-minimizer-options.md @@ -0,0 +1,5 @@ +--- +"@webpack/css-plugins-to-native-css": patch +--- + +Migrate supported css-minimizer-webpack-plugin options from cssnano's default preset to webpack's native CSS minifier. Preserve the build's minimize switch, other asset types, custom minimizers, and compatible native settings; retain unsupported or conflicting configurations for manual migration. diff --git a/.gitattributes b/.gitattributes index 4339578..1c889e4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,4 +3,5 @@ # CRLF fixtures exercise the editor's EOL detection — keep their bytes as-is. codemods/*/tests/crlf/* -text +codemods/*/tests/minimizer-crlf/* -text codemods/html-plugins-to-native-html/tests/template-chunks/crlf/* -text diff --git a/README.md b/README.md index c16dc66..9bb0012 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ npx codemod run @webpack/ | Codemod | Description | | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | -| [`css-plugins-to-native-css`](codemods/css-plugins-to-native-css) | Migrate `mini-css-extract-plugin` and `style-loader`/`css-loader` rules to webpack's native CSS support (`experiments.css`). | +| [`css-plugins-to-native-css`](codemods/css-plugins-to-native-css) | Migrate `mini-css-extract-plugin`, `style-loader`/`css-loader` rules, and supported `css-minimizer-webpack-plugin` options to webpack's native CSS support and minification. | | [`html-plugins-to-native-html`](codemods/html-plugins-to-native-html) | Migrate `html-webpack-plugin` and `html-loader` to native HTML support and minification. | ## Contributing diff --git a/codemods/css-plugins-to-native-css/README.md b/codemods/css-plugins-to-native-css/README.md index 55cc643..2ae88f3 100644 --- a/codemods/css-plugins-to-native-css/README.md +++ b/codemods/css-plugins-to-native-css/README.md @@ -1,9 +1,11 @@ # @webpack/css-plugins-to-native-css -Migrates webpack configurations from `mini-css-extract-plugin` and `style-loader`/`css-loader` rules to webpack's [native CSS support](https://webpack.js.org/configuration/experiments/#experimentscss) (`experiments.css`). +Migrates webpack configurations from `mini-css-extract-plugin`, `style-loader`/`css-loader` rules, and supported `css-minimizer-webpack-plugin` options to webpack's [native CSS support](https://webpack.js.org/configuration/experiments/#experimentscss) (`experiments.css`) and minification. > Requires **webpack >= 5.109.0**: the transform relies on the `experiments.css: "auto"` default introduced there, which enables native CSS whenever no user rule matches `.css` files. +> Migrating `css-minimizer-webpack-plugin` requires **webpack >= 5.112.0** for the native minifier options, including comment extraction control. + ## What it does - Removes rules that only wire up `style-loader`, `css-loader`, and/or `MiniCssExtractPlugin.loader` (cascading to empty `rules`/`module` entries): with no user rule matching `.css`, webpack's `experiments.css: "auto"` default enables native CSS by itself, so no explicit option is needed. @@ -11,6 +13,7 @@ Migrates webpack configurations from `mini-css-extract-plugin` and `style-loader - Any other loader in the chain (`sass-loader`, `less-loader`, `postcss-loader`, custom ones, …) keeps working in front of native CSS: it stays in `use` while the injection/extraction loaders are dropped, and the rule gets `type: "css/auto"`. - Removes `new MiniCssExtractPlugin(...)` from `plugins` (and the whole `plugins` entry when it becomes empty), migrating its options to their native counterparts: `filename` → `output.cssFilename`, `chunkFilename` → `output.cssChunkFilename`. - Removes the `mini-css-extract-plugin` `require`/`import` once it is unused. +- Migrates supported `css-minimizer-webpack-plugin` configurations to `optimization.minimizeOptions.css`, translating cssnano's default preset options and removing the unused plugin import. Existing native options are merged only when they do not conflict. The build's `mode` and `optimization.minimize` switch are preserved. - Migrates `MiniCssExtractPlugin.getCompilationHooks(...)` taps to the native runtime's `webpack.web.CssLoadingRuntimeModule.getCompilationHooks(...)`: `linkPreload`/`linkPrefetch` keep their name and signature, and `beforeTagInsert` maps to `linkInsert` — note its callback now receives `(source, chunk)` instead of `(source, varNames)`, so review taps that used the second argument. - Understands conditional patterns (including ejected Create React App configs): the `isDev ? "style-loader" : MiniCssExtractPlugin.loader` ternary, `isEnvDevelopment && "style-loader"` guards, `require.resolve("css-loader")`, and `[...].filter(Boolean)` around `use` and `plugins`. Function-form configs (`module.exports = (env) => ({...})`) and `webpack-merge` fragments work too. - Loader options are translated while migrating. `importLoaders`, `esModule`, and `sourceMap: true` are dropped silently (native CSS covers them). css-loader's boolean `url`/`import` become the rule's `parser: { url, import }`, `sourceMap: false` turns any non-array `devtool` into its per-asset-type form (`[{ type: "javascript", use: … }, { type: "css", use: false }]`), and on `.module.css`-scoped rules the `modules` sub-options map too: `localIdentName`/`exportOnlyLocals`/`exportLocalsConvention` → `generator`, `namedExport` → `parser.namedExports`. More translations: `exportType: "css-style-sheet"`/`"string"` → `parser.exportType`, the extract loader's `emit: false` (SSR) → `generator: { exportsOnly: true }`, `modules.mode` → `type: "css/global"` for `"global"` / `parser: { pure: true }` for `"pure"`, style-loader's `attributes.crossorigin` → `output.crossOriginLoading`, and the extract loader's `layer` → the rule-level `layer` (enabling `experiments.layers`). A flagged `attributes.nonce` migrates manually: set the `__webpack_nonce__` runtime global, or `output.html.csp.nonce` when webpack emits your HTML. Options native CSS cannot replicate — `modules.getLocalIdent`, style-loader's `insert`/`attributes`, non-literal values, or `modules` on a rule that also matches plain `.css` files — are dropped with a `// Removed loader options without a native CSS equivalent: …` comment so you can review the behavior change. @@ -89,3 +92,76 @@ module.exports = { ``` The codemod also removes `mini-css-extract-plugin`, `style-loader`, and `css-loader` from your `package.json` (`dependencies` and `devDependencies`). If other tooling in the repo still uses them (Storybook, test setups, …), reinstall the ones you need. + +## Minifier options + +The [cssnano default preset](https://cssnano.github.io/cssnano/docs/presets/) uses different option names from [webpack's native CSS minifier](https://webpack.js.org/configuration/optimization/#optimizationminimizecss). The codemod translates supported literal options instead of copying the cssnano object unchanged. + +Before: + +```js +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { + optimization: { + minimizer: [ + "...", + new CssMinimizerPlugin({ + minimizerOptions: { + preset: ["default", { + discardComments: { removeAll: true }, + colormin: false, + mergeLonghand: false, + }], + }, + }), + ], + }, +}; +``` + +After: + +```js +module.exports = { + optimization: { + minimizeOptions: { + css: { + comments: false, + extractComments: false, + shortenColors: false, + mergeLonghands: false, + }, + }, + minimizer: ["..."], + }, +}; +``` + +Supported preset options: + +| cssnano option | Native CSS option | +| --- | --- | +| `discardComments: false` | `comments: true` | +| `discardComments: { removeAll: true }` | `comments: false` | +| Default comment handling | `comments: /^!/`, keeping `/*!` comments in the stylesheet | +| `colormin` | `shortenColors` | +| `mergeLonghand` | `mergeLonghands` | +| `mergeRules` | `mergeRules`; disabling it also disables `mergeDistantRules` | +| `discardDuplicates`, `discardEmpty`, `discardOverridden` | `removeDeadRules` | +| `normalizeString`, `normalizeUrl` | `normalizeQuotes` | +| `calc`, `minifyGradients`, `reduceTransforms`, `normalizeTimingFunctions` | `reduceFunctions` | +| `minifySelectors`, `uniqueSelectors` | `shortenSelectors` | +| `minifyParams` | `shortenMediaQueries` | +| `reduceInitial`, `minifyFontValues`, `orderedValues`, `normalizeDisplayValues`, `normalizePositions`, `normalizeRepeatStyle` | `shortenValues` | +| `cssDeclarationSorter` | `reorderDeclarations` | +| `convertValues` | `shortenNumbers`; `{ length: true/false }` sets `convertLengthUnits` | +| `merge` | `mergeLonghands`, `mergeRules`, `removeDeadRules`; `{ rules: false }` disables rule merging only | + +Transform toggles accept booleans, empty objects, and `{ exclude: true/false }`. A native switch can cover several cssnano passes: disabling any of them disables the whole native group, so the migrated build may perform fewer optimizations. Comment extraction is disabled to keep cssnano's comments in the stylesheet. + +When the original `minimizer` array has no `"..."`, the migrated CSS plugin is replaced with `"..."` and the native JavaScript, HTML, JSON, and XML minimizers are disabled. Other custom minimizers stay in their original order. Existing `minimizeOptions` takes precedence over the object shorthand in `minimize`, following webpack's normalization. + +Unsupported settings keep the original plugin and all its options: custom engines or presets, callbacks, asset filters, worker limits, dynamic/spread options, multiple CSS minimizers, conditional minimizers, and conflicting native options. Nested settings without an equivalent, such as `calc.precision`, or disabling whitespace normalization also require manual migration. An explicit `minimizerOptions` object without a preset is retained because cssnano can load an external configuration. + +The `css-minimizer-webpack-plugin` package dependency is retained because other files or unsupported configurations may still use it. Remove it after reviewing the remaining uses in your project. diff --git a/codemods/css-plugins-to-native-css/codemod.yaml b/codemods/css-plugins-to-native-css/codemod.yaml index 1f56e8e..69a4951 100644 --- a/codemods/css-plugins-to-native-css/codemod.yaml +++ b/codemods/css-plugins-to-native-css/codemod.yaml @@ -1,7 +1,7 @@ schema_version: "1.0" name: "@webpack/css-plugins-to-native-css" version: "1.0.0" -description: Migrate mini-css-extract-plugin and style-loader/css-loader rules to webpack's native CSS support (experiments.css) +description: Migrate CSS plugins, loaders, and supported css-minimizer-webpack-plugin options to webpack's native CSS support and minification author: bjohansebas (Sebastian Beltran) license: MIT workflow: workflow.yaml diff --git a/codemods/css-plugins-to-native-css/package.json b/codemods/css-plugins-to-native-css/package.json index 618e796..b6b1295 100644 --- a/codemods/css-plugins-to-native-css/package.json +++ b/codemods/css-plugins-to-native-css/package.json @@ -2,7 +2,7 @@ "name": "@webpack/css-plugins-to-native-css", "private": true, "version": "1.0.0", - "description": "Migrate mini-css-extract-plugin and style-loader/css-loader rules to webpack's native CSS support (experiments.css).", + "description": "Migrate CSS plugins, loaders, and supported css-minimizer-webpack-plugin options to webpack's native CSS support and minification.", "type": "module", "scripts": { "test": "npm run test:workflow && npm run test:dependencies", diff --git a/codemods/css-plugins-to-native-css/src/minification.ts b/codemods/css-plugins-to-native-css/src/minification.ts new file mode 100644 index 0000000..c27b78b --- /dev/null +++ b/codemods/css-plugins-to-native-css/src/minification.ts @@ -0,0 +1,283 @@ +import type Js from "@codemod.com/jssg-types/langs/javascript"; +import type Ts from "@codemod.com/jssg-types/langs/typescript"; +import type { SgNode } from "@codemod.com/jssg-types/main"; +import { + ConfigEditor, + type ModuleBinding, + collectModuleBindings, + keyName, + namedChildren, + parseExpression, + sameSyntax, + staticString, +} from "@webpack/codemod-utils"; + +import { cssnanoOptions, literalProperties, type NativeCssOptions } from "./minimizer-options"; + +const MINIMIZER_MODULE = "css-minimizer-webpack-plugin"; +const OTHER_ASSETS = ["javascript", "html", "json", "xml"]; + +function expressionOf(node: SgNode): SgNode { + while (node.is("parenthesized_expression")) { + const inner = namedChildren(node).find((child) => !child.is("comment")); + + if (!inner) { + break; + } + + node = inner; + } + + return node; +} + +function isMinimizer(node: SgNode, bindings: ModuleBinding[]): boolean { + node = expressionOf(node); + + if (node.is("identifier")) { + const binding = bindings.find((binding) => binding.name === node.text()); + const definition = binding && node.definition({ resolveExternal: false }); + + if (!binding || !definition || definition.root.filename() !== node.getRoot().filename()) { + return false; + } + + const position = definition.node.range().start.index; + const statement = binding.statement.range(); + + return position >= statement.start.index && position < statement.end.index; + } + + if (node.is("member_expression") && node.field("property")?.text() === "default") { + const object = node.field("object"); + + return !!object && isMinimizer(object, bindings); + } + + if (!node.is("call_expression")) { + return false; + } + + const callee = node.field("function"); + const argumentsNode = node.field("arguments"); + const args = argumentsNode && namedChildren(argumentsNode).filter((arg) => !arg.is("comment")); + + return ( + !!callee?.is("identifier") && + callee.text() === "require" && + !callee.definition({ resolveExternal: false }) && + args?.length === 1 && + staticString(args[0]) === MINIMIZER_MODULE + ); +} + +function collectOptions(instance: SgNode, bindings: ModuleBinding[]): NativeCssOptions | null { + const argumentsNode = instance.field("arguments"); + const args = argumentsNode + ? namedChildren(argumentsNode).filter((arg) => !arg.is("comment")) + : []; + + if (!args.length) { + return cssnanoOptions(); + } + + const properties = args.length === 1 && literalProperties(args[0]); + + if (!properties) { + return null; + } + + for (const [name, value] of properties) { + if (name === "minimizerOptions" || (name === "parallel" && value.is("true"))) { + continue; + } + + if (name === "minify" && value.is("member_expression")) { + const object = value.field("object"); + + if ( + object && + isMinimizer(object, bindings) && + value.field("property")?.text() === "cssnanoMinify" + ) { + continue; + } + } + + // Asset filters, custom engines, warning filters and worker limits have no + // equivalent in minimizeOptions.css. Keep the plugin and all its options. + return null; + } + + return cssnanoOptions(properties.get("minimizerOptions")); +} + +function nativeOptionsText(options: NativeCssOptions): string { + return `{ ${[...options].map(([name, value]) => `${name}: ${value}`).join(", ")} }`; +} + +// Compute every insertion before touching the AST so conflicts leave the +// original minimizer intact. Explicit minimizeOptions overrides the shorthand. +function planOptions( + editor: ConfigEditor, + optimization: SgNode, + properties: Map>, + css: NativeCssOptions, + hasDefaults: boolean, +): (() => void) | null { + const minimize = properties.get("minimize"); + const options = + properties.get("minimizeOptions") ?? (minimize?.is("object") ? minimize : undefined); + const existing = options ? literalProperties(options) : new Map>(); + + if (!existing) { + return null; + } + + const existingCss = existing.get("css"); + const cssProperties = existingCss + ? literalProperties(existingCss) + : new Map>(); + + if (!cssProperties) { + return null; + } + + for (const [name, value] of css) { + const configured = cssProperties.get(name); + + if (configured && !sameSyntax(configured, parseExpression(value))) { + return null; + } + } + + const additions: string[] = []; + + if (!hasDefaults) { + // Adding "..." must not turn on JS/HTML/JSON/XML minification that the + // original custom minimizer array had disabled. + for (const type of OTHER_ASSETS) { + const configured = existing.get(type); + + if (configured && !configured.is("false")) { + return null; + } + + if (!configured) { + additions.push(`${type}: false`); + } + } + } + + const missingCss = [...css].filter(([name]) => !cssProperties.has(name)); + + if (!existingCss) { + additions.push(`css: ${nativeOptionsText(css)}`); + } + + return () => { + if (existingCss && missingCss.length) { + editor.insertIntoObject(existingCss, () => + missingCss.map(([name, value]) => `${name}: ${value}`), + ); + } + + if (!additions.length) { + return; + } + + if (options) { + editor.insertIntoObject(options, () => additions); + } else { + editor.insertIntoObject(optimization, () => [`minimizeOptions: { ${additions.join(", ")} }`]); + } + }; +} + +export function migrateMinimizers(editor: ConfigEditor): ModuleBinding[] { + const assignments = editor.rootNode.findAll({ + rule: { any: [{ kind: "assignment_expression" }, { kind: "augmented_assignment_expression" }] }, + }); + const assignedNames = new Set(assignments.flatMap((assignment) => { + const target = assignment.field("left"); + const names = target?.findAll({ + rule: { any: [{ kind: "identifier" }, { kind: "shorthand_property_identifier_pattern" }] }, + }); + + return names?.map((node) => node.text()) ?? []; + })); + const bindings = collectModuleBindings(editor.rootNode, MINIMIZER_MODULE).filter( + (binding) => !assignedNames.has(binding.name), + ); + + for (const pair of editor.rootNode.findAll({ rule: { kind: "pair" } })) { + if (keyName(pair) !== "optimization") { + continue; + } + + const config = pair.parent(); + const optimization = pair.field("value"); + + if (!config || !literalProperties(config) || !optimization) { + continue; + } + + const properties = literalProperties(optimization); + const minimizer = properties?.get("minimizer"); + + if (!properties || !minimizer?.is("array")) { + continue; + } + + const elements = namedChildren(minimizer).filter((node) => !node.is("comment")); + + if (elements.some((element) => element.is("spread_element"))) { + continue; + } + + const instances = minimizer.findAll({ rule: { kind: "new_expression" } }).filter((node) => { + const constructor = node.field("constructor"); + + return constructor && isMinimizer(constructor, bindings); + }); + + if (instances.length !== 1) { + continue; + } + + const instance = instances[0]; + const element = elements.find( + (node) => expressionOf(node).range().start.index === instance.range().start.index, + ); + const css = collectOptions(instance, bindings); + + if (!element || !css) { + continue; + } + + const hasDefaults = elements.some((node) => staticString(node) === "..."); + const applyOptions = planOptions(editor, optimization, properties, css, hasDefaults); + + if (!applyOptions) { + continue; + } + + applyOptions(); + + if (hasDefaults) { + editor.markForRemoval(element); + } else { + editor.replace(element, '"..."'); + } + } + + // ConfigEditor checks ordinary identifier references. Retain bindings also + // used as shorthand properties or TypeScript types outside a constructor. + const otherReferences = (editor.rootNode as unknown as SgNode).findAll({ + rule: { any: [{ kind: "shorthand_property_identifier" }, { kind: "type_identifier" }] }, + }); + + return bindings.filter( + (binding) => !otherReferences.some((reference) => reference.text() === binding.name), + ); +} diff --git a/codemods/css-plugins-to-native-css/src/minimizer-options.ts b/codemods/css-plugins-to-native-css/src/minimizer-options.ts new file mode 100644 index 0000000..ba2d0c6 --- /dev/null +++ b/codemods/css-plugins-to-native-css/src/minimizer-options.ts @@ -0,0 +1,234 @@ +import type Js from "@codemod.com/jssg-types/langs/javascript"; +import type { SgNode } from "@codemod.com/jssg-types/main"; +import { namedChildren, staticString } from "@webpack/codemod-utils"; + +export type NativeCssOptions = Map; + +// A native switch can cover several cssnano passes. Disabling any of those +// passes disables the whole group, even if another pass is explicitly enabled. +const TRANSFORMS = new Map([ + ["colormin", ["shortenColors"]], + ["mergeLonghand", ["mergeLonghands"]], + ["mergeRules", ["mergeRules"]], + ["discardDuplicates", ["removeDeadRules"]], + ["discardEmpty", ["removeDeadRules"]], + ["discardOverridden", ["removeDeadRules"]], + ["normalizeString", ["normalizeQuotes"]], + ["normalizeUrl", ["normalizeQuotes"]], + ["calc", ["reduceFunctions"]], + ["minifyGradients", ["reduceFunctions"]], + ["reduceTransforms", ["reduceFunctions"]], + ["normalizeTimingFunctions", ["reduceFunctions"]], + ["minifySelectors", ["shortenSelectors"]], + ["uniqueSelectors", ["shortenSelectors"]], + ["minifyParams", ["shortenMediaQueries"]], + ["reduceInitial", ["shortenValues"]], + ["minifyFontValues", ["shortenValues"]], + ["orderedValues", ["shortenValues"]], + ["normalizeDisplayValues", ["shortenValues"]], + ["normalizePositions", ["shortenValues"]], + ["normalizeRepeatStyle", ["shortenValues"]], + ["cssDeclarationSorter", ["reorderDeclarations"]], + ["merge", ["mergeLonghands", "mergeRules", "removeDeadRules"]], +]); + +// Spreads, getters, computed keys and duplicate keys need runtime evaluation. +// Reject the whole object rather than silently discard an option. +export function literalProperties(node: SgNode): Map> | null { + if (!node.is("object")) { + return null; + } + + const properties = new Map>(); + + for (const child of namedChildren(node)) { + if (child.is("comment")) { + continue; + } + + const key = child.field("key"); + const value = child.field("value"); + const name = key?.is("property_identifier") ? key.text() : staticString(key); + + if (!child.is("pair") || name === null || !value || properties.has(name)) { + return null; + } + + properties.set(name, value); + } + + return properties; +} + +function enabledOption(node: SgNode): boolean | null { + if (node.is("true") || node.is("false")) { + return node.is("true"); + } + + const properties = literalProperties(node); + + if (!properties) { + return null; + } + + if (!properties.size) { + return true; + } + + const exclude = properties.get("exclude"); + + return properties.size === 1 && (exclude?.is("true") || exclude?.is("false")) + ? exclude.is("false") + : null; +} + +function setTransform(options: NativeCssOptions, name: string, enabled: boolean): void { + if (options.get(name) !== "false") { + options.set(name, String(enabled)); + } + + if (name === "mergeRules" && !enabled) { + options.set("mergeDistantRules", "false"); + } +} + +function translateComments(node: SgNode, options: NativeCssOptions): boolean { + const enabled = enabledOption(node); + + if (enabled !== null) { + options.set("comments", enabled ? "/^!/" : "true"); + + return true; + } + + const properties = literalProperties(node); + + if (!properties) { + return false; + } + + for (const [name, value] of properties) { + if (name === "removeAll" && (value.is("true") || value.is("false"))) { + continue; + } + + if (name === "removeAllButFirst" && value.is("false")) { + continue; + } + + return false; + } + + options.set("comments", properties.get("removeAll")?.is("true") ? "false" : "/^!/"); + + return true; +} + +function translateConversions(node: SgNode, options: NativeCssOptions): boolean { + const enabled = enabledOption(node); + + if (enabled !== null) { + setTransform(options, "shortenNumbers", enabled); + options.set("convertLengthUnits", "false"); + + return true; + } + + const properties = literalProperties(node); + const length = properties?.get("length"); + + if (properties?.size !== 1 || (!length?.is("true") && !length?.is("false"))) { + return false; + } + + options.set("convertLengthUnits", length.text()); + + return true; +} + +function translatePreset(node: SgNode, options: NativeCssOptions): boolean { + const properties = literalProperties(node); + + if (!properties) { + return false; + } + + for (const [name, value] of properties) { + if (name === "discardComments") { + if (!translateComments(value, options)) { + return false; + } + + continue; + } + + if (name === "convertValues") { + if (!translateConversions(value, options)) { + return false; + } + + continue; + } + + // cssnano's combined merge pass also allows just rule merging to be off. + if (name === "merge" && value.is("object")) { + const merge = literalProperties(value); + const rules = merge?.get("rules"); + + if (merge?.size === 1 && (rules?.is("true") || rules?.is("false"))) { + setTransform(options, "mergeRules", rules.is("true")); + + continue; + } + } + + const enabled = enabledOption(value); + const transforms = TRANSFORMS.get(name); + + if (!transforms || enabled === null) { + return false; + } + + for (const transform of transforms) { + setTransform(options, transform, enabled); + } + } + + return true; +} + +export function cssnanoOptions(value?: SgNode): NativeCssOptions | null { + // cssnano keeps /*! comments in the CSS, without extracting a LICENSE file. + const options: NativeCssOptions = new Map([ + ["comments", "/^!/"], + ["extractComments", "false"], + ]); + + if (!value) { + return options; + } + + const properties = literalProperties(value); + const preset = properties?.get("preset"); + + // Without an explicit preset, cssnano may load an external config file. + if (properties?.size !== 1 || !preset) { + return null; + } + + if (staticString(preset) === "default") { + return options; + } + + if (!preset.is("array")) { + return null; + } + + const entries = namedChildren(preset).filter((node) => !node.is("comment")); + + if (staticString(entries[0]) !== "default" || entries.length > 2) { + return null; + } + + return entries.length === 1 || translatePreset(entries[1], options) ? options : null; +} diff --git a/codemods/css-plugins-to-native-css/src/workflow.ts b/codemods/css-plugins-to-native-css/src/workflow.ts index 50942bd..af5538d 100644 --- a/codemods/css-plugins-to-native-css/src/workflow.ts +++ b/codemods/css-plugins-to-native-css/src/workflow.ts @@ -20,6 +20,8 @@ import { unwrapFilterCall, } from "@webpack/codemod-utils"; +import { migrateMinimizers } from "./minification"; + const PLUGIN_MODULE = "mini-css-extract-plugin"; const REMOVABLE_LOADERS = new Set(["style-loader", "css-loader"]); const EXTRACT_LOADER_NAME = "MiniCssExtractPlugin.loader"; @@ -145,9 +147,12 @@ class CssMigration { this.transformPlugins(pluginsPairs); this.migrateCompilationHooks(); this.planConfigInsertions(); + + const minimizerBindings = migrateMinimizers(this.editor); + this.editor.finalizeRemovals(); if (!this.editor.hasEdits) return null; - for (const binding of this.pluginBindings) { + for (const binding of [...this.pluginBindings, ...minimizerBindings]) { if (this.repurposedStatements.has(binding.statement.range().start.index)) continue; this.editor.removeBindingIfUnused(binding); } diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-comment-callback/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-comment-callback/expected.js new file mode 100644 index 0000000..468af5f --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-comment-callback/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { discardComments: { remove: (comment) => comment.includes("license") } }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-comment-callback/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-comment-callback/input.js new file mode 100644 index 0000000..468af5f --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-comment-callback/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { discardComments: { remove: (comment) => comment.includes("license") } }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-conflict/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-conflict/expected.js new file mode 100644 index 0000000..e55b018 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-conflict/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { css: { comments: false } }, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-conflict/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-conflict/input.js new file mode 100644 index 0000000..e55b018 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-conflict/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { css: { comments: false } }, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-crlf/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-crlf/expected.js new file mode 100644 index 0000000..deaedce --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-crlf/expected.js @@ -0,0 +1,6 @@ +module.exports = { + optimization: { + minimizeOptions: { css: { comments: /^!/, extractComments: false } }, + minimizer: ["..."], + }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-crlf/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-crlf/input.js new file mode 100644 index 0000000..542a638 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-crlf/input.js @@ -0,0 +1,7 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { + optimization: { + minimizer: ["...", new CssMinimizerPlugin()], + }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-css-disabled/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-css-disabled/expected.js new file mode 100644 index 0000000..ef8a704 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-css-disabled/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { css: false }, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-css-disabled/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-css-disabled/input.js new file mode 100644 index 0000000..ef8a704 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-css-disabled/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { css: false }, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-custom-engine/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-custom-engine/expected.js new file mode 100644 index 0000000..7d70cf4 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-custom-engine/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minify: CssMinimizerPlugin.lightningCssMinify, minimizerOptions: { targets: { chrome: 80 } } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-custom-engine/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-custom-engine/input.js new file mode 100644 index 0000000..7d70cf4 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-custom-engine/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minify: CssMinimizerPlugin.lightningCssMinify, minimizerOptions: { targets: { chrome: 80 } } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-custom-preset/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-custom-preset/expected.js new file mode 100644 index 0000000..fa787c3 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-custom-preset/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: "advanced" } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-custom-preset/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-custom-preset/input.js new file mode 100644 index 0000000..fa787c3 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-custom-preset/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: "advanced" } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-default/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-default/expected.js new file mode 100644 index 0000000..8d442f8 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-default/expected.js @@ -0,0 +1,6 @@ +module.exports = { + optimization: { + minimizeOptions: { css: { comments: /^!/, extractComments: false } }, + minimizer: ["..."], + }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-default/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-default/input.js new file mode 100644 index 0000000..ae29924 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-default/input.js @@ -0,0 +1,7 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { + optimization: { + minimizer: ["...", new CssMinimizerPlugin()], + }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-duplicate-options/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-duplicate-options/expected.js new file mode 100644 index 0000000..9352d72 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-duplicate-options/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { colormin: false, colormin: true }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-duplicate-options/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-duplicate-options/input.js new file mode 100644 index 0000000..9352d72 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-duplicate-options/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { colormin: false, colormin: true }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-cssnano/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-cssnano/expected.js new file mode 100644 index 0000000..081a550 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-cssnano/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: options })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-cssnano/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-cssnano/input.js new file mode 100644 index 0000000..081a550 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-cssnano/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: options })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-native-options/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-native-options/expected.js new file mode 100644 index 0000000..632e875 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-native-options/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: options, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-native-options/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-native-options/input.js new file mode 100644 index 0000000..632e875 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-native-options/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: options, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-plugin/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-plugin/expected.js new file mode 100644 index 0000000..c01ba6d --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-plugin/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin(options)] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-plugin/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-plugin/input.js new file mode 100644 index 0000000..c01ba6d --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-dynamic-plugin/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin(options)] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-esm/expected.mjs b/codemods/css-plugins-to-native-css/tests/minimizer-esm/expected.mjs new file mode 100644 index 0000000..69f3a58 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-esm/expected.mjs @@ -0,0 +1,6 @@ +export default { + optimization: { + minimizeOptions: { css: { comments: true, extractComments: false } }, + minimizer: ["..."], + }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-esm/input.mjs b/codemods/css-plugins-to-native-css/tests/minimizer-esm/input.mjs new file mode 100644 index 0000000..7f1c12c --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-esm/input.mjs @@ -0,0 +1,7 @@ +import MinifyCss from "css-minimizer-webpack-plugin"; + +export default { + optimization: { + minimizer: ["...", new MinifyCss({ minimizerOptions: { preset: ["default", { discardComments: false }] } })], + }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-existing-options/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-existing-options/expected.js new file mode 100644 index 0000000..399c31b --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-existing-options/expected.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimizeOptions: { javascript: { compress: false }, css: { comments: /^!/, extractComments: false, mergeDistantRules: false, mergeRules: false } }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-existing-options/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-existing-options/input.js new file mode 100644 index 0000000..8a1f387 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-existing-options/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { javascript: { compress: false }, css: { mergeRules: false } }, minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { mergeRules: false }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-explicit-engine/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-explicit-engine/expected.js new file mode 100644 index 0000000..0477d47 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-explicit-engine/expected.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimizeOptions: { css: { comments: /^!/, extractComments: false } }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-explicit-engine/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-explicit-engine/input.js new file mode 100644 index 0000000..b406740 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-explicit-engine/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ parallel: true, minify: CssMinimizerPlugin.cssnanoMinify, minimizerOptions: { preset: "default" } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-external-config/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-external-config/expected.js new file mode 100644 index 0000000..ce9ed9a --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-external-config/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: {} })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-external-config/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-external-config/input.js new file mode 100644 index 0000000..ce9ed9a --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-external-config/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: {} })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-filters/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-filters/expected.js new file mode 100644 index 0000000..0e63c0c --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-filters/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ include: /vendor/, minimizerOptions: { preset: "default" } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-filters/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-filters/input.js new file mode 100644 index 0000000..0e63c0c --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-filters/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ include: /vendor/, minimizerOptions: { preset: "default" } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-first-comment/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-first-comment/expected.js new file mode 100644 index 0000000..4623ad5 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-first-comment/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { discardComments: { removeAllButFirst: true } }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-first-comment/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-first-comment/input.js new file mode 100644 index 0000000..4623ad5 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-first-comment/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { discardComments: { removeAllButFirst: true } }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-grouped-options/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-grouped-options/expected.js new file mode 100644 index 0000000..a18057b --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-grouped-options/expected.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimizeOptions: { css: { comments: /^!/, extractComments: false, reduceFunctions: false, removeDeadRules: false, shortenNumbers: false, convertLengthUnits: false, mergeRules: false, mergeDistantRules: false } }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-grouped-options/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-grouped-options/input.js new file mode 100644 index 0000000..2b7713d --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-grouped-options/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { calc: false, reduceTransforms: true, discardEmpty: { exclude: true }, discardDuplicates: {}, convertValues: false, merge: { rules: false } }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-guarded/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-guarded/expected.js new file mode 100644 index 0000000..fc8d040 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-guarded/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", isProduction && new CssMinimizerPlugin()].filter(Boolean) } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-guarded/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-guarded/input.js new file mode 100644 index 0000000..fc8d040 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-guarded/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", isProduction && new CssMinimizerPlugin()].filter(Boolean) } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-idempotent/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-idempotent/expected.js new file mode 100644 index 0000000..0477d47 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-idempotent/expected.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimizeOptions: { css: { comments: /^!/, extractComments: false } }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-idempotent/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-idempotent/input.js new file mode 100644 index 0000000..0477d47 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-idempotent/input.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimizeOptions: { css: { comments: /^!/, extractComments: false } }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-inactive-other-options/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-inactive-other-options/expected.js new file mode 100644 index 0000000..10f1c09 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-inactive-other-options/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { javascript: { compress: false } }, minimizer: [new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-inactive-other-options/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-inactive-other-options/input.js new file mode 100644 index 0000000..10f1c09 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-inactive-other-options/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { javascript: { compress: false } }, minimizer: [new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-inline-shadowed/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-inline-shadowed/expected.js new file mode 100644 index 0000000..ac41586 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-inline-shadowed/expected.js @@ -0,0 +1,3 @@ +module.exports = (require) => ({ + optimization: { minimizer: [new (require("css-minimizer-webpack-plugin"))()] }, +}); diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-inline-shadowed/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-inline-shadowed/input.js new file mode 100644 index 0000000..ac41586 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-inline-shadowed/input.js @@ -0,0 +1,3 @@ +module.exports = (require) => ({ + optimization: { minimizer: [new (require("css-minimizer-webpack-plugin"))()] }, +}); diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-inline/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-inline/expected.js new file mode 100644 index 0000000..5565411 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-inline/expected.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimizeOptions: { javascript: false, html: false, json: false, xml: false, css: { comments: /^!/, extractComments: false } }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-inline/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-inline/input.js new file mode 100644 index 0000000..a8c6ee6 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-inline/input.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimizer: [new (require("css-minimizer-webpack-plugin"))()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-keep-binding/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-keep-binding/expected.js new file mode 100644 index 0000000..4a2c75e --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-keep-binding/expected.js @@ -0,0 +1,4 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +console.log(CssMinimizerPlugin); +module.exports = { optimization: { minimizeOptions: { css: { comments: /^!/, extractComments: false } }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-keep-binding/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-keep-binding/input.js new file mode 100644 index 0000000..d70b78f --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-keep-binding/input.js @@ -0,0 +1,4 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +console.log(CssMinimizerPlugin); +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-keep-shorthand/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-keep-shorthand/expected.js new file mode 100644 index 0000000..1f5ba38 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-keep-shorthand/expected.js @@ -0,0 +1,4 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { css: { comments: /^!/, extractComments: false } }, minimizer: ["..."] } }; +const otherTools = { CssMinimizerPlugin }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-keep-shorthand/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-keep-shorthand/input.js new file mode 100644 index 0000000..52d52ef --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-keep-shorthand/input.js @@ -0,0 +1,4 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin()] } }; +const otherTools = { CssMinimizerPlugin }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-multiconfig/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-multiconfig/expected.js new file mode 100644 index 0000000..e2f4401 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-multiconfig/expected.js @@ -0,0 +1,4 @@ +module.exports = [ + { optimization: { minimizeOptions: { css: { comments: false, extractComments: false } }, minimizer: ["..."] } }, + { optimization: { minimizeOptions: { css: { comments: true, extractComments: false } }, minimizer: ["..."] } }, +]; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-multiconfig/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-multiconfig/input.js new file mode 100644 index 0000000..8fa80fa --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-multiconfig/input.js @@ -0,0 +1,6 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = [ + { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { discardComments: { removeAll: true } }] } })] } }, + { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { discardComments: false }] } })] } }, +]; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-multiple/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-multiple/expected.js new file mode 100644 index 0000000..6a93233 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-multiple/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin(), new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-multiple/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-multiple/input.js new file mode 100644 index 0000000..6a93233 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-multiple/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin(), new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-namespace/expected.mjs b/codemods/css-plugins-to-native-css/tests/minimizer-namespace/expected.mjs new file mode 100644 index 0000000..2198305 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-namespace/expected.mjs @@ -0,0 +1 @@ +export default { optimization: { minimizeOptions: { css: { comments: /^!/, extractComments: false } }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-namespace/input.mjs b/codemods/css-plugins-to-native-css/tests/minimizer-namespace/input.mjs new file mode 100644 index 0000000..29157b4 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-namespace/input.mjs @@ -0,0 +1,3 @@ +import * as CssMinimizer from "css-minimizer-webpack-plugin"; + +export default { optimization: { minimizer: ["...", new CssMinimizer.default()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-native-spread/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-native-spread/expected.js new file mode 100644 index 0000000..34b364a --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-native-spread/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { ...options }, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-native-spread/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-native-spread/input.js new file mode 100644 index 0000000..34b364a --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-native-spread/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizeOptions: { ...options }, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-nested-options/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-nested-options/expected.js new file mode 100644 index 0000000..744d913 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-nested-options/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { calc: { precision: 2 } }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-nested-options/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-nested-options/input.js new file mode 100644 index 0000000..744d913 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-nested-options/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { calc: { precision: 2 } }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-only-css/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-only-css/expected.js new file mode 100644 index 0000000..bec9bf6 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-only-css/expected.js @@ -0,0 +1 @@ +module.exports = { mode: "development", optimization: { minimizeOptions: { javascript: false, html: false, json: false, xml: false, css: { comments: /^!/, extractComments: false } }, minimize: false, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-only-css/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-only-css/input.js new file mode 100644 index 0000000..e8d3a6a --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-only-css/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { mode: "development", optimization: { minimize: false, minimizer: [new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-options/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-options/expected.js new file mode 100644 index 0000000..627fa8e --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-options/expected.js @@ -0,0 +1,8 @@ +module.exports = { + mode: "production", + optimization: { + minimizeOptions: { css: { comments: false, extractComments: false, shortenColors: false, mergeLonghands: false, mergeRules: false, mergeDistantRules: false, removeDeadRules: false, normalizeQuotes: false, reduceFunctions: false, shortenSelectors: false, shortenMediaQueries: false, shortenValues: false, reorderDeclarations: false, convertLengthUnits: true } }, + minimize: true, + minimizer: ["..."], + }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-options/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-options/input.js new file mode 100644 index 0000000..805c6d7 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-options/input.js @@ -0,0 +1,26 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { + mode: "production", + optimization: { + minimize: true, + minimizer: ["...", new CssMinimizerPlugin({ + minimizerOptions: { + preset: ["default", { + discardComments: { removeAll: true }, + colormin: false, + mergeLonghand: false, + mergeRules: false, + discardEmpty: false, + normalizeString: false, + calc: false, + minifySelectors: false, + minifyParams: false, + reduceInitial: false, + cssDeclarationSorter: false, + convertValues: { length: true }, + }], + }, + })], + }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-other-minimizer/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-other-minimizer/expected.js new file mode 100644 index 0000000..a645d91 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-other-minimizer/expected.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimizeOptions: { javascript: false, html: false, json: false, xml: false, css: { comments: /^!/, extractComments: false } }, minimizer: [new TerserPlugin({ extractComments: false }), "..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-other-minimizer/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-other-minimizer/input.js new file mode 100644 index 0000000..26dcda1 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-other-minimizer/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: [new TerserPlugin({ extractComments: false }), new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-parallel/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-parallel/expected.js new file mode 100644 index 0000000..16518af --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-parallel/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ parallel: false })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-parallel/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-parallel/input.js new file mode 100644 index 0000000..16518af --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-parallel/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ parallel: false })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-reassigned/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-reassigned/expected.js new file mode 100644 index 0000000..aab55ac --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-reassigned/expected.js @@ -0,0 +1,3 @@ +let CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); +CssMinimizerPlugin = CustomPlugin; +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-reassigned/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-reassigned/input.js new file mode 100644 index 0000000..aab55ac --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-reassigned/input.js @@ -0,0 +1,3 @@ +let CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); +CssMinimizerPlugin = CustomPlugin; +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-separate-options-precedence/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-separate-options-precedence/expected.js new file mode 100644 index 0000000..72a2ac6 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-separate-options-precedence/expected.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimize: { css: false }, minimizeOptions: { css: { comments: /^!/, extractComments: false }, javascript: false }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-separate-options-precedence/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-separate-options-precedence/input.js new file mode 100644 index 0000000..4af010c --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-separate-options-precedence/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimize: { css: false }, minimizeOptions: { javascript: false }, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-shadowed/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-shadowed/expected.js new file mode 100644 index 0000000..1f538d6 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-shadowed/expected.js @@ -0,0 +1,5 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = (CssMinimizerPlugin) => ({ + optimization: { minimizer: [new CssMinimizerPlugin()] }, +}); diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-shadowed/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-shadowed/input.js new file mode 100644 index 0000000..1f538d6 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-shadowed/input.js @@ -0,0 +1,5 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = (CssMinimizerPlugin) => ({ + optimization: { minimizer: [new CssMinimizerPlugin()] }, +}); diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-shorthand/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-shorthand/expected.js new file mode 100644 index 0000000..7d08adf --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-shorthand/expected.js @@ -0,0 +1 @@ +module.exports = { optimization: { minimize: { css: { comments: /^!/, extractComments: false }, javascript: false }, minimizer: ["..."] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-shorthand/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-shorthand/input.js new file mode 100644 index 0000000..9fe6e01 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-shorthand/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimize: { javascript: false }, minimizer: ["...", new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-spread-array/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-spread-array/expected.js new file mode 100644 index 0000000..596245e --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-spread-array/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: [...otherMinimizers, new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-spread-array/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-spread-array/input.js new file mode 100644 index 0000000..596245e --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-spread-array/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: [...otherMinimizers, new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-spread-config/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-spread-config/expected.js new file mode 100644 index 0000000..5a2456e --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-spread-config/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin()] }, ...otherConfig }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-spread-config/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-spread-config/input.js new file mode 100644 index 0000000..5a2456e --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-spread-config/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin()] }, ...otherConfig }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-spread-options/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-spread-options/expected.js new file mode 100644 index 0000000..88600cc --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-spread-options/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { ...options, colormin: false }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-spread-options/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-spread-options/input.js new file mode 100644 index 0000000..88600cc --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-spread-options/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { ...options, colormin: false }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-typescript/expected.ts b/codemods/css-plugins-to-native-css/tests/minimizer-typescript/expected.ts new file mode 100644 index 0000000..fcd4323 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-typescript/expected.ts @@ -0,0 +1,8 @@ +import type { Configuration } from "webpack"; + +export default { + optimization: { + minimizeOptions: { css: { comments: true, extractComments: false } }, + minimizer: ["..."], + }, +} satisfies Configuration; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-typescript/input.ts b/codemods/css-plugins-to-native-css/tests/minimizer-typescript/input.ts new file mode 100644 index 0000000..e7cf292 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-typescript/input.ts @@ -0,0 +1,8 @@ +import CssMinimizerPlugin from "css-minimizer-webpack-plugin"; +import type { Configuration } from "webpack"; + +export default { + optimization: { + minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { discardComments: false }] } })], + }, +} satisfies Configuration; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-unknown-option/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-unknown-option/expected.js new file mode 100644 index 0000000..689a41a --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-unknown-option/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { unknown: false }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-unknown-option/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-unknown-option/input.js new file mode 100644 index 0000000..689a41a --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-unknown-option/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { unknown: false }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-unrelated/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-unrelated/expected.js new file mode 100644 index 0000000..500ae68 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-unrelated/expected.js @@ -0,0 +1,2 @@ +class CssMinimizerPlugin {} +module.exports = { optimization: { minimizer: [new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-unrelated/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-unrelated/input.js new file mode 100644 index 0000000..500ae68 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-unrelated/input.js @@ -0,0 +1,2 @@ +class CssMinimizerPlugin {} +module.exports = { optimization: { minimizer: [new CssMinimizerPlugin()] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-whitespace/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-whitespace/expected.js new file mode 100644 index 0000000..b1541a0 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-whitespace/expected.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { normalizeWhitespace: false }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-whitespace/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-whitespace/input.js new file mode 100644 index 0000000..b1541a0 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-whitespace/input.js @@ -0,0 +1,3 @@ +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { optimization: { minimizer: ["...", new CssMinimizerPlugin({ minimizerOptions: { preset: ["default", { normalizeWhitespace: false }] } })] } }; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-with-loaders/expected.js b/codemods/css-plugins-to-native-css/tests/minimizer-with-loaders/expected.js new file mode 100644 index 0000000..8538728 --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-with-loaders/expected.js @@ -0,0 +1,7 @@ + +module.exports = { + output: { + cssFilename: "[name].css", + }, + optimization: { minimizeOptions: { css: { comments: /^!/, extractComments: false } }, minimizer: ["..."] }, +}; diff --git a/codemods/css-plugins-to-native-css/tests/minimizer-with-loaders/input.js b/codemods/css-plugins-to-native-css/tests/minimizer-with-loaders/input.js new file mode 100644 index 0000000..a6d6dcb --- /dev/null +++ b/codemods/css-plugins-to-native-css/tests/minimizer-with-loaders/input.js @@ -0,0 +1,8 @@ +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +module.exports = { + module: { rules: [{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] }] }, + plugins: [new MiniCssExtractPlugin({ filename: "[name].css" })], + optimization: { minimizer: ["...", new CssMinimizerPlugin()] }, +}; diff --git a/codemods/css-plugins-to-native-css/workflow.yaml b/codemods/css-plugins-to-native-css/workflow.yaml index c43846e..098546c 100644 --- a/codemods/css-plugins-to-native-css/workflow.yaml +++ b/codemods/css-plugins-to-native-css/workflow.yaml @@ -9,7 +9,7 @@ nodes: runtime: type: direct steps: - - name: Migrate mini-css-extract-plugin and style-loader/css-loader rules to webpack's native CSS support (experiments.css) + - name: Migrate CSS plugins, loaders, and supported css-minimizer-webpack-plugin options to webpack's native CSS support and minification js-ast-grep: js_file: src/workflow.ts base_path: . @@ -25,6 +25,7 @@ nodes: exclude: - "**/node_modules/**" language: typescript + semantic_analysis: file - name: Remove mini-css-extract-plugin, style-loader, and css-loader from package.json js-ast-grep: js_file: src/remove-dependencies.ts