webpack中的loader 且 手写一个简易的loader

2023-5-24 948 5/24

loader,webpack的核心之一,因为webpack只能识别js,json文件,那么jsx,ts,vue,less,sass这类文件的就需要使用loader处理。

Loader 本质上是导出为函数的 JavaScript 模块。它接收资源文件或者上一个 Loader 产生的结果作为入参,也可以用多个 Loader 函数组成 loader chain(链),最终输出转换后的结果。它接收三个参数:content 源文件的内容,map SourceMap 数据,meta 数据,可以是任何内容。

 

loader的执行顺序:从右往左执行。

举个栗子,如果我们去配置一个简单的脚手架,那么怎么去处理对应less,sass,styles这类文件呢,

loader链

  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          "style-loader", //将css内容变成style标签插入到html中去
          "css-loader", //解析css文件的路径等
          "less-loader", //将less=>css
        ],
      },
    ],
  },

其实在生产环境中会替换掉style-loader替换为 MiniCssExtractPlugin.loader将CSS代码从打包后的JavaScript文件中提取出来,单独生成一个CSS文件。以免造成闪屏现象。

 

按照loader的执行顺序分类:前置  ,  普通  , 行内  ,后置( loader的类型和他本身没有任何关系,而是和配置的enforce属性有关系)

举个栗子,处理图片,图标这些资源

  module: {
        rules: [
            {
                test: /\.(png|jpe?g|gif|svg)$/,
                type: "asset",
                 enforce: "pre", //这里也可以是post,默认不写就是normal
            },//图片的处理
         
        ],
    },

loader的执行会有两个阶段,pithching阶段与normal阶段

pitching阶段:调用loader上的 pitch 方法,按照 后置(post)、行内(inline)、普通(normal)、前置(pre) 的顺序调用。

normal阶段: Loader 上的 常规方法,按照 前置(pre)、普通(normal)、行内(inline)、后置(post) 的顺序调用。我们需要对文件进行转换,就是在这个阶段去操作的。

 

首先在loaders下定义三个loader

function oneMalLoader(content, map, meta) {
  console.log(" one 的normal阶段");
  return content
}

oneMalLoader.pitch = function (remainingRequest, previousRequest, data) {
  console.log(" one 的pitch阶段");
}

module.exports = oneMalLoader;

 

 

function towMalLoader(content, map, meta) {
    console.log(" tow 的normal阶段");
    return content
}


towMalLoader.pitch = function (remainingRequest, previousRequest, data) {
    console.log(" tow 的pitch阶段");
}

module.exports = towMalLoader;

 

function threeMalLoader(content, map, meta) {
    console.log(" three 的normal阶段");
    return content
}


threeMalLoader.pitch = function (remainingRequest, previousRequest, data) {
    console.log(" three 的pitch阶段");
}


module.exports = threeMalLoader;

 

这里的话直接使用的最常用的方式去调用的

resolveLoader: {
    //找loader的时候,先去loaders目录下找,找不到再去node_modules下面找
    modules: ["loaders", "node_modules"],
  },
  module: {
    rules: [
    {
      test: /\.js$/,
      use: [
    "one-loader","tow-loader","three-loader" 
    ],
    }
    ],
  },

 

 

然后run一run,看看打印的结果

webpack中的loader 且 手写一个简易的loader

 

所以说在 Loader 的运行过程中,如果发现该 Loader 上有pitch属性,会先执行 pitch 阶段,再执行 normal 阶段。

pitch阶段的参数有三个PreviousRequestCurrentRequestremainingRequest

function oneMalLoader(content, map, meta) {
  console.log(" one 的normal阶段参数",'content',content,'map',map,'meta',meta);
  console.log('this.data',this.data,'one0loader  normal阶段的参数');
  return content
}


oneMalLoader.pitch = function (remainingRequest, previousRequest, data) {
  console.log(" one 的pitch阶段");
  console.log('remainingRequest',remainingRequest, 'previousRequest',previousRequest, 'data',data,'one0loader  pitch阶段的参数');
  this.data.name='李华'
}


module.exports = oneMalLoader;

 

先打印一下看一下

webpack中的loader 且 手写一个简易的loader

 

这就很好理解了

PreviousRequest代表的是之前执行过pitch阶段的loader,

remainingRequest代表未执行过pitch阶段的loader,

data,可以用于数据传递。即在 pitch 函数中往 data 对象上添加数据,之后在 normal 函数中通过 this.data 的方式读取已添加的数据,也就是注入上下文。

 

那么写一下简单的loader吧

例如,清除我们项目中的console.log

module.exports = function cleanLogLoader(content, map, meta) {
   /**
    * 将源文件正则替换后返回
    */
    return content.replace(/console\.log\(.*\);?/g, "");
  };

先看一下最开始打包后的代码

webpack中的loader 且 手写一个简易的loader

使用clearnLog  loader打包后的代码

webpack中的loader 且 手写一个简易的loader

 

个人的理解还不是很深入,后续学习深入学习后会继续补充。

 

- THE END -
0

共有 0 条评论