pitcher.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.pitch = void 0;
  4. const qs = require("querystring");
  5. const loaderUtils = require("loader-utils");
  6. const selfPath = require.resolve('./index');
  7. // const templateLoaderPath = require.resolve('./templateLoader')
  8. const stylePostLoaderPath = require.resolve('./stylePostLoader');
  9. const styleInlineLoaderPath = require.resolve('./styleInlineLoader');
  10. const isESLintLoader = (l) => /(\/|\\|@)eslint-loader/.test(l.path);
  11. const isNullLoader = (l) => /(\/|\\|@)null-loader/.test(l.path);
  12. const isCSSLoader = (l) => /(\/|\\|@)css-loader/.test(l.path);
  13. const isCacheLoader = (l) => /(\/|\\|@)cache-loader/.test(l.path);
  14. const isNotPitcher = (l) => l.path !== __filename;
  15. const pitcher = (code) => code;
  16. // This pitching loader is responsible for intercepting all vue block requests
  17. // and transform it into appropriate requests.
  18. const pitch = function () {
  19. const context = this;
  20. const rawLoaders = context.loaders.filter(isNotPitcher);
  21. let loaders = rawLoaders;
  22. // do not inject if user uses null-loader to void the type (#1239)
  23. if (loaders.some(isNullLoader)) {
  24. return;
  25. }
  26. const query = qs.parse(context.resourceQuery.slice(1));
  27. const isInlineBlock = /\.vue$/.test(context.resourcePath);
  28. // eslint-loader may get matched multiple times
  29. // if this is an inline block, since the whole file itself is being linted,
  30. // remove eslint-loader to avoid duplicate linting.
  31. if (isInlineBlock) {
  32. loaders = loaders.filter((l) => !isESLintLoader(l));
  33. }
  34. // Important: dedupe loaders since both the original rule
  35. // and the cloned rule would match a source import request or a
  36. // resourceQuery-only rule that intends to target a custom block with no lang
  37. const seen = new Map();
  38. loaders = loaders.filter((loader) => {
  39. const identifier = typeof loader === 'string'
  40. ? loader
  41. : // Dedupe based on both path and query if available. This is important
  42. // in Vue CLI so that postcss-loaders with different options can co-exist
  43. loader.path + loader.query;
  44. if (!seen.has(identifier)) {
  45. seen.set(identifier, true);
  46. return true;
  47. }
  48. });
  49. // Inject style-post-loader before css-loader for scoped CSS and trimming
  50. if (query.type === `style`) {
  51. const cssLoaderIndex = loaders.findIndex(isCSSLoader);
  52. if (cssLoaderIndex > -1) {
  53. // if inlined, ignore any loaders after css-loader and replace w/ inline
  54. // loader
  55. const afterLoaders = query.inline != null
  56. ? [styleInlineLoaderPath]
  57. : loaders.slice(0, cssLoaderIndex + 1);
  58. const beforeLoaders = loaders.slice(cssLoaderIndex + 1);
  59. return genProxyModule([...afterLoaders, stylePostLoaderPath, ...beforeLoaders], context, !!query.module || query.inline != null);
  60. }
  61. }
  62. // if a custom block has no other matching loader other than vue-loader itself
  63. // or cache-loader, we should ignore it
  64. if (query.type === `custom` && shouldIgnoreCustomBlock(loaders)) {
  65. return ``;
  66. }
  67. // Rewrite request. Technically this should only be done when we have deduped
  68. // loaders. But somehow this is required for block source maps to work.
  69. return genProxyModule(loaders, context, query.type !== 'template');
  70. };
  71. exports.pitch = pitch;
  72. function genProxyModule(loaders, context, exportDefault = true) {
  73. const request = genRequest(loaders, context);
  74. // return a proxy module which simply re-exports everything from the
  75. // actual request. Note for template blocks the compiled module has no
  76. // default export.
  77. return ((exportDefault ? `export { default } from ${request}; ` : ``) +
  78. `export * from ${request}`);
  79. }
  80. function genRequest(loaders, context) {
  81. const loaderStrings = loaders.map((loader) => {
  82. return typeof loader === 'string' ? loader : loader.request;
  83. });
  84. const resource = context.resourcePath + context.resourceQuery;
  85. return loaderUtils.stringifyRequest(context, '-!' + [...loaderStrings, resource].join('!'));
  86. }
  87. function shouldIgnoreCustomBlock(loaders) {
  88. const actualLoaders = loaders.filter((loader) => {
  89. // vue-loader
  90. if (loader.path === selfPath) {
  91. return false;
  92. }
  93. // cache-loader
  94. if (isCacheLoader(loader)) {
  95. return false;
  96. }
  97. return true;
  98. });
  99. return actualLoaders.length === 0;
  100. }
  101. exports.default = pitcher;