index.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = loader;
  6. var _path = _interopRequireDefault(require("path"));
  7. var _semver = require("semver");
  8. var _package = _interopRequireDefault(require("postcss/package.json"));
  9. var _Warning = _interopRequireDefault(require("./Warning"));
  10. var _options = _interopRequireDefault(require("./options.json"));
  11. var _utils = require("./utils");
  12. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  13. let hasExplicitDependencyOnPostCSS = false;
  14. /**
  15. * **PostCSS Loader**
  16. *
  17. * Loads && processes CSS with [PostCSS](https://github.com/postcss/postcss)
  18. *
  19. * @method loader
  20. *
  21. * @param {String} content Source
  22. * @param {Object} sourceMap Source Map
  23. * @param {Object} meta Meta
  24. *
  25. * @return {callback} callback Result
  26. */
  27. async function loader(content, sourceMap, meta) {
  28. const options = this.getOptions(_options.default);
  29. const callback = this.async();
  30. const configOption = typeof options.postcssOptions === "undefined" || typeof options.postcssOptions.config === "undefined" ? true : options.postcssOptions.config;
  31. const postcssFactory = (0, _utils.getPostcssImplementation)(this, options.implementation);
  32. if (!postcssFactory) {
  33. callback(new Error(`The Postcss implementation "${options.implementation}" not found`));
  34. return;
  35. }
  36. let loadedConfig;
  37. if (configOption) {
  38. try {
  39. loadedConfig = await (0, _utils.loadConfig)(this, configOption, options.postcssOptions);
  40. } catch (error) {
  41. callback(error);
  42. return;
  43. }
  44. }
  45. const useSourceMap = typeof options.sourceMap !== "undefined" ? options.sourceMap : this.sourceMap;
  46. const {
  47. plugins,
  48. processOptions
  49. } = await (0, _utils.getPostcssOptions)(this, loadedConfig, options.postcssOptions);
  50. if (useSourceMap) {
  51. processOptions.map = {
  52. inline: false,
  53. annotation: false,
  54. ...processOptions.map
  55. };
  56. }
  57. if (sourceMap && processOptions.map) {
  58. processOptions.map.prev = (0, _utils.normalizeSourceMap)(sourceMap, this.context);
  59. }
  60. let root;
  61. // Reuse PostCSS AST from other loaders
  62. if (meta && meta.ast && meta.ast.type === "postcss" && (0, _semver.satisfies)(meta.ast.version, `^${_package.default.version}`)) {
  63. ({
  64. root
  65. } = meta.ast);
  66. }
  67. if (!root && options.execute) {
  68. // eslint-disable-next-line no-param-reassign
  69. content = (0, _utils.exec)(content, this);
  70. }
  71. let result;
  72. let processor;
  73. try {
  74. processor = postcssFactory(plugins);
  75. result = await processor.process(root || content, processOptions);
  76. } catch (error) {
  77. // Check postcss versions to avoid using PostCSS 7.
  78. // For caching reasons, we use the readFileSync and existsSync functions from the context,
  79. // not the functions from the `fs` module.
  80. if (!hasExplicitDependencyOnPostCSS && processor && processor.version && processor.version.startsWith("7.")) {
  81. // The `findPackageJsonDir` function returns `string` or `null`.
  82. // This is used to do for caching, that is, an explicit comparison with `undefined`
  83. // is used to make the condition body run once.
  84. const packageJSONDir = (0, _utils.findPackageJSONDir)(process.cwd(), this.fs.statSync);
  85. if (packageJSONDir) {
  86. let bufferOfPackageJSON;
  87. try {
  88. bufferOfPackageJSON = this.fs.readFileSync(_path.default.resolve(packageJSONDir, "package.json"), "utf8");
  89. } catch (_error) {
  90. // Nothing
  91. }
  92. if (bufferOfPackageJSON) {
  93. let pkg;
  94. try {
  95. pkg = JSON.parse(bufferOfPackageJSON);
  96. } catch (_error) {
  97. // Nothing
  98. }
  99. if (pkg) {
  100. if (!pkg.dependencies.postcss && !pkg.devDependencies.postcss) {
  101. this.emitWarning(new Error("Add postcss as project dependency. postcss is not a peer dependency for postcss-loader. " + "Use `npm install postcss` or `yarn add postcss`"));
  102. } else {
  103. hasExplicitDependencyOnPostCSS = true;
  104. }
  105. }
  106. }
  107. }
  108. }
  109. (0, _utils.reportError)(this, callback, error);
  110. return;
  111. }
  112. for (const warning of result.warnings()) {
  113. this.emitWarning(new _Warning.default(warning));
  114. }
  115. for (const message of result.messages) {
  116. // eslint-disable-next-line default-case
  117. switch (message.type) {
  118. case "dependency":
  119. this.addDependency(message.file);
  120. break;
  121. case "build-dependency":
  122. this.addBuildDependency(message.file);
  123. break;
  124. case "missing-dependency":
  125. this.addMissingDependency(message.file);
  126. break;
  127. case "context-dependency":
  128. this.addContextDependency(message.file);
  129. break;
  130. case "dir-dependency":
  131. this.addContextDependency(message.dir);
  132. break;
  133. case "asset":
  134. if (message.content && message.file) {
  135. this.emitFile(message.file, message.content, message.sourceMap, message.info);
  136. }
  137. }
  138. }
  139. // eslint-disable-next-line no-undefined
  140. let map = result.map ? result.map.toJSON() : undefined;
  141. if (map && useSourceMap) {
  142. map = (0, _utils.normalizeSourceMapAfterPostcss)(map, this.context);
  143. }
  144. let ast;
  145. try {
  146. ast = {
  147. type: "postcss",
  148. version: result.processor.version,
  149. root: result.root
  150. };
  151. } catch (error) {
  152. (0, _utils.reportError)(this, callback, error);
  153. return;
  154. }
  155. callback(null, result.css, map, {
  156. ast
  157. });
  158. }