Webpack打包优化之Css-Shaking


PurgeCSS 介绍

在开发中我们经常编写大量的 CSS,用于美化我们的网页,但是也不排除我们编写了一些错误的 CSS,比如:选择器名字写错,就导致我们的 CSS 体积增大,使用 PurgeCSS 可以去除这些无效的 CSS。

PurgeCSS

  • PurgeCSS is a tool to remove unused CSS. It can be part of your development workflow.
    When you are building a website, you might decide to use a CSS framework like TailwindCSS, Bootstrap, MaterializeCSS, Foundation, etc… But you will only use a small set of the framework, and a lot of unused CSS styles will be included.

  • This is where PurgeCSS comes into play. PurgeCSS analyzes your content and your CSS files. Then it matches the selectors used in your files with the one in your content files. It removes unused selectors from your CSS, resulting in smaller CSS files.

命令行使用 PurgeCSS

  1. 安装 purgecss
npm i purecss -D
  1. 文件目录
.
|-- ./build
|   `-- ./build/css
|       `-- ./build/css/a.css
|-- ./css
|   `-- ./css/a.css
|-- ./index.html
|-- ./package-lock.json
`-- ./package.json
<!-- ./index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      http-equiv="X-UA-Compatible"
      content="IE=edge"
    />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0"
    />
    <title>Document</title>
    <link
      rel="stylesheet"
      href="./css/a.css"
    />
  </head>
  <body>
    <div class="header"></div>
  </body>
</html>
/* ./css/a.css */
.nav {
  width: 100px;
  height: 10px;
}

.header {
  background-color: bisque;
  width: 100%;
  height: 30px;
}

.title {
  color: lightcoral;
}

.footer {
  background: #000;
}

body {
  background-color: #c59f9f;
}
  1. 创建 build 文件夹,在里面在创建 css 文件夹,执行 npx purgecss –css css/a.css –content index.html -o build/css/就得到产物
/* ./build/css/a.css */
.header {
  background-color: bisque;
  width: 100%;
  height: 30px;
}

.title {
  color: lightcoral;
}

body {
  background-color: #c59f9f;
}

更多命令使用,参考:https://purgecss.com/CLI.html

webpack 中使用 PurgeCSS

  1. 安装 webpack webpack-cli html-webpack-plugin mini-css-extract-plugin purgecss-webpack-plugin glob css-loader less-loader style-loader postcss-loader postcss-preset-env sass-loader sass css-minimizer-webpack-plugin
npm i webpack webpack-cli html-webpack-plugin mini-css-extract-plugin purgecss-webpack-plugin glob css-loader less-loader style-loader postcss-loader postcss-preset-env sass-loader sass css-minimizer-webpack-plugin -D
  1. 文件目录
.
|-- ./build
|   |-- ./build/css
|   |   `-- ./build/css/main.223704.min.css
|   |-- ./build/index.html
|   `-- ./build/js
|       `-- ./build/js/main.1a5a2e-bundle.js
|-- ./package-lock.json
|-- ./package.json
|-- ./public
|   `-- ./public/index.html
|-- ./src
|   |-- ./src/css
|   |   |-- ./src/css/style.css
|   |   |-- ./src/css/style.less
|   |   `-- ./src/css/style.scss
|   `-- ./src/main.js
`-- ./webpack.config.js
// ./webpack.config.js
const path = require("path");
// 匹配某一文件夹下的所有文
const glob = require("glob");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { DefinePlugin } = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

const { PurgeCSSPlugin } = require("purgecss-webpack-plugin");

module.exports = {
  mode: "production",
  entry: "./src/main.js",
  output: {
    clean: true,
    path: path.resolve(__dirname, "./build"),
    filename: "js/[name].[chunkhash:6]-bundle.js",
    chunkFilename: "js/[name].[contenthash:6]_chunk.js",
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              // 希望被前边几个 loader 处理
              importLoaders: 1,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [["postcss-preset-env"]],
              },
            },
          },
        ],
      },
      {
        test: /\.less$/i,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              importLoaders: 2,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [["postcss-preset-env"]],
              },
            },
          },
          "less-loader",
        ],
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              importLoaders: 2,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [["postcss-preset-env"]],
              },
            },
          },
          "sass-loader",
        ],
      },
    ],
  },
  resolve: {
    extensions: [".js", ".ts", ".json"],
  },
  optimization: {
    minimize: true,
    minimizer: [
      // CSS 压缩插件:CSSMinimzerPlugin
      new CssMinimizerPlugin({
        // 并发默认开启
        // parallel: true,
      }),
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "Webpack App",
      template: "./public/index.html",
      // html是否有改变,有就生成新的
      cache: true,
      // 默认值为 true,压缩html
    }),
    new DefinePlugin({
      BASE_URL: "'./'",
    }),
    // 实现 Css 的抽取
    new MiniCssExtractPlugin({
      filename: "css/[name].[contenthash:6].min.css",
    }),

    // 对 CSS 进行 TreeShaking
    new PurgeCSSPlugin({
      // src下的所有文件 不需要所有文件夹
      paths: glob.sync(`${path.resolve(__dirname, "./src")}/**/*`, {
        nodir: true,
      }),
      // 哪些选择器需要保留
      satisfies: function () {
        return {
          standard: [":root"],
        };
      },
    }),
  ],
};
<!-- ./public/index.html -->
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8" />
    <meta
      http-equiv="X-UA-Compatible"
      content="IE=edge"
    />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1.0"
    />
    <title><%= htmlWebpackPlugin.options.title %></title>
    <style>
      .nav-transparent .github-corner {
        display: none !important;
      }

      .github-corner {
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        border: 0;
        transform: scale(1.1);
      }

      .github-corner svg {
        fill: #fff;
        height: 64px;
        width: 64px;
      }

      .github-corner:hover .octo-arm {
        animation: a 0.56s ease-in-out;
      }

      .github-corner .octo-arm {
        animation: none;
      }

      @keyframes a {
        0%,
        to {
          transform: rotate(0);
        }
        20%,
        60% {
          transform: rotate(-25deg);
        }
        40%,
        80% {
          transform: rotate(10deg);
        }
      }
    </style>
  </head>
  <body>
    <div class="scss"></div>
    <noscript>
      <strong>
        We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
        properly without JavaScript enabled. Please enable it to continue.
      </strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
// ./src/main.js
import "./css/style.css";
import "./css/style.less";
import "./css/style.scss";

// 添加 div
const divEl = document.createElement("div");
divEl.className = "less";
divEl.textContent = "hahah";
document.body.append(divEl);

const aEl = document.createElement("a");
aEl.className = "a-active";
aEl.innerHTML = "我是a元素";
divEl.appendChild(aEl);
/* ./src/css/style.css */
:root {
  background-color: aqua;
}

.name {
  color: #333;
}

a {
  font-size: 50px;
}
.a-active {
  color: burlywood;
}
.less {
  font-size: medium;
}

button {
  color: red;
}
.scss {
  background-color: lightcoral;
  width: 100px;
  height: 100px;
}
  1. 执行 npx webpack 就得到打包后的产物

注意:如果发现打包后的 css 不是预期的 css-shaking,windows 系统请把 glob 降级,执行 npm i glob@7 -D


文章作者: PaoMo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 PaoMo !
  目录