pitcher.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
  5. }) : (function(o, m, k, k2) {
  6. if (k2 === undefined) k2 = k;
  7. o[k2] = m[k];
  8. }));
  9. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  10. Object.defineProperty(o, "default", { enumerable: true, value: v });
  11. }) : function(o, v) {
  12. o["default"] = v;
  13. });
  14. var __importStar = (this && this.__importStar) || function (mod) {
  15. if (mod && mod.__esModule) return mod;
  16. var result = {};
  17. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  18. __setModuleDefault(result, mod);
  19. return result;
  20. };
  21. Object.defineProperty(exports, "__esModule", { value: true });
  22. exports.pitch = void 0;
  23. const qs = __importStar(require("querystring"));
  24. const util_1 = require("./util");
  25. const selfPath = require.resolve('./index');
  26. // const templateLoaderPath = require.resolve('./templateLoader')
  27. const stylePostLoaderPath = require.resolve('./stylePostLoader');
  28. const styleInlineLoaderPath = require.resolve('./styleInlineLoader');
  29. const isESLintLoader = (l) => /(\/|\\|@)eslint-loader/.test(l.path);
  30. const isNullLoader = (l) => /(\/|\\|@)null-loader/.test(l.path);
  31. const isCSSLoader = (l) => /(\/|\\|@)css-loader/.test(l.path);
  32. const isCacheLoader = (l) => /(\/|\\|@)cache-loader/.test(l.path);
  33. const isNotPitcher = (l) => l.path !== __filename;
  34. const pitcher = (code) => code;
  35. // This pitching loader is responsible for intercepting all vue block requests
  36. // and transform it into appropriate requests.
  37. const pitch = function () {
  38. var _a;
  39. const context = this;
  40. const rawLoaders = context.loaders.filter(isNotPitcher);
  41. let loaders = rawLoaders;
  42. // do not inject if user uses null-loader to void the type (#1239)
  43. if (loaders.some(isNullLoader)) {
  44. return;
  45. }
  46. const query = qs.parse(context.resourceQuery.slice(1));
  47. const isInlineBlock = /\.vue$/.test(context.resourcePath);
  48. // eslint-loader may get matched multiple times
  49. // if this is an inline block, since the whole file itself is being linted,
  50. // remove eslint-loader to avoid duplicate linting.
  51. if (isInlineBlock) {
  52. loaders = loaders.filter((l) => !isESLintLoader(l));
  53. }
  54. // Important: dedupe loaders since both the original rule
  55. // and the cloned rule would match a source import request or a
  56. // resourceQuery-only rule that intends to target a custom block with no lang
  57. const seen = new Map();
  58. loaders = loaders.filter((loader) => {
  59. const identifier = typeof loader === 'string'
  60. ? loader
  61. : // Dedupe based on both path and query if available. This is important
  62. // in Vue CLI so that postcss-loaders with different options can co-exist
  63. loader.path + loader.query;
  64. if (!seen.has(identifier)) {
  65. seen.set(identifier, true);
  66. return true;
  67. }
  68. });
  69. // Inject style-post-loader before css-loader for scoped CSS and trimming
  70. const isWebpack5 = (0, util_1.testWebpack5)(context._compiler);
  71. const options = ((0, util_1.getOptions)(context) || {});
  72. if (query.type === `style`) {
  73. if (isWebpack5 && ((_a = context._compiler) === null || _a === void 0 ? void 0 : _a.options.experiments.css)) {
  74. // If user enables `experiments.css`, then we are trying to emit css code directly.
  75. // Although we can target requests like `xxx.vue?type=style` to match `type: "css"`,
  76. // it will make the plugin a mess.
  77. if (!options.experimentalInlineMatchResource) {
  78. context.emitError(new Error('`experimentalInlineMatchResource` should be enabled if `experiments.css` enabled currently'));
  79. return '';
  80. }
  81. if (query.inline || query.module) {
  82. context.emitError(new Error('`inline` or `module` is currently not supported with `experiments.css` enabled'));
  83. return '';
  84. }
  85. const loaderString = [stylePostLoaderPath, ...loaders]
  86. .map((loader) => {
  87. return typeof loader === 'string' ? loader : loader.request;
  88. })
  89. .join('!');
  90. const styleRequest = (0, util_1.stringifyRequest)(context, `${context.resourcePath}${query.lang ? `.${query.lang}` : ''}${context.resourceQuery}!=!-!${loaderString}!${context.resource}`);
  91. return `@import ${styleRequest};`;
  92. }
  93. const cssLoaderIndex = loaders.findIndex(isCSSLoader);
  94. if (cssLoaderIndex > -1) {
  95. // if inlined, ignore any loaders after css-loader and replace w/ inline
  96. // loader
  97. const afterLoaders = query.inline != null
  98. ? [styleInlineLoaderPath]
  99. : loaders.slice(0, cssLoaderIndex + 1);
  100. const beforeLoaders = loaders.slice(cssLoaderIndex + 1);
  101. return genProxyModule([...afterLoaders, stylePostLoaderPath, ...beforeLoaders], context, !!query.module || query.inline != null, query.lang || 'css');
  102. }
  103. }
  104. // if a custom block has no other matching loader other than vue-loader itself
  105. // or cache-loader, we should ignore it
  106. if (query.type === `custom` && shouldIgnoreCustomBlock(loaders)) {
  107. return ``;
  108. }
  109. // Rewrite request. Technically this should only be done when we have deduped
  110. // loaders. But somehow this is required for block source maps to work.
  111. return genProxyModule(loaders, context, query.type !== 'template', query.ts ? 'ts' : query.lang);
  112. };
  113. exports.pitch = pitch;
  114. function genProxyModule(loaders, context, exportDefault = true, lang = 'js') {
  115. const request = genRequest(loaders, lang, context);
  116. // return a proxy module which simply re-exports everything from the
  117. // actual request. Note for template blocks the compiled module has no
  118. // default export.
  119. return ((exportDefault ? `export { default } from ${request}; ` : ``) +
  120. `export * from ${request}`);
  121. }
  122. function genRequest(loaders, lang, context) {
  123. const isWebpack5 = (0, util_1.testWebpack5)(context._compiler);
  124. const options = ((0, util_1.getOptions)(context) || {});
  125. const enableInlineMatchResource = isWebpack5 && options.experimentalInlineMatchResource;
  126. const loaderStrings = loaders.map((loader) => {
  127. return typeof loader === 'string' ? loader : loader.request;
  128. });
  129. const resource = context.resourcePath + context.resourceQuery;
  130. if (enableInlineMatchResource) {
  131. return (0, util_1.stringifyRequest)(context, `${context.resourcePath}${lang ? `.${lang}` : ''}${context.resourceQuery}!=!-!${[...loaderStrings, resource].join('!')}`);
  132. }
  133. return (0, util_1.stringifyRequest)(context, '-!' + [...loaderStrings, resource].join('!'));
  134. }
  135. function shouldIgnoreCustomBlock(loaders) {
  136. const actualLoaders = loaders.filter((loader) => {
  137. // vue-loader
  138. if (loader.path === selfPath) {
  139. return false;
  140. }
  141. // cache-loader
  142. if (isCacheLoader(loader)) {
  143. return false;
  144. }
  145. return true;
  146. });
  147. return actualLoaders.length === 0;
  148. }
  149. exports.default = pitcher;