CssExportsGenerator.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Sergey Melyukov @smelukov
  4. */
  5. "use strict";
  6. const { ReplaceSource, RawSource, ConcatSource } = require("webpack-sources");
  7. const { UsageState } = require("../ExportsInfo");
  8. const Generator = require("../Generator");
  9. const RuntimeGlobals = require("../RuntimeGlobals");
  10. const Template = require("../Template");
  11. /** @typedef {import("webpack-sources").Source} Source */
  12. /** @typedef {import("../Dependency")} Dependency */
  13. /** @typedef {import("../Generator").GenerateContext} GenerateContext */
  14. /** @typedef {import("../Generator").UpdateHashContext} UpdateHashContext */
  15. /** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
  16. /** @typedef {import("../NormalModule")} NormalModule */
  17. /** @typedef {import("../util/Hash")} Hash */
  18. /**
  19. * @template T
  20. * @typedef {import("../InitFragment")<T>} InitFragment
  21. */
  22. const TYPES = new Set(["javascript"]);
  23. class CssExportsGenerator extends Generator {
  24. constructor() {
  25. super();
  26. }
  27. // TODO add getConcatenationBailoutReason to allow concatenation
  28. // but how to make it have a module id
  29. /**
  30. * @param {NormalModule} module module for which the code should be generated
  31. * @param {GenerateContext} generateContext context for generate
  32. * @returns {Source} generated code
  33. */
  34. generate(module, generateContext) {
  35. const source = new ReplaceSource(new RawSource(""));
  36. /** @type {InitFragment<TODO>[]} */
  37. const initFragments = [];
  38. const cssExports = new Map();
  39. generateContext.runtimeRequirements.add(RuntimeGlobals.module);
  40. const runtimeRequirements = new Set();
  41. const templateContext = {
  42. runtimeTemplate: generateContext.runtimeTemplate,
  43. dependencyTemplates: generateContext.dependencyTemplates,
  44. moduleGraph: generateContext.moduleGraph,
  45. chunkGraph: generateContext.chunkGraph,
  46. module,
  47. runtime: generateContext.runtime,
  48. runtimeRequirements: runtimeRequirements,
  49. concatenationScope: generateContext.concatenationScope,
  50. codeGenerationResults: generateContext.codeGenerationResults,
  51. initFragments,
  52. cssExports
  53. };
  54. /**
  55. * @param {Dependency} dependency the dependency
  56. */
  57. const handleDependency = dependency => {
  58. const constructor = /** @type {new (...args: any[]) => Dependency} */ (
  59. dependency.constructor
  60. );
  61. const template = generateContext.dependencyTemplates.get(constructor);
  62. if (!template) {
  63. throw new Error(
  64. "No template for dependency: " + dependency.constructor.name
  65. );
  66. }
  67. template.apply(dependency, source, templateContext);
  68. };
  69. module.dependencies.forEach(handleDependency);
  70. if (generateContext.concatenationScope) {
  71. const source = new ConcatSource();
  72. const usedIdentifiers = new Set();
  73. for (const [k, v] of cssExports) {
  74. let identifier = Template.toIdentifier(k);
  75. let i = 0;
  76. while (usedIdentifiers.has(identifier)) {
  77. identifier = Template.toIdentifier(k + i);
  78. }
  79. usedIdentifiers.add(identifier);
  80. generateContext.concatenationScope.registerExport(k, identifier);
  81. source.add(
  82. `${
  83. generateContext.runtimeTemplate.supportsConst ? "const" : "var"
  84. } ${identifier} = ${JSON.stringify(v)};\n`
  85. );
  86. }
  87. return source;
  88. } else {
  89. const otherUsed =
  90. generateContext.moduleGraph
  91. .getExportsInfo(module)
  92. .otherExportsInfo.getUsed(generateContext.runtime) !==
  93. UsageState.Unused;
  94. if (otherUsed) {
  95. generateContext.runtimeRequirements.add(
  96. RuntimeGlobals.makeNamespaceObject
  97. );
  98. }
  99. return new RawSource(
  100. `${otherUsed ? `${RuntimeGlobals.makeNamespaceObject}(` : ""}${
  101. module.moduleArgument
  102. }.exports = {\n${Array.from(
  103. cssExports,
  104. ([k, v]) => `\t${JSON.stringify(k)}: ${JSON.stringify(v)}`
  105. ).join(",\n")}\n}${otherUsed ? ")" : ""};`
  106. );
  107. }
  108. }
  109. /**
  110. * @param {NormalModule} module fresh module
  111. * @returns {Set<string>} available types (do not mutate)
  112. */
  113. getTypes(module) {
  114. return TYPES;
  115. }
  116. /**
  117. * @param {NormalModule} module the module
  118. * @param {string=} type source type
  119. * @returns {number} estimate size of the module
  120. */
  121. getSize(module, type) {
  122. return 42;
  123. }
  124. /**
  125. * @param {Hash} hash hash that will be modified
  126. * @param {UpdateHashContext} updateHashContext context for updating hash
  127. */
  128. updateHash(hash, { module }) {}
  129. }
  130. module.exports = CssExportsGenerator;