一. loader综述

loaderwebpack的外围概念之一,它的根本工作流是将一个文件以字符串的模式读入,对其进行语法分析及转换(或者间接在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》