loader.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. var loaderUtils = require("loader-utils");
  6. var processCss = require("./processCss");
  7. var getImportPrefix = require("./getImportPrefix");
  8. var compileExports = require("./compile-exports");
  9. module.exports = function(content, map) {
  10. var callback = this.async();
  11. var query = loaderUtils.getOptions(this) || {};
  12. var moduleMode = query.modules;
  13. var camelCaseKeys = query.camelCase;
  14. var sourceMap = query.sourceMap || false;
  15. if(sourceMap) {
  16. if (map) {
  17. if (typeof map === "string") {
  18. map = JSON.stringify(map);
  19. }
  20. if (map.sources) {
  21. map.sources = map.sources.map(function (source) {
  22. return source.replace(/\\/g, '/');
  23. });
  24. map.sourceRoot = '';
  25. }
  26. }
  27. } else {
  28. // Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
  29. map = null;
  30. }
  31. processCss(content, map, {
  32. mode: moduleMode ? "local" : "global",
  33. from: loaderUtils.getRemainingRequest(this).split("!").pop(),
  34. to: loaderUtils.getCurrentRequest(this).split("!").pop(),
  35. query: query,
  36. loaderContext: this,
  37. sourceMap: sourceMap
  38. }, function(err, result) {
  39. if(err) return callback(err);
  40. var cssAsString = JSON.stringify(result.source);
  41. // for importing CSS
  42. var importUrlPrefix = getImportPrefix(this, query);
  43. var alreadyImported = {};
  44. var importJs = result.importItems.map(function(imp) {
  45. // fixes #781 when importing `url(filename.css )`
  46. imp.url = imp.url.trim();
  47. return imp;
  48. }).filter(function(imp) {
  49. if(!imp.mediaQuery) {
  50. if(alreadyImported[imp.url])
  51. return false;
  52. alreadyImported[imp.url] = true;
  53. }
  54. return true;
  55. }).map(function(imp) {
  56. if(!loaderUtils.isUrlRequest(imp.url)) {
  57. return "exports.push([module.id, " +
  58. JSON.stringify("@import url(" + imp.url + ");") + ", " +
  59. JSON.stringify(imp.mediaQuery) + "]);";
  60. } else {
  61. var importUrl = importUrlPrefix + imp.url;
  62. return "exports.i(require(" + loaderUtils.stringifyRequest(this, importUrl) + "), " + JSON.stringify(imp.mediaQuery) + ");";
  63. }
  64. }, this).join("\n");
  65. function importItemMatcher(item) {
  66. var match = result.importItemRegExp.exec(item);
  67. var idx = +match[1];
  68. var importItem = result.importItems[idx];
  69. var importUrl = importUrlPrefix + importItem.url;
  70. return "\" + require(" + loaderUtils.stringifyRequest(this, importUrl) + ").locals" +
  71. "[" + JSON.stringify(importItem.export) + "] + \"";
  72. }
  73. cssAsString = cssAsString.replace(result.importItemRegExpG, importItemMatcher.bind(this));
  74. // helper for ensuring valid CSS strings from requires
  75. var urlEscapeHelper = "";
  76. if(query.url !== false && result.urlItems.length > 0) {
  77. urlEscapeHelper = "var escape = require(" + loaderUtils.stringifyRequest(this, require.resolve("./url/escape.js")) + ");\n";
  78. cssAsString = cssAsString.replace(result.urlItemRegExpG, function(item) {
  79. var match = result.urlItemRegExp.exec(item);
  80. var idx = +match[1];
  81. var urlItem = result.urlItems[idx];
  82. var url = urlItem.url;
  83. idx = url.indexOf("?#");
  84. if(idx < 0) idx = url.indexOf("#");
  85. var urlRequest;
  86. if(idx > 0) { // idx === 0 is catched by isUrlRequest
  87. // in cases like url('webfont.eot?#iefix')
  88. urlRequest = url.substr(0, idx);
  89. return "\" + escape(require(" + loaderUtils.stringifyRequest(this, urlRequest) + ")) + \"" +
  90. url.substr(idx);
  91. }
  92. urlRequest = url;
  93. return "\" + escape(require(" + loaderUtils.stringifyRequest(this, urlRequest) + ")) + \"";
  94. }.bind(this));
  95. }
  96. var exportJs = compileExports(result, importItemMatcher.bind(this), camelCaseKeys);
  97. if (exportJs) {
  98. exportJs = "exports.locals = " + exportJs + ";";
  99. }
  100. var moduleJs;
  101. if(sourceMap && result.map) {
  102. // add a SourceMap
  103. map = result.map;
  104. if(map.sources) {
  105. map.sources = map.sources.map(function(source) {
  106. return source.split("!").pop().replace(/\\/g, '/');
  107. }, this);
  108. map.sourceRoot = "";
  109. }
  110. map.file = map.file.split("!").pop().replace(/\\/g, '/');
  111. map = JSON.stringify(map);
  112. moduleJs = "exports.push([module.id, " + cssAsString + ", \"\", " + map + "]);";
  113. } else {
  114. moduleJs = "exports.push([module.id, " + cssAsString + ", \"\"]);";
  115. }
  116. // embed runtime
  117. callback(null, urlEscapeHelper +
  118. "exports = module.exports = require(" +
  119. loaderUtils.stringifyRequest(this, require.resolve("./css-base.js")) +
  120. ")(" + sourceMap + ");\n" +
  121. "// imports\n" +
  122. importJs + "\n\n" +
  123. "// module\n" +
  124. moduleJs + "\n\n" +
  125. "// exports\n" +
  126. exportJs);
  127. }.bind(this));
  128. };