webpack如何打包css样式

759 阅读2分钟

前言

今天我们一起来学习webpack是怎么打包CSS样式的。

webpack本身是无法打包CSS文件的,我们在使用时会遇到如下图中的报错。所以我们用借助loader来打包,loader的作用就是对特定类型的模块进行转换。

1678773045162.png

css-loader的使用

在项目目录下添加文件:

1678777902511.png

测试代码

// src -> main.js
​
import "./css/style_a.css";
// 测试less时放开
// import "./css/style_less.less"  
​
const h1Ele = document.createElement("h1");
h1Ele.innerText = "hello CSS";
h1Ele.className = "title";
​
const divEle = document.createElement("div");
divEle.innerText = "webpack bundle css";
divEle.className = "content";
​
document.body.append(h1Ele);
document.body.append(divEle);
 /* src -> css ->  style_a.css */.title {
    color: red;
    font-size: 32px;
    font-weight: 700;
}
.content {
    color: aqua;
    font-size: 14px;
}

安装css-loader

npm install css-loader -D
yarn add css-loader -D

loader配置方式:

// webpack.config.js 文件
​
const path = require("path");
module.exports = {
    entry: "./src/main.js",
    output: {
        path: path.resolve(__dirname,"./dist"),
        filename: "./build.js"
    },
    module: {
       rules: [
         {
            test: /.css$/,
            loader:"css-loader" // 当只有一个loader时,可以这样写
             // 有多个loader时,要用use
             // use:["loader-a","loader-b"]
         }
       ]
    }
}

说明:

  • module是一个对象,rules属性对应的值是一个数组,其中允许配置多个loader;

  • test属性:用于配置资源,通常设置成正则表达式;

  • use属性:对应一个数组 [UseEntry]

    • UseEntry是一个对象,可以通过对象的属性来设置一些属性
    • loader:对应一个loader的名称,对用的值是一个字符串
    • options:可选属性,设置一些其他属性

执行打包 npx webapck打包后,浏览器页面的效果

1678779187102.png

如上图所示,css样式并没有生效!

这是为什么呢?

  • css-loader只是负责将.css文件进行解析,并不会将解析之后的css插入到页面中;
  • 如果希望完成插入style的操作,那我们还需要另外一个loader,就是style-loader

style-loader的使用

安装style-loader

npm install style-laoder -D
yarn add style-laoder -D

配置style-loader

// webpack.config.js文件module.exports = {
    // ........
    module: {
       rules: [
         {
            test: /.css$/,
            use:["style-loader","css-loader"]  // 这里style-loader要写在css-loader前面,因为laoder的执行顺序是从右向左的
         }
       ]
    },
}
​

重新执行编译,发现样式生效了。

1678779798732.png

可以发现当前css样式是通过内联方式添加进来的。(在head标签中引入style)

在开发中,我们可能会使用less、sass等预处理器来编写css样式,效率会更高。

那么我们就要用相应的loader来转换,比如用less-loader把less转换成css。

less-loader的使用

安装

npm install less-loader -D
yarn add less-loader -D

配置less-loader

// webpack.config.js
​
module: {
       rules: [
         {
            test: /.less$/,
            use: ["style-loader","css-loader","less-loader"]
         }
       ]
},

编写less样式

@textColor: green;
@fontSize: 14px;
​
.content {
    color: @textColor;
    font-size: @fontSize;
}

重新执行编译,样式会生效

1678780684591.png

开发中有些样式需要适配不同的浏览器,根据目标浏览器添加前缀或者运行时环境添加所需的polyfill等。这时候需要postcss-loader来帮助我们完成。

postcss-loader的使用

添加前缀的插件我们不使用autoprefixer,用另一个插件:postcss-preset-env

postcss-preset-env是一个postcss插件,也可以自动帮助我们添加前缀

安装:

npm install postcss-loader postcss-preset-env -D
yarn add postcss-loader postcss-preset-env -D

配置:

// webpack.config.js
​
module: {
       rules: [
         {
            test: /.css$/,
            use:[
                "style-loader",
                "css-loader",
                {
                    loader: "postcss-loader",
                    options:{
                        postcssOptions: {
                            plugins: [
                                "postcss-preset-env"
                            ]
                        }
                    }
                }
            ]
         }
       ]
    },

单独的postcss配置文件

  • 在根目录下创建postcss.config.js
// postcss.config.jsmodule.exports ={
    plugins:[
        "postcss-preset-env"
    ]
}

页面效果如图所示:

1678781727538.png

  • 目前所有的样式都是以内联方式直接插入到head中的,随着开发的页面越来越多,head标签会越来越复杂,而已静态文件会越来越大,下载bundle时消耗很大的流量;
  • 这个时候在生产环境中我们需要优化,把css提取到独立的css文件中;
  • MiniCssExtractPlugin可以帮助我们完成;

MiniCssExtractPlugin

安装:

npm install mini-css-extract-plugin -D
yarn add mini-css-extract-plugin -D

配置:

// webpack.config.jsconst MiniCssExtractPlugin = require("mini-css-extract-plugin");
​
mudule.exports ={
    // .......
     module: {
       rules: [
         {
            test: /.css$/,
            use:[
                MiniCssExtractPlugin.loader,   // MiniCssExtractPlugin.loader可以取代style-loader
                "css-loader"
            ]
         }
       ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: "css/[name].css",   // 打包后css文件的名称
            chunkFilename: "css/[name].css"
            // 更多配置请查阅相关文档
        })
    ]
}

重新打包后,dist目录下新增了css文件,在index.html可以看到以link形式引入了css样式。

1678783253484.png

1678783280279.png

在生产环境中,css优化手段还有压缩,下图中是打包过后的css文件,还有很多空格,空格也会占用空间的大小。

1678783471871.png

css的压缩

  • css的压缩通常是去除无用的空格,因为很难去修改选择器、属性的名称、值等;
  • css的压缩我们可以使用另外一个插件:css-minimizer-webpack-plugin;
  • css-minimizer-webpack-plugin底层是用cssnano工具来优化、压缩css的;

安装:

npm install css-minimizer-webpack-plugin -D
yarn add css-minimizer-webpack-plugin -D

在optimization.minimizer中配置

// webpack.config.jsconst CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
​
module.exports = {
    // ..................
    optimization:{
      minimize: true, // 开启压缩
      minimizer: [
        new CssMinimizerPlugin({
            // 更多配置请查阅相关文档
        })
      ]
    }
    // ...............
}
​
​

打包后的css文件,如图

1678784987086.png

css中消除无用的代码

我们在生产环境还需要消除css中无用的代码(死代码)来进一步的优化;

这时候需要借助purgecss-webpack-plugin插件来帮助实现;

安装:

npm install purgecss-webpack-plugin -D

配置:

// webpack.config.jsconst glob = require("glob");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { PurgeCSSPlugin } = require("purgecss-webpack-plugin");
​
module.exports = {
  // ........
  module: {
    rules: [
      {
        test: /.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name].css",
      chunkFilename: "css/[name].css",
    }),
    new PurgeCSSPlugin({   // 配合MiniCssExtractPlugin一起使用
      paths: glob.globSync(`${path.join(__dirname, "src")}/**/*`, { nodir: true }) 
      // 更多配置请查阅相关文档
    }),
  ],
};
/* src -> css ->  style_a.css */.title {
​
    color: red;
​
    font-size: 32px;
​
    font-weight: 700;
​
}
​
/* 这个类没有用到,将会被清除 */.content {
​
    color: aqua;
​
    font-size: 14px;
​
}
​

以上就是全部,谢谢!