loader是什么?
webpack默认只支持解析打包.js文件和.json文件,当我们在项目中使用其他资源时,会失败的,所以为了能够解析多种类型资源,webpack提出了为资源设置loader的概念
loader的使用:
webpack.config.js项目中
module。exports={
.....
module:{
rules:[ //rules是一个数组,一个项目可以放置多个loader
{
test:'/\.css$/', //正则匹配 .css文件时使用以下loader
use:['style-loader','css-loader'], //解析test匹配成功的文件使用的loader css-loader解析.css文件,style-loader则是将解析结果内嵌入html中
},
{
test:/\.(png|jpg|jpeg)$/,
use:[
{
loader: 'url-loader',
options:{ //loader还支持options选项,可以配置loader
limit:10*1024 //小于10*1024大小的文件直接变成base64
}
}
]
},
]
}
}
loader类型
- 同步loader:JS单线程,需要等待该loader完成才去执行下一个操作
- 异步loader:当需要进行异步操作才能完成的loader,例如:读取文件,需要网络请求等
loader机制
- 从后往前解析
- Loader加载发生在编译阶段,compiler实例化之后
- 串行解析,use:[‘style-loader’,‘css-loader’]----当css-loader解析完毕之后,将结果传给下一个loader:style-loader
- 默认开启loader缓存,当loader加载过的文件没有发生变化时,不再去使用loader解析此文件,this.cacheable(false)可更改
编写一个简单的loader
- loader目的:解析.txt文件,将一个目标字段替换成需求字段
- 匹配文件:.txt
- options配置:targetName—目标字段 demandName----需求字段
1、创建raw-loader.js文件
一般编写loader会建立一个loader文件夹,里面是我们自写编写的loader,loader命名规范为xxx-loader.js
2、raw-loader文件需要导出一个模块获取文件内容
因为webpack是一个模块管理器,所有经由webpack管理的项目是由一个个模块组成的,所以raw-loader.js 导出也是一个模块
loader解析发生在编译阶段,compiler实例化之后,compiler由entry入口开始,寻找module(模块),将module经由loader处理,文件内容是由compiler获取,然后通过参数传入loader
上一个loader处理过的内容将直接传送给下一个loader
module.exports=functionmm(source){
//注意这里的参数source 是compiler对象传递给raw-loader的,是webpack找到.txt文件的内容
......
}
3、获取options传递的参数
我们需要targetName和demandName字段,所以需要借助loader的API,
const loaderUtlis=require('loader-utils'); //引入 loader-utils工具
module.exports=function(source){
.......
const {targetName}=loaderUtils.getOptions(this); //获取targetName
const {demandName}=loaderUtlis.getOptions(this); //获取demandName
}
4、逻辑处理
const loaderUtlis=require('loader-utils')
module.exports=function(source){
const json=JSON.stringify(source); //使用JSON去解析
const {targetName}=loaderUtlis.getOptions(this);
const {demandName}=loaderUtlis.getOptions(this);
const result= json.replace(targetName,demandName);
}
5、返回处理的内容
可以直接return 或者this.callback(…),this.callback更加灵活
const loaderUtlis=require('loader-utils')
module.exports=function(source){
const json=JSON.stringify(source); //使用JSON去解析
const {targetName}=loaderUtlis.getOptions(this);
const {demandName}=loaderUtlis.getOptions(this);
return json.replace(targetName,demandName);
}
6、使用loader
我们在webpack.config.js中直接使用path.resolve(’./loaders/raw-loader’)引入
在options中加入我们的配置
const path =require('path');
module.exports={
entry:'./src/index.js',
output:{
filename:'[name].js',
path:path.join(__dirname,'./dist')
},
module:{
rules:[
{
test:/.txt$/,
use:[
{
loader:'file-loader',
options:{
name:'[name]-[hash:2].[ext]'
}
},
{
loader:path.resolve('./loaders/raw-loader'),
options:{
targetName:'列侬',
demandName:'甲壳虫乐队'
}
}
]
}
]
},
plugins:[
],
mode:'development'
}
异步loader
只需要使用const callback=this.async()即可进行异步loader了
const loaderUtlis=require('loader-utils')
const fs=require('fs');
const path=require('path');
module.exports=function(source){
const json=JSON.stringify(source); //使用JSON去解析
const callback=this.async(); //异步调用loader
const {targetName}=loaderUtlis.getOptions(this);
const {demandName}=loaderUtlis.getOptions(this);
fs.readFile(path.join(__dirname,'./async.txt'),'utf-8',(err,data)=>{ //读取文件---异步操作
const result=json.replace(targetName,demandName)
callback(null,result);
})
}