webpack做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。
更多的功能需要借助webpack loaders和webpack plugins完成
webpack loader: loader本质上是一个函数,它的作用是将某个源码字符串转换成另一个源码字符串返回。
image.png
loader函数的将在模块解析的过程中被调用,以得到最终的源码

全流程:

image.png
image.png
当加入loaders时的详细流程图
image.png
从上图可以看出webpack读取文件内容后经过loaders函数后才会交给抽象语法树,
如下案例

loaders 的简易使用

index.js 的源码

  1. 变量 a = 123;
  2. console.log(a)

loader1.js的源码

  1. module.exports = function(srcCode){
  2. // 函数内的参数在此环境中是index.js的源码,以文本的形式的代码,因为的loaders函数的上一步是读取文件内容
  3. // 注意此文件的模块化只能使用commonjs 此处的代码是运行在node环境中的 ,es6的模块化node是无法识别的
  4. return srcCode.replace(/变量/g , 'var'); // 进行正则匹配与字符替换
  5. }

webpack.config.js 的配置如下

  1. module.exports = {
  2. mode: "development",
  3. module: {
  4. rules: [ //模块的匹配规则
  5. // 规则1
  6. {
  7. test: /index\.js$/, // 正则表达式匹配模块路径
  8. use: [ //匹配到之后,使用哪些加载器
  9. {
  10. loader: "./loaders/loader1.js",
  11. }
  12. ]
  13. }
  14. ]
  15. }
  16. }

从上面代码可以看出 当index.js 在进行抽象语法树分析时是会报错的,因为里面有无法识别的语法错误,而我使用loader 将其index.js 的源码进行匹配将代码里”变量” 替换为 “var” 替换后再交给抽象语法树
如下图webpack打包后的代码 你会发现红框里的代码别应该是 变量 a = 123 , 结果变成啦 var a = 123;
image.png
工程目录 注意画红线的都是此测试无用的
image.png

loaders函数的参数接收与传递

还可以给loaders函数传递参数,如下代码

  1. module.exports = {
  2. mode: "development",
  3. module: {
  4. rules: [
  5. {
  6. test: /index\.js$/,// 正则表达式匹配模块路径
  7. use: [//模块的匹配规则
  8. {
  9. loader: "./loaders/loader1.js",//匹配到之后,使用哪些加载器 等效于 require("./loaders/loader1.js")
  10. options: {
  11. changeVar: "变量" // 传递参数
  12. }
  13. }
  14. ]
  15. // 可以简写为 use:["./loaders/loader1.js?changeVar=变量" , "./loaders/loader2.js?changeVar=a"]
  16. }
  17. ]
  18. }
  19. }

如上面代码向./loaders/loader1.js下的默认导出的函数传入参数,但是这个默认导出的函数是的参数列表是没有的,这个参数存在thisl里可以使用依赖包 loader-utils , 它会帮我们获取传递过来的参数
loader1.js 修改如下

  1. var loaderUtils = require('loader-utils') // 引入依赖包loader-utils 来获取传递过来的参数
  2. module.exports = function (srcCode) {
  3. // return srcCode.replace(/变量/g , 'var');
  4. console.log("loader 运行啦")
  5. var options = loaderUtils.getOptions(this) // 获取参数列表
  6. var reg = new RegExp(options.changeVar, 'g'); //新建正则表达式
  7. return srcCode.replace(reg, "var ")
  8. }

其打包的结果为
image.png

匹配规则的运行顺序

当有多个匹配规则时他们的运行顺序为?
image.png

如上图的执行顺序如下代码所实现的效果
webpack.config.js 的配置如下

  1. module.exports = {
  2. mode: "development",
  3. module: {
  4. rules: [
  5. {
  6. test: /index\.js$/,
  7. use:["./loaders/loader1.js?changeVar=变量" , "./loaders/loader2.js?changeVar=a"]
  8. },
  9. {
  10. test: /index\.js$/,
  11. use:["./loaders/loader3.js?changeVar=变量"]
  12. }
  13. ]
  14. }
  15. }

loader1.js 的代码如下

  1. module.exports = function (srcCode) {
  2. console.log("这是loader1")
  3. return "这是loader1"
  4. }

loader2.js 的代码如下

  1. module.exports = function (srcCode){
  2. console.log("这是loader2")
  3. return "这是loader2"
  4. }

loader3.js 的代码如下

  1. module.exports = function (srcCode){
  2. console.log("这是loader2")
  3. return "这是loader2"
  4. }

运行代码效果如下图
image.png
你会发现他会从最后一个开始运行
看 webpack.config.js的配置项

  1. module.exports = {
  2. mode: "development",
  3. module: {
  4. rules: [
  5. {
  6. test: /index\.js$/,
  7. use:["./loaders/loader1.js?changeVar=变量" , "./loaders/loader2.js?changeVar=a"]
  8. },
  9. {
  10. test: /index\.js$/,
  11. use:["./loaders/loader3.js?changeVar=变量"]
  12. }
  13. ]
  14. }
  15. }

配置项中的use 会合并为一个 如下所示

  1. use = ["./loaders/loader1.js?changeVar=变量" , "./loaders/loader2.js?changeVar=a","./loaders/loader3.js?changeVar=变量"]

执行顺序从最后开始执行
当其解析的顺序为从前往后,当其执行的顺序为从后往前,会将读取到的文件内容送入最后一个也就是loader3 ,d当loader3 处理完后将其处理过的文件内容返回到loader2,loader2处理完后将其处理过文件内容返回到第一个

当为多个文件匹配时的顺序为

webpack.config.js 的配置项为

  1. module.exports = {
  2. mode: "development",
  3. module: {
  4. rules: [
  5. {
  6. test: /index\.js$/,
  7. use:["./loaders/loader1.js?changeVar=变量" ]
  8. },
  9. {
  10. test: /\.js$/,
  11. use:["./loaders/loader2.js?changeVar=变量", "./loaders/loader3.js"]
  12. }
  13. ]
  14. }
  15. }

loader1.js 里的源码

  1. var loaderUtils = require('loader-utils') // 引入依赖包loader-utils 来获取传递过来的参数
  2. module.exports = function (srcCode) {
  3. console.log("这是loader1")
  4. // return srcCode.replace(/变量/g , 'var');
  5. var options = loaderUtils.getOptions(this) // 获取参数列表
  6. var reg = new RegExp(options.changeVar, 'g'); //新建正则表达式
  7. return srcCode.replace(reg, "var")
  8. }

loader2.js 里的源码

  1. var loaderUtil = require('loader-utils')
  2. module.exports = function(srcCode){
  3. var options = loaderUtil.getOptions(this);
  4. var reg = new RegExp(options.changeVar , "g");
  5. console.log("这是loader2")
  6. return srcCode.replace(reg, 'var')
  7. }

loader3.js 里的源码

  1. module.exports = function (srcCode){
  2. console.log("这是loader3")
  3. return srcCode
  4. }

index.js 里的代码

  1. 变量 a = 123;
  2. console.log(a)
  3. require("./a")

a.js 的代码

  1. 变量 b = 111;

执行顺序为
image.png
如上图的运行顺序 如下图思考一下就知道啦
image.png