loader.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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.filter(function(imp) {
  45. if(!imp.mediaQuery) {
  46. if(alreadyImported[imp.url])
  47. return false;
  48. alreadyImported[imp.url] = true;
  49. }
  50. return true;
  51. }).map(function(imp) {
  52. if(!loaderUtils.isUrlRequest(imp.url)) {
  53. return "exports.push([module.id, " +
  54. JSON.stringify("@import url(" + imp.url + ");") + ", " +
  55. JSON.stringify(imp.mediaQuery) + "]);";
  56. } else {
  57. var importUrl = importUrlPrefix + imp.url;
  58. return "exports.i(require(" + loaderUtils.stringifyRequest(this, importUrl) + "), " + JSON.stringify(imp.mediaQuery) + ");";
  59. }
  60. }, this).join("\n");
  61. function importItemMatcher(item) {
  62. var match = result.importItemRegExp.exec(item);
  63. var idx = +match[1];
  64. var importItem = result.importItems[idx];
  65. var importUrl = importUrlPrefix + importItem.url;
  66. return "\" + require(" + loaderUtils.stringifyRequest(this, importUrl) + ").locals" +
  67. "[" + JSON.stringify(importItem.export) + "] + \"";
  68. }
  69. cssAsString = cssAsString.replace(result.importItemRegExpG, importItemMatcher.bind(this));
  70. // helper for ensuring valid CSS strings from requires
  71. var urlEscapeHelper = "";
  72. if(query.url !== false && result.urlItems.length > 0) {
  73. urlEscapeHelper = "var escape = require(" + loaderUtils.stringifyRequest(this, require.resolve("./url/escape.js")) + ");\n";
  74. cssAsString = cssAsString.replace(result.urlItemRegExpG, function(item) {
  75. var match = result.urlItemRegExp.exec(item);
  76. var idx = +match[1];
  77. var urlItem = result.urlItems[idx];
  78. var url = urlItem.url;
  79. idx = url.indexOf("?#");
  80. if(idx < 0) idx = url.indexOf("#");
  81. var urlRequest;
  82. if(idx > 0) { // idx === 0 is catched by isUrlRequest
  83. // in cases like url('webfont.eot?#iefix')
  84. urlRequest = url.substr(0, idx);
  85. return "\" + escape(require(" + loaderUtils.stringifyRequest(this, urlRequest) + ")) + \"" +
  86. url.substr(idx);
  87. }
  88. urlRequest = url;
  89. return "\" + escape(require(" + loaderUtils.stringifyRequest(this, urlRequest) + ")) + \"";
  90. }.bind(this));
  91. }
  92. var exportJs = compileExports(result, importItemMatcher.bind(this), camelCaseKeys);
  93. if (exportJs) {
  94. exportJs = "exports.locals = " + exportJs + ";";
  95. }
  96. var moduleJs;
  97. if(sourceMap && result.map) {
  98. // add a SourceMap
  99. map = result.map;
  100. if(map.sources) {
  101. map.sources = map.sources.map(function(source) {
  102. return source.split("!").pop().replace(/\\/g, '/');
  103. }, this);
  104. map.sourceRoot = "";
  105. }
  106. map.file = map.file.split("!").pop().replace(/\\/g, '/');
  107. map = JSON.stringify(map);
  108. moduleJs = "exports.push([module.id, " + cssAsString + ", \"\", " + map + "]);";
  109. } else {
  110. moduleJs = "exports.push([module.id, " + cssAsString + ", \"\"]);";
  111. }
  112. // embed runtime
  113. callback(null, urlEscapeHelper +
  114. "exports = module.exports = require(" +
  115. loaderUtils.stringifyRequest(this, require.resolve("./css-base.js")) +
  116. ")(" + sourceMap + ");\n" +
  117. "// imports\n" +
  118. importJs + "\n\n" +
  119. "// module\n" +
  120. moduleJs + "\n\n" +
  121. "// exports\n" +
  122. exportJs);
  123. }.bind(this));
  124. };