本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
本插件基于 webpack v5 的新特性构建,并且需要 webpack 5 才能正常工作。
与 extract-text-webpack-plugin 相比:
首先,你需要安装 mini-css-extract-plugin:
npm install --save-dev mini-css-extract-plugin建议 mini-css-extract-plugin 与 css-loader 一起使用。
之后将 loader 与 plugin 添加到你的 webpack 配置文件中。 例如:
style.css
body {
background: green;
}component.js
import "./style.css";webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};⚠️ 注意,如果你从 webpack 入口处导入 CSS 或者在 初始 chunk 中引入 style,
mini-css-extract-plugin则不会将这些 CSS 加载到页面中。请使用html-webpack-plugin自动生成link标签或者在创建index.html文件时使用link标签。
⚠️ source map 只在
source-map/nosources-source-map/hidden-nosources-source-map/hidden-source-map值情况下起作用,因为 CSS 仅支持带有sourceMappingURL注释的 source map (例如//# sourceMappingURL=style.css.map)。如果你需要将devtool设置为其他值,你可以使用css-loader中的sourceMap: true来启用提取并生成 CSS 的 source map。
| 选项名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
filename | {String|Function} | [name].css | 此选项决定了输出的每个 CSS 文件的名称 |
chunkFilename | {String|Function} | based on filename | 此选项决定了非入口的 chunk 文件名称 |
ignoreOrder | {Boolean} | false | 移除 Order 警告 |
insert | {String|Function} | var head = document.getElementsByTagName("head")[0];head.appendChild(linkTag); | 在指定位置将 非初始(由 async 修饰) 的 CSS chunk 插入 link 标签 |
attributes | {Object} | {} | 为 非初始(由 async 修饰) 的 CSS chunk 所处的 link 标签添加自定义属性 |
linkType | {String|Boolean} | text/css | 允许使用自定义 link 类型加载异步 chunk |
runtime | {Boolean} | true | 允许启动/禁用 runtime 生成 |
experimentalUseImportModule | {Boolean} | undefined | 使用实验性的 webpack API 来执行模块,而非子代编译器 |
filename类型:String|Function
默认值:[name].css
此选项决定了输出的每个 CSS 文件的名称。
机制类似于 output.filename。
chunkFilename类型:String|Function
默认值:based on filename
将
chunkFilename设置为function,仅在 webpack@5 下可用。
此选项决定了非入口的 chunk 文件名称
机制类似于 output.chunkFilename
ignoreOrder类型:Boolean
默认值:false
移除 Order 警告 具体细节请参阅示例。
insert类型:String|Function
默认值:document.head.appendChild(linkTag);
⚠️ 仅对 非初始(由 async 修饰) chunk 有效。
默认情况下,mini-css-extract-plugin 会将 styles(<link> 元素)附加到当前 window 的 document.head 中。
但在某些情况下,可能需要对附加的目标进行精细化管理,甚至延迟 link 元素的插入。
例如,当你在 iframe 中运行应用程序异步加载样式时,就属于此情况。
对于此类情况,insert 可被配置为函数或自定义的选择器。
如果附加目标为 iframe,请确保父文档有足够的访问权限进入 frame document,并将元素附加到它上面。
String允许设置自定义的 query selector。
新的 <link> 元素将被插入到找到的 item 之后。
webpack.config.js
new MiniCssExtractPlugin({
insert: "#some-element",
});找到 id 为 some-element 的元素,在它之后插入新的 <link> 元素。
Function允许覆盖默认行为,并在任意位置插入样式。
⚠ 注意,这段代码将与你的应用程序一起在浏览器中运行。由于并非所有浏览器都支持 ESMA 特性,如
let,const,arrow function expression等,我们建议只使用 ECMA 5 的特性和语法。
⚠
insert函数被序列化为字符串并传递给插件。这意味着它将无法访问 webpack 配置模块的作用域。
webpack.config.js
new MiniCssExtractPlugin({
insert: function (linkTag) {
var reference = document.querySelector("#some-element");
if (reference) {
reference.parentNode.insertBefore(linkTag, reference);
}
},
});找到 id 为 some-element 的元素,在它之后插入新的 <link> 元素。
attributes类型:Object
默认值:{}
⚠️ 仅对 非初始(由 async 修饰) chunk 有效。
如果定义了此选项,mini-css-extract-plugin 将把指定的属性和值附加到 <link> 元素上。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
attributes: {
id: "target",
"data-target": "example",
},
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};注意:它只适用于动态加载的 css chunk,如果你想修改 html 文件内的链接属性,请使用 html-webpack-plugin。
linkType类型:String|Boolean
默认值:text/css
此选项运行使用自定义链接类型加载异步 chunk,例如 <link type="text/css" ...>。
String可选值:text/css
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
linkType: "text/css",
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};Booleanfalse 禁用 link 的 type 属性
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
linkType: false,
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};runtimeType: Boolean
Default: true
允许开启/禁用 runtime 生成。 CSS 仍将被提取,并可用于自定义加载方法。 例如,你可以使用 assets-webpack-plugin 来检索它们,然后当需要时使用你自己的 runtime 代码下载静态资源。
设置为 true 以跳过。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
runtime: false,
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};experimentalUseImportModule类型:Boolean
默认值:undefined
如果没有显式启用,则默认启用(即可以通过 true 与 false 显式控制该配置),并且新 API 处于可用状态(webpack 版本至少为 5.52.0)。
布尔值在 5.33.2 版本后可用,但是你需要启用 experiments.executeModule(webpack 5.52.0 版本不需要)。
使用新的 webpack API 来执行模块而不是子编译器。 这大大提高了性能和内存使用。
当与 experiments.layers 相结合时,添加了一个 layer 选项到 loader 配置项中,以指定 CSS 执行的 layer。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// `>= 5.52.0` 版本的 webpack 不需要该配置,因为该配置项默认启用
// 仅 `>= 5.33.2 & <= 5.52.0` 版本的 webpack 需要该配置
// 对于 `<= 5.33.2` 版本的 webpack 不可用/不安全
experimentalUseImportModule: true,
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
publicPath | {String|Function} | webpackOptions.output.publicPath | 为图片、文件等外部资源指定一个自定义的公共路径。 |
emit | {Boolean} | true | 如果设为 false,插件将会提取 CSS 但不会 生成文件 |
esModule | {Boolean} | true | 使用 ES modules 语法 |
publicPath类型:String|Function
默认值:webpackOptions.output 选项中的 publicPath
为 CSS 内的图片、文件等外部资源指定一个自定义的公共路径。
机制类似于 output.publicPath。
Stringwebpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// 类似于 webpackOptions.output 中的选项
// 所有选项都是可选的
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "/public/path/to/",
},
},
"css-loader",
],
},
],
},
};Functionwebpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// 类似于 webpackOptions.output 中的选项
// 所有选项都是可选的
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: (resourcePath, context) => {
return path.relative(path.dirname(resourcePath), context) + "/";
},
},
},
"css-loader",
],
},
],
},
};emit类型:Boolean
默认值:true
如果设置为 true,会发送一个文件(向文件系统中写入一个文件)。如果设置为 false,该插件将会提取 CSS 但是 不会 发送文件。 禁用该配置对服务侧的包比较有用。
esModule类型:Boolean
默认值:true
默认情况下 mini-css-extract-plugin 将会生成使用 ES 模块语法的 JS 模块。
在某些情况下,使用 ES 模块是有益的,比如:module concatenation 和 tree shaking。
你可以使用以下方式启用 CommonJS 语法:
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
"css-loader",
],
},
],
},
};推荐 production 环境的构建将 CSS 从你的 bundle 中分离出来,这样可以使用 CSS/JS 文件的并行加载。
这可以通过使用 mini-css-extract-plugin 来实现,因为它可以创建单独的 CSS 文件。
对于 development 模式(包括 webpack-dev-server),你可以使用 style-loader,因为它可以使用多个 标签将 CSS 插入到 DOM 中,并且反应会更快。
i 不要同时使用
style-loader与mini-css-extract-plugin。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devMode = process.env.NODE_ENV !== "production";
module.exports = {
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
devMode ? "style-loader" : MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
],
},
plugins: [].concat(devMode ? [] : [new MiniCssExtractPlugin()]),
};webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// all options are optional
filename: "[name].css",
chunkFilename: "[id].css",
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// you can specify a publicPath here
// by default it uses publicPath in webpackOptions.output
publicPath: "../",
},
},
"css-loader",
],
},
],
},
};⚠ 命名会被修改为
camelCase的形式。
⚠ 不允许在 css 的 class name 中使用 JavaScript 关键字。
⚠ 应启用
css-loader中的esModule以及modules.namedExport选项。
styles.css
.foo-baz {
color: red;
}
.bar {
color: blue;
}index.js
import { fooBaz, bar } from "./styles.css";
console.log(fooBaz, bar);你可以按照如下配置启用 ES 模块命名导出:
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: "css-loader",
options: {
esModule: true,
modules: {
namedExport: true,
localIdentName: "foo__[name]__[local]",
},
},
},
],
},
],
},
};publicPath 选项为函数webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// 类似于 webpackOptions.output 中的选项
// 所有选项都是可选的
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: (resourcePath, context) => {
// publicPath 是资源相对于上下文的相对路径
// 例如:对于 ./css/admin/main.css publicPath 将会是 ../../
// 而对于 ./css/main.css publicPath 将会是 ../
return path.relative(path.dirname(resourcePath), context) + '/';
},
},
},
"css-loader",
],
},
],
},
};此插件不能与 loader 链中的 style-loader 一同使用。
这是一个在 development 构建中使用 HMR 并且在 production 构建中将样式文件提取到独立文件中的示例。
(为了更加清楚的表达,省略了 Loader 的选项,以适应需要。)
如果你使用的是 webpack-dev-server,那么就无需使用 HotModuleReplacementPlugin plugin。
webpack-dev-server 使用 hot 选项决定是否启用/禁用 HMR。
webpack.config.js
const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devMode = process.env.NODE_ENV !== "production";
const plugins = [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: devMode ? "[name].css" : "[name].[contenthash].css",
chunkFilename: devMode ? "[id].css" : "[id].[contenthash].css",
}),
];
if (devMode) {
// only enable hot in development
plugins.push(new webpack.HotModuleReplacementPlugin());
}
module.exports = {
plugins,
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
],
},
};注意:在 webpack 5 中 HMR 已自动支持。无需配置。你可以跳过以下内容:
mini-css-extract-plugin 支持在开发中热重载实际的 CSS 文件。
我们提供了一些选项来启动标准 stylesheets 和本地范围内 CSS 和 CSS modules 的 HMR 支持。
以下是 mini-css 用于启动 HMR CSS modules 的示例配置。
如果你使用的是 webpack-dev-server,那么你无需使用 HotModuleReplacementPlugin 插件。
webpack-dev-server 使用 hot 选项来控制启用/禁用 HMR。
webpack.config.js
const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const plugins = [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: devMode ? "[name].css" : "[name].[contenthash].css",
chunkFilename: devMode ? "[id].css" : "[id].[contenthash].css",
}),
];
if (devMode) {
// only enable hot in development
plugins.push(new webpack.HotModuleReplacementPlugin());
}
module.exports = {
plugins,
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {},
},
"css-loader",
],
},
],
},
};为了压缩输出文件,请使用类似于 css-minimizer-webpack-plugin 这样的插件。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css",
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
optimization: {
minimizer: [
// For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
// `...`,
new CssMinimizerPlugin(),
],
},
};这将只在生产模式下启用 CSS 压缩优化。如果你需要在开发模式下使用,请设置 optimization.minimize 选项为 true。
运行时代码通过 <link> 或者<style> 标签检测已经添加的 CSS。
当在服务端注入 CSS 代码 以及做 SSR 时将会很有用。
<link> 标签的 href 属性必须与将要被加载的 CSS chunk 的 URL 相匹配。
data-href 属性也可以被用在 <link> 和 <style> 标签中
使用内联 CSS 时,必须使用 data-href 属性。
用过使用 optimization.splitChunks.cacheGroups 选项,所有的 CSS 可以被提取到一个 CSS 文件中。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: "styles",
type: "css/mini-extract",
chunks: "all",
enforce: true,
},
},
},
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};请注意在 webpack 5 中应该使用 type 而不是 test,否则将会生成 .js 文件而不是 .css。这是因为 test 不知道应该去掉哪个模块(在这种情况下,它不会检测到 .js 应该被删除)。
你可以基于 webpack 的入口名称提取 CSS。 当你使用路由动态加载但是想要通过入口加载对应的 CSS 文件时这将会非常有用。 这样也避免了 ExtractTextPlugin 造成的 CSS 重复复制问题。
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
foo: path.resolve(__dirname, "src/foo"),
bar: path.resolve(__dirname, "src/bar"),
},
optimization: {
splitChunks: {
cacheGroups: {
fooStyles: {
type: "css/mini-extract",
name: "styles_foo",
chunks: (chunk) => {
return chunk.name === "foo";
},
enforce: true,
},
barStyles: {
type: "css/mini-extract",
name: "styles_bar",
chunks: (chunk) => {
return chunk.name === "bar";
},
enforce: true,
},
},
},
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};使用 filename 选项,你可以使用 chunk 数据来定制文件名。
这点在处理多个入口,并且希望对给定的 入口/chunk 文件进行更多处理时,非常有用。
下面示例中,我们使用 filename 将生成的 css 输出到不同的目录中。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: ({ chunk }) => `${chunk.name.replace("/js/", "/css/")}.css`,
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};使用 filename: "[contenthash].css" 启动长期缓存。根据需要添加 [name]。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
chunkFilename: "[id].[contenthash].css",
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};对于通过使用 scoping 或命名约定来解决 css order 的项目,可以通过将插件的 ignoreOrder 选项设置为 true 来禁用 css order 警告。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
ignoreOrder: true,
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/index.js",
module: {
rules: [
{
test: /\.s[ac]ss$/i,
oneOf: [
{
resourceQuery: "?dark",
use: [
Self.loader,
"css-loader",
{
loader: "sass-loader",
options: {
additionalData: `@use 'dark-theme/vars' as vars;`,
},
},
],
},
{
use: [
Self.loader,
"css-loader",
{
loader: "sass-loader",
options: {
additionalData: `@use 'light-theme/vars' as vars;`,
},
},
],
},
],
},
],
},
plugins: [
new Self({
filename: "[name].css",
attributes: {
id: "theme",
},
}),
],
};src/index.js
import "./style.scss";
let theme = "light";
const themes = {};
themes[theme] = document.querySelector("#theme");
async function loadTheme(newTheme) {
// eslint-disable-next-line no-console
console.log(`CHANGE THEME - ${newTheme}`);
const themeElement = document.querySelector("#theme");
if (themeElement) {
themeElement.remove();
}
if (themes[newTheme]) {
// eslint-disable-next-line no-console
console.log(`THEME ALREADY LOADED - ${newTheme}`);
document.head.appendChild(themes[newTheme]);
return;
}
if (newTheme === "dark") {
// eslint-disable-next-line no-console
console.log(`LOADING THEME - ${newTheme}`);
import(/* webpackChunkName: "dark" */ "./style.scss?dark").then(() => {
themes[newTheme] = document.querySelector("#theme");
// eslint-disable-next-line no-console
console.log(`LOADED - ${newTheme}`);
});
}
}
document.onclick = () => {
if (theme === "light") {
theme = "dark";
} else {
theme = "light";
}
loadTheme(theme);
};src/dark-theme/_vars.scss
$background: black;src/light-theme/_vars.scss
$background: white;src/styles.scss
body {
background-color: vars.$background;
}public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Document</title>
<link id="theme" rel="stylesheet" type="text/css" href="./main.css" />
</head>
<body>
<script src="./main.js"></script>
</body>
</html>如果您想从 CSS 文件中提取媒体查询(因为移动用户不需要加载电脑或平板专用的 CSS ),应使用以下插件之一:
如果你还没有阅读过我们的贡献指南,请花一点时间阅读它。