loader
webpack做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。 更多的功能需要借助webpack loaders和webpack plugins完成。
webpack loader: loader本质上是一个函数,它的作用是将某个源码字符串转换成另一个源码字符串返回。
loader函数的将在模块解析的过程中被调用,以得到最终的源码。
全流程:
chunk中解析模块的流程:
chunk中解析模块的更详细流程:
处理loaders流程:
loader配置:
完整配置
js
module.exports = {
module: { //针对模块的配置,目前版本只有两个配置,rules、noParse
rules: [ //模块匹配规则,可以存在多个规则
{ //每个规则是一个对象
test: /\.js$/, //匹配的模块正则
use: [ //匹配到后应用的规则模块
{ //其中一个规则
loader: "模块路径", //loader模块的路径,该字符串会被放置到require中
options: { //向对应loader传递的额外参数
changeStr:"未知数"
}
}
]
}
]
}
}
简化配置
js
module.exports = {
module: { //针对模块的配置,目前版本只有两个配置,rules、noParse
rules: [ //模块匹配规则,可以存在多个规则
{ //每个规则是一个对象
test: /\.js$/, //匹配的模块正则
use: ["模块路径1", "模块路径2"]//loader模块的路径,该字符串会被放置到require中
}
]
}
}
注意:
1.loaders本质是一个函数,将源代码从一个字符串转换为另一个字符串。
2.loaders中只能使用common.js规范,因为loaders是在webpack编译的时候被执行的,而webpack又是在node环境下执行的。
3.loaders的匹配规则是从上往下的,但是执行loaders的时候却是从最后开始往前的。
4.大多数开发场景下,我们不需要自己写loader,因为现在的webpack生态比较成熟,几乎99%都有解决方案
案例
写一个loader,将index.js中的错误给替换掉
src/index.js
js
变量 a=10;//这个是错误的,虽然可以打包,但是无法执行
根目录下/loaders/test-loader.js
js
//使用loader-utils来获取在webpack.config中传递给loader的参数
const loaderUtils = require("loader-utils");
/**
* 编写的loader函数
* @param {*} sourceCode 源代码
* @returns 处理后的源代码
*/
module.exports = function (sourceCode) {
console.log("loader1执行了");
const options = loaderUtils.getOptions(this); //获取loader的参数,参数存在webpack的this中,this太复杂,所以使用loaderUtils来获取
console.log(options);
const reg = new RegExp(options.changeVar, "g"); //将参数中的变量替换为var
return sourceCode.replace(reg, "var");
};
webpack.config.js
js
module.exports = {
mode: "development",
//应用loaders
module: {
//模块匹配规则,可以配置多个规则
rules: [
//规则1
{
test: /index\.js$/, //规则:正则表达式,符合的化,就会应用loader
//匹配后,应用的规则模块
use: [
{
loader: "./loaders/loader1", //模块路径,该字符串会被webpack放置在require()中
//给loaders传递参数
options: {
changeVar: "变量",
},
},
],
},
],
},
};
//options还可以进行简写
module.exports = {
mode: "development",
//应用loaders
module: {
//模块匹配规则,可以配置多个规则
rules: [
//规则1
{
test: /index\.js$/, //规则:正则表达式,符合的化,就会应用loader
//匹配后,应用的规则模块
use: [
{
loader: "./loaders/loader1?changeVar: "变量",", //简写options
},
],
},
],
},
};
案例2--loader的执行顺序
index.js
js
require("./a");
console.log("我是index.js");
变量 a=10;
a.js
js
console.log("我是a.js");
loader1.js和loader2.js和loader3.js
js
module.exports = function (sourceCode) {
console.log("loader1执行了");
return sourceCode;
};
module.exports = function (sourceCode) {
console.log("loader2执行了");
return sourceCode;
};
module.exports = function (sourceCode) {
console.log("loader3执行了");
return sourceCode;
};
webpack.config.js
js
module.exports = {
mode: "development",
//应用loaders
module: {
rules: [
{
test: /index\.js$/,
use: ["./loaders/loader1?changeVar=变量", "./loaders/loader2"],
},
//规则2
{
test: /\.js/,
use: ["./loaders/loader3"],
},
],
},
};
请问控制台输出什么?
js
答案:
/*
3
2
1
3
*/
//为什么?
/*
1.首先loader是从后往前执行的,而遇到符合的就会去执行loader
2.不输出index.js中的"我是index"是因为,loader只是在webpack编译的时候执行的,而代码不会被执行。
3.不理解的话就需要看上面的**chunk中解析模块的更详细流程图,一个chunk会到AST之前去判断是否符合loader的规则,并且AST分析出依赖的模块之后会递归所依赖的模块。
*/