如何??编写一个Loader

如何??编写一个Loader

?己编写一个Loader的过程是比较简单的,

Loader就是?个函数,声明式函数,不能?用箭头函数

拿到源代码,作进一步的修饰处理,再返回处理后的源码就可以了

简单案例

创建一个替换源码中字符串的loader

//index.js

console.log("hello world");

//replaceLoader.js

module.exports = function(source) {

console.log(source, this, this.query);

return source.replace(world,‘大家好‘)

};

//需要?声明式函数,因为要上到上下文的this,用到this的数据,该函数接受一个参数

在配置文件中使用loader

//需要使用node核心模块path来处理路径

const path = require(‘path‘);

......

module: {

rules: [

{

test: /\.js$/,

use: path.resolve(__dirname, "./loader/replaceLoader.js")

}

]

},

如何给loader配置参数,loader如何接受参数?

² this.query

² loader-utils

²

//需要使用node核?心模块path来处理路径

const path = require(‘path‘);

module: {

rules: [

{

test: /\.js$/,

use: path.resolve(__dirname, "./loader/replaceLoader.js")

}

]

},

//webpack.config.js

.........

module: {

rules: [

{

test: /\.js$/,

use: [

{

loader: path.resolve(__dirname, "./loader/replaceLoader.js"),

options: {

name: "你好吗"

}

}

]

}

]

},

//replaceLoader.js

//方式一: this.query获取参数

module.exports = function(source) {

//this.query 通过this.query来接受配置文件传递进来的参数

//return source.replace("world", this.query.name);

return source.replace("world", options.name);

}

//方式二: loader-utils获取参数,官方推荐

const loaderUtils = require("loader-utils");//官方推荐处理loader,query的?具

module.exports = function(source) {

//this.query 通过this.query来接受配置文件传递进来的参数

const options = loaderUtils.getOptions(this);

return source.replace("world", options.name);

}

this.callback :如何返回多个信息,不止是处理好的源码呢,可以使用this.callback来处理

//replaceLoader.js

const loaderUtils = require("loader-utils");//官?方推荐处理理loader,query的?工具

module.exports = function(source) {

const options = loaderUtils.getOptions(this);

const result = source.replace("world", options.name);

this.callback(null, result);

};

//this.callback(

err: Error | null,

content: string | Buffer,

sourceMap?: SourceMap,

meta?: any );

this.async:如果loader??有异步的事情要怎么处理理呢

我们使?this.async来处理,他会返回this.callback

//replaceLoader.js

const loaderUtils = require("loader-utils");//官?方推荐处理理loader,query的?工具

module.exports = function(source) {

const options = loaderUtils.getOptions(this);

const result = source.replace("world", options.name);

this.callback(null, result);

};

//this.callback(

err: Error | null,

content: string | Buffer,

sourceMap?: SourceMap,

meta?: any

);

const loaderUtils = require("loader-utils");

module.exports = function(source) {

const options = loaderUtils.getOptions(this);

setTimeout(() => {

const result = source.replace("world", options.name);

return result;

}, 1000);

};

//先?setTimeout处理下试试,发现会报错

我们使?用this.async来处理理,他会返回this.callback

const loaderUtils = require("loader-utils");

module.exports = function(source) {

const options = loaderUtils.getOptions(this);

//定义一个异步处理,告诉webpack,这个loader?有异步事件,在里?调?下这个异步

//callback 就是 this.callback 注意参数的使?

const callback = this.async();

setTimeout(() => {

const result = source.replace("world", options.name);

callback(null, result);

}, 3000);

};

多个loader的使?

//replaceLoader.js

module.exports = function(source) {

return source.replace("软谋课堂", "word");

};

//replaceLoaderAsync.js

const loaderUtils = require("loader-utils");

module.exports = function(source) {

const options = loaderUtils.getOptions(this);

//定义?一个异步处理理,告诉webpack,这个loader?里里有异步事件,在?里里?面调?用下这个异步

const callback = this.async();

setTimeout(() => {

const result = source.replace("world", options.name);

callback(null, result);

}, 3000); };

//webpack.config.js

module: {

rules: [

{

test: /\.js$/,

use: [

path.resolve(__dirname, "./loader/replaceLoader.js"),

{

loader: path.resolve(__dirname, "./loader/replaceLoaderAsync.js"),

options: {

name: "你好吗"

}

}

]

// use: [path.resolve(__dirname, "./loader/replaceLoader.js")]

}

]

}

顺序,自下?上,自右到左

处理loader的路径问题

resolveLoader: {

modules: ["node_modules", "./loader"]

},

module: {

rules: [

{

test: /\.js$/,

use: [

"replaceLoader",

{

loader: "replaceLoaderAsync",

options: {

name: "软谋课堂"

}

}

]

}

]

},

..............

参考:loader API

https://webpack.js.org/api/loaders

如何?己编写一个Plugins

Plugin: 开始打包,在某个时刻,帮助我们处理一些什么事情的机制 plugin要比loader稍微复杂一些,在webpack的源码中,用plugin的机制还是占有非常大的场景,可以说plugin是webpack的灵魂

l 设计模式

l 事件驱动

l 发布订阅

plugin是一个类,?面包含一个apply函数,接受一个参数,compiler

案例:

创建copyright-webpack-plugin.js

  1. plugin实际是一个类(构造函数),通过在plugins配置中实例化进行调用
  2. 它在原型对象上指定了一个apply方法,入参是compiler对象
  3. 指定一个事件钩子,并调用内部提供的API
  4. 完成操作后,调用webpack 提供的callback方法

class CopyrightWebpackPlugin {

constructor() {  }

// 将 `apply` 定义为其原型方法,此方法以 compiler 作为参数

apply(compiler) {  }

}

module.exports = CopyrightWebpackPlugin;

配置文件里使?

const CopyrightWebpackPlugin = require("./plugin/copyright-webpack-plugin");

plugins: [new CopyrightWebpackPlugin()]

如何传递参数

//webpack配置?文件

plugins: [

new CopyrightWebpackPlugin({

name: "你好吗"

})

]

//copyright-webpack-plugin.js

class CopyrightWebpackPlugin {

constructor(options) {

//接受参数

console.log(options);

}

apply(compiler) { }

}

module.exports = CopyrightWebpackPlugin;

配置plugin在什么时刻进?

class CopyrightWebpackPlugin {

constructor(options) {

// console.log(options);

}

apply(compiler) {

//hooks.emit 定义在某个时刻 ,

// 指定要附加到的事件钩子函数

compiler.hooks.emit.tapAsync(

"CopyrightWebpackPlugin",

(compilation, cb) => {

// 使用 webpack 提供的 plugin API 操作构建结果

compilation.assets["copyright.txt"] = {

source: function() {

return "hello copy";

},

size: function() {

return 20;

}

};

cb();

} );

//同步的写法

//compiler.hooks.compile.tap("CopyrightWebpackPlugin", compilation => {

//  console.log("开始了了");

//});

}

}

module.exports = CopyrightWebpackPlugin;

参考:compiler-hooks

https://webpack.js.org/api/compiler-hooks

实现插件的背景知识

由上面的步骤可知,插件功能的实现主要依赖于compiler和complation对象,而两者都是继承自Tapable对象。它暴露三种注册监听的方法Tapable对象主要是9种钩子:

const {

SyncHook,

SyncBailHook,

SyncWaterfallHook,

SyncLoopHook,

AsyncParallelHook,

AsyncParallelBailHook,

AsyncSeriesHook,

AsyncSeriesBailHook,

AsyncSeriesWaterfallHook

} = require("tapable");

其中同步四种,异步并行两种,异步串行3种。

同步钩子进行同步操作;异步钩子中进行异步操作。

compiler和compilation中的钩子都是来自这9种钩子。钩子的工作机制类似于浏览器的事件监听。

1)生成的钩子可以注册监听事件,其中同步钩子通过tap方法监听,异步钩子通过tapAsync(+回调函数)和tapPromise(+返回promise)进行监听。

2)还可以进行拦截,通过intercept方法。

3)对于监听事件的触发,同步钩子通过call方法; 异步钩子通过callAsync方法和promise

原文地址:https://www.cnblogs.com/laneyfu/p/12269965.html

时间: 2024-07-30 16:28:00

如何??编写一个Loader的相关文章

Java基础-继承-编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight。小车类Car是Vehicle的子类,其中包含的属性有载人数 loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。每个 类都有构造方法和输出相关数据的方法。最后,写一个测试类来测试这些类的功 能。

#29.编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight.小车类Car是Vehicle的子类,其中包含的属性有载人数 loader.卡车类Truck是Car类的子类,其中包含的属性有载重量payload.每个 类都有构造方法和输出相关数据的方法.最后,写一个测试类来测试这些类的功 能. package hanqi; public class Vehicle { private int wheels; private int weight

如何编写一个带命令行参数的Python文件

看到别人执行一个支持命令行参数的python文件,瞬间觉得高大上起来.牛逼起来,那么如何编写一个带命令行参数的python脚本呢?不用紧张,下面将简单易懂地让你学会如何让自己的python脚本,支持命令行参数. 首先你要知道python中的sys模块的一些功能: import sys print "the number of python program's argument:",len(sys.argv) print "the value of every argument

如何编写一个编译c#控制台应用程序的批处理程序

如何编写一个编译c#控制台应用程序的批处理程序 2011-03-22 18:14 dc毒蘑菇 | 浏览 579 次 最近在网上看了一个教程,是学C#的,但是我的机子上装不上vs,所以想写一个批处理来编译,因为每次都要我更改目录,然后复制路径,再编译,输出,特别的浪费时间,所以特来求助网友,希望帮帮忙 分享到: 2011-03-22 19:17 #快乐假期,智慧随行# 提问者采纳 不知道你有没有使用过ANT,你可以创建ANT脚本来构建你的应用程序.如果不是很了解,也不愿意编写的话,我介绍你一款可视

【前端小小白的学习之路】---->用JS编写一个函数,返回数组中重复出现过的元素

用JS编写一个函数,返回数组中重复出现过的元素,见下面的代码: var arr = [1, 2, 3, 1, 2, 3, 4, 5]; var getRepeat = function (arr) { var obj = {}; for (var i = 0, len = arr.length; i < len; i++) { if (obj[arr[i]] == undefined) { obj[arr[i]] = 1; } else { obj[arr[i]]++; } } for (var

网络攻防学习 1编写一个端口扫描器

谨以此文献给初学的自己! 我有太多的名词不认识通过学习 一步步巩固基础 一步步提高自己r 任何一个靠谱的网络攻击都是起步于侦查的.我们将学习编写一个扫描主机开放的tcp端口的侦察小脚本,为了与tcp端交互,我们先建立TCP套接字. 套接字: 英文名字为socket, 是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程.

如何编写一个gulp插件

很久以前,我们在"细说gulp"随笔中,以压缩JavaScript为例,详细地讲解了如何利用gulp来完成前端自动化. 再来短暂回顾下,当时除了借助gulp之外,我们还利用了第三方gulp插件”gulp-uglify”,来达到压缩JavaScript文件的目的. 代码如下: 今儿,我们的重点就是,自己也来实现一个gulp插件. 正文 其实,如果只是单纯地想要编写一个gulp插件不难,可以借助through2或者through-gulp来编写(through-gulp是基于through

面试题之java 编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 要求不能出现截半的情况

题目:10. 编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串. 但是要保证汉字不被截半个,如“我ABC”4,应该截为“我AB”,输入“我ABC汉DEF”,6,应该输出为“我ABC”而不是“我ABC+汉的半个”. 一.需要分析 1.输入为一个字符串和字节数,输出为按字节截取的字符串-------------->按照字节[byte]截取操作字符串,先将String转换成byte类型 .2.汉字不可以截半----------------------------------

Java基础-接口中国特色社会主义的体制中有这样的现象:地方省政府要坚持党的领导和按 照国务院的指示进行安全生产。请编写一个java应用程序描述上述的体制现象。 要求如下: (1)该应用程序中有一个“党中央”接口:CentralPartyCommittee,该接口中 有个“坚持党的领导”方法:void partyLeader() (2)该应用程序中有一个“国务院”抽象类:StateCouncil,

36.中国特色社会主义的体制中有这样的现象:地方省政府要坚持党的领导和按 照国务院的指示进行安全生产.请编写一个java应用程序描述上述的体制现象. 要求如下: (1)该应用程序中有一个“党中央”接口:CentralPartyCommittee,该接口中 有个“坚持党的领导”方法:void partyLeader() (2)该应用程序中有一个“国务院”抽象类:StateCouncil,该抽象类中有个“安 全生产”的抽象方法:abstract void safetyInProduction() (

java基础,继承类题目:编写一个Java应用程序,该程序包括3个类:Monkey类、People类和主类 E

21.编写一个Java应用程序,该程序包括3个类:Monkey类.People类和主类 E.要求: (1) Monkey类中有个构造方法:Monkey (String s),并且有个public void speak() 方法,在speak方法中输出“咿咿呀呀......”的信息. (2)People类是Monkey类的子类,在People类中重写方法speak(),在speak方法 中输出“小样的,不错嘛!会说话了!”的信息. (3)在People类中新增方法void think(),在thi