UNPKG

4.36 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5var htmlMinifier = require("html-minifier");
6var attrParse = require("./lib/attributesParser");
7var loaderUtils = require("loader-utils");
8var url = require("url");
9var assign = require("object-assign");
10var compile = require("es6-templates").compile;
11
12function randomIdent() {
13 return "xxxHTMLLINKxxx" + Math.random() + Math.random() + "xxx";
14}
15
16function getLoaderConfig(context) {
17 var query = loaderUtils.getOptions(context) || {};
18 var configKey = query.config || 'htmlLoader';
19 var config = context.options && context.options.hasOwnProperty(configKey) ? context.options[configKey] : {};
20
21 delete query.config;
22
23 return assign(query, config);
24}
25
26module.exports = function(content) {
27 this.cacheable && this.cacheable();
28 var config = getLoaderConfig(this);
29 var attributes = ["img:src"];
30 if(config.attrs !== undefined) {
31 if(typeof config.attrs === "string")
32 attributes = config.attrs.split(" ");
33 else if(Array.isArray(config.attrs))
34 attributes = config.attrs;
35 else if(config.attrs === false)
36 attributes = [];
37 else
38 throw new Error("Invalid value to config parameter attrs");
39 }
40 var root = config.root;
41 var links = attrParse(content, function(tag, attr) {
42 var res = attributes.find(function(a) {
43 if (a.charAt(0) === ':') {
44 return attr === a.slice(1);
45 } else {
46 return (tag + ":" + attr) === a;
47 }
48 });
49 return !!res;
50 });
51 links.reverse();
52 var data = {};
53 content = [content];
54 links.forEach(function(link) {
55 if(!loaderUtils.isUrlRequest(link.value, root)) return;
56
57 if (link.value.indexOf('mailto:') > -1 ) return;
58
59 var uri = url.parse(link.value);
60 if (uri.hash !== null && uri.hash !== undefined) {
61 uri.hash = null;
62 link.value = uri.format();
63 link.length = link.value.length;
64 }
65
66 do {
67 var ident = randomIdent();
68 } while(data[ident]);
69 data[ident] = link.value;
70 var x = content.pop();
71 content.push(x.substr(link.start + link.length));
72 content.push(ident);
73 content.push(x.substr(0, link.start));
74 });
75 content.reverse();
76 content = content.join("");
77
78 if (config.interpolate === 'require'){
79
80 var reg = /\$\{require\([^)]*\)\}/g;
81 var result;
82 var reqList = [];
83 while(result = reg.exec(content)){
84 reqList.push({
85 length : result[0].length,
86 start : result.index,
87 value : result[0]
88 })
89 }
90 reqList.reverse();
91 content = [content];
92 reqList.forEach(function(link) {
93 var x = content.pop();
94 do {
95 var ident = randomIdent();
96 } while(data[ident]);
97 data[ident] = link.value.substring(11,link.length - 3)
98 content.push(x.substr(link.start + link.length));
99 content.push(ident);
100 content.push(x.substr(0, link.start));
101 });
102 content.reverse();
103 content = content.join("");
104 }
105
106 if(typeof config.minimize === "boolean" ? config.minimize : this.minimize) {
107 var minimizeOptions = assign({}, config);
108
109 [
110 "removeComments",
111 "removeCommentsFromCDATA",
112 "removeCDATASectionsFromCDATA",
113 "collapseWhitespace",
114 "conservativeCollapse",
115 "removeAttributeQuotes",
116 "useShortDoctype",
117 "keepClosingSlash",
118 "minifyJS",
119 "minifyCSS",
120 "removeScriptTypeAttributes",
121 "removeStyleTypeAttributes",
122 ].forEach(function(name) {
123 if(typeof minimizeOptions[name] === "undefined") {
124 minimizeOptions[name] = true;
125 }
126 });
127
128 content = htmlMinifier.minify(content, minimizeOptions);
129 }
130
131 if(config.interpolate && config.interpolate !== 'require') {
132 // Double escape quotes so that they are not unescaped completely in the template string
133 content = content.replace(/\\"/g, "\\\\\"");
134 content = content.replace(/\\'/g, "\\\\\'");
135 content = compile('`' + content + '`').code;
136 } else {
137 content = JSON.stringify(content);
138 }
139
140 var exportsString = "module.exports = ";
141 if (config.exportAsDefault) {
142 exportsString = "exports.default = ";
143
144 } else if (config.exportAsEs6Default) {
145 exportsString = "export default ";
146 }
147
148 return exportsString + content.replace(/xxxHTMLLINKxxx[0-9\.]+xxx/g, function(match) {
149 if(!data[match]) return match;
150
151 var urlToRequest;
152
153 if (config.interpolate === 'require') {
154 urlToRequest = data[match];
155 } else {
156 urlToRequest = loaderUtils.urlToRequest(data[match], root);
157 }
158
159 return '" + require(' + JSON.stringify(urlToRequest) + ') + "';
160 }) + ";";
161
162}