webpack做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。
更多的功能需要借助webpack loaders和webpack plugins完成
webpack loader: loader本质上是一个函数,它的作用是将某个源码字符串转换成另一个源码字符串返回。
loader函数的将在模块解析的过程中被调用,以得到最终的源码
全流程:
当加入loaders时的详细流程图
从上图可以看出webpack读取文件内容后经过loaders函数后才会交给抽象语法树,
如下案例
loaders 的简易使用
index.js 的源码
变量 a = 123;
console.log(a)
loader1.js的源码
module.exports = function(srcCode){
// 函数内的参数在此环境中是index.js的源码,以文本的形式的代码,因为的loaders函数的上一步是读取文件内容
// 注意此文件的模块化只能使用commonjs 此处的代码是运行在node环境中的 ,es6的模块化node是无法识别的
return srcCode.replace(/变量/g , 'var'); // 进行正则匹配与字符替换
}
webpack.config.js 的配置如下
module.exports = {
mode: "development",
module: {
rules: [ //模块的匹配规则
// 规则1
{
test: /index\.js$/, // 正则表达式匹配模块路径
use: [ //匹配到之后,使用哪些加载器
{
loader: "./loaders/loader1.js",
}
]
}
]
}
}
从上面代码可以看出 当index.js 在进行抽象语法树分析时是会报错的,因为里面有无法识别的语法错误,而我使用loader 将其index.js 的源码进行匹配将代码里”变量” 替换为 “var” 替换后再交给抽象语法树
如下图webpack打包后的代码 你会发现红框里的代码别应该是 变量 a = 123 , 结果变成啦 var a = 123;
工程目录 注意画红线的都是此测试无用的
loaders函数的参数接收与传递
还可以给loaders函数传递参数,如下代码
module.exports = {
mode: "development",
module: {
rules: [
{
test: /index\.js$/,// 正则表达式匹配模块路径
use: [//模块的匹配规则
{
loader: "./loaders/loader1.js",//匹配到之后,使用哪些加载器 等效于 require("./loaders/loader1.js")
options: {
changeVar: "变量" // 传递参数
}
}
]
// 可以简写为 use:["./loaders/loader1.js?changeVar=变量" , "./loaders/loader2.js?changeVar=a"]
}
]
}
}
如上面代码向./loaders/loader1.js下的默认导出的函数传入参数,但是这个默认导出的函数是的参数列表是没有的,这个参数存在thisl里可以使用依赖包 loader-utils
, 它会帮我们获取传递过来的参数
loader1.js 修改如下
var loaderUtils = require('loader-utils') // 引入依赖包loader-utils 来获取传递过来的参数
module.exports = function (srcCode) {
// return srcCode.replace(/变量/g , 'var');
console.log("loader 运行啦")
var options = loaderUtils.getOptions(this) // 获取参数列表
var reg = new RegExp(options.changeVar, 'g'); //新建正则表达式
return srcCode.replace(reg, "var ")
}
匹配规则的运行顺序
当有多个匹配规则时他们的运行顺序为?
如上图的执行顺序如下代码所实现的效果
webpack.config.js 的配置如下
module.exports = {
mode: "development",
module: {
rules: [
{
test: /index\.js$/,
use:["./loaders/loader1.js?changeVar=变量" , "./loaders/loader2.js?changeVar=a"]
},
{
test: /index\.js$/,
use:["./loaders/loader3.js?changeVar=变量"]
}
]
}
}
loader1.js 的代码如下
module.exports = function (srcCode) {
console.log("这是loader1")
return "这是loader1"
}
loader2.js 的代码如下
module.exports = function (srcCode){
console.log("这是loader2")
return "这是loader2"
}
loader3.js 的代码如下
module.exports = function (srcCode){
console.log("这是loader2")
return "这是loader2"
}
运行代码效果如下图
你会发现他会从最后一个开始运行
看 webpack.config.js的配置项
module.exports = {
mode: "development",
module: {
rules: [
{
test: /index\.js$/,
use:["./loaders/loader1.js?changeVar=变量" , "./loaders/loader2.js?changeVar=a"]
},
{
test: /index\.js$/,
use:["./loaders/loader3.js?changeVar=变量"]
}
]
}
}
配置项中的use 会合并为一个 如下所示
use = ["./loaders/loader1.js?changeVar=变量" , "./loaders/loader2.js?changeVar=a","./loaders/loader3.js?changeVar=变量"]
执行顺序从最后开始执行
当其解析的顺序为从前往后,当其执行的顺序为从后往前,会将读取到的文件内容送入最后一个也就是loader3 ,d当loader3 处理完后将其处理过的文件内容返回到loader2,loader2处理完后将其处理过文件内容返回到第一个
当为多个文件匹配时的顺序为
webpack.config.js 的配置项为
module.exports = {
mode: "development",
module: {
rules: [
{
test: /index\.js$/,
use:["./loaders/loader1.js?changeVar=变量" ]
},
{
test: /\.js$/,
use:["./loaders/loader2.js?changeVar=变量", "./loaders/loader3.js"]
}
]
}
}
loader1.js 里的源码
var loaderUtils = require('loader-utils') // 引入依赖包loader-utils 来获取传递过来的参数
module.exports = function (srcCode) {
console.log("这是loader1")
// return srcCode.replace(/变量/g , 'var');
var options = loaderUtils.getOptions(this) // 获取参数列表
var reg = new RegExp(options.changeVar, 'g'); //新建正则表达式
return srcCode.replace(reg, "var")
}
loader2.js 里的源码
var loaderUtil = require('loader-utils')
module.exports = function(srcCode){
var options = loaderUtil.getOptions(this);
var reg = new RegExp(options.changeVar , "g");
console.log("这是loader2")
return srcCode.replace(reg, 'var')
}
loader3.js 里的源码
module.exports = function (srcCode){
console.log("这是loader3")
return srcCode
}
index.js 里的代码
变量 a = 123;
console.log(a)
require("./a")
a.js 的代码
变量 b = 111;
执行顺序为
如上图的运行顺序 如下图思考一下就知道啦