parseResourceHintOptions.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. */
  4. "use strict";
  5. const memoize = require("../util/memoize");
  6. const getUnsupportedFeatureWarning = memoize(() =>
  7. require("../errors/UnsupportedFeatureWarning")
  8. );
  9. /** @import { DependencyLocation } from "../Dependency" */
  10. /** @import NormalModule from "../NormalModule" */
  11. /**
  12. * @typedef {object} ResourceHintOptions
  13. * @property {true=} prefetch
  14. * @property {true=} preload
  15. * @property {("high" | "low" | "auto")=} fetchPriority
  16. * @property {string=} as
  17. * @property {string=} type
  18. * @property {string=} media
  19. */
  20. /**
  21. * Reads `webpackPrefetch` / `webpackPreload` / `webpackFetchPriority` /
  22. * `webpackAs` / `webpackType` / `webpackMedia` from a parsed magic-comment
  23. * options object. Invalid values emit warnings to the given module.
  24. * @param {Record<string, EXPECTED_ANY> | null | undefined} importOptions parsed comment options
  25. * @param {NormalModule} module the module to attach warnings to
  26. * @param {DependencyLocation} loc location for warnings
  27. * @returns {ResourceHintOptions} parsed hints (empty when no comments matched)
  28. */
  29. const parseResourceHintOptions = (importOptions, module, loc) => {
  30. /** @type {ResourceHintOptions} */
  31. const hints = {};
  32. if (!importOptions) return hints;
  33. /**
  34. * @param {string} message warning text
  35. * @returns {void}
  36. */
  37. const warn = (message) => {
  38. module.addWarning(new (getUnsupportedFeatureWarning())(message, loc));
  39. };
  40. if (importOptions.webpackPrefetch !== undefined) {
  41. if (importOptions.webpackPrefetch === true) {
  42. hints.prefetch = true;
  43. } else {
  44. warn(
  45. `\`webpackPrefetch\` expected true, but received: ${importOptions.webpackPrefetch}.`
  46. );
  47. }
  48. }
  49. if (importOptions.webpackPreload !== undefined) {
  50. if (importOptions.webpackPreload === true) {
  51. hints.preload = true;
  52. } else {
  53. warn(
  54. `\`webpackPreload\` expected true, but received: ${importOptions.webpackPreload}.`
  55. );
  56. }
  57. }
  58. if (importOptions.webpackFetchPriority !== undefined) {
  59. const fp = importOptions.webpackFetchPriority;
  60. if (fp === "high" || fp === "low" || fp === "auto") {
  61. hints.fetchPriority = fp;
  62. } else {
  63. warn(
  64. `\`webpackFetchPriority\` expected "low", "high" or "auto", but received: ${fp}.`
  65. );
  66. }
  67. }
  68. if (importOptions.webpackAs !== undefined) {
  69. if (typeof importOptions.webpackAs === "string") {
  70. hints.as = importOptions.webpackAs;
  71. } else {
  72. warn(
  73. `\`webpackAs\` expected a string, but received: ${importOptions.webpackAs}.`
  74. );
  75. }
  76. }
  77. if (importOptions.webpackType !== undefined) {
  78. if (typeof importOptions.webpackType === "string") {
  79. hints.type = importOptions.webpackType;
  80. } else {
  81. warn(
  82. `\`webpackType\` expected a string, but received: ${importOptions.webpackType}.`
  83. );
  84. }
  85. }
  86. if (importOptions.webpackMedia !== undefined) {
  87. if (typeof importOptions.webpackMedia === "string") {
  88. hints.media = importOptions.webpackMedia;
  89. } else {
  90. warn(
  91. `\`webpackMedia\` expected a string, but received: ${importOptions.webpackMedia}.`
  92. );
  93. }
  94. }
  95. return hints;
  96. };
  97. /**
  98. * Maps a request/filename to the value of the `<link>` `as` attribute. Best
  99. * effort — falls back to `"fetch"` when the type cannot be guessed. Pattern
  100. * matches against the path part, ignoring any query string suffix.
  101. * @param {string} request request/filename
  102. * @returns {string} value for the `as` attribute
  103. */
  104. const guessAsAttribute = (request) => {
  105. if (/\.(png|jpe?g|gif|svg|webp|avif|bmp|ico|tiff?)(\?.*)?$/i.test(request)) {
  106. return "image";
  107. }
  108. if (/\.(woff2?|ttf|otf|eot)(\?.*)?$/i.test(request)) return "font";
  109. if (/\.css(\?.*)?$/i.test(request)) return "style";
  110. if (/\.[cm]?jsx?(\?.*)?$/i.test(request)) return "script";
  111. if (/\.[cm]?tsx?(\?.*)?$/i.test(request)) return "script";
  112. if (/\.(mp3|wav|flac|aac|m4a|ogg|oga)(\?.*)?$/i.test(request)) return "audio";
  113. if (/\.(mp4|webm|mkv|mov|m4v|ogv|avi)(\?.*)?$/i.test(request)) return "video";
  114. if (/\.vtt(\?.*)?$/i.test(request)) return "track";
  115. return "fetch";
  116. };
  117. parseResourceHintOptions.guessAsAttribute = guessAsAttribute;
  118. module.exports = parseResourceHintOptions;