loader的入口需要导出一个函数,这个函数要干的事情就是转换一个文件的内容。
函数接收的参数content是一个文件在转换前的字符串形式内容,需要返回一个新的字符串形式内容作为转换后的结果,所有通过模块化倒入的文件都会经过loader。从这里可以看出loader只能处理一个个单独的文件而不能处理代码块。可以参考官方文档
2、编写webpack plugin
plugin应用场景广泛,所以稍微复杂点。以end-webpack-plugin为例:
class EndWebpackPlugin { constructor(doneCallback, failCallback) { this.doneCallback = doneCallback; this.failCallback = failCallback; } apply(compiler) { // 监听webpack生命周期里的事件,做相应的处理 compiler.plugin('done', (stats) => { this.doneCallback(stats); }); compiler.plugin('failed', (err) => { this.failCallback(err); }); } } module.exports = EndWebpackPlugin;loader的入口需要导出一个class,在new EndWebpackPlugin()的时候通过构造函数传入这个插件需要的参数,在webpack启动的时候会先实例化plugin,再调用plugin的apply方法,插件在apply函数里监听webpack生命周期里的事件,做相应的处理。
webpack plugin的两个核心概念:
(1)compiler:从webpack启动到退出只存在一个Compiler,compiler存放着webpack的配置。
(2)compilation:由于webpack的监听文件变化自动编译机制,compilation代表一次编译。
Compiler 和 Compilation 都会广播一系列事件。webpack生命周期里有非常多的事件
以上只是一个最简单的demo,更复杂的可以查看 how to write a plugin或参考web-webpack-plugin。
五、总结
webpack其实比较简单,用一句话概括本质:
webpack是一个打包模块化js的工具,可以通过loader转换文件,通过plugin扩展功能。如果webpack让你感到复杂,一定是各种loader和plugin的原因。
六、一些问题
1、webpack与grunt、gulp的不同?
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
总结:(1)从构建思路来说:gulp和grunt需要开发者将整个前端构建过程拆分成多个`Task`,并合理控制所有`Task`的调用关系 webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工;
(2)对于知识背景:gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路。
2、 与webpack类似的工具还有哪些?谈谈你为什么最终选择(或放弃)使用webpack?
同样是基于入口的打包工具还有以下几个主流的:webpack,rollup,parcel。
从应用场景上来看:(1)webpack适合大型复杂的前端站点构建;(2)rollup适合基础库的打包,比如vue,react;(3)parcel适用于简单的实验室项目,但是打包出错很难调试。
3、有哪些常见的Loader?他们是解决什么问题的?
(1)babel-loader:把es6转成es5;
(2)css-loader:加载css,支持模块化,压缩,文件导入等特性;
(3)style-loader:把css代码注入到js中,通过dom操作去加载css;
(4)eslint-loader:通过Eslint检查js代码;
(5)image-loader:加载并且压缩图片晚间;
(6)file-loader:文件输出到一个文件夹中,在代码中通过相对url去引用输出的文件;
(7)url-loader:和file-loader类似,文件很小的时候可以base64方式吧文件内容注入到代码中。
(8)source-map-loader:加载额外的source map文件,方便调试。
4、有哪些常见的Plugin?他们是解决什么问题的?
(1)uglifyjs-webpack-plugin:通过UglifyJS去压缩js代码;
(2)commons-chunk-plugin:提取公共代码;
(3)define-plugin:定义环境变量。
5、loader和plugin的不同