一. 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.js
module.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》