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;
执行顺序为
如上图的运行顺序 如下图思考一下就知道啦
