loader的作用
因为webpack是跑在node环境中,打包他只认识 .js 文件和 .json 文件,所以有一些其他的文件资源、比如图片、css等等这些文件就导致webpack无法识别、所以这个时候 loader 就出来了、准确的说他是文件处理器、针对webpack不认识的文件做转换、转换成webpack能够识别的内容!
loader的基础
在开始写自定义loader的时候我们需要了解下loader和loader加载机制、loader本质是导出一个函数,函数接收三个参数、同步模式直接通过return返回出去给下一个loader使用、而异步的话需要通过调用this.async()方法通知结束
/**
*
* @param {string|Buffer} content 源文件的内容
* @param {object} [map] 可以被 https://github.com/mozilla/source-map 使用的 SourceMap 数据
* @param {any} [meta] meta 数据,可以是任何内容
*/
function webpackLoader(content, map, meta) {
// 同步模式直接return
content += 'gf111'
return content;
// 异步调用this.async
let callback = this.async()
setTimeout( () =>{
content += 'gf111';
callback(null,content)
},2000)
}
loader的执行过程类似一个管道、A => B => C (有点像责任链模式哈)loader 一共有四种类型:同步loader 、异步loader、Raw-loader、Pitching-loader、然后讲下loader的执行顺序 loader总是从右往左执行,也就是说会最先执行最后的loader然后往上、在实际(右到左)执行过程中会先 从左到右调用loader上的pitch
loader类型
- pre (前置)
- normal(普通)
- inline(内联)
- post(后置)
loader的类型可以通过 enforce 去配置、正常默认loader类型是普通(normal ) 四种loader执行优先级为 pre > normal > inline > post
loader执行流程
- 总是右往左执行( 没有配置enforce )情况下
- 右往左执行前,会先调用所有loader上的pitch方法、这个顺序是左往右
创建loders文件夹下面三个a-loader.js、b-loader.js、c-loader.js
配置loader和loader加载路径
module.exports = {
entry: {
'main':'./src/main.js'
},
devtool: 'inline-source-map',
devServer: {
static: 'dist',
compress: true,
port: 9000
},
mode: 'development',
resolveLoader: {
modules: ['node_modules','build/laoders'], // build/loaders 配置自定义loader路径
extensions: ['.js', '.json'],
mainFields: ['loader', 'main']
},
module:{
rules:[
{
test: /\.js$/,
use:['a-loader']
},
{
test: /\.js$/,
use:['b-loader']
},
{
test: /\.js$/,
use:['c-loader']
},
]
}
}
执行的顺序
我们发现我们按rules正常写loader的执行顺序是右往左、那我们试试在每个loader里面添加 pitch 方法
// Aloader
function Aloader(content, map, meta){
return content;
}
Aloader.pitch = function(a,b,c){
console.log('a-loader---pitch')
}
// Bloader
function Bloader(content, map, meta){
return content;
}
Bloader.pitch = function(){
console.log('b-loader---pitch')
}
// Cloader
function Cloader(content, map, meta){
return content;
}
Cloader.pitch = function(a,b,c){
console.log('c-loader---pitch')
}
串行loader和pitch阶段
获取loader参数(this.getOptions)
// webpack.config.js
{
test: /\.js$/,
use:{
loader:"a-loader",
options:{
name:'1111'
}
}
}
// loader
function Aloader(content, map, meta){
console.log("getOptions",this.getOptions()) //获取参数
return content;
}
module.exports = Aloader
异步(this.async)内容返回和同步
同步就很简单、直接在方法里面return出去、而异步得话是需要通过this.async 告诉 loader-runner当前loader是一个异步
function Bloader(content, map, meta){
const cb = this.async()
setTimeout( () =>{
cb(null, content + ';const asyncs = 1111;') // 最后会等待异步结束后执行打包
},2000)
}