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