webpack Loader

128 阅读7分钟

Loader可以看作具有文件转换功能的翻译员,告诉webpack在遇到哪些文件时用哪些Loader去加载和转换。

loader特点

1.单一职责。一个Loader只做一件事情,正因为职责越单一,所以Loaders的组合性强,可配置性好。

2.loader支持链式调用。上一个loader的处理结果可以传给下一个loader接着处理,直到最后一个loader,返回Webpack所期望的JavaScript。

3.顺序:从右到左,从下到上执行。

// less-loader先执行,再执行css-loader,最后执行style-loader。
rules: [
    {
        test: /\.less$/,
        use: ['style-loader','css-loader','less-loader']
    },
],
或者
rules: [
    {
        test: /\.less$/,
        use:[
            {
                loader:'style-loader'
            },
            {
                loader:'css-loader'
            },
            {
                loader:'less-loader'
            }
            
        ]
    },
],

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


常用的loader

  • 转换样式文件:style-loader、css-loader、sass-loader、less-loader、postcss-loader
  • 加载图片、字体等文件:raw-loader、file-loader、url-loader
  • 编译转换脚本语言:babel-loader、ts-loader、coffee-loader
  • 检查测试代码:eslint-loader、tslint-loader、mocha-loader测试用例代码

loader的使用方式

一般loader的使用方式分为三种:

1:[配置](推荐)在配置文件webpack.config.js中配置

module.exports = {
  module: {
    rules: [
      {
        test: /\.txt$/,
        use: 'raw-loader'
      }
    ]
  }
}

2:[CLI]:通过命令行参数方式

    webpack --module-bind 'txt=raw-loader'

3:[内联]:通过内联使用

   import txt from 'raw-loader!./file.txt'

loader配置

通过module.rules来配置,module.rules的含义是创建模块的规则, rules是个数组,其中每一项都是一项规则。loader是用来生成符合Webpack的模块的。然后Webpack把这些模块打包起来生成对应的js文件。loader是在打包前执行的。

module.rules每一项规则为rule,rule配置如下:

1.rule的条件

Rule.test

作用:是筛选资源,符合条件的资源让这项规则中的loader处理。

值:字符串、数组、函数、正则表达式。

  • 字符串:可以是资源所在目录绝对路径 、资源的绝对路径
  • 函数: 接收的参数为资源的绝对路径。返回true表示该资源可以交给user选项里面的loader处理一下。
  • 数组:数组每一项可以为字符串、正则表达式、函数,只要符合数组中任一项条件的资源就可以交给user选项里面的loader处理一下。
  • 正则表达式
 1.字符串
 const path = require('path');
 module.exports = { 
     module: { 
         rules: [
            { 
                test: path.resolve(__dirname, 'src/css'), 
                //test: path.resolve(__dirname, 'src/css/index.css'),
                use: ['style-loader','css-loader'] 
            }, 
         ], 
    }, 
 }
 
 2.函数 \project\03personal\05Webpack_demo\src\css\index.css
 module.exports = {
    module: {
        rules: [
            {
                test: function (path) {
                    return path.indexOf('.css') > -1
                },
                use: ['style-loader','css-loader']
            },
        ],
    },
}
3.数组
const path = require('path');
module.exports = {
    module: {
        rules: [
            {
                test: [/\.css$/,path.resolve(__dirname, 'src/css')]
                use: ['style-loader','css-loader']
            },
        ],
    },
}

Rule.include

符合条件的资源让这项规则中的loader处理,用法和Rule.test一样。

const path = require('path');
module.exports = {
    module: {
        rules: [
            {
                include:/\.css$/,
                //include: path.resolve(__dirname, 'src/css'),
                //include: path.resolve(__dirname, 'src/css/index.css'),
                //include: [/\.css$/,path.resolve(__dirname, 'src/css')],
                //include:function (content) {
                    //return content.indexOf('src/css') > -1
                //},
                use: ['style-loader','css-loader']
            },
            {  
                test:/\.js$/,  // 命中js文件
                use: ['babel-loader?cacheDirectory'], // ?cacheDirectory 表示传给 babel-loader 的参数,用于缓存babel 编译结果加快重新编译速度
                include: path.resolve(__dirname, 'src') // 只命中src目录里的js文件,加快 Webpack 搜索速度
            },
        ],
    },
}

Rule.exclude

符合条件的资源要排除在外,不能让这项规则中的loader处理,用法和Rule.test一样。

例如:排除node_modules中的css文件。

const path = require('path');
module.exports = {
    module: {
        rules: [
            {
                exclude:/node_modules/,
                //exclude: path.resolve(__dirname, 'node_modules'),
                //exclude: [/node_modules/ , path.resolve(__dirname, 'node_modules')],
                //exclude:function (content) {
                    //return content.indexOf('node_modules') > -1
                //},
                use: ['style-loader','css-loader']
            },
        ],
    },
}

Rule.issuer

用法和Rule.test一样,但是要注意是匹配引入资源的文件路径

如在main.js中引入css/index.css

const path = require('path');
module.exports = {
    module: {
        rules: [
            {
                issuer: /\main\.js$/,
                //issuer: path.resolve(__dirname, 'main.js'),
                //issuer: [/\main\.js$/ , path.resolve(__dirname, 'main.js')],
                //issuer:function (content) {
                    //return content.indexOf('main.js') > -1
                //},
                use: ['style-loader', 'css-loader']
            },
        ],
    },
}

Rule.issuer 和 Rule.test、Rule.include 、Rule.exclude同时使用时候,也是“与”的关系。

Rule.resource

此选项也可筛选资源,符合条件的资源让这项规则中的loader处理。

但配置resource选项后,testincludeexclude选项不能使用。issuer选项不生效。

resource选项中有以下子选项

  • test选项,用法和Rule.test一样。
  • exclude选项,用法和Rule.exclude一样。
  • include选项,用法和Rule.include一样。
  • not选项,值为数组,数组每一项可以为字符串、正则表达式、函数,只要符合数组中任一项条件的资源就不能交给user选项里面的loader处理一下。
  • and选项,值为数组,数组每一项可以为字符串、正则表达式、函数,必须符合数组中每一项条件的资源才能交给user选项里面的loader处理一下。
  • or选项,值为数组,数组每一项可以为字符串、正则表达式、函数,只要符合数组中任一项条件的资源就可以交给user选项里面的loader处理一下。
const path = require('path');
module.exports = {
    module: {
        rules: [
            {
                resource:{
                    test:/\.css$/,
                    include: path.resolve(__dirname, 'src/css'),
                    exclude: path.resolve(__dirname, 'node_modules'),
                },
                use: ['style-loader', 'css-loader']
            },
        ],
    },
}

Rule.resourceQuery

匹配资源引入路径上从问号开始的部分。例

import './ass/main.css?inline'

上面代码中Rule.resourceQuery要匹配?inline,例

const path = require('path');
module.exports = {
    module: {
        rules: [
            {
                resourceQuery:/inline/,
                // resourceQuery:function (content) {
                    //return content.indexOf('inline') > -1
                // },
                //resourceQuery:[/inline/],
                use: ['style-loader', 'css-loader']
            },
        ],
    },
}

注意

  • Rule.test、Rule.include、Rule.exclude、Rule.issuer、Rule.resourceQuery同时使用时候,是“与”的关系,必须同时符合以上所有配置的条件才可以让这项规则中的loader处理。

  • Rule.issuer、Rule.resourceQuery、Rule.resource同时使用时候,也是“与”的关系。必须同时符合以上所有配置的条件才可以让这项规则中的loader处理。

2.rule的loader

Rule.use

意思是使用哪些loader处理符合条件的资源。use的值:数组或者函数。

use: ['style-loader']其实是use: [ { loader: 'style-loader'} ]的简写。

use每一项是一个UseEntry数组或者一个loaderName字符串,每个入口指定使用一个loader。

UseEntry:

  • loader:必填,字符串类型
  • options:字符串或对象,值可以传递到 loader 中。具体参数详见个loader

还可以通过options传入loader,可以理解为loader的选项。

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1
                        }
                    },
                ]
            },
        ],
    },
}

use的值为函数时,返回一个数组,参数为info,info中有以下内容

  • compiler:当前webpack的编译器(可以是undefined值)。

  • issuer:引入被处理资源的所在文件的绝对路径。

  • realResource:被处理资源的绝对路径。

  • resource:被处理资源的绝对路径,它常常与realResource替代,只有当资源名称被请求字符串中的!=!覆盖时才不近似。

  • resourceQuery:被处理资源的绝对路径中?后面的部分。

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: (info) =>{
                    console.log(info)
                    return [
                        'style-loader',
                        {
                            "loader": 'css-loader',
                        },
                    ]
                },
            },
        ],
    },
}

Rule.loader

loader: 'css-loader' 是 use: [ { loader: 'css-loader'} ]的简写。

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                loader: 'css-loader',
            },
        ],
    },
}

Rule.oneOf

当规则匹配时,只使用第一个匹配规则。

例如说要处理css文件资源时,one.css要用url-loader处理,two.css要用file-loader处理。可以用Rule.oneOf来配置,其用法和module.rules一样。

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                oneOf: [
                    {
                        resourceQuery: /one/, // one.css?one
                        //test: /one\.css/,
                        use: 'url-loader'
                    },
                    {
                        resourceQuery: /two/, // two.css?two
                        //test: /one\.css/,
                        use: 'file-loader'
                    }
                ]
            },
        ],
    },
}

Rule.enforce

可以用Rule.enforce来控制loader的执行顺序:

  • pre:优先执行
  • post:最后执行
rules: [
    {
        test:/\.less$/,
        loader:'less-loader',
        enforce:'pre'
    },
    {
        test: /\.less$/,
        loader:'css-loader',
    },
    {
        test: /\.less$/,
        loader:'style-loader',
        enforce:'post'
    },
],

常用loader详解

1.style-loader

定义:将模块导出的内容作为样式并添加到 DOM 中。

内部使用了模块热替换功能来加载css,幕后使用了module.hot.accept。

安装: npm install style-loader --save-dev

建议:建议将 style-loader 与 css-loader 结合使用

2.css-loader

原理:webpack是用JS写的,运行在node环境,所以默认webpack打包的时候只会处理JS之间的依赖关系,不原生支持解析css文件。要支持非js类型的文件,需要使用webpack的Loader机制。 .css文件需要css-loader去处理。

定义:加载 CSS 文件并解析 import 的 CSS 文件,最终返回 CSS 代码。css-loader会处理 import / require() @import / url 引入的内容。

css-loader支持使用CSS Modules,参数: modules:false(默认) 启用/禁用 CSS 模块和设置模式

注意:style-loader应该在css-loader前面(use里的loader从左到右被配置,从右到左先配置,即loader执行顺序为从右到左)。

先使用css-loader读取css文件,再使用style-loader把css内容注入到js里。
    module.exports={
        module:{
            rules:[
                {
                    test:/\.css$/i,
                    use:['style-loader']
                },
                {
                    test: /\.css$/i,
                    exclude: /node_modules/,
                    loader: 'css-loader',
                    options: {modules: { localIdentName: '[local]--[hash:base64:5]' } },
              },
            ]
        }
    }

3.less-loader

安装: npm install less-loader --save-dev(npm i less-loader -D)

定义:处理 less 的 webpack loader。将 Less 编译为 CSS。

// webpack.config.js
module.exports = {
  ...
  module: {
    rules: [{
      test: /\.less$/i,
      loader: 'less-loader' // 将 Less 编译为 CSS
    }]
  }
};

4.sass-loader

安装:npm install sass-loader node-sass --save-dev

// webpack.config.js
module.exports = {
    ...
    module: {
        rules: [{
            test: /\.scss$/i,
            use: [
                "style-loader", // 将 JS 字符串生成为 style 节点
                "css-loader", // 将 CSS 转化成 CommonJS 模块
                "sass-loader" // 将 Sass 编译成 CSS,默认使用 Node Sass
            ]
        }]
    }
};

5.postcss-loader

安装: npm i -D postcss-loader

注意:如果要使用最新版本的话,你需要使用 webpack v5。如果使用 webpack v4 的话,你需要安装 postcss-loader v4。

配置:新建postcss.config.js文件。

原理:webpack把css文件的内容传送给postcss-loader,postcss-loader会解析配置文件postcss.config.js文件中的插件,传输给postcss,postcss会解析传入的css,将其转换为一个AST,然后通过各种不同的插件来对这个AST进行操作,最终序列化一个新的css,然后将结果返回给postcss-loader,进行webpack下一个loader的操作。

配置:

  • 在项目跟目录建postcss.config.js配置文件(推荐)
  • 在webpack loader中配置

6.babel-loader

作用:babel-loader这个loader主要作用是在Webpack打包的时候,用Babel将ES6的代码转换成ES5版本的。

安装:

  • npm install babel-loader --save-dev
  • npm i --save-dev @babel/core:babel核心包
  • npm i --save-dev @babel/preset-env:预设即一组插件,用来转码
module: {
    rules: [
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-react',
                [
                  '@babel/preset-env',
                  {
                    targets:{
                      chrome: '40',
                      ie: '11',
                    },
                  },
                ],
              ],
              plugins: [
                ['react-activation/babel'],
                ['@babel/plugin-transform-runtime', { corejs: 3 }],
                '@babel/plugin-proposal-optional-chaining',
                '@babel/plugin-proposal-nullish-coalescing-operator',
                ['@babel/plugin-proposal-decorators', { legacy: true }],
                ['@babel/plugin-proposal-private-methods', { loose: true }],
                ['@babel/plugin-proposal-class-properties', { loose: true }],
              ],
            },
          },
        ],
      },

7.file-loader

安装:npm install file-loader --save-dev

作用:从名字就上大概可以猜测出来,是一个通用文件处理loader。

  • 用import/require 语法引入一个文件时,原生的JS并不支持这种import语法引入文件的。配置file-loader就可以实现
  • 可以指定该文件生成的输出目录,并在代码中返回该文件的地址
  • 处理css引入的图片

生成文件名:file-loader生成的文件默认的文件名是"[contenthash].[ext]"。

  • [contenthash]:资源内容hash值
  • [ext]:文件扩展名
  • [hash]:也是根据内容计算出的hash值
  • [name]:文件的原始名称

注意:file-loader不仅仅可以处理图片资源,它本质功能是复制资源文件并替换访问地址,音视频等资源也可以使用它。

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(ttf|eot|woff|woff2)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
                name: `assets/[name].[hash:8].[ext]`,
            },
          },
        ],
      },
    ],
  },
};

8.url-loader

安装:npm install --save-dev url-loader

url-loader是file-loader的增强版,它支持file-loader的所有功能,另外还有一个特殊的功能。

作用:url-loader的特殊功能是可以计算出文件的base64编码,在文件体积小于我们指定的值(单位 byte)的时候,可以返回一个base64编码的DataURL来代替访问地址。(在CSS中引入图片也是同样的道理。)。

这也是url-loader起这个名字的原因,因为它可以使用base64编码的URL来加载图片。

// 例子
// 正常img引入图片地址是
<img src="be735c18be4066a1df0e48a1173b538e.jpg">
// 使用base64编码后,引入图片地址是"data:image/jpg;base64,iVBORw0KGgoA…"这种格式的,这样就不用去请求存储在服务器上的图片了,而是使用图片资源的base64编码。
<img src="data:image/jpg;base64,iVBORw0KGgoA..."> <!-- 省略号...表示省略了剩下的base64编码数据 -->

limit参数,对于图片体积小于8KB(1024 * 8)的,我们转成base64编码的URL直接写入打包后的JS文件里。

module: {
    rules: [
      {
        test: /\.(jpg|png|gif|svg)$/,
        loader: 'url-loader',
        options: {
          limit: 1024 * 8,
          name: `assets/[name].[hash:8].[ext]`,
        },
      },

importLoaders

定义:css文件中如果有@import 语句,importLoaders的作用是决定@import模块在使用css-loader前,要使用几个其它的loaders处理。

// a.css
@import './b.css';
body{color: red}

module: {
    rules: [
      {
        test: /.css$/,
        use: [
          "style-loader",
          { loader: "css-loader", options: { importLoaders: 0 } },
          "postcss-loader",
        ],
      },
    ],
  },
// 由于importLoaders为0,所以postcss-loader不处理b.css,只有css-loader处理b.css,如果importLoaders为1,那么postcss-loader,css-loader都会处理b.css

github.com/ruanyf/webp…

引入自『Webpack系列』—— loader配置详解

注意事项

  • 每一个Loader可以通过URL querystring的方式传入参数,例如css-loader?minimize中的minimize告诉css-loader要开启css压缩。