一. loader综述
loader
是webpack
的外围概念之一,它的根本工作流是将一个文件以字符串的模式读入,对其进行语法分析及转换(或者间接在loader
中引入现成的编译工具,例如sass-loader
中就引入了node-sass
将SCSS代码转换为CSS代码,再交由css-loader
解决),而后交由下一环节进行解决,所有载入的模块最终都会通过moduleFactory
解决,转成javascript能够辨认和运行的代码,从而实现模块的集成。
loader
反对链式调用,所以开发上须要严格遵循“繁多职责”准则,即每个loader
只负责本人须要负责的事件:将输出信息进行解决,并输入为下一个loader
可辨认的格局。
理论开发中,很少会呈现须要本人写loader
来实现简单需要的场景,如果某个扩展名的文件无奈疾速集成到自动化构建工具里,预计很快就会被抛弃了,大家都那么忙是吧。然而理解loader
的基本原理和编译器的基本原理却是十分有必要的。
二. 如何写一个loader
如果须要编写一个性能残缺的loader
,倡议先到webpack
的官方网站浏览一下loader有哪些API
,地址:webpack官网-loader API,其中对于编写同步loader,异步loader,如何跳过loader,如何获取options
配置项等等都做了十分具体的解释,本篇中不再赘述。
假如当初要实现一个dash-loader
,它的性能是加载并解决名称为*.tpl.html
的文件,将其变为一个CommonJs
模块。也就是说要实现一个如下的根本转换:
转换前的文本:
<div> <h3>这里是题目</h3> <p>这里是内容</p> </div>
转换后的文本:
var str = '<div><h3>这里是题目</h3><p>这里是内容</p></div>';module.exports = str;
那么webpack.config.js
中须要减少如下的配置:
...module:{ rules:[{ test: /\.tpl\.html$/, use:[{ loader:'dash-loader' }] }]}
在我的项目的node_modules
依赖文件夹中新建dash-loader
文件夹,并在其中新建一个index.js
文件,内容的根本格局为:
//index.jsmodule.exports = function(source){ var tpl=""; source.split(/\r?\n/).forEach(function(line){ line=line.trim(); if(!line.length){ return; } //对line进行解决... tpl+=line; }); return "var tpl=\'" + tpl + "\'\nmodule.exports = tpl"; }
最终由dash-loader
返回的数据就如同是从某个CommonJs
模块中读入的一样了。
三. loader的编译器实质
理解了loader
的根本构造,那么loader里到底应该写点什么能力实现代码转换呢?这就波及到了一个新的概念——编译器(Compiler)。一个根本的编译器,须要通过tokenize
,parse
,transform
,stringify
几个外围步骤,它的利用是十分广的,SPA中的virtual-DOM
的解析,babel中的ES6
语法解析等等,babel
的官网已经举荐过一个十分棒的开源我的项目(10k+Star),具体讲述了如何一步一步实现一个编译器的,倡议感兴趣的同学能够自行学习:
【The-Super-Tiny-Compiler】——https://github.com/jamiebuilds/the-super-tiny-compiler
笔者最近在浏览《你不晓得的javascript》一书,发现第一节就在讲述根本的编译原理,是的,你每天都在用的javascript的编译过程,和下面提及的都是一样的,你说要不要学?
【参考】
《如何编写一个loader》