| /* |
| MIT License http://www.opensource.org/licenses/mit-license.php |
| Author Tobias Koppers @sokra |
| */ |
| var htmlMinifier = require("html-minifier"); |
| var attrParse = require("./lib/attributesParser"); |
| var loaderUtils = require("loader-utils"); |
| var url = require("url"); |
| var assign = require("object-assign"); |
| var compile = require("es6-templates").compile; |
| |
| function randomIdent() { |
| return "xxxHTMLLINKxxx" + Math.random() + Math.random() + "xxx"; |
| } |
| |
| function getLoaderConfig(context) { |
| var query = loaderUtils.getOptions(context) || {}; |
| var configKey = query.config || 'htmlLoader'; |
| var config = context.options && context.options.hasOwnProperty(configKey) ? context.options[configKey] : {}; |
| |
| delete query.config; |
| |
| return assign(query, config); |
| } |
| |
| module.exports = function(content) { |
| this.cacheable && this.cacheable(); |
| var config = getLoaderConfig(this); |
| var attributes = ["img:src"]; |
| if(config.attrs !== undefined) { |
| if(typeof config.attrs === "string") |
| attributes = config.attrs.split(" "); |
| else if(Array.isArray(config.attrs)) |
| attributes = config.attrs; |
| else if(config.attrs === false) |
| attributes = []; |
| else |
| throw new Error("Invalid value to config parameter attrs"); |
| } |
| var root = config.root; |
| var links = attrParse(content, function(tag, attr) { |
| var res = attributes.find(function(a) { |
| if (a.charAt(0) === ':') { |
| return attr === a.slice(1); |
| } else { |
| return (tag + ":" + attr) === a; |
| } |
| }); |
| return !!res; |
| }); |
| links.reverse(); |
| var data = {}; |
| content = [content]; |
| links.forEach(function(link) { |
| if(!loaderUtils.isUrlRequest(link.value, root)) return; |
| |
| if (link.value.indexOf('mailto:') > -1 ) return; |
| |
| var uri = url.parse(link.value); |
| if (uri.hash !== null && uri.hash !== undefined) { |
| uri.hash = null; |
| link.value = uri.format(); |
| link.length = link.value.length; |
| } |
| |
| do { |
| var ident = randomIdent(); |
| } while(data[ident]); |
| data[ident] = link.value; |
| var x = content.pop(); |
| content.push(x.substr(link.start + link.length)); |
| content.push(ident); |
| content.push(x.substr(0, link.start)); |
| }); |
| content.reverse(); |
| content = content.join(""); |
| |
| if (config.interpolate === 'require'){ |
| |
| var reg = /\$\{require\([^)]*\)\}/g; |
| var result; |
| var reqList = []; |
| while(result = reg.exec(content)){ |
| reqList.push({ |
| length : result[0].length, |
| start : result.index, |
| value : result[0] |
| }) |
| } |
| reqList.reverse(); |
| content = [content]; |
| reqList.forEach(function(link) { |
| var x = content.pop(); |
| do { |
| var ident = randomIdent(); |
| } while(data[ident]); |
| data[ident] = link.value.substring(11,link.length - 3) |
| content.push(x.substr(link.start + link.length)); |
| content.push(ident); |
| content.push(x.substr(0, link.start)); |
| }); |
| content.reverse(); |
| content = content.join(""); |
| } |
| |
| if(typeof config.minimize === "boolean" ? config.minimize : this.minimize) { |
| var minimizeOptions = assign({}, config); |
| |
| [ |
| "removeComments", |
| "removeCommentsFromCDATA", |
| "removeCDATASectionsFromCDATA", |
| "collapseWhitespace", |
| "conservativeCollapse", |
| "removeAttributeQuotes", |
| "useShortDoctype", |
| "keepClosingSlash", |
| "minifyJS", |
| "minifyCSS", |
| "removeScriptTypeAttributes", |
| "removeStyleTypeAttributes", |
| ].forEach(function(name) { |
| if(typeof minimizeOptions[name] === "undefined") { |
| minimizeOptions[name] = true; |
| } |
| }); |
| |
| content = htmlMinifier.minify(content, minimizeOptions); |
| } |
| |
| 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); |
| } |
| |
| 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) + ') + "'; |
| }) + ";"; |
| |
| } |