此插件将 CSS 提取到单独的文件中。它为每个包含 CSS 的 JS 文件创建一个 CSS 文件。它支持 CSS 的按需加载和 Source Map。
它基于 webpack v5 的新特性构建,需要 webpack 5 才能工作。
与 extract-text-webpack-plugin 相比
首先,你需要安装 mini-css-extract-plugin
npm install --save-dev mini-css-extract-plugin
或
yarn add -D mini-css-extract-plugin
或
pnpm add -D mini-css-extract-plugin
建议将 mini-css-extract-plugin
与 css-loader
结合使用。
然后将 loader 和插件添加到你的 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 中导入样式,
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
类型
type filename =
| string
| ((pathData: PathData, assetInfo?: AssetInfo) => string);
默认值:[name].css
此选项决定每个输出 CSS 文件的名称。
作用类似于 output.filename
chunkFilename
类型
type chunkFilename =
| string
| ((pathData: PathData, assetInfo?: AssetInfo) => string);
默认值:基于 filename
将
chunkFilename
指定为function
仅在 webpack@5 中可用
此选项决定非入口 chunk 文件的名称。
作用类似于 output.chunkFilename
ignoreOrder
类型
type ignoreOrder = boolean;
默认值:false
移除顺序警告。更多详情请参阅示例。
insert
类型
type insert = string | ((linkTag: HTMLLinkElement) => void);
默认值:document.head.appendChild(linkTag);
在给定位置为非初始(异步) CSS chunk 插入 link
标签
[!警告]
仅适用于非初始(异步) chunk。
默认情况下,mini-css-extract-plugin
将样式(<link>
元素)附加到当前 window
的 document.head
中。
然而,在某些情况下,可能需要更精细地控制追加目标,甚至延迟 link
元素的插入。例如,当你异步加载在 iframe 中运行的应用程序的样式时,就是这种情况。在这种情况下,insert
可以配置为一个函数或一个自定义选择器。
如果你目标是 iframe,请确保父文档有足够的访问权限来进入帧文档并向其追加元素。
string
允许设置自定义的 查询选择器。新的 <link>
元素将插入到找到的项之后。
webpack.config.js
new MiniCssExtractPlugin({
insert: "#some-element",
});
新的 <link>
标签将插入到 ID 为 some-element
的元素之后。
function
允许覆盖默认行为并在任何位置插入样式。
⚠ 不要忘记此代码将在浏览器中与你的应用程序一起运行。由于并非所有浏览器都支持最新的 ECMA 特性,例如
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);
}
},
});
新的 <link>
标签将插入到 ID 为 some-element
的元素之前。
attributes
类型
type attributes = Record<string, string>};
默认值:{}
[!警告]
仅适用于非初始(异步) 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 文件中的
<link>
属性,请使用 html-webpack-plugin。
linkType
类型
type 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"],
},
],
},
};
boolean
false
完全禁用 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"],
},
],
},
};
runtime
类型
type runtime = boolean;
默认值:true
允许启用/禁用运行时生成。CSS 仍将被提取,并可用于自定义加载方法。例如,你可以使用 assets-webpack-plugin 来检索它们,然后使用自己的运行时代码在需要时下载资产。
设置为 false
以跳过。
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
类型
type experimentalUseImportModule = boolean;
默认值:undefined
如果未明确启用(即 true
和 false
允许你显式控制此选项)且新 API 可用(至少需要 webpack 5.52.0
)时,此选项默认启用。布尔值自版本 5.33.2
起可用,但你需要启用 experiments.executeModule
(从 webpack 5.52.0
起不再需要)。
使用新的 webpack API 来执行模块而不是子编译器,显著提升性能和内存使用。
与 experiments.layers
结合使用时,这会为 loader 选项添加一个 layer
选项,用于指定 CSS 执行的层。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// You don't need this for `>= 5.52.0` due to the fact that this is enabled by default
// Required only for `>= 5.33.2 & <= 5.52.0`
// Not available/unsafe for `<= 5.33.2`
experimentalUseImportModule: true,
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};
publicPath
类型
type publicPath =
| string
| ((resourcePath: string, rootContext: string) => string);
默认值:webpackOptions.output
中的 publicPath
为 CSS
中外部资源(如图片、文件等)指定自定义的公共路径。作用类似于 output.publicPath
string
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "[name].css",
chunkFilename: "[id].css",
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "/public/path/to/",
},
},
"css-loader",
],
},
],
},
};
function
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
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
类型
type emit = boolean;
默认值:true
如果为 true
,则会发出文件(将文件写入文件系统)。如果为 false
,插件将提取 CSS 但不会发出文件。对于服务器端包,禁用此选项通常很有用。
esModule
类型
type esModule = boolean;
默认值:true
默认情况下,mini-css-extract-plugin
生成使用 ES 模块语法的 JS 模块。在某些情况下,使用 ES 模块是有益的,例如模块连接和摇树优化。
你可以通过以下方式启用 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",
],
},
],
},
};
defaultExport
类型
type defaultExport = boolean;
默认值:false
[!注意]
此选项仅在你将
css-loader
中的namedExport
设置为true
时才有效。
默认情况下,mini-css-extract-plugin
根据 css-loader
中的 esModule
和 namedExport
选项生成 JS 模块。使用 esModule
和 namedExport
选项将使你能够更好地优化代码。如果你为 css-loader
设置 esModule: true
和 namedExport: true
,mini-css-extract-plugin
将只生成命名导出。我们官方推荐仅使用命名导出以获得更好的未来兼容性。但对于某些应用程序,将代码从默认导出快速重写为命名导出并不容易。
如果你同时需要默认导出和命名导出,可以启用此选项:
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: {
defaultExport: true,
},
},
{
loader: "css-loader",
options: {
esModule: true,
modules: {
namedExport: true,
},
},
},
],
},
],
},
};
对于 production
构建,建议从你的 bundle 中提取 CSS,以便之后能够并行加载 CSS/JS 资源。这可以通过使用 mini-css-extract-plugin
实现,因为它创建单独的 CSS 文件。对于 development
模式(包括 webpack-dev-server
),你可以使用 style-loader,因为它使用多种方式将 CSS 注入到 DOM 中并且工作速度更快。
重要提示:不要同时使用
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: [
{
// If you enable `experiments.css` or `experiments.futureDefaults`, please uncomment line below
// type: "javascript/auto",
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 类名中使用 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
选项你可以将 publicPath
指定为一个函数,以根据每个资源相对于项目根目录或上下文的位置动态确定公共路径。
webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "[name].css",
chunkFilename: "[id].css",
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: (resourcePath, context) => {
// publicPath is the relative path of the resource to the context
// e.g. for ./css/admin/main.css the publicPath will be ../../
// while for ./css/main.css the publicPath will be ../
return path.relative(path.dirname(resourcePath), context) + "/";
},
},
},
"css-loader",
],
},
],
},
};
此插件不应与 loader 链中的 style-loader
一起使用。
这是一个示例,可以在 development
环境中启用 HMR,并在 production
构建中将样式提取到文件中。
(为清晰起见,省略了 Loader 选项,请根据你的需求进行调整。)
如果你正在使用 webpack-dev-server
,则不应使用 HotModuleReplacementPlugin
插件。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 文件进行热重载。提供了一些选项来启用标准样式表以及局部作用域 CSS 或 CSS 模块的 HMR。以下是 mini-css 与 CSS 模块结合使用 HMR 的配置示例。
如果你正在使用 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 o keep JS minimizers and add CSS minimizer:
// `...`,
new CssMinimizerPlugin(),
],
},
};
optimization.minimize
选项设置为 true
。运行时代码会检测通过 <link>
或 <style>
标签已添加的 CSS,并避免重复加载 CSS。
<link>
标签的 href
必须与用于加载 CSS chunk 的 URL 匹配。data-href
属性可用于 <link>
和 <style>
元素。data-href
。可以使用 optimization.splitChunks.cacheGroups
并将 type
设置为 "css/mini-extract"
来将 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
,否则除了 .css
文件之外还会生成一个额外的 .js
文件。这是因为 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"],
},
],
},
};
对于通过一致使用作用域或命名约定(例如 CSS Modules)来解决 CSS 排序问题的项目,可以通过将插件的 ignoreOrder 标志设置为 true 来禁用 CSS 顺序警告。
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"],
},
],
},
};
通过使用查询参数有条件地加载不同的 SCSS 变体来切换主题。
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: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "sass-loader",
options: {
additionalData: `@use 'dark-theme/vars' as vars;`,
},
},
],
},
{
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "sass-loader",
options: {
additionalData: `@use 'light-theme/vars' as vars;`,
},
},
],
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
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),你应该使用以下插件之一:
mini-css-extract-plugin 提供了钩子(hooks),以满足你的扩展需求。
SyncWaterfallHook
在为 link 标签注入插入代码之前调用。应该返回一个字符串。
MiniCssExtractPlugin.getCompilationHooks(compilation).beforeTagInsert.tap(
"changeHref",
(source, varNames) =>
Template.asString([
source,
`${varNames.tag}.setAttribute("href", "/plugins/mini-css-extract-plugin/));`,
])
);
我们欢迎所有贡献!如果您是新用户,请在提交问题或拉取请求之前花一些时间阅读我们的贡献指南。