Webpack5学习笔记(基础篇七)—— Loader加载器

1、Loader的作用

webpack可以自动解析jsjson格式的文件,这个是webpack开箱即用的功能,那如果要解析其他类型的文件呢,比如一张图片?

前面我们讲过 Asset Module功能可以,而作为最常用的解析工具,loader也可以将这些非js的文件转化为有效的模块。

webpack允许我们使用loader来处理文件,loader是一个导出为function的node模块,说白了,loader就是一个函数function。可以将匹配到的文件进行一次转换,同时loader可以链式传递

2、Loader和Plugin的区别

在之前的文章,我也简单的聊过Plugin的作用,而两者经常被用来作比较,我也容易搞混。

其实,但是他们是完全两个不同的东西:

  • Loaders(加载器):是在打包构建过程中用来处理源文件的(JSX,Scss,Less…),一次处理一个
  • Plugins(插件):并不直接操作单个文件,它直接对整个构建过程其作用

在这里插入图片描述
这里,我在网上找到了一张还不错的图示,从上面也能看出,Plugins是直接对整个构建过程生效,而Loaders是作用于某个具体的源文件类型。

所以,在后续使用的过程中,大家就不要在搞混了。

3、Loader的使用方式

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

3.1、webpack.config.js配置文件

一般情况下,我们通过使用webbpack.config.js配置文件的方式来加载引入各种loaders

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

其中test这个属性用来识别哪些文件被转换,use这个属性用来在转换的时候,定义用哪个loader来进行转换

3.2、命令行参数

第二种方式,就是通过命令行参数方式

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

3.3、内联

第三种方式,就是通过内联使用

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

4、常用的Loader

处理样式的Loader:style-loadercss-loaderless-loadersass-loader

处理文件的Loader:raw-loaderfile-loaderurl-loader

用于编译的Loader:babel-loadercoffee-loaderts-loader

用于校验测试的Loader:mocha-loaderjshint-loadereslint-loader


比如下面的配置文件,可以匹配.scss的文件,分别经过sass-loadercss-loaderstyle-loader的处理。

module.exports = {
  module: {
    rules: [
        {
          test: /\.scss$/,
          
          use:[
              {loader:'style-loader'},
              {loader:'css-loader',options:{sourceMap:true,modules:true}},
              {loader:'sass-loader',options:{sourceMap:true}}
          ],
          或
          use:['style-loader','css-loader','sass-loader']
          
          exclude:/node_modules/
      }
    ]
  }
}


  • sass-loader转化sass为css文件,并且包一层module.exports成为一个js module
  • css-loader则处理其中的@import和url()
  • style-loader将创建一个style标签将css文件嵌入到html中,且该标签在head头里面

vue-loadercoffee-loaderbabel-loader等可以将特定文件格式转成js模块,将其他语言转化为js语言和编译下一代js语言。


file-loaderurl-loader等可以处理资源。file-loader可以复制和放置资源位置,并可以指定文件名模板,用hash命名更好利用缓存;url-loader可以将小于配置limit大小的文件转换成内敛Data Url的方式,减少请求。


raw-loader可以将文件已字符串的形式返回。


imports-loaderexports-loader等可以向模块注入变量或者提供导出模块功能,

比如 imports-loader(导入加载器)允许您使用依赖于特定全局变量的模块,这对于依赖全局变量$this作为window对象的第三方模块非常有用。常见场景是:

  1. jQuery插件注入$,imports-loader?$=jquery
  2. 禁用AMD,imports-loader?define=false,等同于:var $ = require(“jquery”) 和 var define = false;

5、Loader的执行顺序

正常情况下,loader执行顺序遵循从右向左从下到上的原则

1、数组方式使用(执行的顺序为倒序即 loader1 > loader2 > loader3

module: {
    rules: [
      {
        test: /\.js$/,
        use: ["loader3", "loader2","loader1"],
      },
    ],
  },

2、多个rules方式(执行的顺序为倒序即 loader1 > loader2 > loader3

  module: {
    rules: [
      {
        test: /\.js$/,
        use: "loader3",
      },
      {
        test: /\.js$/,
        use: "loader2",
      },
      {
        test: /\.js$/,
        use: "loader1",
      },
    ],
  },

6、Loader的分类

一般情况下,loader分为 pre(前置)normalpost(后置)inline(行内,嵌在代码中的loader),这四大类(默认是normal),loader的执行顺序为:

pre(前置) > normal > inline(行内)> post(后置)

上面说loader的执行顺序是倒序,那如果我真的是希望强制更改loader3在 loader1之前执行就可以这么做(此时的执行顺序为 loader3 > loader1 > loader2

module: {
    rules: [
      {
        test: /\.js$/,
        use: "loader3",
        enforce:"pre" //增加了此行
      },
      {
        test: /\.js$/,
        use: "loader2",
      },
      {
        test: /\.js$/,
        use: "loader1",
      },
    ],
  },

inline loader的使用方式

console.log("hello")
let str = require("inline-loader!./a.js");
//这句话的意思就是把a.js的内容导入,并传递到inline-loader,然后require的是inline-loader处理后的结果

loader中可以使用的webpack提供的常用api

7、Loader加载CSS

首先我们先新建一个文件夹来测试,文件夹目录如下,这里我沿用了上一部分:Webpack5学习笔记(基础篇六)—— Assets资源模块的加载
的文件内容目录,除此之外,我们在src下面创建一个基础的.css文件。
在这里插入图片描述
style.css

.hello{
    color:red
}

index.js

import hello from './hello'
import img1 from './assets/man.jpeg'
import img2 from './assets/store.svg'
import img3 from './assets/women.jpg'
import Txt from './assets/wenzi.txt'
import dynamic from './assets/dongtu.gif'
import './style.css'
hello()

const IMG1 = document.createElement('img')
IMG1.src = img1
document.body.appendChild(IMG1)

const IMG2 = document.createElement('img')
IMG2.src = img2
IMG2.style.cssText = 'width:200px;height:200px'
document.body.appendChild(IMG2)

const IMG3 = document.createElement('img')
IMG3.src = img3
document.body.appendChild(IMG3)

const TXT = document.createElement('div')
TXT.textContent = Txt
TXT.style.cssText = 'width:200px;height:200px;backGround:aliceblue'
document.body.appendChild(TXT)

const DYNAMIC = document.createElement('img')
DYNAMIC.src = dynamic
document.body.appendChild(DYNAMIC)

document.body.classList.add('hello')

hello.js

function hello(){
    console.log("hello-world!!!")
}

export default hello

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>kobe,永远的神!!</title>
</head>
<body>
</body>
</html>

webpack.config.js本文之后的webpack.config.js均是在此基础上增加

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry : './src/index.js',

    output : {
        filename:'bundle.js',
        path:path.resolve(__dirname,'./dist'),
        clean:true,
        //如果不设置,打包完之后资源会直接打包在dist目录下
        assetModuleFilename:'images/[contenthash][ext][query]'
    },

    mode : 'development',

    devtool:'inline-source-map',

    plugins:[
        new HtmlWebpackPlugin({
            template:'./index.html',
            filename:'app.html',
            inject:"body"
        })
    ],

    devServer:{
        static:'./dist'
    },

    module:{
        rules:[{
            test:/\.jpeg$/,
            type:"asset/resource",
            generator:{
               filename:'images/[contenthash][ext][query]'
            }
        },{
            test:/\.svg$/,
            type:'asset/inline'
        },{
            test:/\.txt$/,
            type:'asset/source'
        },{
            test:/\.(gif|jpg)$/,
            type:'asset',
            parser:{
                dataUrlCondition:{
                    maxSize : 10 * 1024 * 1024
                }
            }
        }
      ]
    }
    
}

可以看到,我们通过style.css给hello设置了字体红色,并且在index.js中引入改css,同时给body加了一个class名hello,假如我们不安装任何css相关Loader,直接执行npx webpack打包,我们发现控制台会提示报错,提示我们应该使用一个合适的loader来帮助我们加载css
在这里插入图片描述

7.1、css-loader

所以我们需要安装css-loader,执行:

npm install css-loader -D 

安装完成后,我们需要在webpack.config.js中的module的rules里面配置一下

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

配置好后,再次执行npx webpack,这时候就可以顺利打包了。
然后我们可以执行npx webpack-dev-server --open,打开浏览器,观察这个样式是否生效。

可以看出,body被加上了一个hello的class名,但是head里面并没有引入外部css的样式或者有style这个属性
在这里插入图片描述
body中的文本字体颜色并没有变成红色
在这里插入图片描述

7.2、style-loader

所以表明,只有这一个css-loader是不能正常将css样式加载到页面,我们需要再安装另一个style-loader

npm install style-loader -D

这个style-loader会在当前的页面引入我们的css样式 ,安装完成之后,我们在webpack.config.js配置文件中引入

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

注意:

- style-loadercss-loader的位置不能颠倒,我们需要先用css-loader处理css文件,再用style-loader引入css文件

我们再次执行npx webpack打包,然后npx webpack-dev-server --open打开浏览器,这次我们发现head里面多了一个<style>标签,里面使我们写的css样式
在这里插入图片描述
页面上的字也变成了红色
在这里插入图片描述

7.3、less-loader

通常在平时工作中,我们常使用less或者sass等于处理工具,来帮助我们加载样式,所以我们也可以在webpack中配置它们,这里我们以less-loader为例。

首先,安装less-loader

npm install less-loader -D

然后我们在webpack.config,js配置文件里面配置一下

module:{
  rules:[
        ···
        {
      	 test: /\.(css|less)$/,
      	 use: ['style-loader','css-loader','less-loader']
    	}
    	 ···
  	]
}

然后我们在src目录下面,跟刚才style.css同级的位置创建一个style-less文件
style.less
在这里插入图片描述

@color:#f9efd4;
body{
    background-color:@color
}

并在index.js里面引入,完成后执行npx webpack打包,并执行npx webpack-dev-server --open打开浏览器,我们发现head头里面多了一个style的标签,表明我们的less样式被添加成功
在这里插入图片描述
body的背景也变成了浅色
在这里插入图片描述

7.4、mini-css-extract-plugin(Webpack5新增

通过上面的三种loader,我们成功的在页面上加载了css样式,但是我们发现都是通过在head头中的<style>来加载的,我们能不能将css样式单独抽离出来,然后在html中统一引入,这就要用到mini-css-extract-plugin这个插件了。

注意:
mini-css-extract-plugin这个插件是Webpack5新增加的,所以在使用的时候,我们Webpack的版本必须在5以上

安装mini-css-extract-plugin

npm install mini-css-extract-plugin -D

安装完成后,在webpack.config.js中配置,引入这个插件,并实例化

webpack.config.js

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

module.exports = {
    entry : './src/index.js',

    output : {
        filename:'bundle.js',
        path:path.resolve(__dirname,'./dist'),
        clean:true,
        //如果不设置,打包完之后资源会直接打包在dist目录下
        assetModuleFilename:'images/[contenthash][ext][query]'
    },

    mode : 'development',

    devtool:'inline-source-map',

    plugins:[
        new HtmlWebpackPlugin({
            template:'./index.html',
            filename:'app.html',
            inject:"body"
        })new MiniCssExtractPlugin()
    ],

    devServer:{
        static:'./dist'
    },

    module:{
        rules:[
        ···
        {
        	test:/\.(css|less)$/,
        	//MiniCssExtractPlugin将css样式抽离
           use:[MiniCssExtractPlugin.loader,'css-loader','less-loader']
      	 }
      	 ···
      ]
    }
}

值得注意的是,之前我们是使用style-loader将css样式通过<style>放在head头里,现在我们要换一种引用方式,用实例化的MiniCssExtractPlugin.loader代替style-loader

配置完后,执行npx webpack打包,我们发现style.cssstyle.less都被打包在了main.css
在这里插入图片描述
同时打包后的html文件是通过<link>标签来引入
在这里插入图片描述
我们可以执行npx webpack-dev-server --open打开浏览器,发现浏览器上也是通过<link>标签来引入外部main.css
在这里插入图片描述

正如前面图片的引入路径可以自定义设置,css样式也可以,我们只需要在webpack.config.js实例化这个插件的时候,加上filename这个属性,这样我们就可以自己定义css的打包输出的文件夹名字文件名字

webpack.config.js

···
	plugins:[
        new HtmlWebpackPlugin({
            template:'./index.html',
            filename:'app.html',
            inject:"body"
        })new MiniCssExtractPlugin({
            filename:"styles/[contenthash].css"
        })
	],
···

配置完成后,再次执行npx webpack打包,发现生成了styles文件夹
在这里插入图片描述
执行npx webpack-dev-server --open打开浏览器,这次<link>标签引入的css就是一个新的路径了
在这里插入图片描述

7.5、css-minimizer-webpack-plugin(生产环境压缩CSS)

在上面,我们已经成功将css抽离提取出来了,但是发现打包后的css代码还是很多,并没有进行压缩,而在生产环境中,我们往往都是将代码进行压缩,所以我们需要借助一个新的插件css-minimizer-webpack-plugin

安装css-minimizer-webpack-plugin

npm install css-minimizer-webpack-plugin -D

安装完成后,我们在webpack.config.js中进行配置,我们引入css-minimizer-webpack-plugin后,不是在plugins里面实例化,而是在optimizationminimizer中进行实例化,同时我们将mode改为production生产环境模式

webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
    entry : './src/index.js',

    output : {
        filename:'bundle.js',
        path:path.resolve(__dirname,'./dist'),
        clean:true,
        //如果不设置,打包完之后资源会直接打包在dist目录下
        assetModuleFilename:'images/[contenthash][ext][query]'
    },

    mode : 'production',

    devtool:'inline-source-map',

    plugins:[
        new HtmlWebpackPlugin({
            template:'./index.html',
            filename:'app.html',
            inject:"body"
        })new MiniCssExtractPlugin({
            filename:"styles/[contenthash].css"
        })
    ],

    devServer:{
        static:'./dist'
    },

    module:{
        rules:[
        ···
        {
        	test:/\.(css|less)$/,
        	//MiniCssExtractPlugin将css样式抽离
           use:[MiniCssExtractPlugin.loader,'css-loader','less-loader']
      	 }
      	 ···
      ]
    },
    
    //production环境压缩css代码
    optimization:{ 
        minimizer:[
            new CssMinimizerPlugin()
        ]
    }
}

配置完后,执行npx webpack打包,我们发现这时打包后被抽离的css代码已经被压缩了
在这里插入图片描述

7.6、利用css插入images图像

在上一篇博客中,我们通过在webpack.config.js中配置4种Asset Modules Type来加载图片,而平常我们可能在css中引入background-image背景图之类,现在我们来尝试一下webpack是否可以正常编译

我们在刚才index.js的文本处加一个class名
在这里插入图片描述
然后在style.css给这个类名加一个background背景图
在这里插入图片描述
执行webpack.config.js打包,我们看到打包后的css确实有这张背景图

(这里及下文中webpack.config.js中的mode已恢复development
在这里插入图片描述
执行npx webpack-dev-server --open,打开浏览器,发现确实背景图已添加成功
在这里插入图片描述

7.7、利用css加载fonts字体

在CSS3中增加了一个webfont, 我们可以在css中加载一个font字库,这样就可以在代码中定义icon图标了,这里我们需要用到前面的Asset Modules 资源模块,资源模块可以帮助我们加载任何的资源类型

我们在assets中放入事先准备好的iconfont.ttf文件
在这里插入图片描述
我们在style.css中定义用font-face定义这个字体,format设置成truetype
在这里插入图片描述

然后在index.js中引入当前style.css,并创建一个DOM元素,添加个类名,注意这里的innerHTML要设置成下载这个字体时的文字(这里是&#xe668;
在这里插入图片描述
webbpack.config.js中进行配置

module:{
        rules:[
        ···
        {
        	test:/\.(css|less)$/,
        	//MiniCssExtractPlugin将css样式抽离
           use:[MiniCssExtractPlugin.loader,'css-loader','less-loader']
      	 },
      	 {
                test:/\.(woff|woff2|eot|ttf|otf)$/i,
                type:"asset/resource"
          }
      	 ···
      ]
  },
    

执行npx webpack打包,

npx webpack-dev-server --open打开浏览器,发现页面上成功加载了iconfont图标

在这里插入图片描述

8、Loader加载csv、xml等数据

其实前面提到的 图片,iconfont图标,文本文件都属于数据,这里我们聊得数据是像csv、tsv、xml、json等,而json在webpack天然支持,其他几个我们需要借助于loader

安装csv-loader、xml-loader

npm install csv-loader、xml-loader -D

我们在assets中创建一个csvxml文件

csv使用逗号来分割,tsv使用type来分割)
在这里插入图片描述
在这里插入图片描述
然后在index.js中引入这两个文件,并打印一下
在这里插入图片描述

webpack.config.js中通过csv-loader、xml-loader配置一下

module:{
        rules:[
        ···
        {
            test: /\.(csv|tsv)$/,
            use:'csv-loader'
         },{  
            test:/\.xml$/,
             use:'xml-loader'
        },
        ···
      ]
  },
    

执行npx webpack打包,npx webpack-dev-server --open打开浏览器,查看控制台,可以看出,csv被打包成一个数组,cml被打包成一个对象
在这里插入图片描述

9、Loader加载自定义JSON模块parser

这里我们使用yaml、toml、json5来测试,其中json5相比于json文件,他可以添加注释,同时key也不用单引号来包裹起来,同时可以使用\n\r这种转义字符

安装yaml、toml、json5

npm install yaml toml json5 -D

我们在assets中创建一个yaml、tomljson5文件
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述然后在index.js中引入这三个文件,并打印一下
在这里插入图片描述
webpack.config.js中引入这三个插件,并使用parser解析器进行配置

···
const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')
···

module:{
        rules:[
        ···
        {
                test:/\.toml$/,
                type:'json',
                parser:{
                    parse:toml.parse
                }
            },{
                test:/\.yaml$/,
                type:'json',
                parser:{
                    parse:yaml.parse
                }
            },{
                test:/\.json5$/,
                type:'json',
                parser:{
                    parse:json5.parse
                }
            }
      	 ···
      ]
  },
 			

执行npx webpack打包,npx webpack-dev-server --open打开浏览器,查看控制台
在这里插入图片描述

10、Babel-Loader

babel-loader使得 webpack 可以通过 babel 转译 JavaScript 代码,用来处理ES5以上的语法,将其编译为浏览器可以执行的js语法

10.1、未使用babel-loader

我们创建一个hello.js,在里面写一个ES6的Promise函数,函数内通过setTimeout,2秒以后打印”中国男足,永远的神“,然后通过async await来调用
在这里插入图片描述
index.js里面执行hello(),执行npx webpack打包,在bundle.js中查看打包后的代码,发现这段ES6的代码并没有做转化,原封不动的被打包了
在这里插入图片描述
执行npx webpack-dev-server --open打开浏览器,2秒后打印字符串 “中国男足,永远的神”
在这里插入图片描述
现在是浏览器支持ES6的代码,那万一浏览器不支持,我们就不能正常打印

10.2、使用babel-loader

前面我们提到过,babel-loader是一个 npm 包,它使得 webpack 可以通过 babel 转译 JavaScript 代码。

babel 7 中 babel-corebabel-preset 被建议使用 @babel 开头声明作用域,因此应该分别下载 @babel/core@babel/presets

  • babel 的功能在于「代码转译」,具体一点,即将目标代码转译为能够符合期望语法规范的代码。在转译的过程中,babel 内部经历了「解析 - 转换 - 生成」三个步骤
  • @babel/core 这个库则负责「解析」,具体的「转换」和「生成」步骤则交给各种插件(plugin)预设(preset)来完成。注意:babel-loader必须和babel-core结合使用,babel-core封装了babel-loader需要用到的api
  • @babel/preset-* 实际上就是各种插件的打包组合,也就是说各种转译规则的统一设定,目的是告诉loader要以什么规则来转化成对应的js版本

首先,安装babel-loader @babel/core @babel/preset-env

npm install  babel-loader @babel/core @babel/preset-env -D

还是上面的hello.js
在这里插入图片描述
我们在webpack.config.js中配置一下

module:{
        rules:[
        ···
        {
                test:/\.js$/,
                //排除node_modules文件夹
                exclude:/node_modules/,
                use:{
                    //Es6转为Es5的写法
                    loader:'babel-loader',
                    options:{
                        presets:['@babel/preset-env'],
                    }
                }
            }
      	 ···
      ]
  },
    

执行npx webpack打包,执行npx webpack-dev-server --open打开浏览器,发现浏览器上面没有内容,控制台报错,提示regeneratorRuntime is not defined
在这里插入图片描述
我们打开bundle.js发现这里面hello这个地方确实貌似用到regeneratorRuntime,所以我们需要继续安装
在这里插入图片描述

注意:
regeneratorRuntime 是webpack打包生成的全局辅助函数,由babel生成,用于兼 容async/await的语法

regeneratorRuntime is not defined这个错误显然是未能正确配置babel,我们需要继续安装以下插件:

npm install @babel/runtime -D

这个包中包含了regeneratorRuntime


npm install @babel/plugin-transform-runtime -D

这个插件会在需要regeneratorRuntime的地方自动require导包

webpack.config.js中配置一下这两个插件

module:{
        rules:[
        ···
        {
                test:/\.js$/,
                exclude:/node_modules/,
                use:{
                    //Es6转为Es5的写法
                    loader:'babel-loader',
                    options:{
                        presets:['@babel/preset-env'],
                        //兼容async/await写法
                        plugins:[
                            [
                                '@babel/plugin-transform-runtime'
                            ]
                        ]
                    }
                }
            }
      	 ···
      ]
  },
    

执行npx webpack打包,查看bundle.js,webpack帮助我们进行处理,将ES6的代码转化了
在这里插入图片描述
然后npx webpack-dev-server --open打开浏览器,发现可以正常打印
在这里插入图片描述


本博客参考:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值