【webpack快速入门】webpack有哪些常用的loader加载器?

前言

大家好,我是东东吖,一名前端工程师。通过上篇文章【webpack快速入门】如何手动给项目配置一个webpack打包工具?我想你对webpack已经有了一个初步的认识,没有webapck相关经验的朋友,建议先看上篇文章哦。今天我们来学习webpack是如何加载资源文件的,打包时有哪些常用的loader加载器。

Webpack核心工作原理

在学习lodder加载器之前,我们先来康康Webpack核心工作原理,让你对webpack有一个全面的认识,对于Webpack核心工作原理,查看官网的这张首屏就知道了。

image.png

webpack是基于模块化的打包(构建)工具,它把一切视为模块。

它通过一个开发时态的入口模块为起点,分析出所有的依赖关系,然后经过一系列的过程(压缩、合并),最终生成运行时态的文件。

他解决了在浏览器端,开发时态(devtime)和运行时态(runtime)的侧重点不一样的问题,所以webpack主要做的就是让你开发的时候随便写,然后其他的交给webpack帮你处理好,能用在生产环境的代码。 首先我们需要知道一些关键词:

Entry: 入口,webpack构建第一步从entry开始。

module:模块,在webpack中一个模块对应一个文件。webpack会从entry开始,递归找出所有依赖的模块。

Chunk:代码块,一个chunk由多个模块组合而成,用于代码合并与分割。

Loader: 模块转换器,用于将模块的原内容按照需求转换成新内容。

Plugin:拓展插件,在webpack构建流程中的特定时机会广播对应的事件,插件可以监听这些事件的发生,在特定的时机做对应的事情。 image.png

以上就是webpack的核心工作原理,今天我们将学习loader加载器。

Webpack常用加载器分类

  • 编译转换类 css-loader 

  • 文件操作类 file-loader

  • 代码检查类 eslint-loader

css-loader加载器

webpack不仅仅是javaScript的打包工具,更是整个前端工程化的打包工具。

我们在src下面创建index.css文件,编写一个简单的样式,我们来尝试打包css文件

image.png

再把我们的打包入口改成这个css文件,执行打包命令,就会报错。因为webpack默认只会对javaScrip的文件进行打包,也就是它会默认把所有文件当成js文件去解析,而我们是让它执行css文件,css文件里面是css样式,所有自然会报错。

image.png

我们来看错误信息的提示,翻译过来就是需要一个loader加载器

image.png

webpack内部的loader只能对js进行加载,我们需要加载其他资源,就需要添加其他相应的loader加载器。

下载安装 css loader

yarn add css-loader --dev
复制代码

安装完成之后,我们需要在配置文件中添加相应的配置。

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'none',         //使用开发模式打包
    entry:'./src/index.css',     //打包前入口
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test: /.css$/,
                use:'css-loader'
            }
        ]
    }

}
复制代码

再次执行打包命令,我们发现就没有报错了,我们启动http-server,发现样式并没有生效?

image.png

原因在于打包之后有了css样式,但是没有使用它,所以还需要下载一个style loader 加载器来使用它。

下载安装 style loader

yarn add style-loader --dev
复制代码

配置loader,使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面。

//webpack.config.js

const path =require('path')
module.exports={
    mode:'none',         //使用开发模式打包
    entry:'./src/index.css',     //打包前入口
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            }
        ]
    }

}
复制代码

再次打包,我们就会发现打包文件里面不仅有css相关的代码,还有style相关的代码。

image.png

启动http-server,我们就会发现样式生效了,我们的字体变成了红色。

image.png

通过以上做法,我们确实可以打包css,但是webpack的打包入口还是以js,所以我们需要改写一下导入css的方式。我们在webpack配置文件中,将打包入口重新还原为main.js,始终以mian.js作为打包的入口。

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'none',         //使用开发模式打包
    entry:'./src/main.js',     //打包前入口
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            }
        ]
    }

}
复制代码

然后我们在main.js中引入css:

image.png


// 有点类似Java导入,这里teacher随意命名
import teacher from './common.js'
import "./index.css"

// 一定要带上teacher
teacher.getList()
teacher.save()

复制代码

重新打包,启动应用,我们发现样式还是生效的,当然我们除了在main中引入css,还可以在common.js中引入css,我们把main.js中引入css的代码注释,在common.js中引入。

image.png

//common.is

import "./index.css"
// 有点像类定义
export default {
    getList() {
        // ajax调用
        console.log('东东吖,获取讲师列表')
    },
    save() {
        // ajax调用
        console.log('东东吖,保存讲师')
    }

}
复制代码

重新打包,启动应用,我们发现样式,同样是生效的,这样我们就始终了以main.js为入口文件,其他模块通过引入的方式导入。看到这儿,熟悉vue的朋友们,你会发现它和vue有类似之处,是不是对vue项目理解更加深刻了呢?

file-loader加载器

目前,webpack社区提供了非常多的loader加载器,大多数加载器都类似css-loader,将资源文件转化为js代码的方式去工作,但是还有一些我们用到的资源文件,例如图片,字体,这类资源文件是没有办法通过js的方式去表现的,那么这类资源文件,我们需要用到文件资源加载器file-loader

我们在项目中添加一张图片图片,大家可以找任意一张图片放进项目中。

image.png

//下载文件资源加载器file-loader
yarn  add file-loader --dev
复制代码

配置文件资源加载器规则

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'development',         //使用开发模式打包
    entry:'./src/main.js',     //打包前入口
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            },
            {
                test:/.jpg$/,
                use:[
                    'file-loader'
                ]
            }
        ]
    }

}
复制代码

执行打包命令,我们会发现在dist文件下会多出一个图片文件,不过图片文件的名字变了。

image.png

启动应用,输入localhost,我们就会发现图片正常显示了,并在能看见图片引用的地址就是我们打包后dist下的图片文件。

image.png

如果你的图片没有正常显示,图片指向的地址不是dist,而是项目根目录下,而根目录下是没有这张图片的,所有如果有这种情况,那么请在配置文件中加入这行配置代码。

image.png

如果没有报错,如果图片正常加载,就不要配这个publicPath:'dist/' , 配这个打包反而会报错。

image.png

配置了会是无效属性,请注释掉。

image.png

这里大家思考一下,在日常开发中,我们的资源文件并不是资源图片,就算是图片也不止只有jpg,还有png、jpeg等等。那么我们该怎么配置呢? 是复制一个文件加载器吗? 其实不是的,只需要写个与,也就是'|',然后我们就可以在项目中使用其他资源文件了。

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'development',         //使用开发模式打包
    entry:'./src/main.js',     //打包前入口
    // publicPath:'dist/'  ,        //注意dist后面的/不能省略
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            },
            {
                test:/.(png|jpg)$/,
                use:[
                    'file-loader'
                ]
            }
        ]
    }

}
复制代码

大家可以在项目中自己再添加一张png图片进行尝试,我就不赘述了,直接看结果吧。

image.png

总结:文件加载器工作过程中,webpack遇到了我们的图片文件,根据我们在配置文件中的配置,匹配到对应的文件加载器,文件加载器开始工作,将导入的文件拷贝到输出目录,再将拷贝到输出目录的路径作为当前模块的返回值返回,对应应用,资源就被发布出来了,对于模块,也能拿到对应的路径。

url-loader加载器

data url给了我们一种很巧妙的将图片“嵌入”到HTML中的方法。跟传统的用img标记将服务器上的图片引用到页面中的方式不一样,在Data URL协议中,图片被转换成base64编码的字符串形式,并存储在URL中。

图片在网页中的使用方法通常是下面这种利用img标记的形式:

  <img src="images/myimg.gif ">  

  这种方式中,img标记的src属性指定了一个远程服务器上的资源。当网页加载到浏览器中 时,浏览器会针对每个外部资源都向服务器发送一次拉取资源请求,占用网络资源。大多数的浏览器都有一个并发请求数不能超过4个的限制。这意味着,如果一个 网页里嵌入了过多的外部资源,这些请求会导致整个页面的加载延迟。而使用Data URL技术,图片数据以base64字符串格式嵌入到了页面中,与HTML成为一体,它的形式如下:

image.png

从上面的base64字符串中你看不出任何跟图片相关的东西,我们将传统的img写法和现在的Data URL用法左右对比显示,你就能看出它们是完全一样的效果。但实际上它们是不一样的,它们一个是引用了外部资源,一个是使用了Data URL。

安装url-loader
 yarn  add url-loader --dev
复制代码

更改file-loader为url-loader

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'development',         //使用开发模式打包
    entry:'./src/main.js',     //打包前入口
    // publicPath:'dist/'  ,        //注意dist后面的/不能省略
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            },
            {
                test:/.(png|jpg)$/,
                use:[
                    'url-loader'
                ]
            }
        ]
    }

}

复制代码

我们删除以前的dist文件,重新执行打包,就会发现dist下面没有再生成图片文件。

image.png 我们打开bundle.js,就能发现我们的data url

image.png

我们把完整的data url地址复制到浏览器,就可以访问我们这张图片。

image.png

我们在来启动应用,会发现图片还是成功显示了,并且是以date url 的形式。

image.png

项目最佳实践方式:

  • 小文件使用Data URL,减少请求次数。
  • 大文件单独提取存放,提高加载速度。

url-loader支持配合选项,来满足最佳实践方式。

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'development',         //使用开发模式打包
    entry:'./src/main.js',     //打包前入口
    // publicPath:'dist/'  ,        //注意dist后面的/不能省略
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            },
            {
                test:/.(png|jpg)$/,
                use:{
                    loader:'url-loader',
                    options:{
                        limit :30*1024,  //30KB,因为这里的单位是字节,所有需要*1024
                    }
                }
            }
        ]
    }

}
复制代码

我们再次执行打包命令,就会发现dist文件下只会出现一张图片文件。但是我们的项目其实是有两张图片的。

image.png

原因就在于我们项目中的两张图片一张其实是25KB

image.png

而另外一张是48KB

image.png

那么我们刚刚在配置文件中配置了30KB的文件,那么超过30KB的文件还是会以url-loader的形式加载,而没有超过30KB的文件,则以data url的形式加载。

image.png

值得注意的是,如果要按这种配置,就必须同时下载url-loader和file-loader,因为超过配置限制的文件还是会以url的形式加载。

image.png

babel-loader加载器

因为模块打包需要,所以需要处理import和export; webapck需要将es6的语法编译成es5,需要babel-loader加载器

//下载bale-loader加载器、核心模块、插件

yarn add babel-loader @babel/core  @babel/preset-env --dev
复制代码

在webpack中配置 babel-loader

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'development',         //使用开发模式打包
    entry:'./src/main.js',     //打包前入口
    // publicPath:'dist/'  ,        //注意dist后面的/不能省略
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test:/.js$/,
                use:"babel-loader"

            },
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            },
            {
                test:/.(png|jpg)$/,
                use:{
                    loader:'url-loader',
                    options:{
                        limit :30*1024,  //30KB,因为这里的单位是字节,所有需要*1024
                    }
                }
            }
        ]
    }

}
复制代码

在common.js中新增一个箭头函数的方法

image.png

//common.is

// import "./index.css"
// 有点像类定义
export default {
    getList() {
        // ajax调用
        console.log('东东吖,获取讲师列表')
    },
    save() {
        // ajax调用
        console.log('东东吖,保存讲师')
    },

    

}

// // 定义一个简单的箭头函数
export var  sum = (num1, num2) => { num1 = num1+1;return num1 + num2; }


    
复制代码

在main.js中引入调用

image.png

//main.js

// 有点类似Java导入,这里teacher随意命名
import teacher ,{ sum } from './common.js'
import "./index.css"

import bg from "./bg.jpg"   //引入图片路径
import icon from "./icon.png"   //引入图片路径

const img = new Image()    //创建img
img.src=bg                 //设置imgd的src路径
document.body.append(img)   //追加到body中


 const iconImg = new Image()    //创建img
 iconImg.src=icon                 //设置imgd的src路径
document.body.append(iconImg)  //追加到body中



// 一定要带上teacher
console.log("teacher",teacher);
teacher.getList()
teacher.save()

console.log("sum",sum(1,1));




复制代码

执行打包命令,启动应用,查看结果。

image.png

在bundle.js中查看打包结果,我们发现还是es6得写法。

image.png

配置插件

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'development',         //使用开发模式打包
    entry:'./src/main.js',     //打包前入口
    // publicPath:'dist/'  ,        //注意dist后面的/不能省略
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test:/.js$/,
                use:{
                    loader:"babel-loader",
                    options:{
                        presets:['@babel/preset-env']
                    }
                }

            },
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            },
            {
                test:/.(png|jpg)$/,
                use:{
                    loader:'url-loader',
                    options:{
                        limit :30*1024,  //30KB,因为这里的单位是字节,所有需要*1024
                    }
                }
            }
        ]
    }

}
复制代码

执行打包命令查看打包结果,这个时候我们发现箭头函数已经变成了普通函数了。

image.png

webpack只是打包工具,想要编译和转换es6及更高版本的新特性,需要使用加载器。

html-loader加载器

  • 遵循ES Modules 标准的 ipport声明
  • 遵循CommonJS标准的require函数
  • 遵循 AMD标准的difine函数和require函数
    • 样式代码中的@import指令和url函数
    • HTML代码中图片标签的src属性

建议使用一个标准,不要混用,提高代码的可维护性。

接下来,我们来尝试一下。

  • 样式代码中的@import指令和url函数

在index.css中写入样式

image.png

/* index.css */

h1{
    color: red;

}
body{
    min-height: 100vh;
    background-color: #fff;
    background-image: url(tiger.gif);
    background-size: cover;
}
复制代码

在main.js中引入,并注释掉其他无关的代码。

image.png

在打包过程中,会先执行我们的css-loader,当webpack中遇到url就会去执行url-loader,执行打包命令,启动应用。

image.png

我们再来看@import指令,新增一个样式文件reset.css

image.png

在index.css使用@import指令引入: @import url(reset.css);

image.png

执行打包命令,启动应用,查看效果。

image.png

  • HTML代码中图片标签的src属性

新建html文件

image.png

下载html-loader

下载html-loader
yarn  add html-loader --dev
复制代码

配置html-loader

image.png

//webpack.config.js

const path =require('path')
module.exports={
    mode:'development',         //使用开发模式打包
    entry:'./src/main.js',     //打包前入口
    // publicPath:'dist/'  ,        //注意dist后面的/不能省略
    output:{                   //打包后出口
        filename:'bundle.js',  //打包后文件名
        path:path.join(__dirname,'dist')          //打包后路径
    },

    module:{ 
        // 匹配不同的资源loader加载器
        rules:[
            {
                test:/.js$/,
                use:{
                    loader:"babel-loader",
                    options:{
                        presets:['@babel/preset-env']
                    }
                }

            },
            {
                test: /.css$/,
                use:[
                    'style-loader',
                    'css-loader'          //使用多个loader,是从后往前执行,所有要先写样式,再把样式通过标签渲染到页面
                ]
            },
            {
                test:/.(png|jpg)$/,
                use:{
                    loader:'url-loader',
                    options:{
                        limit :30*1024,  //30KB,因为这里的单位是字节,所有需要*1024
                    }
                }
            },{
                test:/.html$/,
                use:{
                    loader:'html-loader'
                }

            }
        ]
    }

}
复制代码

在main中引入:

image.png

执行打包,启动应用,查看效果:

image.png

点击src属性可以正常访问

image.png

注意:html不止有src属性,如a标签的href属性,要自己设置配置项。

自己开发一个Loader

我们本次来自己开发一个名字为markdown-loader加载器,加深大家对loader加载器的理解。

新建一个.md文件,在main.js中引入

image.png

创建一个loader,webpack配置文件配置loader。

image.png

执行打包命令,发现已经打印出来了soure,但是也同时报了一个错。

image.png

原因就在于返回的不是html代码,需要一个loader,那么有两种方式,①返回html代码,②添加一个loader。

image.png

一、我们把returen里面的东西写成html代码,再次执行打包,就发现没有报错了。

image.png 二、安装一个loader

//安装解析md的loader
yarn  add marked --dev
复制代码

在loader里面编写代码,发现打包报错。

image.png require(“marked”)获得,需要使用marked函数的marked属性才可以,或者使用解构赋值,再次打包。可发现打包成功了。

image.png

查看打包结果,md文件已经被转化成为html了。

image.png

结束

相信通过本文,你将对webpack的loader加载器有了一个深入的了解, 对于本文章,你有任何疑问,可在评论区留言。如果想进前端交流群(目前群里有40余人前端工程师,气氛活跃,欢迎大家加入),可以加我微信fangdongdong_25,请备注掘金哦。

猜你喜欢

转载自juejin.im/post/7129314542919614495