一、css-loader

从代码案例开始

  1. import './css/index.css'
  2. function component() {
  3. let element = document.createElement('div');
  4. element.innerHTML = ['Hello', 'Webpack'].join(' ');
  5. element.className = 'content';
  6. return element;
  7. }
  8. document.body.appendChild(component());

设置样式:

  1. .content{
  2. color:aqua
  3. }

此时进行打包:

ERROR in ./src/css/index.css 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> .content{
|     color:aqua
| }
 @ ./src/component.js 1:0-24
 @ ./src/main.js 2:0-23

上面的错误信息告诉我们需要一个loader来加载这个css文件,但是loader是什么呢?

  • loader 可以用于对模块的源代码进行转换;
  • 我们可以将css文件也看成是一个模块,我们是通过import来加载这个模块的;
  • 在加载这个模块时,webpack其实并不知道如何对其进行加载,我们必须制定对应的loader来完成这个功能
  • 那么我们需要一个什么样的loader呢?

    • 对于加载css文件来说,我们需要一个可以读取css文件的loader;
    • 这个loader最常用的是css-loader;
    • css-loader的安装: npm install css-loader -D

loader使用方案

  1. 内联方式;
  2. CLI方式(webpack5中不再使用);
  3. 配置方式;

内联方式:使用较少,因为不方便管理; 在引入的样式前加上使用的loader,并且使用!分割

import 'css-loader!../css/index.css'

CLI方式 :在webpack5的文档中已经没有了—module-bind; 实际应用中也比较少使用,因为不方便管理

配置方式 - 重点

配置方式表示的意思是在我们的webpack.config.js文件中写明配置信息:

  • module.rules中允许我们配置多个loader(因为我们也会继续使用其他的loader,来完成其他文件的加载);
  • 这种方式可以更好的表示loader的配置,也方便后期的维护,同时也让你对各个Loader有一个全局的概览;

module.rules的配置如下:

  • rules属性对应的值是一个数组:[Rule] 数组中存放的是一个个的Rule,Rule是一个对象,对象中可以设置多个属性:

    • test属性:用于对 resource(资源)进行匹配的,通常会设置成正则表达式;
    • use属性:对应的值时一个数组:[UseEntry] UseEntry是一个对象,可以通过对象的属性来设置一些其他属性

      • loader:必须有一个 loader属性,对应的值是一个字符串;
      • options:可选的属性,值是一个字符串或者对象,值会被传入到loader中
      • query:目前已经使用options来替代;

传递字符串(如:use: [ ‘style-loader’ ])是 loader 属性的简写方式(如:use: [ { loader: ‘style-loader’} ])

loader属性: Rule.use: [ { loader } ] 的简写。

代码:

const path = require('path');
module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    //__dirname,当前文件的上级目录的绝对路径
    path: path.resolve(__dirname, './build'),
  },
  module: {
    rules: [
      {
        test: /\.css&/,
        // use: [{ loader: 'css-loader'}],

        // //上面方式的简写方式
        use:["css-loader"],

        // //上上面方式的简写方式
        // loader:"css-loader"
      },

    ],
  },
};

二、style-loader

此时会发现这个css在我们的代码中并没有生效(页面没有效果)。 这是为什么呢?

  1. 因为css-loader只是负责将.css文件进行解析,并不会将解析之后的css插入到页面中;
  2. 如果我们希望再完成插入style的操作,那么我们还需要另外一个loader,就是style-loader;
  3. 安装style-loader: npm install style-loader -D
use: [
          //webpack自下而上自右到左进行解析,
          //先要解析css,在加载样式
          //所以css-loader放上面
          'style-loader',
          'css-loader',
        ],

loader的执行顺序是从右向左(或者说从下到上,或者说从后到前的),

所以我们需要将style-loader写到css-loader的前面;

重新执行编译npm run build,可以发现打包后的css已经生效了:

当前目前我们的css是通过页内样式的方式添加进来的,放到了header里

2、webpack-loader的使用 - 图1

后续我们也会讲如何将css抽取到单独的文件中,并且进行压缩等操作;

三、less-loader

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

那么,如何可以让我们的环境支持这些预处理器呢?

首先我们需要确定,less、sass等编写的css需要通过工具转换成普通的css;

比如我们编写如下的less样式:

@fontSize: 26px;
@fontWeight: 700;

.content {
    font-size: @fontSize;
    font-weight: @fontWeight;
}

可以使用less工具来完成它的编译转换:

执行如下命令:

npm install less -D

npx less ./src/css/title.less > title.css

在引入相应css文件即可

但是有很多less文件呢?还是得使用less-loader

npm i less less-loader -D

{
        test: /\.less$/,
        use: [
          { loader: 'style-loader' },
          { loader: 'css-loader' },
          { loader: 'less-loader' },
        ],
      },

此时就可以正常显示了。

四、浏览器兼容性

开发中,浏览器的兼容性问题,我们应该如何去解决和处理?

  • 这里说的兼容性问题不是指屏幕大小的变化适配;
  • 而是针对不同的浏览器支持的特性:比如css特性、js语法,之间的兼容性;

市面上有大量的浏览器:

  • 有Chrome、Safari、IE、Edge、Chrome for Android、UC Browser、QQ Browser等等
  • 它们的市场占率是多少?要不要兼容它们呢?

其实在很多的脚手架配置中,都能看到类似于这样的配置信息:

这里的百分之一,就是指市场占有率

>1% 

last 2 versions 

not dead

哪里可以查询到浏览器的市场占有率呢?

最好用的网站,也是我们工具通常会查询的一个网站就是caniuse:https://caniuse.com/usage-table

browserslist工具

有一个问题,我们如何可以在css兼容性和js兼容性下共享我们配置的兼容性条件呢?

  • 就是当我们设置了一个条件: > 1%;
  • 表达的意思是css要兼容市场占有率大于1%的浏览器,js也要兼容市场占有率大于1%的浏览器

如果我们是通过工具来达到这种兼容性的,比如后面我们会讲到的postcss-prest-env、babel、autoprefixer等

如何可以让他们共享(知道)我们的配置呢? 这个问题的答案就是Browserslist;

Browserslist是什么?

Browserslist是一个在不同的前端工具之间,共享目标浏览器和Node.js版本的配置的工具:

Autoprefixer

Babel

postcss-preset-env

eslint-plugin-compat

stylelint-no-unsupported-browser-features

postcss-normalize

obsolete-webpack-plugin

浏览器查询过程

我们可以编写类似于这样的配置:

>1% 

last 2 versions 

not dead

之后,这些工具会根据我们的配置来获取相关的浏览器信息,以方便决定是否需要进行兼容性的支持:

条件查询使用的是caniuse-lite的工具,这个工具的数据来自于caniuse的网站上;

Browserslist编写规则一:

那么在开发中,我们可以编写的条件都有哪些呢?(加粗部分是最常用的)

defaults:

  • Browserslist的默认浏览器(> 0.5%, last 2 versions, Firefox ESR, not dead)。

5%:

  • 通过全局使用情况统计信息选择的浏览器版本。 >=,<和<=。
5% in US:使用美国使用情况统计信息。它接受两个字母的国家/地区代码。
> 5% in alt-AS:使用亚洲地区使用情况统计信息。有关所有区域代码的列表,请参见caniuse-lite/data/regions  
>5% in my stats:使用自定义用法数据。 
> 5% in browserslist-config-mycompany stats:使用 来自的自定义使用情况数据browserslist-config-mycompany/browserslist-stats.json。 
cover 99.5%:提供覆盖率的最受欢迎的浏览器。 
cover 99.5% in US:与上述相同,但国家/地区代码由两个字母组成。 
cover 99.5% in my stats:使用自定义用法数据。

last 2 versions:

  • 每个浏览器的最后2个版本。
  • last 2 Chrome versions:最近2个版本的Chrome浏览器。
  • last 2 major versions或last 2 iOS major versions:最近2个主要版本的所有次要/补丁版本。

dead:

  • 24个月内没有官方支持或更新的浏览器。
  • 现在是IE 10,IE_Mob 11,BlackBerry 10,BlackBerry 7, Samsung 4和OperaMobile 12.1。

Browserslist编写规则二:

node 10和node 10.4:选择最新的Node.js10.x.x 或10.4.x版本。

current node:Browserslist现在使用的Node.js版本。

maintained node versions:所有Node.js版本,仍由 Node.js Foundation维护。

iOS 7:直接使用iOS浏览器版本7。

Firefox > 20:Firefox的版本高于20 >=,<并且<=也可以使用。它也可以与Node.js一起使用。

ie 6-8:选择一个包含范围的版本。

Firefox ESR:最新的[Firefox ESR]版本。

PhantomJS 2.1和PhantomJS 1.9:选择类似于PhantomJS运行时的Safari版本。

extends browserslist-config-mycompany:从browserslist-config-mycompanynpm包中查询 。

supports es6-module:支持特定功能的浏览器。 es6-module这是“我可以使用” 页面feat的URL上的参数。有关所有可用功能的列表,请参见 。caniuselite/data/features

browserslist config:在Browserslist配置中定义的浏览器。在差异服务中很有用,可用于修改用户的配置,例如 browserslist config and supports es6-module。

since 2015或last 2 years:自2015年以来发布的所有版本(since 2015-03以及since 2015-03-10)。

unreleased versions或unreleased Chrome versions:Alpha和Beta版本。

not ie <= 8:排除先前查询选择的浏览器。

命令行使用browserslist

我们可以直接通过命令来查询某些条件所匹配到的浏览器:

npx browserslist “>1%, last 2 version, not dead”

bb 10
bb 7
ie 10
ie 9
ie 8
ie 7
ie 6
ie 5.5
ie_mob 11
ie_mob 10
op_mob 12.1
op_mob 12
op_mob 11.5
op_mob 11.1
op_mob 11
op_mob 10
samsung 4

配置browserslist

方案一:在package.json中配置

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

方案二:单独的一个配置文件.browserslistrc文件

2、webpack-loader的使用 - 图2

如果没有配置,那么也会有一个默认配置:

2、webpack-loader的使用 - 图3

我们编写了多个条件之后,多个条件之间是什么关系呢?

2、webpack-loader的使用 - 图4

五、postcss

PostCSS是一个通过JavaScript来转换样式的工具;

这个工具可以帮助我们进行一些CSS的转换和适配,

比如自动添加浏览器前缀、css样式的重置;

但是实现这些工具,我们需要借助于PostCSS对应的插件;

如何使用PostCSS呢?主要就是两个步骤:

  • 第一步:查找PostCSS在构建工具中的扩展,比如webpack中的postcss-loader;
  • 第二步:选择可以添加你需要的PostCSS相关的插件;

总结:postcss本身功能较少,实现相关的功能需要借助相关的插件。

命令行使用postcss

能不能也直接在终端使用PostCSS呢? 也是可以的,但是我们需要单独安装一个工具postcss-cli;

可以安装一下它们:postcss、postcss-cli

npm i postcss postcss-cli -D

编写一个需要添加前缀的css:

:fullscreen {
}
.contant {
  user-select: none;
}

https://autoprefixer.github.io/ 我们可以在上面的网站中查询一些添加css属性的样式;

执行命令

npx postcs -o res.css ./src/css/test.css
  • -o 指定输出文件名称
  • ./src/css/test:因为postcss在node_modules目录下。src与node_modules同级,所以./

执行完res.css文件并没有加上浏览器前缀,因为默认postcss没有这个功能,需要插件协助。

npm i autoprefixer -D

指定使用插件autoprefixer

npx postcss --use autoprefixer -o end.css ./src/css/style.css

此时的res.css文件:

六、postcss-loader

真实开发中必然不会直接使用命令行工具来对css进行处理,而是可以借助于构建工具:

在webpack中使用postcss就是使用postcss-loader来处理的

  • 安装postcss-loader
  • 修改加载css的loader
  • 注意:因为postcss需要有对应的插件才会起效果,所以我们需要配置它的plugin;

npm i postcss-loader

use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [require('autoprefixer')],
              },
            },
          },
        ],

postcss-preset-env

在配置postcss-loader时,我们配置插件并不需要使用autoprefixer。

我们可以使用另外一个插件:postcss-preset-env

  • ppostcss-preset-env也是一个postcss的插件;
  • 它可以帮助我们将一些现代的CSS特性,转成大多数浏览器认识的CSS,并且会根据目标浏览器或者运行时环境添加所需的polyfill;
  • 也包括会自动帮助我们添加autoprefixer(所以相当于已经内置了autoprefixer

首先,我们需要安装postcss-preset-env:

之后,我们直接修改掉之前的autoprefixer即可

{
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  require('postcss-preset-env'),
                ],
              },
            },
          },

使用十六进制的颜色时设置了8位;但是某些浏览器可能不认识这种语法,我们最好可以转成RGBA的形式; 但是autoprefixer是不会帮助我们转换的; p而postcss-preset-env就可以完成这样的功能;

.content {color:#12345678}

2、webpack-loader的使用 - 图5

注意:

我们在使用某些postcss插件时,也可以直接传入字符串

{
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: ['postcss-preset-env'],
              },
            },
          },

可以单独配置postcss

根目录下创建postcss.config.js

module.exports = {
  plugins: [require('postcss-preset-env')],
};

importLoaders

我们css文件中导入css文件

index.css文件中:

@import './component.css'

那么loader在解析index.css的时候

postcss-loader会处理index.css文件的样式

然后交给css-loader处理,css-loader发现@import ‘./component.css’会导入并处理相关文件

但这个文件就不会被postcss-loader处理了

这就是一个问题,怎么处理呢?

{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader',

代表遇到@import导入其他css文件时,上一个loader先处理一下,也就是postcss-loader

这个数字视情况而定,需要几个就写几。

七、file-loader

要处理jpg、png等格式的图片,我们也需要有对应的loader:file-loader

file-loader的作用就是帮助我们处理import/require()方式引入的一个文件资源,并且会将它放到我们输出的文件夹中

当然我们待会儿可以学习如何修改它的名字和所在文件夹

安装file-loader

npm install file-loader -D

编写代码:

/创建一个img标签
  const imgEL = new Image();
  imgEL.src = require('../img/7.jpg').default;
  element.appendChild(imgEL);

  //创建一个div 设置背景图片
  const divEL = document.createElement('div');
  divEL.style.width = 200 + 'px';
  divEL.style.height = 200 + 'px';
  // divEL.className = 'bg-img';
  element.appendChild(divEL);
.bg-color {
  background-image: url('../img/avatar.jpg');
  background-color: lightblue;
}

配置处理图片的Rule:

{
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: ['file-loader'],
      },

2、webpack-loader的使用 - 图6

正常是可以显示的,但报了一个错误,后续再解决吧

2、webpack-loader的使用 - 图7

文件名称命名规则

有时候我们处理后的文件名称按照一定的规则进行显示:

比如保留原来的文件名、扩展名,同时为了防止重复,包含一个hash值等;

介绍几个最常用的placeholder:

  • [ext]: 处理文件的扩展名;
  • [name]:处理文件的名称;
  • [hash]:文件的内容,使用MD4的散列函数处理,生成的一个128位的hash值(32个十六进制)
  • [contentHash]:在file-loader中和[hash]结果是一致的(在webpack的一些其他地方不一样,后面会讲到)
  • [hash:length]:截图hash的长度,默认32个字符太长了
  • [path]:文件相对于webpack配置文件的路径;

设置文件名称

那么我们可以按照如下的格式编写

这个也是vue的写法

{
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: [{loader:'file-loader',options:{
          name:'img/[name].[hash:8].[ext]',
          // outputPath:'img'
        }}],
      },

2、webpack-loader的使用 - 图8

刚才通过 img/ 已经设置了文件夹,这个也是vue、react脚手架中常见的设置方式:

其实按照这种设置方式就可以了

当然我们也可以通过outputPath来设置输出的文件夹

outputPath:'img'

八、url-loader

url-loader和file-loader的工作方式是相似的,但是可以将较小的文件,转成base64的URI。

安装url-loader:

npm install url-loader -D

  • 显示结果是一样的,并且图片可以正常显示
  • 但是在build文件夹中,我们会看不到图片文件
  • 这是因为我的两张图片的大小分别是38kb和295kb
  • 默认情况下url-loader会将所有的图片文件转成base64编码
{
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: [{loader:'url-loader',options:{
          name:'img/[name].[hash:8].[ext]',
          // outputPath:'img'
        }}],
      },

2、webpack-loader的使用 - 图9

limit

开发中我们往往是小的图片需要转换,但是大的图片直接使用图片即可

  • 这是因为小的图片转换base64之后可以和页面一起被请求,减少不必要的请求过程
  • 而大的图片也进行转换,反而会影响页面的请求速度

那么,我们如何可以限制哪些大小的图片转换和不转换呢

  • purl-loader有一个options属性limit,可以用于设置转换的限制;
  • 下面的代码38kb的图片会进行base64编码,而295kb的不会;
{
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: [{loader:'url-loader',options:{
          limint:100 * 1024,
          name:'img/[name].[hash:8].[ext]',
          // outputPath:'img'
        }}],
      },

100 * 1024即100kb。

九、 asset module type

当前使用的webpack版本是webpack5:

  • 在webpack5之前,加载这些资源我们需要使用一些loader,比如raw-loader 、url-loader、file-loader
  • 在webpack5之后,可以直接使用资源模块类型(asset module type),来替代上面的这些loader

资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader

  • passet/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader实现
  • passet/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现
  • passet/source 导出资源的源代码。之前通过使用 raw-loader 实现
  • passet 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现
{
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset/resource',
      },

2、webpack-loader的使用 - 图10

file-loader url-loader可以卸载了

如何可以自定义文件的输出路径和文件名呢?

  • 方式一:修改output,添加assetModuleFilename属性
assetModuleFilename: 'img/[name].[hash:6][ext]',

[ext]自带.不用再另加

  • 方式二:在Rule中,添加一个generator属性,并且设置filename
{
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'img/[name].[hash:6][ext]',
        },
      },

url-loader的limit效果

我们需要两个步骤来实现:

  • 步骤一:将type修改为asset
  • 步骤二:添加一个parser属性,并且制定dataUrl的条件,添加maxSize属性
{
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset',
        generator: {
          filename: 'img/[name].[hash:6][ext]',
        },
        parser: {
          dataUrlCondition: {
            maxSize: 100 * 1024,
          },
        },
      },

2、webpack-loader的使用 - 图11

小的文件已经转成base64编码了

十、字体样式处理

2、webpack-loader的使用 - 图12