1 | /*
|
---|
2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
3 | Author Ivan Kopeykin @vankop
|
---|
4 | */
|
---|
5 |
|
---|
6 | "use strict";
|
---|
7 |
|
---|
8 | const { cssExportConvention } = require("../util/conventions");
|
---|
9 | const createHash = require("../util/createHash");
|
---|
10 | const { makePathsRelative } = require("../util/identifier");
|
---|
11 | const makeSerializable = require("../util/makeSerializable");
|
---|
12 | const memoize = require("../util/memoize");
|
---|
13 | const NullDependency = require("./NullDependency");
|
---|
14 |
|
---|
15 | /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
|
---|
16 | /** @typedef {import("../../declarations/WebpackOptions").CssGeneratorExportsConvention} CssGeneratorExportsConvention */
|
---|
17 | /** @typedef {import("../../declarations/WebpackOptions").CssGeneratorLocalIdentName} CssGeneratorLocalIdentName */
|
---|
18 | /** @typedef {import("../ChunkGraph")} ChunkGraph */
|
---|
19 | /** @typedef {import("../CssModule")} CssModule */
|
---|
20 | /** @typedef {import("../Dependency")} Dependency */
|
---|
21 | /** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */
|
---|
22 | /** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
|
---|
23 | /** @typedef {import("../DependencyTemplate").CssDependencyTemplateContext} DependencyTemplateContext */
|
---|
24 | /** @typedef {import("../ModuleGraph")} ModuleGraph */
|
---|
25 | /** @typedef {import("../NormalModuleFactory").ResourceDataWithData} ResourceDataWithData */
|
---|
26 | /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
|
---|
27 | /** @typedef {import("../css/CssGenerator")} CssGenerator */
|
---|
28 | /** @typedef {import("../css/CssParser").Range} Range */
|
---|
29 | /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
|
---|
30 | /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
|
---|
31 | /** @typedef {import("../util/Hash")} Hash */
|
---|
32 | /** @typedef {import("../util/createHash").Algorithm} Algorithm */
|
---|
33 |
|
---|
34 | const getCssParser = memoize(() => require("../css/CssParser"));
|
---|
35 |
|
---|
36 | /**
|
---|
37 | * @param {string} local css local
|
---|
38 | * @param {CssModule} module module
|
---|
39 | * @param {ChunkGraph} chunkGraph chunk graph
|
---|
40 | * @param {RuntimeTemplate} runtimeTemplate runtime template
|
---|
41 | * @returns {string} local ident
|
---|
42 | */
|
---|
43 | const getLocalIdent = (local, module, chunkGraph, runtimeTemplate) => {
|
---|
44 | const localIdentName =
|
---|
45 | /** @type {CssGenerator} */
|
---|
46 | (module.generator).localIdentName;
|
---|
47 | const relativeResourcePath = makePathsRelative(
|
---|
48 | /** @type {string} */
|
---|
49 | (module.context),
|
---|
50 | module.matchResource || module.resource,
|
---|
51 | runtimeTemplate.compilation.compiler.root
|
---|
52 | );
|
---|
53 | const { hashFunction, hashDigest, hashDigestLength, hashSalt, uniqueName } =
|
---|
54 | runtimeTemplate.outputOptions;
|
---|
55 | const hash = createHash(/** @type {Algorithm} */ (hashFunction));
|
---|
56 |
|
---|
57 | if (hashSalt) {
|
---|
58 | hash.update(hashSalt);
|
---|
59 | }
|
---|
60 |
|
---|
61 | hash.update(relativeResourcePath);
|
---|
62 |
|
---|
63 | if (!/\[local\]/.test(localIdentName)) {
|
---|
64 | hash.update(local);
|
---|
65 | }
|
---|
66 |
|
---|
67 | const localIdentHash =
|
---|
68 | /** @type {string} */
|
---|
69 | (hash.digest(hashDigest)).slice(0, hashDigestLength);
|
---|
70 |
|
---|
71 | return runtimeTemplate.compilation
|
---|
72 | .getPath(localIdentName, {
|
---|
73 | filename: relativeResourcePath,
|
---|
74 | hash: localIdentHash,
|
---|
75 | contentHash: localIdentHash,
|
---|
76 | chunkGraph,
|
---|
77 | module
|
---|
78 | })
|
---|
79 | .replace(/\[local\]/g, local)
|
---|
80 | .replace(/\[uniqueName\]/g, /** @type {string} */ (uniqueName))
|
---|
81 | .replace(/^((-?[0-9])|--)/, "_$1");
|
---|
82 | };
|
---|
83 |
|
---|
84 | class CssLocalIdentifierDependency extends NullDependency {
|
---|
85 | /**
|
---|
86 | * @param {string} name name
|
---|
87 | * @param {Range} range range
|
---|
88 | * @param {string=} prefix prefix
|
---|
89 | */
|
---|
90 | constructor(name, range, prefix = "") {
|
---|
91 | super();
|
---|
92 | this.name = name;
|
---|
93 | this.range = range;
|
---|
94 | this.prefix = prefix;
|
---|
95 | this._conventionNames = undefined;
|
---|
96 | this._hashUpdate = undefined;
|
---|
97 | }
|
---|
98 |
|
---|
99 | get type() {
|
---|
100 | return "css local identifier";
|
---|
101 | }
|
---|
102 |
|
---|
103 | /**
|
---|
104 | * @param {string} name export name
|
---|
105 | * @param {CssGeneratorExportsConvention} convention convention of the export name
|
---|
106 | * @returns {string[]} convention results
|
---|
107 | */
|
---|
108 | getExportsConventionNames(name, convention) {
|
---|
109 | if (this._conventionNames) {
|
---|
110 | return this._conventionNames;
|
---|
111 | }
|
---|
112 | this._conventionNames = cssExportConvention(this.name, convention);
|
---|
113 | return this._conventionNames;
|
---|
114 | }
|
---|
115 |
|
---|
116 | /**
|
---|
117 | * Returns the exported names
|
---|
118 | * @param {ModuleGraph} moduleGraph module graph
|
---|
119 | * @returns {ExportsSpec | undefined} export names
|
---|
120 | */
|
---|
121 | getExports(moduleGraph) {
|
---|
122 | const module = /** @type {CssModule} */ (moduleGraph.getParentModule(this));
|
---|
123 | const convention =
|
---|
124 | /** @type {CssGenerator} */
|
---|
125 | (module.generator).convention;
|
---|
126 | const names = this.getExportsConventionNames(this.name, convention);
|
---|
127 | return {
|
---|
128 | exports: names.map(name => ({
|
---|
129 | name,
|
---|
130 | canMangle: true
|
---|
131 | })),
|
---|
132 | dependencies: undefined
|
---|
133 | };
|
---|
134 | }
|
---|
135 |
|
---|
136 | /**
|
---|
137 | * Update the hash
|
---|
138 | * @param {Hash} hash hash to be updated
|
---|
139 | * @param {UpdateHashContext} context context
|
---|
140 | * @returns {void}
|
---|
141 | */
|
---|
142 | updateHash(hash, { chunkGraph }) {
|
---|
143 | if (this._hashUpdate === undefined) {
|
---|
144 | const module =
|
---|
145 | /** @type {CssModule} */
|
---|
146 | (chunkGraph.moduleGraph.getParentModule(this));
|
---|
147 | const generator =
|
---|
148 | /** @type {CssGenerator} */
|
---|
149 | (module.generator);
|
---|
150 | const names = this.getExportsConventionNames(
|
---|
151 | this.name,
|
---|
152 | generator.convention
|
---|
153 | );
|
---|
154 | this._hashUpdate = `exportsConvention|${JSON.stringify(names)}|localIdentName|${JSON.stringify(generator.localIdentName)}`;
|
---|
155 | }
|
---|
156 | hash.update(this._hashUpdate);
|
---|
157 | }
|
---|
158 |
|
---|
159 | /**
|
---|
160 | * @param {ObjectSerializerContext} context context
|
---|
161 | */
|
---|
162 | serialize(context) {
|
---|
163 | const { write } = context;
|
---|
164 | write(this.name);
|
---|
165 | write(this.range);
|
---|
166 | write(this.prefix);
|
---|
167 | super.serialize(context);
|
---|
168 | }
|
---|
169 |
|
---|
170 | /**
|
---|
171 | * @param {ObjectDeserializerContext} context context
|
---|
172 | */
|
---|
173 | deserialize(context) {
|
---|
174 | const { read } = context;
|
---|
175 | this.name = read();
|
---|
176 | this.range = read();
|
---|
177 | this.prefix = read();
|
---|
178 | super.deserialize(context);
|
---|
179 | }
|
---|
180 | }
|
---|
181 |
|
---|
182 | CssLocalIdentifierDependency.Template = class CssLocalIdentifierDependencyTemplate extends (
|
---|
183 | NullDependency.Template
|
---|
184 | ) {
|
---|
185 | /**
|
---|
186 | * @param {Dependency} dependency the dependency for which the template should be applied
|
---|
187 | * @param {string} local local name
|
---|
188 | * @param {DependencyTemplateContext} templateContext the context object
|
---|
189 | * @returns {string} identifier
|
---|
190 | */
|
---|
191 | static getIdentifier(
|
---|
192 | dependency,
|
---|
193 | local,
|
---|
194 | { module: m, chunkGraph, runtimeTemplate }
|
---|
195 | ) {
|
---|
196 | const dep = /** @type {CssLocalIdentifierDependency} */ (dependency);
|
---|
197 | const module = /** @type {CssModule} */ (m);
|
---|
198 |
|
---|
199 | return (
|
---|
200 | dep.prefix +
|
---|
201 | getCssParser().escapeIdentifier(
|
---|
202 | getLocalIdent(local, module, chunkGraph, runtimeTemplate)
|
---|
203 | )
|
---|
204 | );
|
---|
205 | }
|
---|
206 |
|
---|
207 | /**
|
---|
208 | * @param {Dependency} dependency the dependency for which the template should be applied
|
---|
209 | * @param {ReplaceSource} source the current replace source which can be modified
|
---|
210 | * @param {DependencyTemplateContext} templateContext the context object
|
---|
211 | * @returns {void}
|
---|
212 | */
|
---|
213 | apply(dependency, source, templateContext) {
|
---|
214 | const { module: m, moduleGraph, runtime, cssData } = templateContext;
|
---|
215 | const dep = /** @type {CssLocalIdentifierDependency} */ (dependency);
|
---|
216 | const module = /** @type {CssModule} */ (m);
|
---|
217 | const convention =
|
---|
218 | /** @type {CssGenerator} */
|
---|
219 | (module.generator).convention;
|
---|
220 | const names = dep.getExportsConventionNames(dep.name, convention);
|
---|
221 | const usedNames =
|
---|
222 | /** @type {(string)[]} */
|
---|
223 | (
|
---|
224 | names
|
---|
225 | .map(name =>
|
---|
226 | moduleGraph.getExportInfo(module, name).getUsedName(name, runtime)
|
---|
227 | )
|
---|
228 | .filter(Boolean)
|
---|
229 | );
|
---|
230 | const local = usedNames.length === 0 ? names[0] : usedNames[0];
|
---|
231 | const identifier = CssLocalIdentifierDependencyTemplate.getIdentifier(
|
---|
232 | dep,
|
---|
233 | local,
|
---|
234 | templateContext
|
---|
235 | );
|
---|
236 |
|
---|
237 | source.replace(dep.range[0], dep.range[1] - 1, identifier);
|
---|
238 |
|
---|
239 | for (const used of usedNames.concat(names)) {
|
---|
240 | cssData.exports.set(used, identifier);
|
---|
241 | }
|
---|
242 | }
|
---|
243 | };
|
---|
244 |
|
---|
245 | makeSerializable(
|
---|
246 | CssLocalIdentifierDependency,
|
---|
247 | "webpack/lib/dependencies/CssLocalIdentifierDependency"
|
---|
248 | );
|
---|
249 |
|
---|
250 | module.exports = CssLocalIdentifierDependency;
|
---|