webpack插件怎么手写

webpack插件没什么好说的,用过的都知道怎么配置,只是不知道内部怎么执行。今天学一学插件的一些机制,手写一个插件并不难。

之前介绍过了,webpack本质上是一种事件流机制,核心就是tapable,通过注册事件,触发回调,完成插件在不同生命周期的调用,内部也是通过大量的插件实现的。tapable内部暴露的方法挺多的,主要就是同步和异步,异步分为并行和串行。可以去GitHub上面看看:

https://github.com/webpack/tapable#tapable

这些方法都有用法示例,本来想写写使用方法,发现GitHub上面都有了,就不写了:

const {

	SyncHook,

	SyncBailHook,

	SyncWaterfallHook,

	SyncLoopHook,

	AsyncParallelHook,

	AsyncParallelBailHook,

	AsyncSeriesHook,

	AsyncSeriesBailHook,

	AsyncSeriesWaterfallHook

 } = require("tapable");

在写插件之前,不得不提一下compiler和compilation:

compiler对象代表了完整的 webpack 环境配置,可以访问整个环境。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置(options、loader、plugin等)。使用插件时将收到此 compiler 对象的引用。

compilation 对象代表了一次资源版本构建。在运行过程中,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation提供了很多关键时机的回调供插件做自定义处理时使用。

使用插件就是new一个,所以插件其实就是一个类(构造函数或者class类),内部在prototype定义一个apply方法(会直接调用),并提供compiler,通过compiler提供的hooks注册事件和在相应的回调里面进行操作。而compiler提供的compilation的重要属性是assets,表示所有的静态资源。

关于提供的hook和参数,可以在webpack>lib>Compiler.js搜hooks,其实compiler和compilation都是继承tapable。

关于hooks分别表示什么阶段可以去官网查看:https://www.webpackjs.com/api/compiler-hooks/

还需要明确一下,tapable里面提供的几个hook,同步的(sync开头)注册是tap,异步的(async开头)有tap、tapAsync、tapPromise,后面两个提供了回调函数。

引入自己的插件:

const MyPlugin = require(’./plugins/my-plugin.js’)

plugins里面使用:

new MyPlugin({

  name: 'wade plugin'

})

my-plugin.js里面:

class MyPlugin {

    constructor(options) {

        this.options = options;

    }

    apply(compiler){

        compiler.hooks.done.tap('MyPlugin', (stats) => {

            console.log('MyPlugin ', this.options);

        });

    }

}



module.exports = MyPlugin;

apply提供了compiler,done是编译完成,同步的调用tap,第一个参数没什么意义,一般写自己插件名字,stats里面对象就多了,有 options、 outputOptions等,可以自己命令行那边看看。

异步的:

class MyPlugin {

    constructor(options) {

        this.options = options;

    }

    apply(compiler){

        compiler.hooks.done.tapAsync('DonePlugin', (stats, callback) => {

            console.log('Hello ', this.options.name);

            setTimeout(() => {console.log(1);}, 1000);

            setTimeout(() => {console.log(2);}, 2000);

            setTimeout(() => {console.log(3);}, 3000);

            setTimeout(() => {

                callback();

            }, 4000)

        });

    }

}



module.exports = MyPlugin;

可以看看控制台,看看效果。

一般自己写插件会在emit和afterEmit进行一些操作,这两个钩子的参数是compilation,里面有assets是静态资源,可以进行操作:

compiler.hooks.emit.tap('DonePlugin', (compilation) => {

   let assets = compilation.assets;

    console.log(assets);

});

比如我想给bundle.js添加一个字符串:

let content = assets['bundle.js'].source();

assets['bundle.js'] = {

    source(){

        return '"build by wade"\r\n' + content

    },

    size(){

        return content.length;

    }

}

打包结果:

比如创建一个文件:

let creatContent = '创建一个文件';

assets['creat.js'] = {

    source(){

        return creatContent

    },

    size(){

        return creatContent.length

    }

}


上面都是没什么意义的操作,只是想表达插件的一些方法,比如可以在文件生成之后进行压缩,或者自动化部署到服务器之类的插件。真正写一些有用的插件还是需要根据具体清空具体实现代码,可能还需要引入一些外部的插件,比如进行请求需要引入ajax或者axios,压缩要引入JSZip等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值