CSS and HTML Are Built In

If you set up a webpack project today by following an older tutorial, you will install css-loader, style-loader, mini-css-extract-plugin, html-loader and html-webpack-plugin. You don't need any of them anymore. Since webpack 5.109.0, CSS and HTML are built in, stable and on by default — with no configuration.

What you can remove

PackageReplaced by
css-loaderBuilt-in CSS parsing, @import / url() resolution and CSS Modules
style-loaderexportType: "style"
mini-css-extract-pluginBuilt-in extraction — a .css file per chunk, by default
css-minimizer-webpack-pluginBuilt-in CSS minification and vendor prefixes (5.110.0+)
html-loaderImporting .html from JavaScript
html-webpack-pluginAn HTML entry or output.html
html-minimizer-webpack-pluginBuilt-in HTML minification (5.110.0+)

These packages are deprecated. Preprocessors and template engines — sass-loader, less-loader, postcss-loader, Pug and friends — are not; they keep working, in front of the built-in support.

CSS with no configuration

Import a stylesheet and webpack does the rest:

import "./styles.css";
import * as button from "./button.module.css";

Webpack resolves @import and url(), scopes *.module.css files as CSS Modules and extracts a .css file for each chunk. In mode: "production" (webpack 5.110.0 or later) it minifies the CSS, and with a browserslist target it also adds the vendor prefixes those browsers need. No module.rules, no plugin.

Sass, Less, PostCSS and Tailwind

Keep the preprocessor's loader and drop the CSS loaders behind it. The rule's type hands its output to webpack's CSS pipeline:

 {
   test: /\.s[ac]ss$/i,
-  use: ["style-loader", "css-loader", "sass-loader"],
+  use: ["sass-loader"],
+  type: "css/auto",
 }

One rule covers both layout.scss (global) and button.module.scss (a CSS Module). For PostCSS and Tailwind on .css files, and the few cases where experiments.css: true is needed, see Preprocessors, PostCSS and Tailwind.

HTML pages with no plugin

Point an entry at a page and webpack builds it — every <script>, <link>, <img> and inline <style> it references is bundled, and its URLs are rewritten to the hashed files:

export default {
  entry: "./src/index.html",
};

For a project with a JavaScript entry, output.html: true generates the page and links its scripts and stylesheets. The Native HTML guide covers titles, favicons, Subresource Integrity, CSP and the rest.

Existing projects keep working

experiments.css and experiments.html default to 'auto': when a rule in your module.rules already gives .css or .html files a loader or an explicit type, the built-in support for that file type stays off for the whole build. An existing css-loader or html-loader setup therefore keeps building exactly as before.

To migrate one rule at a time, set experiments.css: true (or experiments.html: true) and give the rules that still use the old loaders type: "javascript/auto", so the built-in support leaves their files to them.

To migrate CSS, run the codemod:

npx codemod @webpack/css-plugins-to-native-css

or follow the Native CSS and Native HTML migration guides. New projects scaffolded with npx create-webpack-app already use the built-in support.

Edit this page·
« Previous
Blog

1 Contributor

alexander-akait