mini-css-extract-plugin(翻译)

1,619 阅读3分钟

原文:github.com/webpack-con…

这个插件将CSS提取到单独的文件中。它为每个包含CSS的JS文件创建一个CSS文件。CSS支持按需加载和源映射。

它建立在新的webpackv4特性(模块类型)之上,需要webpack4才能工作。

与extract-text-webpack-plugin插件相比:

  • 异步加载

  • 无重复编译(性能)

  • 更易于使用

  • 特定于CSS

开始

首先,您需要安装mini-css-extract-plugin

npm install --save-dev mini-css-extract-plugin

建议将mini-css-extract-plugincss-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'],
      },
    ],
  },
};

选项

publicPath

Type: String|Function

Default: publicPathwebpackOptions.output中的等同

指定目标文件的自定义公用路径。

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({
      // 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',
        ],
      },
    ],
  },
};

esModule

Type: Boolean

Default: false

默认情况下,mini-css-extract-plugin生成使用CommonJS modules语法的JS模块。在某些情况下,使用ES模块是有益的,例如在模块连接和tree shaking的情况下。

您可以使用以下方法启用ES模块语法:

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: true,
            },
          },
          'css-loader',
        ],
      },
    ],
  },
};

modules

Type: Object

Default: undefined

配置CSS模块。

namedExport

Type: Boolean

Default: false

启用/禁用名为export for locals的ES模块。

本地的名字被转换成camelCase。

不允许在css类名中使用JavaScript保留字。

选项esModule和modules.namedExport在css加载程序和MiniCssExtractPlugin.loader应启用。

styles.css

.foo-baz {
  color: red;
}
.bar {
  color: blue;
}

index.js

import { fooBaz, bar } from './styles.css';

console.log(fooBaz, bar);

您可以使用以下方法启用名为export的ES模块:

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              esModule: true,
              modules: {
                namedExport: true,
              },
            },
          },
          {
            loader: 'css-loader',
            options: {
              esModule: true,
              modules: {
                namedExport: true,
                localIdentName: 'foo__[name]__[local]',
              },
            },
          },
        ],
      },
    ],
  },
};

示例

最小示例

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: '../',
              hmr: process.env.NODE_ENV === 'development',
            },
          },
          'css-loader',
        ],
      },
    ],
  },
};

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',
        ],
      },
    ],
  },
};

高级配置示例

这个插件应该只在没有style-loader生产版本上使用,特别是如果你想在开发中使用HMR。

下面是一个例子,可以让HMR处于开发阶段,也可以将您的样式提取到一个用于生产构建的文件中。

(为清楚起见,请根据您的需要调整装载机选项。)

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: devMode ? '[name].css' : '[name].[hash].css',
      chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === 'development',
            },
          },
          'css-loader',
          'postcss-loader',
          'sass-loader',
        ],
      },
    ],
  },
};

热模块重新加载(HMR)

mini-css-extract-plugin支持在开发过程中热重新加载实际css文件。提供了一些选项来启用标准样式表和本地范围的CSS或CSS模块的HMR。下面是用于HMR和css模块的迷你css配置示例。

当我们尝试hmr css模块时。当使用自定义块名称进行代码拆分时,不容易执行。reloadAll是一个只有在HMR不能正常工作时才应该启用的选项。css模块的核心挑战是,当代码被拆分时,块id可以并且确实与文件名不同。

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: {
              // only enable hot in development
              hmr: process.env.NODE_ENV === 'development',
              // if hmr does not work, this is a forceful method.
              reloadAll: true,
            },
          },
          'css-loader',
        ],
      },
    ],
  },
};

生产最小化

要缩小输出,请使用类似optimize-css-assets-webpack-plugin这样的插件。设置optimization.minimizer重写webpack提供的默认值,因此请确保同时指定JS minimizer:

webpack.config.js

const TerserJSPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

使用预加载或内联CSS

运行时代码通过<link><style>标记检测已经添加的CSS。当在服务器端注入CSS进行服务器端渲染时,这可能很有用。<link>标记的href必须与用于加载CSS块的URL相匹配。data-href属性也可用于<link><style>。内联CSS数据时必须使用data-href

在单个文件中提取所有CSS

CSS可以在一个CSS文件中使用optimization.splitChunks.cacheGroups

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true,
        },
      },
    },
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

基于条目提取CSS

您也可以根据webpack条目名提取CSS。如果您动态导入路由,但希望根据条目绑定CSS,这一点尤其有用。这也防止了ExtractTextPlugin的CSS重复问题。

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

function recursiveIssuer(m) {
  if (m.issuer) {
    return recursiveIssuer(m.issuer);
  } else if (m.name) {
    return m.name;
  } else {
    return false;
  }
}

module.exports = {
  entry: {
    foo: path.resolve(__dirname, 'src/foo'),
    bar: path.resolve(__dirname, 'src/bar'),
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        fooStyles: {
          name: 'foo',
          test: (m, c, entry = 'foo') =>
            m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
          chunks: 'all',
          enforce: true,
        },
        barStyles: {
          name: 'bar',
          test: (m, c, entry = 'bar') =>
            m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
          chunks: 'all',
          enforce: true,
        },
      },
    },
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

模块文件名选项

使用moduleFilename选项,可以使用块数据自定义文件名。这在处理多个入口点并希望对给定入口点/块从文件名中获得更多控制时特别有用。在下面的示例中,我们将使用moduleFilename将生成的css输出到另一个目录中。

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      moduleFilename: ({ name }) => `${name.replace('/js/', '/css/')}.css`,
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

Long Term Caching

对于长期缓存,请使用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顺序的项目,可以通过将插件的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'],
      },
    ],
  },
};

媒体查询插件

如果您想从提取的CSS中提取媒体查询(这样移动用户就不需要再加载桌面或平板电脑特定的CSS),您应该使用以下插件之一: