utils.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. "use strict";
  2. const NativeModule = require("module");
  3. const path = require("path");
  4. /** @typedef {import("webpack").Compilation} Compilation */
  5. /** @typedef {import("webpack").Module} Module */
  6. /** @typedef {import("webpack").LoaderContext<any>} LoaderContext */
  7. /**
  8. * @returns {boolean}
  9. */
  10. function trueFn() {
  11. return true;
  12. }
  13. /**
  14. * @param {Compilation} compilation
  15. * @param {string | number} id
  16. * @returns {null | Module}
  17. */
  18. function findModuleById(compilation, id) {
  19. const {
  20. modules,
  21. chunkGraph
  22. } = compilation;
  23. for (const module of modules) {
  24. const moduleId = typeof chunkGraph !== "undefined" ? chunkGraph.getModuleId(module) : module.id;
  25. if (moduleId === id) {
  26. return module;
  27. }
  28. }
  29. return null;
  30. }
  31. /**
  32. * @param {LoaderContext} loaderContext
  33. * @param {string | Buffer} code
  34. * @param {string} filename
  35. * @returns {object}
  36. */
  37. function evalModuleCode(loaderContext, code, filename) {
  38. // @ts-ignore
  39. const module = new NativeModule(filename, loaderContext); // @ts-ignore
  40. module.paths = NativeModule._nodeModulePaths(loaderContext.context); // eslint-disable-line no-underscore-dangle
  41. module.filename = filename; // @ts-ignore
  42. module._compile(code, filename); // eslint-disable-line no-underscore-dangle
  43. return module.exports;
  44. }
  45. /**
  46. * @param {string} a
  47. * @param {string} b
  48. * @returns {0 | 1 | -1}
  49. */
  50. function compareIds(a, b) {
  51. if (typeof a !== typeof b) {
  52. return typeof a < typeof b ? -1 : 1;
  53. }
  54. if (a < b) {
  55. return -1;
  56. }
  57. if (a > b) {
  58. return 1;
  59. }
  60. return 0;
  61. }
  62. /**
  63. * @param {Module} a
  64. * @param {Module} b
  65. * @returns {0 | 1 | -1}
  66. */
  67. function compareModulesByIdentifier(a, b) {
  68. return compareIds(a.identifier(), b.identifier());
  69. }
  70. const MODULE_TYPE = "css/mini-extract";
  71. const AUTO_PUBLIC_PATH = "__mini_css_extract_plugin_public_path_auto__";
  72. const ABSOLUTE_PUBLIC_PATH = "webpack:///mini-css-extract-plugin/";
  73. const BASE_URI = "webpack://";
  74. const SINGLE_DOT_PATH_SEGMENT = "__mini_css_extract_plugin_single_dot_path_segment__";
  75. /**
  76. * @param {string} str
  77. * @returns {boolean}
  78. */
  79. function isAbsolutePath(str) {
  80. return path.posix.isAbsolute(str) || path.win32.isAbsolute(str);
  81. }
  82. const RELATIVE_PATH_REGEXP = /^\.\.?[/\\]/;
  83. /**
  84. * @param {string} str
  85. * @returns {boolean}
  86. */
  87. function isRelativePath(str) {
  88. return RELATIVE_PATH_REGEXP.test(str);
  89. } // TODO simplify for the next major release
  90. /**
  91. * @param {LoaderContext} loaderContext
  92. * @param {string} request
  93. * @returns {string}
  94. */
  95. function stringifyRequest(loaderContext, request) {
  96. if (typeof loaderContext.utils !== "undefined" && typeof loaderContext.utils.contextify === "function") {
  97. return JSON.stringify(loaderContext.utils.contextify(loaderContext.context || loaderContext.rootContext, request));
  98. }
  99. const splitted = request.split("!");
  100. const {
  101. context
  102. } = loaderContext;
  103. return JSON.stringify(splitted.map(part => {
  104. // First, separate singlePath from query, because the query might contain paths again
  105. const splittedPart = part.match(/^(.*?)(\?.*)/);
  106. const query = splittedPart ? splittedPart[2] : "";
  107. let singlePath = splittedPart ? splittedPart[1] : part;
  108. if (isAbsolutePath(singlePath) && context) {
  109. singlePath = path.relative(context, singlePath);
  110. if (isAbsolutePath(singlePath)) {
  111. // If singlePath still matches an absolute path, singlePath was on a different drive than context.
  112. // In this case, we leave the path platform-specific without replacing any separators.
  113. // @see https://github.com/webpack/loader-utils/pull/14
  114. return singlePath + query;
  115. }
  116. if (isRelativePath(singlePath) === false) {
  117. // Ensure that the relative path starts at least with ./ otherwise it would be a request into the modules directory (like node_modules).
  118. singlePath = `./${singlePath}`;
  119. }
  120. }
  121. return singlePath.replace(/\\/g, "/") + query;
  122. }).join("!"));
  123. }
  124. /**
  125. * @param {string} filename
  126. * @param {string} outputPath
  127. * @param {boolean} enforceRelative
  128. * @returns {string}
  129. */
  130. function getUndoPath(filename, outputPath, enforceRelative) {
  131. let depth = -1;
  132. let append = ""; // eslint-disable-next-line no-param-reassign
  133. outputPath = outputPath.replace(/[\\/]$/, "");
  134. for (const part of filename.split(/[/\\]+/)) {
  135. if (part === "..") {
  136. if (depth > -1) {
  137. // eslint-disable-next-line no-plusplus
  138. depth--;
  139. } else {
  140. const i = outputPath.lastIndexOf("/");
  141. const j = outputPath.lastIndexOf("\\");
  142. const pos = i < 0 ? j : j < 0 ? i : Math.max(i, j);
  143. if (pos < 0) {
  144. return `${outputPath}/`;
  145. }
  146. append = `${outputPath.slice(pos + 1)}/${append}`; // eslint-disable-next-line no-param-reassign
  147. outputPath = outputPath.slice(0, pos);
  148. }
  149. } else if (part !== ".") {
  150. // eslint-disable-next-line no-plusplus
  151. depth++;
  152. }
  153. }
  154. return depth > 0 ? `${"../".repeat(depth)}${append}` : enforceRelative ? `./${append}` : append;
  155. }
  156. module.exports = {
  157. trueFn,
  158. findModuleById,
  159. evalModuleCode,
  160. compareModulesByIdentifier,
  161. MODULE_TYPE,
  162. AUTO_PUBLIC_PATH,
  163. ABSOLUTE_PUBLIC_PATH,
  164. BASE_URI,
  165. SINGLE_DOT_PATH_SEGMENT,
  166. stringifyRequest,
  167. getUndoPath
  168. };