本插件会将 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"],
},
],
},
};
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: 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
。
String
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: "/public/path/to/",
},
},
"css-loader",
],
},
],
},
};
Function
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) => {
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 ),应使用以下插件之一:
如果你还没有阅读过我们的贡献指南,请花一点时间阅读它。