loader.js 4.6 KB

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