提取 css 文件及处理

SOBER大约 3 分钟

提取 css 文件及处理

在 js 中提取 css

css 文件目前被打包到 js 文件中,当 js 文件加载时,会动态创建一个 style 标签来生成样式

这样对于网站来说,会出现闪屏现象,用户体验不好

我们应该是单独的 css 文件通过 link 标签加载性能才好

1. 下载包

npm install mini-css-extract-plugin -D

2. 配置

  • webpack.prod.js
      const path = require("path")
      const ESlintPlugin = require('eslint-webpack-plugin')
      const HtmlWebpackPlugin = require('html-webpack-plugin')
      const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    
      module.exports = {
          entry: "./src/main.js",
          output: {
              path: path.resolve(__dirname, "../dist"),
              filename: "static/js/main.js",
          },
          module: {
              rules: [
                  /**
                  * 将所有的 style-loader 改为 MiniCssExtractPlugin.loader
                  * MiniCssExtractPlugin.loader 可以提取 css 成单独文件
                  */
                  {
                      test: /\.css$/i,
                      use: [MiniCssExtractPlugin.loader, "css-loader"]
                  },
                  {
                      test: /\.less$/i,
                      use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"]
                  },
                  {
                      test: /\.s[ac]ss$/i,
                      use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"]
                  },
                  {
                      test: /\.styl$/i,
                      use: [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"]
                  },
                  {
                      test: /\.(png|jpe?g|gif|webp|svg)$/,
                      type: "asset",
                      parser: {
                          dataUrlCondition: {
                              maxSize: 600 * 1024, // 600kb
                          }
                      },
                      generator: {
                          filename: "static/images/[hash:10][ext][query]",
                      }
                  },
                  {
                      test: /\.(ttf|woff2|map3|map4|avi)$/,
                      type: "asset/resource",
                      generator: {
                          filename: "static/media/[hash:10][ext][query]",
                      }
                  },
                  {
                      test: /\.js$/,
                      exclude: /node_modules/, /
                      use: {
                          loader: "babel-loader",
                      }
                  }
              ]
          },
    
          plugins: [
              new ESlintPlugin({
                  context: path.resolve(__dirname, "../src")
              }),
              new HtmlWebpackPlugin({
                  template: path.resolve(__dirname, "../public/index.html")
              }),
              new MiniCssExtractPlugin({
                  /** 指定输出文件路径和文件名 */
                  filename: "static/css/main.css"
              })
          ],
          mode: "production",
      }
    

css 兼容性处理

1. 下载包

npm i postcss-loader postcss postcss-preset-env -D

2. 配置

  • webpack.prod.js
      const path = require("path")
      const ESlintPlugin = require('eslint-webpack-plugin')
      const HtmlWebpackPlugin = require('html-webpack-plugin')
      const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    
      module.exports = {
          entry: "./src/main.js",
          output: {
              path: path.resolve(__dirname, "../dist"),
              filename: "static/js/main.js",
          },
          module: {
              rules: [
                  {
                      test: /\.css$/i,
                      use: [
                          MiniCssExtractPlugin.loader, "css-loader",
                          {
                              loader: "postcss-loader",
                              options: {
                                  postcssOptions: {
                                      plugins: ["postcss-preset-env"] // 能解决大多数样式兼容性问题
                                  }
    
                              }
                          }
                      ]
                  },
                  /** 这里注意顺序,less-loader 在后面 */
                  {
                      test: /\.less$/i,
                      use: [MiniCssExtractPlugin.loader, "css-loader",
                      {
                          loader: "postcss-loader",
                          options: {
                              postcssOptions: {
                                  plugins: ["postcss-preset-env"] // 能解决大多数样式兼容性问题
                              }
    
                          }
                      },
                          "less-loader",
                      ]
                  },
                  /** 这里注意顺序,sass-loader 在后面 */
                  {
                      test: /\.s[ac]ss$/i,
                      use: [MiniCssExtractPlugin.loader, "css-loader", 
                      {
                          loader: "postcss-loader",
                          options: {
                              postcssOptions: {
                                  plugins: ["postcss-preset-env"] // 能解决大多数样式兼容性问题
                              }
    
                          }
                      },
                      "sass-loader"
                  ]
                  },
                  /** 这里注意顺序,stylus-loader 在后面 */
                  {
                      test: /\.styl$/i,
                      use: [MiniCssExtractPlugin.loader, "css-loader", 
                      {
                          loader: "postcss-loader",
                          options: {
                              postcssOptions: {
                                  plugins: ["postcss-preset-env"] // 能解决大多数样式兼容性问题
                              }
    
                          }
                      },
                      "stylus-loader"
                  ]
                  },
                  {
                      test: /\.(png|jpe?g|gif|webp|svg)$/,
                      type: "asset",
                      parser: {
                          dataUrlCondition: {
                              maxSize: 600 * 1024, // 600kb
                          }
                      },
                      generator: {
                          filename: "static/images/[hash:10][ext][query]",
                      }
                  },
                  {
                      test: /\.(ttf|woff2|map3|map4|avi)$/,
                      type: "asset/resource",
                      generator: {
                          filename: "static/media/[hash:10][ext][query]",
                      }
                  },
                  {
                      test: /\.js$/,
                      exclude: /node_modules/, 
                      use: {
                          loader: "babel-loader",
                      }
                  }
              ]
          },
    
          plugins: [
              new ESlintPlugin({
                  context: path.resolve(__dirname, "../src")
              }),
              new HtmlWebpackPlugin({
                  template: path.resolve(__dirname, "../public/index.html")
              }),
              new MiniCssExtractPlugin({
                  filename: "static/css/main.css"
              })
          ],
          /** 生产模式 */
          mode: "production",
      }
    

3. 控制兼容性

我们可以在 package.json 文件中添加 browserslist 来控制样式的兼容性做到什么程度。

{
    "browserslist": [
    "ie >= 8"
  ]
}

了解更多的 browserslist 配置open in new window
以上为了测试兼容性所以设置兼容浏览器 ie8 以上。实际开发中我们一般不考虑旧版本浏览器了,所以我们可以这样设置

{
    "browserslist": [
        "last 2 version",
        "> 1%",
        "not dead"
    ]
}

4. 合并配置

const path = require("path")
const ESlintPlugin = require('eslint-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

/** 提取公共配置 */
function getStyleLoader(pre) {
    return [
            MiniCssExtractPlugin.loader, "css-loader",
            {
                loader: "postcss-loader",
                options: {
                    postcssOptions: {
                        plugins: ["postcss-preset-env"] // 能解决大多数样式兼容性问题
                    }
                }
            },
            pre
    ].filter(Boolean) // .filter(Boolean) 会将 pre 的值为 undefined 过滤掉
}

module.exports = {
    entry: "./src/main.js",
    output: {
        path: path.resolve(__dirname, "../dist"),
        filename: "static/js/main.js",
    },
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: getStyleLoader()
            },
            {
                test: /\.less$/i,
                use: getStyleLoader("less-loader")
            },
            {
                test: /\.s[ac]ss$/i,
                use: getStyleLoader("sass-loader")
            },
            {
                test: /\.styl$/i,
                use: getStyleLoader("stylus-loader")
            },
            {
                test: /\.(png|jpe?g|gif|webp|svg)$/,
                type: "asset",
                parser: {
                    dataUrlCondition: {
                        maxSize: 600 * 1024, // 600kb
                    }
                },
                generator: {
                    filename: "static/images/[hash:10][ext][query]",
                }
            },
            {
                test: /\.(ttf|woff2|map3|map4|avi)$/,
                type: "asset/resource",
                generator: {
                    filename: "static/media/[hash:10][ext][query]",
                }
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader",
                }
            }
        ]
    },

    plugins: [
        new ESlintPlugin({
            context: path.resolve(__dirname, "../src")
        }),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, "../public/index.html")
        }),
        new MiniCssExtractPlugin({
            filename: "static/css/main.css"
        })
    ],
    /** 生产模式 */
    mode: "production",
}

css 压缩

1. 下载包

npm install css-minimizer-webpack-plugin -D

2. 配置

const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
    plugins: [
        new CssMinimizerWebpackPlugin()
    ],
    /** 生产模式 */
    mode: "production",
}

html 压缩

默认生产模式已经开启了 html 压缩和 js 压缩

不需要额外进行配置