默认情况下,css 会被打包到 JavaScript 中,在生产环境这么做有一些问题,比如会导致页面闪动。因为浏览器需要加载完 js 以后才能加载样式,此时已有的 html 只能使用浏览器的默认样式。

我们需要将 css 导出到单独的文件中。通过 mini-css-extract-pluginopen in new window 插件我们可以实现将 css 导出到单独的 css bundle 中。mini-css-extract-plugin 插件还可以将多个 css 文件合并成一个 css 文件。出于这个原因,mini-css-extract-plugin 实际上会有一个 loader 来处理导出过程,然后将导出的内容通过插件保存为 css 文件。

mini-css-extract-plugin

安装 mini-css-extract-plugin 插件:

npm add mini-css-extract-plugin --develop
1

mini-css-extract-plugin 包含有一个 loader MiniCssExtractPlugin.loader,这个 loader 负责将最终 css 内容导出,然后插件基于导出的内容处理,最终生成 css 文件。

webpack.parts.js

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

exports.extractCSS = ({ options = {}, loaders = [] } = {}) => {
  return {
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            { loader: MiniCssExtractPlugin.loader, options },
            'css-loader',
          ].concat(loaders),
          sideEffects: true, // 如果构建结果作为一个 npm 包使用时建设设置
        },
      ],
    },
    plugins: [
      new MiniCssExtractPlugin({
        filename: '[name].css',
      }),
    ],
  };
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

[name] 占位符使用了导入 css 文件的那个 entry 的名字,如果需要将 css 生成到目录,则可以将路径也放到 filename 配置项里,比如 filename: "styles/[name].css"

更新 webpack.config.js

const commonConfig = merge([
  ...// parts.loadCSS(),
  parts.extractCSS(),
]);
1
2
3
4

执行 npm run build,输出结果如下:

⬡ webpack: Build Finished
⬡ webpack: asset index.html 229 bytes [compared for emit]
  asset main.js 136 bytes [compared for emit] [minimized] (name: main)
  asset main.css 33 bytes [compared for emit] (name: main)
  Entrypoint main 169 bytes = main.css 33 bytes main.js 136 bytes
  orphan modules 199 bytes [orphan] 2 modules
  code generated modules 298 bytes (javascript) 32 bytes (css/mini-extract) [code generated]
    ./src/index.js + 2 modules 298 bytes [built] [code generated]
    css ./node_modules/css-loader/dist/cjs.js!./src/main.css 32 bytes [code generated]
  webpack 5.11.1 compiled successfully in 572 ms
1
2
3
4
5
6
7
8
9
10

css 被打包到单独的文件中,避免了闪屏问题。

默认情况下,我们需要在应用入口引入 css 文件,换句话说需要在 js 文件中引入 css。如果不想在 js 文件引用 css 的话,则可以通过 webpack entry 和 globopen in new window 的形式实现 css 的加载。示例如下:

const glob = require('glob');

const commonConfig = merge([
  {
    entry: { style: glob.sync('./src/**/*.css') }, // 需要手动保证 css 的顺序
  },
]);
1
2
3
4
5
6
7

总结

通过使用 MiniCssExtractPlugin 插件可以解决闪屏问题,同时也优化了浏览器资源加载性能。

如果不想在 JavaScript 中引入 css 文件,则可以通过 webpack entry 的形式加载 css,但是要额外 css 的引用顺序。

关注微信公众号,获取最新推送~