You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.3 KiB

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