div{display:table-cell;vertical-align:middle}#crayon-theme-info .content *{float:left}#crayon-theme-info .field{font-weight:bold}#crayon-theme-info .field,#crayon-theme-info .value{margin-left:5px}#crayon-theme-info .description.value{font-style:italic;color:#999}#crayon-theme-info .type{text-align:center;min-width:120px;font-weight:bold;border-right:1px solid #ccc;padding-right:5px}#crayon-theme-info .type.stock{color:#666}#crayon-theme-info .type.user{color:#5b9a00}#crayon-editor-table td{vertical-align:top}.small-icon{width:24px;height:24px;display:inline-block;margin:5px 5px 0 0}#twitter-icon{background:url(../images/twitter.png)}#gmail-icon{background:url(../images/google.png)}#docs-icon{background:url(../images/docs.png)}#git-icon{background:url(../images/github.png)}#wp-icon{background:url(../images/wordpress-blue.png)}#donate-icon{background:url(../images/donate.png);width:75px}#crayon-donate,#crayon-donate input{margin:0;display:inline;padding:0}#crayon-theme-editor-info a{text-decoration:none!important;font-style:italic!important;color:#666!important}#crayon-main-wrap .form-table .note{font-style:italic;color:#999}#crayon-change-code-text{width:400px;height:300px}.crayon-syntax{overflow:hidden!important;position:relative!important;direction:ltr;text-align:left;box-sizing:border-box;direction:ltr!important;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-text-size-adjust:none}.crayon-syntax div{background:0;border:0;padding:0;margin:0;text-align:left}.crayon-syntax.crayon-loading{visibility:hidden}.crayon-syntax,.crayon-syntax .crayon-main,.crayon-syntax .crayon-toolbar,.crayon-syntax .crayon-info,.crayon-syntax .crayon-plain,.crayon-syntax .crayon-code{width:100%}.crayon-syntax .crayon-main,.crayon-syntax .crayon-plain{overflow:auto}.crayon-syntax,.crayon-syntax .crayon-main,.crayon-syntax .crayon-plain,.crayon-syntax .crayon-table{padding:0;margin:0}.crayon-syntax-inline{margin:0 2px;padding:0 2px}.crayon-syntax .crayon-table{border:none!important;background:none!important;padding:0!important;margin-top:0!important;margin-right:0!important;margin-bottom:0!important;width:auto!important;border-spacing:0!important;border-collapse:collapse!important;table-layout:auto!important}.crayon-syntax .crayon-table td,.crayon-syntax .crayon-table tr{padding:0!important;border:none!important;background:0;vertical-align:top!important;margin:0!important}.crayon-syntax .crayon-invisible{display:none!important}.crayon-plain-tag{margin-bottom:12px}.crayon-popup .crayon-plain{display:block!important;width:100%!important;height:100%!important;opacity:100!important;position:relative!important}.crayon-popup-window{background:#fff}.crayon-syntax .crayon-num{text-align:center;padding:0 5px;margin:0}.crayon-syntax .crayon-toolbar{position:relative;overflow:hidden;z-index:4}.crayon-syntax .crayon-info{position:absolute;overflow:hidden;display:none;z-index:3;padding:0;min-height:18px;line-height:18px}.crayon-syntax .crayon-info div{padding:2px!important;text-align:center}.crayon-syntax .crayon-toolbar span{padding:0 4px!important}.crayon-syntax .crayon-toolbar .crayon-button{display:inline;float:left!important;position:relative;width:24px;background-repeat:no-repeat;line-height:15px;border:0;text-decoration:none}.crayon-toolbar .crayon-button,.crayon-toolbar .crayon-button:hover,.crayon-toolbar .crayon-button.crayon-pressed:hover{background-position:0 center}.crayon-toolbar .crayon-button.crayon-pressed,.crayon-toolbar .crayon-button:active,.crayon-toolbar .crayon-button.crayon-pressed:active{background-position:-24px 0}.crayon-toolbar .crayon-button.crayon-popup-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-popup-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed:hover .crayon-button-icon{background-position:0 0}.crayon-toolbar .crayon-button.crayon-copy-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-copy-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -16px}.crayon-toolbar .crayon-button.crayon-nums-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-nums-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -32px}.crayon-toolbar .crayon-button.crayon-plain-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-plain-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -48px}.crayon-toolbar .crayon-button.crayon-mixed-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-mixed-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -64px}.crayon-toolbar .crayon-button.crayon-minimize .crayon-button-icon{background-position:0 -80px;background-color:transparent!important}.crayon-toolbar .crayon-button.crayon-expand-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-expand-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -96px}.crayon-toolbar .crayon-button.crayon-wrap-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-wrap-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -112px}.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-popup-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed:active .crayon-button-icon{background-position:-24px 0}.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-copy-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -16px}.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-nums-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -32px}.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-plain-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -48px}.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-mixed-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -64px}.crayon-toolbar .crayon-button.crayon-minimize .crayon-button-icon{background-position:-24px -80px;background-color:transparent!important}.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-expand-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -96px}.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-wrap-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -112px}.crayon-syntax .crayon-toolbar .crayon-language{padding-right:8px!important}.crayon-syntax .crayon-title,.crayon-syntax .crayon-language{float:left}.crayon-main::-webkit-scrollbar,.crayon-plain::-webkit-scrollbar{height:6px;overflow:visible;width:6px;background:#EEE}.crayon-main::-webkit-scrollbar-thumb,.crayon-plain::-webkit-scrollbar-thumb{background-color:#CCC;background-clip:padding-box;border:1px solid #AAA;box-shadow:inset 0 0 2px #999;min-height:8px;padding:0;border-width:1px}.crayon-main::-webkit-scrollbar-button,.crayon-plain::-webkit-scrollbar-button{height:0;width:0;padding:0}.crayon-main::-webkit-scrollbar-track,.crayon-plain::-webkit-scrollbar-track{background-clip:padding-box;border:solid transparent;border-width:0 0 0 4px;border:1px solid #BBB;border-right:0;border-bottom:0}.crayon-main::-webkit-scrollbar-corner,.crayon-plain::-webkit-scrollbar-corner{background:#EEE}.crayon-main::-webkit-scrollbar-thumb:hover,.crayon-plain::-webkit-scrollbar-thumb:hover{background:#AAA;border:1px solid #777;box-shadow:inset 0 0 2px #777}.crayon-syntax .crayon-pre,.crayon-syntax pre{color:#000;white-space:pre;margin:0;padding:0;overflow:visible;background:none!important;border:none!important;tab-size:4}.crayon-syntax .crayon-line{padding:0 5px}.crayon-syntax.crayon-wrapped .crayon-line{white-space:pre-wrap!important;height:auto;word-break:break-all}.crayon-syntax-inline .crayon-pre,.crayon-syntax-inline pre{white-space:normal}.crayon-syntax-inline-nowrap .crayon-pre,.crayon-syntax-inline-nowrap pre{white-space:pre}.crayon-syntax{font-family:Monaco,'MonacoRegular','Courier New',monospace;font-weight:500}.crayon-syntax .crayon-toolbar *::selection,.crayon-syntax .crayon-nums *::selection{background:transparent}.crayon-table .crayon-nums-content{white-space:nowrap}.crayon-syntax .crayon-num,.crayon-syntax .crayon-pre .crayon-line,.crayon-syntax .crayon-toolbar *,.crayon-syntax .crayon-pre *{font-family:inherit;font-size:inherit!important;line-height:inherit!important;font-weight:inherit!important;height:inherit}.crayon-syntax .crayon-toolbar .crayon-button .crayon-button-icon{background-image:url('../images/toolbar/buttons.png');height:16px!important;width:100%;position:absolute;left:0;top:50%;margin-top:-8px}.crayon-syntax .crayon-toolbar .crayon-tools{position:absolute;right:0}.crayon-syntax.crayon-expanded{position:absolute!important;margin:0!important}.crayon-syntax.crayon-expanded .crayon-main{overflow:hidden!important}.crayon-placeholder{width:100%!important}.crayon-toolbar-visible .crayon-toolbar{position:relative!important;margin-top:0!important;display:block!important}.crayon-syntax.crayon-expanded .crayon-toolbar .crayon-tools{position:relative;right:auto;float:left!important}.crayon-syntax .crayon-plain-wrap{height:auto!important;padding:0!important;margin:0!important}.crayon-syntax .crayon-plain{width:100%;height:100%;position:absolute;opacity:0;padding:0 5px;margin:0;border:0;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-shadow:none;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;white-space:pre;word-wrap:normal;overflow:auto;resize:none;color:#000;background:#FFF}.crayon-wrapped .crayon-plain{white-space:pre-wrap}.bbp-body .crayon-syntax{clear:none!important}.crayon-minimized .crayon-toolbar{cursor:pointer}.crayon-minimized .crayon-plain-wrap,.crayon-minimized .crayon-main,.crayon-minimized .crayon-toolbar .crayon-tools *{display:none!important}.crayon-minimized .crayon-toolbar .crayon-tools .crayon-minimize{display:block!important}.crayon-minimized .crayon-toolbar{position:relative!important}.crayon-syntax.crayon-minimized .crayon-toolbar{border-bottom:none!important}.crayon-te *,#crayon-te-bar-content{font-family:"Lucida Grande",Arial,sans-serif!important;font-size:12px}.crayon-te input[type="text"],.crayon-te textarea{background:#f9f9f9;border:1px solid #CCC;box-shadow:inset 1px 1px 1px rgba(0,0,0,0.1);-moz-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.1);-webkit-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.1);padding:2px 4px;-webkit-border-radius:3px;border-radius:3px;border-width:1px;border-style:solid}.crayon-te #crayon-code{font-family:monospace!important}#crayon-te-content,#crayon-te-table{width:100%;height:auto!important}#crayon-range,#crayon-mark{width:100px}#crayon-te-table th,#crayon-te-table td{vertical-align:top;text-align:left}.rtl #crayon-te-table th,.rtl #crayon-te-table td{text-align:right}#crayon-te-table .crayon-tr-center td,#crayon-te-table .crayon-tr-center th{vertical-align:middle}#crayon-te-table .crayon-nowrap{white-space:nowrap}#crayon-te-bar{position:absolute;top:0;left:0;width:100%}#crayon-te-bar-content{border:1px solid #666;border-bottom:0;height:26px;line-height:25px;padding:0 8px;padding-right:0;background-color:#222;color:#cfcfcf}#crayon-te-bar-content a{line-height:25px;padding:5px 10px;color:#DDD;font-weight:bold;text-decoration:none!important}#crayon-te-bar-content a:hover{color:#FFF}.crayon-te-seperator{color:#666;margin:0;padding:0}#crayon-te-bar-block{height:34px;width:100%}#crayon-te-title{float:left}#crayon-te-controls{float:right}#crayon-url-th{vertical-align:top!important;padding-top:5px}.crayon-te-heading{font-size:14px;font-weight:bold}#crayon-te-settings-info{text-align:center}.crayon-te-section{font-weight:bold;padding:0 10px}#crayon-te-sub-section{margin-left:10px}#crayon-te-sub-section .crayon-te-section{font-weight:normal;padding:0}#crayon-code{height:200px;white-space:pre}#crayon-code,#crayon-url{width:555px!important}.crayon-disabled{background:#EEE!important}.qt_crayon_highlight{background-image:-ms-linear-gradient(bottom,#daf2ff,white)!important;background-image:-moz-linear-gradient(bottom,#daf2ff,white)!important;background-image:-o-linear-gradient(bottom,#daf2ff,white)!important;background-image:-webkit-linear-gradient(bottom,#daf2ff,white)!important;background-image:linear-gradient(bottom,#daf2ff,white)!important}.qt_crayon_highlight:hover{background:#ddebf2!important}.crayon-tag-editor-button-wrapper{display:inline-block}.mce_crayon_tinymce{padding:0!important;margin:2px 3px!important}.mce-i-crayon_tinymce,.mce_crayon_tinymce{background:url(../images/crayon_tinymce.png) 0 0!important}a.mce_crayon_tinymce{background-position:2px 0!important}.wp_themeSkin .mceButtonEnabled:hover span.mce_crayon_tinymce,.wp_themeSkin .mceButtonActive span.mce_crayon_tinymce{background-position:-20px 0}.wp_themeSkin span.mce_crayon_tinymce{background:none!important}#crayon-te-table{margin-top:26px;padding:10px;border-collapse:separate!important;border-spacing:2px!important}#crayon-te-table th{width:100px}#crayon-te-clear{margin-left:10px;color:#666;background-color:#f4f4f4;border:1px solid #CCC;border-radius:3px;margin-left:8px}#crayon-title{width:360px}#TB_window.crayon-te-ajax{overflow:auto!important}#TB_window.crayon-te-ajax,#TB_window.crayon-te-ajax #TB_ajaxContent,#TB_window.crayon-te-ajax #TB_title{width:680px!important}#TB_window.crayon-te-ajax #TB_ajaxContent{padding:0!important;margin:0!important;width:100%!important;height:auto!important;margin-top:28px!important}#TB_window.crayon-te-ajax #TB_title{position:fixed!important}#TB_window.crayon-te-ajax #TB_title .crayon-te-submit{margin-top:3px!important;float:right!important}#TB_window.crayon-te-ajax a{color:#2587e2;text-decoration:none}#TB_window.crayon-te-ajax a:hover{color:#499ce9}.crayon-te-quote{background:#DDD;padding:0 2px}#crayon-te-submit-wrapper{display:none}#crayon-te-clear{display:none;margin:0;margin-top:10px}.crayon-syntax-pre{background:red;white-space:pre;overflow:auto;display:block;word-wrap:break-word}.crayon-question{padding:1px 4px!important;text-decoration:none!important;color:#83b3cb!important;border-radius:10px!important;height:15px!important;width:15px!important}.crayon-question:hover{background:#83b3cb!important;color:white!important;height:15px!important;width:15px!important}.crayon-setting-changed,.crayon-setting-selected{background:#fffaad!important}.crayon-question:hover{color:white;background:#a6d6ef}#crayon-te-warning{display:none}.crayon-te-info{padding:5px!important;margin:2px 0!important}#crayon-te-submit{margin-bottom:5px}
/*
Name: Github
Description: Github like color.
Version: 1.0
Author: Dai Akatsuka
URL: http://firn.jp/
*/
.crayon-theme-github {
margin-bottom: 25px !important;
border: 1px solid #dedede !important;
background-color: #f8f8ff !important;
font-size: 100% !important;
line-height: 130% !important;
}

.crayon-theme-github .crayon-toolbar {
border-bottom: 1px solid #dedede !important;
background-color: #eee !important;
}

.crayon-theme-github .crayon-toolbar .crayon-language,
.crayon-theme-github .crayon-toolbar .crayon-title {
font-size: 80% !important;
color: #666 !important;
}

.crayon-theme-github .crayon-table .crayon-nums {
background-color: #eee !important;
}

.crayon-theme-github .crayon-table .crayon-nums-content {
padding-top: 5px !important;
padding-bottom: 3px !important;
}

.crayon-theme-github .crayon-table .crayon-num {
min-width: 1.2em !important;
border-right: 1px solid #dedede !important;
text-align: right !important;
color: #aaa !important;
}

.crayon-theme-github .crayon-pre {
padding-top: 5px !important;
padding-bottom: 3px !important;
}

.crayon-theme-github .crayon-marked-line {
background: #fffee2 !important;

}
.crayon-theme-github .crayon-marked-num {
color: #1561ac !important;
background: #b3d3f4 !important;
border-width: 1px !important;
border-color: #5999d9 !important;
}

.crayon-theme-github .crayon-pre .crayon-c {
color: #999 !important;
font-style: italic !important;
}
.crayon-theme-github .crayon-pre .crayon-s {
color: #d14 !important;
}
.crayon-theme-github .crayon-pre .crayon-p {
color: #b85c00 !important;
}
.crayon-theme-github .crayon-pre .crayon-ta {
color: #FF0000 !important;
}
.crayon-theme-github .crayon-pre .crayon-k {
color: teal !important;
}
.crayon-theme-github .crayon-pre .crayon-st {
color: #000 !important;
font-weight: bold !important;
}
.crayon-theme-github .crayon-pre .crayon-r {
color: #000 !important;
font-weight: bold !important;
}
.crayon-theme-github .crayon-pre .crayon-t {
color: #800080 !important;
font-weight: bold !important;
}
.crayon-theme-github .crayon-pre .crayon-m {
color: #800080 !important;
}
.crayon-theme-github .crayon-pre .crayon-i {
color: #000 !important;
}
.crayon-theme-github .crayon-pre .crayon-e {
color: teal !important;
}
.crayon-theme-github .crayon-pre .crayon-v {
color: #002D7A !important;
}
.crayon-theme-github .crayon-pre .crayon-cn {
color: #099 !important;
}
.crayon-theme-github .crayon-pre .crayon-o {
color: #006fe0 !important;
}
.crayon-theme-github .crayon-pre .crayon-sy {
color: #333 !important;
}
.crayon-theme-github .crayon-pre .crayon-n {
color: #666 !important;
font-style: italic;
}
.crayon-theme-github .crayon-pre .crayon-f {
color: #999 !important;
}
.crayon-theme-github .crayon-pre .crayon-h {
color: #006fe0 !important;
}
.crayon-syntax .crayon-pre, .crayon-syntax pre{
white-space: initial;
}
-->

在上一篇《webpack从入门到上线》介绍了wepack的配置和相关的概念,这一篇介绍怎样写一个webpack loader. 通过写一个js的html模板为例子。

上篇文章已提及,loader加载器就是对各种非正常资源的解析,转化成浏览器可以识别的js/css文件等,甚至可以说loader就是一个小型的编译器。例如sass loader:将sass格式编译成css,在安装sass的过程中你会发现,其实sass用的是C++,sass本身是面向对象的。但是本文不会介绍怎样写一个编译器(我也不知道),只是简单介绍下怎样写一个loader,抛砖引玉。

有什么样的场景需要写一个loader呢?

有一个就是在js里面写html的模板,会有点不太方便,一个是语法不是高亮的,第二个是需要双引号把每一行包起来,或者用数组push之类的,所以如果能够require一个html文件,然后转化成相应的js字符串,那就比较方便了。(如果你用react开发的,用jsx是比较自然的事情)。我在网上找了下,没有找到能够比较符合上面两点需求的loader,所以就自己尝试写一个吧。

js模板通常有三种场景:

  1. 纯html,一个文件就是一个模板,直接转成字符串即可;
  2. 需要有变量,一个文件有几个模板,每个模板对应一个变量
  3. 再复杂一点,模板是require了其它的工厂模块生成的字符串

现在开始来写loader

loader的基本框架

首先在工程的node_modules下面新建一个文件夹html-template-loader,在里面创建一个index.js做为这个loader的js文件。这样就可以在webpack.config.js里面添加一个loader了:

添加loader配置

 
 
 
 
 

JavaScript

 
{
test:/\.tpl\.html$/,
loader: 'html-template-loader'
}
1
2
3
4
{
     test:/\.tpl\.html$/,
     loader:'html-template-loader'
}

以.tpl.html作为后缀名,也就是说在逻辑代码里面引入一个.tpl.html结尾的文件,就归这个loader处理

require tpl html

 
 
 
 
 

JavaScript

 
var tpl = require("./dialog.tpl.html");
1
vartpl=require("./dialog.tpl.html");

重点就在于,这个loader怎么写呢?

loader也需要写成一个模块,一个基本的loader的写法:

html-template-loader/index.js

 
 
 
 
 

JavaScript

 
/**
* source为原文件的字符串格式
*/
module.exports = function(source, map){
//对source进行解析
var exports = process(source);
return "module.exports = " + exports;
}
1
2
3
4
5
6
7
8
/**
* source为原文件的字符串格式
*/
module.exports=function(source,map){
    //对source进行解析
    varexports=process(source);
    return"module.exports = "+exports;
}

是的,你没看错,一个loader就是这么简单。关键在于理解loader的机制——其实loader最后会创建一个模块,当我们require一个需要让loader的解析的文件之后,通过上面第7行的return——return里面的内容就是自动创建的模块的内容,跟平时自已写的模块的区别就在于这个要自己拼成一个js语法合法的字符串。

如上面生成的exports为:

 
 
 
 
 

JavaScript

 
var exports = "var tpl = {email: '<div>1</div>', hello: '<p>2</p>'}";
return "var tpl = " + tpl + ";\n module.exports = tpl;";
1
2
var exports="var tpl = {email: '<div>1</div>', hello: '<p>2</p>'}";
return"var tpl = "+tpl+";\n module.exports = tpl;";

那么webpack自动创建这样一个模块:

webpack自动创建的模块

 
 
 
 
 

JavaScript

 
/***/ 109:
/***/ function(module, exports) {
var tpl = {email: '<div>1</div>', hello: '<p>2</p>'};
module.exports = tpl;
/***/ }
1
2
3
4
5
/***/109:
/***/function(module,exports){
var tpl={email:'<div>1</div>',hello:'<p>2</p>'};
module.exports=tpl;
/***/}

在我这个工程,这个模块的id为109,然后require的返回结果就是这个tpl的object。

另外一方面,初始化的时候可以拿到source,这个source就是webpack以utf-8读的整个文件的内容,以字符串的形式作为一个参数传进来。

所以现在目标就很明确了,我们需要处理这个source的字符串,然后再返回一个可以eval的字符串。需要定义loader的输入和输出的格式,这是作为loader开发者的权利,同时中间的处理过程对用户屏蔽。

loader的具体实现

把source这整一个文件,拆成一行一行处理:

把source拆成一行一行

 
 
 
 
 

JavaScript

 
var tpl = "";
source.split(/\r?\n/).forEach(function(line){
line = line.trim();
if(!line.length){
return;
}
//对line进行处理...
tpl += process(line);
}
return "module.exports = ...";
1
2
3
4
5
6
7
8
9
10
    var tpl="";
    source.split(/\r?\n/).forEach(function(line){
        line=line.trim();
        if(!line.length){
            return;
        }
        //对line进行处理...
        tpl+=process(line);
    }
    return "module.exports = ...";

难点就在于第8行的process函数怎么写,怎样拼成一个合法的tpl字符串。

如果是上面提到的第一种场景,则很简单,直接加就好了;

如果是第二种场景需要用变量区分的,那么需要自定义一个语法,由于我们用的是html,因为有高亮的功能。所以可考虑用html的注释的标签:

用<!--%变量名%-->的格式定义变量名

 
 
<!--%email%-->
<div>
<p>hello, world</p>
</div>

<!--%alert%-->
<p>hi</p>
<span>man</span>

1
2
3
4
5
6
7
8
<!--%email%-->
<div>
    <p>hello,world</p>
</div>
 
<!--%alert%-->
<p>hi</p>
<span>man</span>

我们的语法就是<!–%变量名%–>,像上面定义了两个变量email和alert,接下来在process函数里面就可以进行识别、拼一个object的字符串。

如果是第三种场景需要引入第三方模块的,则需要在最后一行return的时候加上require这个函数的代码,即:

 
 
 
 
 

JavaScript

 
return "var widget = require(../widgetFactory");\n" +
"module.exports = widget.make()";
1
2
return "var widget = require(../widgetFactory");\n" +
       "module.exports=widget.make()";

同样地,需要定义一个语法,require的代码用script的方式:

需要依赖的代码格式

 
 
 
 
 

JavaScript

 
<script generate>var SELECT = require("js/select");</script>
1
<script generate>varSELECT=require("js/select");</script>

以一个generate的属性标志,这块是需要依赖的代码,也就是说要把它拼在前面。

正常的调用就用一个script,不带属性:

 
 
<!--%email%-->
<div>
<p>hello, world</p>
</div>
<script>
widget.make()
</script>
1
2
3
4
5
6
7
<!--%email%-->
<div>
    <p>hello,world</p>
</div>
<script>
    widget.make()
</script>

最后把它转成一个object.

经过合适的处理之后,最后生成的模块是这样的:

 
 
 
 
 

JavaScript

 
/***/ 110:
/***/ function(module, exports, __webpack_require__) {

var widget = __webpack_require__(111);
var tpl = {
email:'<div>'+
'<p>\'tpl\'</p>'+
'<p>hello, world</p>'+
'</div>'+
widget.make() +
'<p>good</p>'+
'',
alert:'<p>hi</p>'+
'<span>man</span>'+
''
}
module.exports = tpl

/***/ },

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/***/110:
/***/function(module,exports,__webpack_require__){
 
var widget=__webpack_require__(111);
var tpl={
    email:'<div>'+
        '<p>\'tpl\'</p>'+
        '<p>hello, world</p>'+
        '</div>'+
        widget.make()+
        '<p>good</p>'+
        '',
    alert:'<p>hi</p>'+
        '<span>man</span>'+
        ''
         }
module.exports=tpl
 
/***/},

具体处理代码略,详见github

loader的高阶话题

1.  loader支持链式,上一个loader的处理结果可以给下一个loader,像sass的loader是这样写的:

sass loader

 
 
 
 
 

JavaScript

 
require("!style!css!sass!./file.scss");
1
require("!style!css!sass!./file.scss");

或者是写在配置文件里面:

webpack.config.js

 
 
 
 
 

JavaScript

 
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
1
2
3
4
{
        test:/\.scss$/,
        loaders:["style","css","sass"]
}

sass处理完之后给css的loader,css的loader处理完后给style的loader,loader间的数据传递通过loader的定义的callback函数,例如上面的loader可以在return之前再加一行:

 
 
 
 
 

JavaScript

 
this.callback(null, source, map);
1
this.callback(null,source,map);

这样就可以传给下一个loader,最后一个loader一定要有return的内容;

2. loader可以缓存,可以加快速度

 
 
 
 
 

JavaScript

 
this.cacheable();
1
this.cacheable();

3. 其它:loader支持异步,loader的加载可以用异步的方式,loader可以传参数等等,详见官方文档:HOW TO WRITE A LOADER,官方文档比较绕,不是从0开始,也没有给一个完整的demo,具体可以再另外查查。

写loader关键在于怎么编译这个文件,上面是用的把它拆成一行一行的方式,然后做了个简单的处理,一般编译是要用到语法树。

我的个人博客:http://yincheng.site/webpack-loader

怎样写一个webpack loader的更多相关文章

  1. 案例实战之如何写一个webpack loader

    通过以下几个实例掌握webpack loader的写法 1.写一个多语言替换的loader 在index.js在页面上插入了一个{{title}}文本,我们需要在打包的时候将其替换成对应的多语言 fu ...

  2. 案例实战之如何写一个webpack plugin

    案例实战之如何写一个webpack plugin 1.写一个生成打包文件目录的file.md文件 // 生成一个目录项目目录的文件夹 class FileListPlugin { constructo ...

  3. 手把手教你撸一个 Webpack Loader

    文:小 boy(沪江网校Web前端工程师) 本文原创,转载请注明作者及出处 经常逛 webpack 官网的同学应该会很眼熟上面的图.正如它宣传的一样,webpack 能把左侧各种类型的文件(webpa ...

  4. 手写一个webpack,看看AST怎么用

    本文开始我会围绕webpack和babel写一系列的工程化文章,这两个工具我虽然天天用,但是对他们的原理理解的其实不是很深入,写这些文章的过程其实也是我深入学习的过程.由于webpack和babel的 ...

  5. 80行代码教你写一个Webpack插件并发布到npm

    1. 前言 最近在学习 Webpack 相关的原理,以前只知道 Webpack 的配置方法,但并不知道其内部流程,经过一轮的学习,感觉获益良多,为了巩固学习的内容,我决定尝试自己动手写一个插件. 这个 ...

  6. 发布一个npm包(webpack loader)

    发布一个npm包,webpack loader: reverse-color-loader,实现颜色反转. 初始化项目 mkdir reverse-color-loader cd ./reverse- ...

  7. 如何开发webpack loader

    关于webpack 作为近段时间风头正盛的打包工具,webpack基本占领了前端圈.相信你都不好意思说不知道webpack. 有兴趣的同学可以参考下我很早之前的webpack简介 . 确实webpac ...

  8. 写一个为await自动加上catch的loader逐渐了解AST以及babel

    为什么要写这个loader 我们在日常开发中经常用到async await去请求接口,解决异步.可async await语法的缺点就是若await后的Promise抛出错误不能捕获,整段代码区就会卡住 ...

  9. Java基础-继承-编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight。小车类Car是Vehicle的子类,其中包含的属性有载人数 loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。每个 类都有构造方法和输出相关数据的方法。最后,写一个测试类来测试这些类的功 能。

    #29.编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight.小车类Car是Vehicle的子类,其中包含的属性有载人数 loader.卡车类T ...

随机推荐

  1. [C#] 了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数

    了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数 目录 简介 特点 方法的参数 方法的返回值 与批处理交互的一个示例 简介 我们知道,新建一个控制台应用程序的时候,IDE 会同时创建 ...

  2. [转]Patch文件结构详解

    N久不来 于是不知道扔在哪儿于是放这里先 如果你觉得碍事的话 帮我扔到合适的版块去.. 导读这是一篇说明文 它介绍了标准冒险岛更新文件(*.patch;*.exe)的格式文章的最后附了一段C#的参考代 ...

  3. java中易错点(一)

    由于replaceAll方法的第一个参数是一个正则表达式,而"."在正则表达式中表示任何字符,所以会把前面字符串的所有字符都替换成"/".如果想替换的只是&qu ...

  4. NGINX引入线程池 性能提升9倍

    1. 引言 正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为 ...

  5. cesium核心类Viewer简介

    1.简单描述Viewer Viewer类是cesium的核心类,是地图可视化展示的主窗口,cesium程序应用的切入口,扮演必不可少的核心角色. 官网的英文解析如下: A base widget fo ...

  6. Atitit.研发管理如何避免公司破产倒闭的业务魔咒

    Atitit.如何避免公司破产倒闭的业务魔咒 1. 大型公司的衰落或者倒闭破产案例1 1.1. 摩托罗拉1 1.2. 诺基亚2 1.3. sun2 2. 为什么他们会倒闭?? 常见的一些倒闭元素2 2 ...

  7. [转]thinkphp 模板显示display和assign的用法

    thinkphp 模板显示display和assign的用法 $this->assign('name',$value); //在 Action 类里面使用 assign 方法对模板变量赋值,无论 ...

  8. Linux 系统中发博客必备的五大图片处理神器

    发博客时,总免不了要用图片说话.经过长时间的磨合,在 Linux 桌面系统下有几款图片处理软件我已经用得比较顺手了.这几款软件在 Linux 世界使用广泛,各个 Linux 发行版的软件仓库中都有自带 ...

  9. 在同一个硬盘上安装多个 Linux 发行版及 Fedora 21 、Fedora 22 初体验

    在同一个硬盘上安装多个 Linux 发行版 以前对多个 Linux 发行版的折腾主要是在虚拟机上完成.我的桌面电脑性能比较强大,玩玩虚拟机没啥问题,但是笔记本电脑就不行了.要在我的笔记本电脑上折腾多个 ...

  10. WCF : 如何将NetTcpBinding寄宿在IIS7上

    摘要 : 从IIS 7 开始, IIS增加了对非HTTP协议的支持. 因此, 自IIS 7之后, 可以将NetTcpBinding等非HTTP协议的Bindings直接寄宿在IIS上面. 本文将介绍如 ...