手把手带你学webpack(2)-- Webpack与css预处理器、PostCSS

901 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

上一章我们讲解了什么是webpack,以及在webpack中使用css-loader解析css模块,并用style-css将解析出来的样式添加到页面中

这章我们会讲一下怎么在webpack中使用less/sasscss预处理器,以及PostCSS的使用

1. 在webpack中使用less

首先需要安装less

pnpm i less -D

然后在src/less中创建index.less,并编写一些less样式

@primaryColor: #1d3557;
@successColor: #a8dadc;
@fontColor: #8d99ae;
@fontSize: 48px;
@fontWeight: 700;

* {
  margin: 0;
  padding: 0;
}

html,
body {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 64px;
  height: 100%;
  width: 100%;
  background-color: @primaryColor;
}

.box {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 500px;
  width: 500px;
  border-radius: 20px;
  box-shadow: 0 5px 2px 0 rgba(0, 0, 0, 0.5);
  background-color: @successColor;

  p {
    font-size: @fontSize;
    font-weight: @fontWeight;
    color: @fontColor;
  }
}

入口文件index.js中导入less样式以及创建DOM元素

// src/index.js
import './less/index.less';

(() => {
  // 创建盒子
  const boxEl = createEl('div', 'box');
  boxEl.innerHTML = `
    <p>Hello Webpack!</p>
  `;
  document.body.appendChild(boxEl);
})();

/**
 * 创建指定标签和类名的 DOM 元素
 * @param {string} elTag 标签名
 * @param {string} className 类名
 * @returns HTMLElement DOM 元素
 */
function createEl(elTag, className) {
  const el = document.createElement(elTag);

  el.className = className;

  return el;
}

less是可以单独使用的,通过lessc命令可以将less文件编译成css文件

npx lessc .\src\less\index.less .\src\css\index.css

但是每次都要这样去手动编译一下太麻烦了,我们希望能够交给webpack去解析less文件的模块,并且添加到页面中使其生效,那么就需要用到less-loader

pnpm i less-loader -D

webpack.config.js中配置less-loader

/**
 * @type { import('webpack').Configuration }
 */
module.exports = {
  module: {
    rules: [
      {
        test: /\.less/,
        use: ['style-loader', 'css-loader', 'less-loader'],
      },
    ],
  },
};

还记得上一章讲过的吗?webpackloader的使用顺序是逆序的,我们需要先加载less文件,让其处理成css文件,然后再加载css文件,得到样式后再通过style-loader添加到页面中,因此顺序是['style-loader', 'css-loader', 'less-loader'],千万不能将顺序写错!

接下来运行npm run build即可看到效果 image.png


2. 在webpack中使用sass/scss

和使用less的原理一样,首先我们肯定是需要一个sass-loader去加载sass/scss文件成css文件,然后通过css-loader加载css文件变成样式,再通过style-loader将样式添加到页面中

首先写一个简单的scss样式文件,src/scss/index.scss

$circleColor: #f1faee;

.circle {
  height: 300px;
  width: 300px;
  background-color: $circleColor;
  border-radius: 50%;
}

然后修改入口文件,导入scss样式文件,并创建两个类名为circleDOM元素

// src/index.js
import './less/index.less';
import './scss/index.scss';

(() => {
  // 创建中间的盒子
  const boxEl = createEl('div', 'box');
  boxEl.innerHTML = `
    <p>Hello Webpack!</p>
  `;

  // 创建两个圆圈
  const circleEl1 = createEl('div', 'circle');
  const circleEl2 = createEl('div', 'circle');

  // 将圆圈和盒子作为 body 的子节点
  document.body.appendChild(circleEl1);
  document.body.appendChild(boxEl);
  document.body.appendChild(circleEl2);
})();

/**
 * 创建指定标签和类名的 DOM 元素
 * @param {string} elTag 标签名
 * @param {string} className 类名
 * @returns HTMLElement DOM 元素
 */
function createEl(elTag, className) {
  const el = document.createElement(elTag);

  el.className = className;

  return el;
}

运行pnpm run build看看结果 image.png scss文件也被正常解析啦!可见项目中是可以同时使用lessscss的,只要正确安装和配置了相应的loader即可

相信到目前为止,你对webpackloader有一个大概的了解了,也应该能够明白它的重要性,正是有各种各样的loader,才使得webpack能够加载各种类型的文件作为模块

这也就意味着只要有相应的loader,就能在js中通过import导入任何文件类型到你的项目中,但是如果遇到那么一种情况,这个文件类型是你自己定义的,没有相应的loader去加载它,这时候就需要自己编写属于你的loader去处理你定义的这种文件了,这个之后会专门开一篇文章讲解如何编写自定义loader,敬请期待!


3. 在webpack中使用PostCSS

PostCSS是什么?

  • PostCSS是一个工具,它能够通过js来转换样式
  • PostCSS本身单独使用并没有什么作用,要结合各种插件才能感受到它的强大

3.1 体验PostCSS

可以通过安装postcsspostcss-cli在命令行中体验一下postcss

pnpm i postcss postcss-cli -D

我们使用postcss中最常用的一个插件autoprefixer,这个插件是用于解决浏览器兼容性问题的,大家都知道,有的css3特性在个别内核的浏览器中是需要添加对应前缀的

webpack官方文档中的示例为例,假设我们想要在css中使用:fullscreen这个伪类,但是由于兼容性的问题,如果要让它在webkit和微软的浏览器中生效,我们需要再写两个:-webkit-fullscreen:-ms-fullscreen的伪类选择器,十分麻烦

通过autoprefixer这个postcss的插件,就可以自动帮我们加上兼容性相关的前缀,当然,这取决于你需要适配什么样的浏览器,这个可以通过browserslist这个小工具进行配置,关于该工具大家可以自行谷歌,这里不多赘述

现在我们来安装一下autoprefixer

pnpm i autoprefixer -D

然后创建一个css文件,使用:fullscreen伪类选择器写一些样式

:fullscreen {
  padding: 10px;
  background-color: cyan;
}

然后运行如下命令

npx postcss --use autoprefixer  -o foo.css .\src\css\index.css

然后就在项目根目录下生成了foo.css,其内容如下

:-webkit-full-screen {
  padding: 10px;
  background-color: cyan;
}
:-ms-fullscreen {
  padding: 10px;
  background-color: cyan;
}
:fullscreen {
  padding: 10px;
  background-color: cyan;
}

为我们自动加上了前缀和相应的样式,大大节省了浏览器兼容性适配上的机械操作!


3.2 结合webpack使用

3.2.1 在webpack的配置文件中配置

和之前类似,要想在webpack中使用PostCSS,首先需要安装postcss-loaderwebpack支持使用PostCSS

这个loader和之前不一样,它不是去加载某种格式的文件,而是去调用js代码去处理css文件,调用的js就是前面安装的postcss,相当于帮我们干了刚刚在命令行里干的那些事情

首先安装postcss-loader

pnpm i postcss-loader -D

然后在webpack.config.js中配置postcss-loader去处理css文件

/**
 * @type { import('webpack').Configuration }
 */
module.exports = {
  module: {
    rules: [
      {
        test: /\.css/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [require('autoprefixer')],
              },
            },
          },
        ],
      },
    ],
  },
};

由于需要指定postcss使用autoprefixer插件,因此这里use中采用对象形式而不是字符串形式去配置loader了,在options中提供postcss规定好的配置项即可

因为需要先修改css文件,添加浏览器兼容性前缀,所以我们需要在css-loader被使用之前先让postcss-loader去修改css文件,因此它应当被放在use数组的最后

index.js中导入css文件

// src/index.js
import './css/index.css';

打包查看结果 image.png 成功生效!


3.2.2 使用单独的配置文件postcss.config.js

实际上除了在webpack.config.js中配置postcss使用autoprefixer插件之外,还可以在项目根目录下创建一个postcss.config.js去配置postcss

我们将webpack.config.js中使用autoprefixer的配置注释掉,只配置使用postcss-loader

// webpack.config.js
/**
 * @type { import('webpack').Configuration }
 */
module.exports = {
  module: {
    rules: [
      {
        test: /\.css/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            // options: {
            //   postcssOptions: {
            //     plugins: [require('autoprefixer')],
            //   },
            // },
          },
        ],
      },
    ],
  },
};

然后在项目根目录下创建postcss.config.js

module.exports = {
  plugins: [require('autoprefixer')],
};

重新打包后仍然能够生效