diff --git a/src/content/guides/native-css.mdx b/src/content/guides/native-css.mdx new file mode 100644 index 000000000000..5ef8185e7fed --- /dev/null +++ b/src/content/guides/native-css.mdx @@ -0,0 +1,280 @@ +--- +title: Native CSS +sort: 27 +contributors: + - phoekerson +--- + +This guide shows how to use webpack native CSS handling with `experiments.css`. + +T> `experiments.css` is still experimental. It is expected to become the default in webpack v6, but behavior can still change while development continues. + +## Getting Started + +Enable native CSS support in your webpack configuration: + +**webpack.config.js** + +```js +export default { + experiments: { + css: true, + }, +}; +``` + +With this option enabled, webpack can process CSS without adding `css-loader` and `mini-css-extract-plugin` for the basic flow. + +## Importing CSS + +After enabling the experiment, import `.css` files directly from JavaScript: + +**src/index.js** + +```js +import "./styles.css"; + +const element = document.createElement("h1"); +element.textContent = "Hello native CSS"; +document.body.appendChild(element); +``` + +**src/styles.css** + +```css +h1 { + color: #1f6feb; +} +``` + +Webpack will process the CSS and include it in the build output. + +## CSS Modules + +Native CSS support also includes CSS Modules. The recommended approach is: + +- keep `type: "css/auto"` for mixed CSS handling, +- use `.module.css` (or `.modules.css`) naming for CSS Modules files. + +**src/button.module.css** + +```css +.button { + background: #0d6efd; + color: white; + border: 0; + border-radius: 4px; + padding: 8px 12px; +} +``` + +**src/index.js** + +```js +import * as styles from "./button.module.css"; + +const button = document.createElement("button"); +button.className = styles.button; +button.textContent = "Click me"; +document.body.appendChild(button); +``` + +T> CSS Modules class names are exported. By default, named exports are enabled for CSS modules. + +You can customize CSS Modules behavior using parser and generator options: + +**webpack.config.js** + +```js +export default { + experiments: { + css: true, + }, + module: { + parser: { + "css/module": { + namedExports: true, + }, + }, + generator: { + "css/module": { + exportsConvention: "camel-case-only", + localIdentName: "[uniqueName]-[id]-[local]", + }, + }, + }, +}; +``` + +## Production Build + +With `experiments.css: true`, webpack provides native CSS extraction and content hashing for CSS assets in production builds. + +Compared to the classic setup: + +- Traditional approach: `css-loader` + `mini-css-extract-plugin` +- Native approach: `experiments.css` with built-in extraction behavior + +This reduces configuration and keeps the CSS pipeline closer to webpack core features. + +## Experimental Status & Known Limitations + +`experiments.css` is explicitly experimental, so treat it as opt-in and test carefully before broad rollout. + +Known points to keep in mind: + +- APIs and behavior may still evolve before webpack v6 defaults. +- Some loader-specific options are not part of native CSS behavior (for example, loader-specific filters). +- If your project relies on advanced loader chains, validate each part before migrating fully. + +## Migration Guide + +If you currently use `css-loader`, `mini-css-extract-plugin`, and `style-loader`, migrate in small steps. + +### 1) Start from a classic setup + +**webpack.config.js** + +```js +import MiniCssExtractPlugin from "mini-css-extract-plugin"; + +export default { + module: { + rules: [ + { + test: /\.css$/i, + use: [MiniCssExtractPlugin.loader, "css-loader"], + }, + ], + }, + plugins: [new MiniCssExtractPlugin()], +}; +``` + +### 2) Switch to native CSS + +**webpack.config.js** + +```js +export default { + experiments: { + css: true, + }, +}; +``` + +### 3) Migrate `css-loader` options first + +Most CSS Modules-related options should move to native parser/generator config. + +**webpack.config.js** + +```js +export default { + experiments: { + css: true, + }, + module: { + parser: { + css: { + import: true, + url: true, + }, + "css/module": { + namedExports: true, + }, + }, + generator: { + "css/module": { + exportsConvention: "camel-case-only", + localIdentName: "[local]-[hash:base64:6]", + }, + }, + }, +}; +``` + +Notes: + +- `import` and `url` are native parser switches for CSS handling. +- `namedExports` controls CSS Modules exports behavior. +- `exportsConvention` and `localIdentName` provide class export/name shaping. +- `localIdentName` supports hash placeholders (for example `[hash:base64:6]`); you can tune hashing globally with [`output.hashFunction`](/configuration/output/#outputhashfunction), [`output.hashDigest`](/configuration/output/#outputhashdigest), [`output.hashDigestLength`](/configuration/output/#outputhashdigestlength), and [`output.hashSalt`](/configuration/output/#outputhashsalt). +- `css-loader` filter-style options are not available as direct equivalents; use webpack mechanisms such as `IgnorePlugin` when needed. + +### 4) Replace `mini-css-extract-plugin` + +When `experiments.css` is enabled, webpack provides native CSS extraction and content hash handling for CSS output files. + +**webpack.config.js** + +```diff +-import MiniCssExtractPlugin from "mini-css-extract-plugin"; +- + export default { ++ experiments: { ++ css: true, ++ }, + module: { + rules: [ + { + test: /\.css$/i, +- use: [MiniCssExtractPlugin.loader, "css-loader"], ++ use: ["css-loader"], + }, + ], + }, +- plugins: [new MiniCssExtractPlugin()], + }; +``` + +You can remove: + +- `MiniCssExtractPlugin.loader` from `module.rules`, +- the `new MiniCssExtractPlugin()` plugin instance. + +### 5) Replace `style-loader` with `exportType: "style"` + +If you used `style-loader` for runtime style injection, keep `css/auto` and use module naming (`.module.css` or `.modules.css`), then set `exportType: "style"`: + +**webpack.config.js** + +```js +export default { + experiments: { + css: true, + }, + module: { + rules: [ + { + test: /\.css$/i, + type: "css/auto", + parser: { + exportType: "style", + }, + }, + ], + }, +}; +``` + +This mode injects a `