从ejs-loader和html-loader出发,做一个自己的loader

前几天,没事做的时候,我想用ejs语法去写模板,可是刚配置完成,就开始报错,说是图片资源找不到,上网查阅相关资料,我知道了有html-loader这个东西可以编译模板中导入的图片资源为base64,在打包的时候根据限制的图片大小,大的图片转换为图片,小的依然保留base64,但是它的缺点就是不能注入参数,成为模板,比如


	
		
		
	
	
		<%=require("@tpl/container.tpl")({rightbox:require('./index.tpl')()})%>
	

在这个模板中我想获取container.tpl,并向其注入rightbox变量,此变量是index.tpl的模板,container模板内容如下

<%= require('./header.tpl')() %>
<%= require('./leftnav.tpl')() %>
<%= rightbox %>
<%= require('./footer.tpl')() %>

然后container中获取header,左侧导航栏,footer的模板文件,rightbox存放模板字符串的变量注入其中,让其拼接成完整页面,html-loader是没有此功能的,于是我想起自己做一个loader,把html-loader和ejs-loader相互结合,制作成自己想要的既能转码base64,又能向其中注入变量。

可能有人说了,webpack中loader可以有依赖表达式,可以在中间加个感叹号表示依赖。

这种方法放在style样式文件是可以的,放在js,或ts是可以的,唯独放在模板文件是不可以的。

为什么呢,我们先简单的看一下html-loader和ejs-loader输出接口的源码:

html-loader

    var exportsString = "module.exports = ";
	if (config.exportAsDefault) {
        exportsString = "exports.default = ";

	} else if (config.exportAsEs6Default) {
        exportsString = "export default ";
	}

 	return exportsString + content.replace(/xxxHTMLLINKxxx[0-9\.]+xxx/g, function(match) {
		if(!data[match]) return match;
var urlToRequest;if (config.interpolate === 'require') {urlToRequest = data[match];} else {urlToRequest = loaderUtils.urlToRequest(data[match], root);}return '" + require(' + JSON.stringify(urlToRequest) + ') + "';}) + ";";
		
var lodash=require("lodash");

ejs-loader

var template = _.template(source, _.extend({}, query, options));
  return 'module.exports = ' + template;

由此可见,这些loader返回给你的都是一个以module.exports=为开头的字符串,html-loader中module.exports等于的是一个真正的html片段,而ejs-loader则是写了一个函数function(x){var str='a'+x+'b';return str;},你写的那些特殊字符全部被转换成字符串中加变量拼接的方式了,require进来的是一个函数,因此还要再给他执行以下,当然也可向其注入变量获取不同的字符串,

html-loader在编译这些字符串已经将字符串编译成没有空格和换行的形式了,如果同时加载了两次loader,那么第二次加载的loader拿到的字符串便是第一次以module.exports开头的已经编译过的字符串,那么结果只会报错。

于是乎,我做了一个自己的jcy-loader,说是自己做的,其实也就是改写了一下html-loader,说到这里,可能有人会说了,你这是抄袭,盗版,但我要说的是,虽然这个loader是基于html-loader改写的,但是他却又html-loader没有的功能,如果能够站在巨人的肩膀上,为什么还要自己去堆一座山呢。我们程序员的工作不是日复一日的创作,因为你的创作很可能是别人已经做过的,我们应该多思考,模仿它并超越它。

首先引用了ejs-loader加载的lodash插件

var lodash=require("lodash");

然后注释掉这段代码,这样就不会对输入进来的字符串进行编译了。然后就可以放进下一个loader进行编译。                            

//	if(config.interpolate && config.interpolate !== 'require') {
//		// Double escape quotes so that they are not unescaped completely in the template string
//		content = content.replace(/\\"/g, "\\\\\"");
//		content = content.replace(/\\'/g, "\\\\\'");
//		content = compile('`' + content + '`').code;
//	} else {
//		content = JSON.stringify(content);
//	}

在html-loader中替换图片资源为为+require()+的字符转的地方加上这句话,然后return出来

var d=content.replace(/xxxHTMLLINKxxx[0-9\.]+xxx/g, function(match) {
		if(!data[match]) return match;
		
		var urlToRequest;

		if (config.interpolate === 'require') {
			urlToRequest = data[match];
		} else {
			urlToRequest = loaderUtils.urlToRequest(data[match], root);
		}
		return "'+require("+JSON.stringify(urlToRequest)+")+'";
	}) + ";";
	return d;

这样便做成了即拥有html-loader加载图片的功能,有可以拥有ejs-loader模板语法的loader编译器了

源码可以以直接npm install jcy-loader就可以看到了


你可能感兴趣的:(从ejs-loader和html-loader出发,做一个自己的loader)