乐趣区

关于javascript:Webpack40各个击破6loader篇

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

退出移动版