1.区别在前面两节中,我们提到了Loader和Plugin对应的概念。首先我们回顾一下loader是一个文件加载器,它可以加载资源文件并对这些文件进行一些处理,比如编译压缩等,最后将它们打包在一起。指定文件中的plugin赋予webpack各种灵活的功能,比如打包优化、资源管理、环境变量注入等,目的是解决其他loader无法实现的事情。从整个运行时间来看,如下图所示:可以看到,两者在运行时序上的区别:loader在打包文件之前运行,plugins贯穿整个编译周期,会广播很多事件在Webpack运行的生命周期中。Plugin可以监听这些事件,并在合适的时间通过Webpack提供。API更改输出结果。对于loader来说,本质上就是一个转换器,将A文件编译成B文件,并对文件进行操作,比如将A.scss或者A.less转换成B.css。简单的文件转换过程2.写一个loader在写一个loader之前,我们首先要了解loader的本质,它是一个函数。函数中的this会被webpack作为上下文填充,所以我们不能将loader设置为箭头函数。该函数接受一个参数,传递给webpack的加载器在文件源内容函数中,这是webpack提供的一个对象,可以获取当前加载器需要的各种信息。函数中有异步或同步操作。异步操作通过this.callback返回,要求返回值是字符串或者Buffer。代码如下所示://导出一个函数,source是webpack传给loader的文件源内容module.exports=function(source){constcontent=doSomeThing2JsString(source);//如果loader配置了options对象,则this.query会指向optionsconstoptions=this.query;//可以作为解析其他模块路径的contextconsole.log('this.context');/**this.callbackparameter:*error:error|null,loader出错时抛出Produceanerror*content:String|Buffer,loader编译后面要导出的内容*sourceMap:编译后生成内容的sourcemap,方便调试*ast:本次编译生成的AST静态语法树,后面执行的loader可以直接使用这个AST,省去重复生成AST*/this.callback(null,content);//异步返回内容;//同步}一般在写loader的过程中,保持单一功能,避免做多个功能。例如,将less文件转换成css文件,并不是一步到位的,而是Less-loader、css-loader、style-loader几个loader的链式调用才能完成转换。3、编写plugin由于webpack是基于发布-订阅模型的,所以在运行的生命周期中会广播很多事件。插件侦听这些事件。您可以在特定阶段执行自己的插件任务。之前了解到,webpack编译会创建两个核心对象:compiler:包含webpack环境的所有配置信息,包括options、loader和plugin,以及webpack的整个生命周期相关hook编译:作为plugin构建的参数-in事件回调函数,包括当前模块资源、编译资源、变化文件、跟踪依赖的状态信息。当检测到文件更改时,将创建一个新的编译。如果要自己实现plugin,还需要遵循一定的规范:plugin必须是一个函数或者是一个包含apply方法的对象,这样才能访问编译器实例,并传递给各个的编译器和编译对象插件都是同一个引用,所以不建议修改异步事件。插件处理完任务需要调用回调函数通知Webpack进入下一个流程,否则会卡死。实现插件的模板如下:classMyPlugin{//webpack会调用MyPlugin实例的apply方法将编译器对象传递给插件实例apply(compiler){//找到合适的事件钩子实现自己的插件functioncompiler.hooks.emit.tap('MyPlugin',compilation=>{//compilation:当前包构建过程的上下文console.log(compilation);//dosomething...})}}当emit事件发生时,意味着源文件的转换和组装已经完成,可以读取最终输出的资源、代码块、模块及其依赖,以及其中的内容可以修改输出资源参考文档https://webpack.docschina.org/api/loaders/https://webpack.docschina.org/api/compiler-hooks/https://segmentfault.com/a/1190000039877943https://vue3js.cn/面试
