手写webpack的loader

一、概念

帮助webpack将不同类型的文件转换为webpack可识别的模块。

二、Loader执行顺序

分类

  • pre:前置loader
  • normal:普通loader
  • inline:内联loader
  • post:后置loader

执行顺序

  • 4类loader的执行顺序为per>normal>inline>post
  • 相同优先级的loader执行顺序为:从右到左,从下到上。
    例如:
// 此时loader执行顺序:loader3 - loader2 - loader1
module: {
  rules: [
    {
      test: /\.js$/,
      loader: "loader1",
    },
    {
      test: /\.js$/,
      loader: "loader2",
    },
    {
      test: /\.js$/,
      loader: "loader3",
    },
  ],
},
// 此时loader执行顺序:loader1 - loader2 - loader3
module: {
  rules: [
    {
      enforce: "pre",
      test: /\.js$/,
      loader: "loader1",
    },
    {
      // 没有enforce就是normal
      test: /\.js$/,
      loader: "loader2",
    },
    {
      enforce: "post",
      test: /\.js$/,
      loader: "loader3",
    },
  ],
},

使用Loader 的方式

  • 配置方式:在 webpack.config.js 文件中指定 loader。(pre、normal、post loader)
  • 内联方式:在每个 import 语句中显式指定 loader。(inline loader)

inline Loader

用法:import Styles from ‘style-loader!css-loader?modules!./styles.css’;

含义:使用 css-loader 和 style-loader 处理 styles.css 文件通过 ! 将资源中的 loader 分开
inline loader 可以通过添加不同前缀,跳过其他类型 loader。! 跳过 normal loader。

import Styles from '!style-loader!css-loader?modules!./styles.css';

-! 跳过 pre 和 normal loader。

import Styles from '-!style-loader!css-loader?modules!./styles.css';

!! 跳过 pre、 normal 和 post loader。

import Styles from '!!style-loader!css-loader?modules!./styles.css';

三、开发一个Loader

最简单的Loader

//loader/loader1.js
module.exports = function (content){
	console.log(content)
	return content;
}

他接受要处理的源码作为参数,输出转换后的js代码

Loader接受的参数

  • content 源文件的内容
  • map sourceMap数据
  • meta 数据可以是任何内容

Loader分类

  1. 同步Loader

module.exports = function (content ,map ,meta) {
    /* 
        第一个参数:err代表是否有错误
        第二个参数:content处理后的内容
        第三个参数:sorce-map继续传递sourcemap 
        第四个参数:meta给下一个loader传递参数
    */
    //相比于普通return方式这种写法可以传递更多参数,不中断loader执行。
    //return content 
    this.callback(null,content,map,meta)
}
  1. 异步Loader

由于同步计算过于耗时,在 Node.js 这样的单线程环境下进行此操作并不是好的方案,我们建议尽可能地使你的 loader 异步化。但如果计算量很小,同步 loader 也是可以的。

module.exports = function (content, map, meta) {
  const callback = this.async();
  // 进行异步操作
  setTimeout(() => {
    callback(null, result, map, meta);
  }, 1000);
};
  1. Raw Loader

默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 raw 为 true,loader 可以接收原始的 Buffer

module.exports = function (content) {
  // content是一个Buffer数据
  return content;
};
module.exports.raw = true; // 开启 Raw Loader
  1. Pitching Loader

webpack 会先从左到右执行 loader 链中的每个 loader 上的 pitch 方法(如果有),然后再从右到左执行 loader 链中的每个 loader 上的普通 loader 方法。在这个过程中如果任何 pitch 有返回值,则 loader 链被阻断。webpack 会跳过后面所有的的 pitch 和 loader,直接进入上一个 loader 。

module.exports = function (content) {
  return content;
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
  console.log("do somethings");
};

手写webpack的loader_第1张图片

手写banner-loader

作用:给代码添加文本注释包括作者、日期

//loader/banner-loader.js
const schema =  require("./schema.json");
module.exports  = function (content,map,meta){
    //获取Loader的options,同时对options做校验
    //schema 是options的校验规则。
    const options = this.getOptions(schema);
    const date = (new Date()).toLocaleString()
    
    const prefix = `
      /* 
        Author ${options.author}
        Date ${date}
      */
    `
    return `${prefix} \n ${content}`
}

下面是schema.json文件

{
    "type":"object",
    "porperties":{
        "author":{
            "type":"string"
        }
    },
    "addtionalProperties":false
}

在webpack.config.js中配置

//...省略
    module: {
        rules: [
            {
                test:/\.js$/,
                loader:'./loader/banner-loader',
                options:{
                    author:'老王'
                }
            }
        ]
    },

在dist压缩文件main.js中

/***/ "./src/main.js":
/*!*********************!*\
  !*** ./src/main.js ***!
  \*********************/
/***/ (() => {

eval("\n      /* \n        Author 老王\n        Date 2024/1/13 14:32:11\n      */\n     \n console.log('hello main')\n\n//# sourceURL=webpack:///./src/main.js?");

/***/ })

/******/ 	});
/************************************************************************/

你可能感兴趣的:(webpack,前端,node.js)