| 1 | /*
|
|---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
|---|
| 3 | Author Tobias Koppers @sokra
|
|---|
| 4 | */
|
|---|
| 5 |
|
|---|
| 6 | "use strict";
|
|---|
| 7 |
|
|---|
| 8 | const { SyncBailHook, SyncHook, SyncWaterfallHook } = require("tapable");
|
|---|
| 9 | const {
|
|---|
| 10 | CachedSource,
|
|---|
| 11 | ConcatSource,
|
|---|
| 12 | PrefixSource,
|
|---|
| 13 | RawSource,
|
|---|
| 14 | ReplaceSource
|
|---|
| 15 | } = require("webpack-sources");
|
|---|
| 16 | const Compilation = require("../Compilation");
|
|---|
| 17 | const HotUpdateChunk = require("../HotUpdateChunk");
|
|---|
| 18 | const { CSS_IMPORT_TYPE, CSS_TYPE } = require("../ModuleSourceTypeConstants");
|
|---|
| 19 | const {
|
|---|
| 20 | CSS_MODULE_TYPE,
|
|---|
| 21 | CSS_MODULE_TYPE_AUTO,
|
|---|
| 22 | CSS_MODULE_TYPE_GLOBAL,
|
|---|
| 23 | CSS_MODULE_TYPE_MODULE
|
|---|
| 24 | } = require("../ModuleTypeConstants");
|
|---|
| 25 | const NormalModule = require("../NormalModule");
|
|---|
| 26 | const RuntimeGlobals = require("../RuntimeGlobals");
|
|---|
| 27 | const Template = require("../Template");
|
|---|
| 28 | const CssIcssExportDependency = require("../dependencies/CssIcssExportDependency");
|
|---|
| 29 | const CssIcssImportDependency = require("../dependencies/CssIcssImportDependency");
|
|---|
| 30 | const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency");
|
|---|
| 31 | const CssImportDependency = require("../dependencies/CssImportDependency");
|
|---|
| 32 | const CssUrlDependency = require("../dependencies/CssUrlDependency");
|
|---|
| 33 | const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
|
|---|
| 34 | const { tryRunOrWebpackError } = require("../errors/HookWebpackError");
|
|---|
| 35 | const WebpackError = require("../errors/WebpackError");
|
|---|
| 36 | const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
|
|---|
| 37 | const ConcatenatedModule = require("../optimize/ConcatenatedModule");
|
|---|
| 38 | const { compareModulesByFullName } = require("../util/comparators");
|
|---|
| 39 | const createHash = require("../util/createHash");
|
|---|
| 40 | const { getUndoPath } = require("../util/identifier");
|
|---|
| 41 | const memoize = require("../util/memoize");
|
|---|
| 42 | const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
|
|---|
| 43 | const removeBOM = require("../util/removeBOM");
|
|---|
| 44 | const CssGenerator = require("./CssGenerator");
|
|---|
| 45 | const CssModule = require("./CssModule");
|
|---|
| 46 | const CssParser = require("./CssParser");
|
|---|
| 47 |
|
|---|
| 48 | /** @typedef {import("webpack-sources").Source} Source */
|
|---|
| 49 | /** @typedef {import("../config/defaults").OutputNormalizedWithDefaults} OutputOptions */
|
|---|
| 50 | /** @typedef {import("../Chunk")} Chunk */
|
|---|
| 51 | /** @typedef {import("../ChunkGraph")} ChunkGraph */
|
|---|
| 52 | /** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
|
|---|
| 53 | /** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
|
|---|
| 54 | /** @typedef {import("../Compiler")} Compiler */
|
|---|
| 55 | /** @typedef {import("./CssModule").Inheritance} Inheritance */
|
|---|
| 56 | /** @typedef {import("./CssModule").CssModuleCreateData} CssModuleCreateData */
|
|---|
| 57 | /** @typedef {import("../Module")} Module */
|
|---|
| 58 | /** @typedef {import("../Module").BuildInfo} BuildInfo */
|
|---|
| 59 | /** @typedef {import("../Module").RuntimeRequirements} RuntimeRequirements */
|
|---|
| 60 | /** @typedef {import("../Template").RuntimeTemplate} RuntimeTemplate */
|
|---|
| 61 | /** @typedef {import("../Chunk").ChunkFilenameTemplate} ChunkFilenameTemplate */
|
|---|
| 62 | /** @typedef {import("../util/Hash")} Hash */
|
|---|
| 63 | /** @typedef {import("../Module").BuildMeta} BuildMeta */
|
|---|
| 64 |
|
|---|
| 65 | /**
|
|---|
| 66 | * Defines the render context type used by this module.
|
|---|
| 67 | * @typedef {object} RenderContext
|
|---|
| 68 | * @property {Chunk} chunk the chunk
|
|---|
| 69 | * @property {ChunkGraph} chunkGraph the chunk graph
|
|---|
| 70 | * @property {CodeGenerationResults} codeGenerationResults results of code generation
|
|---|
| 71 | * @property {RuntimeTemplate} runtimeTemplate the runtime template
|
|---|
| 72 | * @property {string} uniqueName the unique name
|
|---|
| 73 | * @property {string} undoPath undo path to css file
|
|---|
| 74 | * @property {string=} hash compilation hash
|
|---|
| 75 | * @property {CssModule[]} modules modules
|
|---|
| 76 | */
|
|---|
| 77 |
|
|---|
| 78 | /**
|
|---|
| 79 | * Defines the chunk render context type used by this module.
|
|---|
| 80 | * @typedef {object} ChunkRenderContext
|
|---|
| 81 | * @property {Chunk=} chunk the chunk
|
|---|
| 82 | * @property {ChunkGraph=} chunkGraph the chunk graph
|
|---|
| 83 | * @property {CodeGenerationResults=} codeGenerationResults results of code generation
|
|---|
| 84 | * @property {RuntimeTemplate} runtimeTemplate the runtime template
|
|---|
| 85 | * @property {string} undoPath undo path to css file
|
|---|
| 86 | * @property {string=} hash compilation hash
|
|---|
| 87 | * @property {WeakMap<Source, ModuleFactoryCacheEntry>} moduleFactoryCache moduleFactoryCache
|
|---|
| 88 | * @property {Source} moduleSourceContent content
|
|---|
| 89 | */
|
|---|
| 90 |
|
|---|
| 91 | /**
|
|---|
| 92 | * Defines the compilation hooks type used by this module.
|
|---|
| 93 | * @typedef {object} CompilationHooks
|
|---|
| 94 | * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModulePackage
|
|---|
| 95 | * @property {SyncHook<[Chunk, Hash, ChunkHashContext]>} chunkHash
|
|---|
| 96 | * @property {SyncBailHook<[Chunk, Module[], Compilation], Module[] | undefined | void>} orderModules called for each CSS source type (CSS_IMPORT_TYPE, CSS_TYPE) with the chunk's modules pre-sorted by full module name; return an ordered `Module[]` to override the default import-order topological sort, or return `undefined` to keep the default
|
|---|
| 97 | */
|
|---|
| 98 |
|
|---|
| 99 | /**
|
|---|
| 100 | * Defines the module factory cache entry type used by this module.
|
|---|
| 101 | * @typedef {object} ModuleFactoryCacheEntry
|
|---|
| 102 | * @property {string} undoPath - The undo path to the CSS file
|
|---|
| 103 | * @property {string | undefined} hash - The compilation hash
|
|---|
| 104 | * @property {Inheritance} inheritance - The inheritance chain
|
|---|
| 105 | * @property {CachedSource} source - The cached source
|
|---|
| 106 | */
|
|---|
| 107 |
|
|---|
| 108 | const getCssLoadingRuntimeModule = memoize(() =>
|
|---|
| 109 | require("./CssLoadingRuntimeModule")
|
|---|
| 110 | );
|
|---|
| 111 | const getCssInjectStyleRuntimeModule = memoize(() =>
|
|---|
| 112 | require("./CssInjectStyleRuntimeModule")
|
|---|
| 113 | );
|
|---|
| 114 |
|
|---|
| 115 | /**
|
|---|
| 116 | * Returns ], definitions: import("../../schemas/WebpackOptions.json")["definitions"] }} schema.
|
|---|
| 117 | * @param {string} name name
|
|---|
| 118 | * @returns {{ oneOf: [{ $ref: string }], definitions: import("../../schemas/WebpackOptions.json")["definitions"] }} schema
|
|---|
| 119 | */
|
|---|
| 120 | const getSchema = (name) => {
|
|---|
| 121 | const { definitions } = require("../../schemas/WebpackOptions.json");
|
|---|
| 122 |
|
|---|
| 123 | return {
|
|---|
| 124 | definitions,
|
|---|
| 125 | oneOf: [{ $ref: `#/definitions/${name}` }]
|
|---|
| 126 | };
|
|---|
| 127 | };
|
|---|
| 128 |
|
|---|
| 129 | const parserValidationOptions = {
|
|---|
| 130 | name: "Css Modules Plugin",
|
|---|
| 131 | baseDataPath: "parser"
|
|---|
| 132 | };
|
|---|
| 133 |
|
|---|
| 134 | const generatorValidationOptions = {
|
|---|
| 135 | name: "Css Modules Plugin",
|
|---|
| 136 | baseDataPath: "generator"
|
|---|
| 137 | };
|
|---|
| 138 |
|
|---|
| 139 | /** @type {WeakMap<Compilation, CompilationHooks>} */
|
|---|
| 140 | const compilationHooksMap = new WeakMap();
|
|---|
| 141 |
|
|---|
| 142 | const PLUGIN_NAME = "CssModulesPlugin";
|
|---|
| 143 |
|
|---|
| 144 | class CssModulesPlugin {
|
|---|
| 145 | /**
|
|---|
| 146 | * Returns the attached hooks.
|
|---|
| 147 | * @param {Compilation} compilation the compilation
|
|---|
| 148 | * @returns {CompilationHooks} the attached hooks
|
|---|
| 149 | */
|
|---|
| 150 | static getCompilationHooks(compilation) {
|
|---|
| 151 | if (!(compilation instanceof Compilation)) {
|
|---|
| 152 | throw new TypeError(
|
|---|
| 153 | "The 'compilation' argument must be an instance of Compilation"
|
|---|
| 154 | );
|
|---|
| 155 | }
|
|---|
| 156 | let hooks = compilationHooksMap.get(compilation);
|
|---|
| 157 | if (hooks === undefined) {
|
|---|
| 158 | hooks = {
|
|---|
| 159 | renderModulePackage: new SyncWaterfallHook([
|
|---|
| 160 | "source",
|
|---|
| 161 | "module",
|
|---|
| 162 | "renderContext"
|
|---|
| 163 | ]),
|
|---|
| 164 | chunkHash: new SyncHook(["chunk", "hash", "context"]),
|
|---|
| 165 | orderModules: new SyncBailHook(["chunk", "modules", "compilation"])
|
|---|
| 166 | };
|
|---|
| 167 | compilationHooksMap.set(compilation, hooks);
|
|---|
| 168 | }
|
|---|
| 169 | return hooks;
|
|---|
| 170 | }
|
|---|
| 171 |
|
|---|
| 172 | constructor() {
|
|---|
| 173 | /** @type {WeakMap<Source, ModuleFactoryCacheEntry>} */
|
|---|
| 174 | this._moduleFactoryCache = new WeakMap();
|
|---|
| 175 | }
|
|---|
| 176 |
|
|---|
| 177 | /**
|
|---|
| 178 | * Applies the plugin by registering its hooks on the compiler.
|
|---|
| 179 | * @param {Compiler} compiler the compiler instance
|
|---|
| 180 | * @returns {void}
|
|---|
| 181 | */
|
|---|
| 182 | apply(compiler) {
|
|---|
| 183 | compiler.hooks.compilation.tap(
|
|---|
| 184 | PLUGIN_NAME,
|
|---|
| 185 | (compilation, { normalModuleFactory }) => {
|
|---|
| 186 | const hooks = CssModulesPlugin.getCompilationHooks(compilation);
|
|---|
| 187 | compilation.dependencyFactories.set(
|
|---|
| 188 | CssImportDependency,
|
|---|
| 189 | normalModuleFactory
|
|---|
| 190 | );
|
|---|
| 191 | compilation.dependencyTemplates.set(
|
|---|
| 192 | CssImportDependency,
|
|---|
| 193 | new CssImportDependency.Template()
|
|---|
| 194 | );
|
|---|
| 195 | compilation.dependencyFactories.set(
|
|---|
| 196 | CssUrlDependency,
|
|---|
| 197 | normalModuleFactory
|
|---|
| 198 | );
|
|---|
| 199 | compilation.dependencyTemplates.set(
|
|---|
| 200 | CssUrlDependency,
|
|---|
| 201 | new CssUrlDependency.Template()
|
|---|
| 202 | );
|
|---|
| 203 | compilation.dependencyFactories.set(
|
|---|
| 204 | CssIcssImportDependency,
|
|---|
| 205 | normalModuleFactory
|
|---|
| 206 | );
|
|---|
| 207 | compilation.dependencyTemplates.set(
|
|---|
| 208 | CssIcssImportDependency,
|
|---|
| 209 | new CssIcssImportDependency.Template()
|
|---|
| 210 | );
|
|---|
| 211 | compilation.dependencyTemplates.set(
|
|---|
| 212 | CssIcssExportDependency,
|
|---|
| 213 | new CssIcssExportDependency.Template()
|
|---|
| 214 | );
|
|---|
| 215 | compilation.dependencyTemplates.set(
|
|---|
| 216 | CssIcssSymbolDependency,
|
|---|
| 217 | new CssIcssSymbolDependency.Template()
|
|---|
| 218 | );
|
|---|
| 219 | compilation.dependencyTemplates.set(
|
|---|
| 220 | StaticExportsDependency,
|
|---|
| 221 | new StaticExportsDependency.Template()
|
|---|
| 222 | );
|
|---|
| 223 | for (const type of [
|
|---|
| 224 | CSS_MODULE_TYPE,
|
|---|
| 225 | CSS_MODULE_TYPE_GLOBAL,
|
|---|
| 226 | CSS_MODULE_TYPE_MODULE,
|
|---|
| 227 | CSS_MODULE_TYPE_AUTO
|
|---|
| 228 | ]) {
|
|---|
| 229 | normalModuleFactory.hooks.createParser
|
|---|
| 230 | .for(type)
|
|---|
| 231 | .tap(PLUGIN_NAME, (parserOptions) => {
|
|---|
| 232 | /** @type {undefined | "global" | "local" | "auto"} */
|
|---|
| 233 | let defaultMode;
|
|---|
| 234 |
|
|---|
| 235 | switch (type) {
|
|---|
| 236 | case CSS_MODULE_TYPE: {
|
|---|
| 237 | compiler.validate(
|
|---|
| 238 | () => getSchema("CssParserOptions"),
|
|---|
| 239 | parserOptions,
|
|---|
| 240 | parserValidationOptions,
|
|---|
| 241 | (options) =>
|
|---|
| 242 | require("../../schemas/plugins/css/CssParserOptions.check")(
|
|---|
| 243 | options
|
|---|
| 244 | )
|
|---|
| 245 | );
|
|---|
| 246 |
|
|---|
| 247 | break;
|
|---|
| 248 | }
|
|---|
| 249 | case CSS_MODULE_TYPE_GLOBAL: {
|
|---|
| 250 | defaultMode = "global";
|
|---|
| 251 | compiler.validate(
|
|---|
| 252 | () => getSchema("CssModuleParserOptions"),
|
|---|
| 253 | parserOptions,
|
|---|
| 254 | parserValidationOptions,
|
|---|
| 255 | (options) =>
|
|---|
| 256 | require("../../schemas/plugins/css/CssModuleParserOptions.check")(
|
|---|
| 257 | options
|
|---|
| 258 | )
|
|---|
| 259 | );
|
|---|
| 260 | break;
|
|---|
| 261 | }
|
|---|
| 262 | case CSS_MODULE_TYPE_MODULE: {
|
|---|
| 263 | defaultMode = "local";
|
|---|
| 264 | compiler.validate(
|
|---|
| 265 | () => getSchema("CssAutoOrModuleParserOptions"),
|
|---|
| 266 | parserOptions,
|
|---|
| 267 | parserValidationOptions,
|
|---|
| 268 | (options) =>
|
|---|
| 269 | require("../../schemas/plugins/css/CssAutoOrModuleParserOptions.check")(
|
|---|
| 270 | options
|
|---|
| 271 | )
|
|---|
| 272 | );
|
|---|
| 273 | break;
|
|---|
| 274 | }
|
|---|
| 275 | case CSS_MODULE_TYPE_AUTO: {
|
|---|
| 276 | defaultMode = "auto";
|
|---|
| 277 | compiler.validate(
|
|---|
| 278 | () => getSchema("CssAutoOrModuleParserOptions"),
|
|---|
| 279 | parserOptions,
|
|---|
| 280 | parserValidationOptions,
|
|---|
| 281 | (options) =>
|
|---|
| 282 | require("../../schemas/plugins/css/CssAutoOrModuleParserOptions.check")(
|
|---|
| 283 | options
|
|---|
| 284 | )
|
|---|
| 285 | );
|
|---|
| 286 | break;
|
|---|
| 287 | }
|
|---|
| 288 | }
|
|---|
| 289 |
|
|---|
| 290 | return new CssParser({
|
|---|
| 291 | defaultMode,
|
|---|
| 292 | ...parserOptions
|
|---|
| 293 | });
|
|---|
| 294 | });
|
|---|
| 295 | normalModuleFactory.hooks.createGenerator
|
|---|
| 296 | .for(type)
|
|---|
| 297 | .tap(PLUGIN_NAME, (generatorOptions) => {
|
|---|
| 298 | switch (type) {
|
|---|
| 299 | case CSS_MODULE_TYPE: {
|
|---|
| 300 | compiler.validate(
|
|---|
| 301 | () => getSchema("CssGeneratorOptions"),
|
|---|
| 302 | generatorOptions,
|
|---|
| 303 | generatorValidationOptions,
|
|---|
| 304 | (options) =>
|
|---|
| 305 | require("../../schemas/plugins/css/CssGeneratorOptions.check")(
|
|---|
| 306 | options
|
|---|
| 307 | )
|
|---|
| 308 | );
|
|---|
| 309 |
|
|---|
| 310 | break;
|
|---|
| 311 | }
|
|---|
| 312 | case CSS_MODULE_TYPE_GLOBAL: {
|
|---|
| 313 | compiler.validate(
|
|---|
| 314 | () => getSchema("CssModuleGeneratorOptions"),
|
|---|
| 315 | generatorOptions,
|
|---|
| 316 | generatorValidationOptions,
|
|---|
| 317 | (options) =>
|
|---|
| 318 | require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")(
|
|---|
| 319 | options
|
|---|
| 320 | )
|
|---|
| 321 | );
|
|---|
| 322 |
|
|---|
| 323 | break;
|
|---|
| 324 | }
|
|---|
| 325 | case CSS_MODULE_TYPE_MODULE: {
|
|---|
| 326 | compiler.validate(
|
|---|
| 327 | () => getSchema("CssModuleGeneratorOptions"),
|
|---|
| 328 | generatorOptions,
|
|---|
| 329 | generatorValidationOptions,
|
|---|
| 330 | (options) =>
|
|---|
| 331 | require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")(
|
|---|
| 332 | options
|
|---|
| 333 | )
|
|---|
| 334 | );
|
|---|
| 335 |
|
|---|
| 336 | break;
|
|---|
| 337 | }
|
|---|
| 338 | case CSS_MODULE_TYPE_AUTO: {
|
|---|
| 339 | compiler.validate(
|
|---|
| 340 | () => getSchema("CssModuleGeneratorOptions"),
|
|---|
| 341 | generatorOptions,
|
|---|
| 342 | generatorValidationOptions,
|
|---|
| 343 | (options) =>
|
|---|
| 344 | require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")(
|
|---|
| 345 | options
|
|---|
| 346 | )
|
|---|
| 347 | );
|
|---|
| 348 |
|
|---|
| 349 | break;
|
|---|
| 350 | }
|
|---|
| 351 | }
|
|---|
| 352 |
|
|---|
| 353 | return new CssGenerator(
|
|---|
| 354 | generatorOptions,
|
|---|
| 355 | compilation.moduleGraph
|
|---|
| 356 | );
|
|---|
| 357 | });
|
|---|
| 358 | normalModuleFactory.hooks.createModuleClass
|
|---|
| 359 | .for(type)
|
|---|
| 360 | .tap(PLUGIN_NAME, (createData, resolveData) => {
|
|---|
| 361 | const exportType =
|
|---|
| 362 | /** @type {CssParser} */
|
|---|
| 363 | (createData.parser).options.exportType;
|
|---|
| 364 | if (resolveData.dependencies.length > 0) {
|
|---|
| 365 | // When CSS is imported from CSS there is only one dependency
|
|---|
| 366 | const dependency = resolveData.dependencies[0];
|
|---|
| 367 |
|
|---|
| 368 | if (dependency instanceof CssImportDependency) {
|
|---|
| 369 | const parent =
|
|---|
| 370 | /** @type {CssModule} */
|
|---|
| 371 | (compilation.moduleGraph.getParentModule(dependency));
|
|---|
| 372 |
|
|---|
| 373 | if (parent instanceof CssModule) {
|
|---|
| 374 | /** @type {Inheritance | undefined} */
|
|---|
| 375 | let inheritance;
|
|---|
| 376 |
|
|---|
| 377 | if (
|
|---|
| 378 | parent.cssLayer !== undefined ||
|
|---|
| 379 | parent.supports ||
|
|---|
| 380 | parent.media
|
|---|
| 381 | ) {
|
|---|
| 382 | if (!inheritance) {
|
|---|
| 383 | inheritance = [];
|
|---|
| 384 | }
|
|---|
| 385 |
|
|---|
| 386 | inheritance.push([
|
|---|
| 387 | parent.cssLayer,
|
|---|
| 388 | parent.supports,
|
|---|
| 389 | parent.media
|
|---|
| 390 | ]);
|
|---|
| 391 | }
|
|---|
| 392 |
|
|---|
| 393 | if (parent.inheritance) {
|
|---|
| 394 | if (!inheritance) {
|
|---|
| 395 | inheritance = [];
|
|---|
| 396 | }
|
|---|
| 397 |
|
|---|
| 398 | inheritance.push(...parent.inheritance);
|
|---|
| 399 | }
|
|---|
| 400 |
|
|---|
| 401 | return new CssModule(
|
|---|
| 402 | /** @type {CssModuleCreateData} */
|
|---|
| 403 | ({
|
|---|
| 404 | ...createData,
|
|---|
| 405 | cssLayer: dependency.layer,
|
|---|
| 406 | supports: dependency.supports,
|
|---|
| 407 | media: dependency.media,
|
|---|
| 408 | inheritance,
|
|---|
| 409 | exportType: parent.exportType || exportType
|
|---|
| 410 | })
|
|---|
| 411 | );
|
|---|
| 412 | }
|
|---|
| 413 |
|
|---|
| 414 | return new CssModule(
|
|---|
| 415 | /** @type {CssModuleCreateData} */
|
|---|
| 416 | ({
|
|---|
| 417 | ...createData,
|
|---|
| 418 | cssLayer: dependency.layer,
|
|---|
| 419 | supports: dependency.supports,
|
|---|
| 420 | media: dependency.media,
|
|---|
| 421 | exportType
|
|---|
| 422 | })
|
|---|
| 423 | );
|
|---|
| 424 | }
|
|---|
| 425 | }
|
|---|
| 426 |
|
|---|
| 427 | return new CssModule(
|
|---|
| 428 | /** @type {CssModuleCreateData} */
|
|---|
| 429 | (
|
|---|
| 430 | /** @type {unknown} */ ({
|
|---|
| 431 | ...createData,
|
|---|
| 432 | exportType
|
|---|
| 433 | })
|
|---|
| 434 | )
|
|---|
| 435 | );
|
|---|
| 436 | });
|
|---|
| 437 |
|
|---|
| 438 | NormalModule.getCompilationHooks(compilation).processResult.tap(
|
|---|
| 439 | PLUGIN_NAME,
|
|---|
| 440 | (result, module) => {
|
|---|
| 441 | if (module.type === type) {
|
|---|
| 442 | const [source, ...rest] = result;
|
|---|
| 443 |
|
|---|
| 444 | return [removeBOM(source), ...rest];
|
|---|
| 445 | }
|
|---|
| 446 |
|
|---|
| 447 | return result;
|
|---|
| 448 | }
|
|---|
| 449 | );
|
|---|
| 450 | }
|
|---|
| 451 |
|
|---|
| 452 | JavascriptModulesPlugin.getCompilationHooks(
|
|---|
| 453 | compilation
|
|---|
| 454 | ).renderModuleContent.tap(PLUGIN_NAME, (source, module) => {
|
|---|
| 455 | const injectCssStylesVar =
|
|---|
| 456 | module instanceof ConcatenatedModule &&
|
|---|
| 457 | module.modules.find(
|
|---|
| 458 | (m) =>
|
|---|
| 459 | m instanceof CssModule &&
|
|---|
| 460 | m.exportType === "style" &&
|
|---|
| 461 | !(/** @type {CssGenerator} */ (m.generator)._exportsOnly)
|
|---|
| 462 | );
|
|---|
| 463 | const injectHMRCode =
|
|---|
| 464 | (module instanceof CssModule && module.hot) ||
|
|---|
| 465 | (module instanceof ConcatenatedModule &&
|
|---|
| 466 | module.rootModule instanceof CssModule &&
|
|---|
| 467 | module.rootModule.hot);
|
|---|
| 468 |
|
|---|
| 469 | if (injectCssStylesVar) {
|
|---|
| 470 | source = new ConcatSource(
|
|---|
| 471 | "var __webpack_css_styles__ = [];",
|
|---|
| 472 | "\n",
|
|---|
| 473 | source
|
|---|
| 474 | );
|
|---|
| 475 | }
|
|---|
| 476 | if (injectHMRCode) {
|
|---|
| 477 | const currentModule = /** @type {CssModule} */ (
|
|---|
| 478 | module instanceof ConcatenatedModule ? module.rootModule : module
|
|---|
| 479 | );
|
|---|
| 480 | const exportType = currentModule.exportType || "link";
|
|---|
| 481 | // When exportType !== "link", modules behave like JavaScript modules
|
|---|
| 482 | if (["link", "style"].includes(exportType)) {
|
|---|
| 483 | // For exportType === "link", we can optimize with self-acceptance
|
|---|
| 484 | const cssData = /** @type {BuildInfo} */ (module.buildInfo)
|
|---|
| 485 | .cssData;
|
|---|
| 486 | if (!cssData) {
|
|---|
| 487 | return source;
|
|---|
| 488 | }
|
|---|
| 489 | const exports = cssData.exports;
|
|---|
| 490 | /** @type {Record<string, string>} */
|
|---|
| 491 | const exportsObj = {};
|
|---|
| 492 | for (const [key, value] of exports) {
|
|---|
| 493 | exportsObj[key] = value;
|
|---|
| 494 | }
|
|---|
| 495 | const stringifiedExports = JSON.stringify(
|
|---|
| 496 | JSON.stringify(exportsObj)
|
|---|
| 497 | );
|
|---|
| 498 |
|
|---|
| 499 | const hmrCode = Template.asString([
|
|---|
| 500 | "",
|
|---|
| 501 | `var __webpack_css_exports__ = ${stringifiedExports};`,
|
|---|
| 502 | "// only invalidate when locals change",
|
|---|
| 503 | "if (module.hot.data && module.hot.data.__webpack_css_exports__ && module.hot.data.__webpack_css_exports__ != __webpack_css_exports__) {",
|
|---|
| 504 | Template.indent("module.hot.invalidate();"),
|
|---|
| 505 | "} else {",
|
|---|
| 506 | Template.indent("module.hot.accept();"),
|
|---|
| 507 | "}",
|
|---|
| 508 | "module.hot.dispose(function(data) {",
|
|---|
| 509 | Template.indent([
|
|---|
| 510 | "data.__webpack_css_exports__ = __webpack_css_exports__;"
|
|---|
| 511 | ]),
|
|---|
| 512 | "});"
|
|---|
| 513 | ]);
|
|---|
| 514 |
|
|---|
| 515 | source = new ConcatSource(source, "\n", new RawSource(hmrCode));
|
|---|
| 516 | }
|
|---|
| 517 | }
|
|---|
| 518 | if (injectCssStylesVar) {
|
|---|
| 519 | /** @type {ConcatSource} */
|
|---|
| 520 | (source).add(
|
|---|
| 521 | "for (let i = 0; i < __webpack_css_styles__.length; i++) {\n" +
|
|---|
| 522 | `${RuntimeGlobals.cssInjectStyle}(__webpack_css_styles__[i][0], __webpack_css_styles__[i][1]);\n` +
|
|---|
| 523 | "}"
|
|---|
| 524 | );
|
|---|
| 525 | }
|
|---|
| 526 |
|
|---|
| 527 | return source;
|
|---|
| 528 | });
|
|---|
| 529 | /** @type {WeakMap<Chunk, CssModule[]>} */
|
|---|
| 530 | const orderedCssModulesPerChunk = new WeakMap();
|
|---|
| 531 | compilation.hooks.afterCodeGeneration.tap(PLUGIN_NAME, () => {
|
|---|
| 532 | const { chunkGraph } = compilation;
|
|---|
| 533 | for (const chunk of compilation.chunks) {
|
|---|
| 534 | if (CssModulesPlugin.chunkHasCss(chunk, chunkGraph)) {
|
|---|
| 535 | orderedCssModulesPerChunk.set(
|
|---|
| 536 | chunk,
|
|---|
| 537 | this.getOrderedChunkCssModules(chunk, chunkGraph, compilation)
|
|---|
| 538 | );
|
|---|
| 539 | }
|
|---|
| 540 | }
|
|---|
| 541 | });
|
|---|
| 542 | compilation.hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, context) => {
|
|---|
| 543 | hooks.chunkHash.call(chunk, hash, context);
|
|---|
| 544 | });
|
|---|
| 545 | compilation.hooks.contentHash.tap(PLUGIN_NAME, (chunk) => {
|
|---|
| 546 | const {
|
|---|
| 547 | chunkGraph,
|
|---|
| 548 | moduleGraph,
|
|---|
| 549 | runtimeTemplate,
|
|---|
| 550 | outputOptions: {
|
|---|
| 551 | hashSalt,
|
|---|
| 552 | hashDigest,
|
|---|
| 553 | hashDigestLength,
|
|---|
| 554 | hashFunction
|
|---|
| 555 | }
|
|---|
| 556 | } = compilation;
|
|---|
| 557 | const hash = createHash(hashFunction);
|
|---|
| 558 | if (hashSalt) hash.update(hashSalt);
|
|---|
| 559 | const codeGenerationResults =
|
|---|
| 560 | /** @type {CodeGenerationResults} */
|
|---|
| 561 | (compilation.codeGenerationResults);
|
|---|
| 562 | hooks.chunkHash.call(chunk, hash, {
|
|---|
| 563 | chunkGraph,
|
|---|
| 564 | codeGenerationResults,
|
|---|
| 565 | moduleGraph,
|
|---|
| 566 | runtimeTemplate
|
|---|
| 567 | });
|
|---|
| 568 | const modules = orderedCssModulesPerChunk.get(chunk);
|
|---|
| 569 | if (modules) {
|
|---|
| 570 | for (const module of modules) {
|
|---|
| 571 | hash.update(chunkGraph.getModuleHash(module, chunk.runtime));
|
|---|
| 572 | }
|
|---|
| 573 | }
|
|---|
| 574 | const digest = hash.digest(hashDigest);
|
|---|
| 575 | chunk.contentHash.css = nonNumericOnlyHash(digest, hashDigestLength);
|
|---|
| 576 | });
|
|---|
| 577 | compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
|
|---|
| 578 | const { chunkGraph } = compilation;
|
|---|
| 579 | const { hash, chunk, codeGenerationResults, runtimeTemplate } =
|
|---|
| 580 | options;
|
|---|
| 581 |
|
|---|
| 582 | if (chunk instanceof HotUpdateChunk) return result;
|
|---|
| 583 |
|
|---|
| 584 | /** @type {CssModule[] | undefined} */
|
|---|
| 585 | const modules = orderedCssModulesPerChunk.get(chunk);
|
|---|
| 586 | if (modules !== undefined) {
|
|---|
| 587 | const { path: filename, info } = compilation.getPathWithInfo(
|
|---|
| 588 | CssModulesPlugin.getChunkFilenameTemplate(
|
|---|
| 589 | chunk,
|
|---|
| 590 | compilation.outputOptions
|
|---|
| 591 | ),
|
|---|
| 592 | {
|
|---|
| 593 | hash,
|
|---|
| 594 | runtime: chunk.runtime,
|
|---|
| 595 | chunk,
|
|---|
| 596 | contentHashType: "css"
|
|---|
| 597 | }
|
|---|
| 598 | );
|
|---|
| 599 | const undoPath = getUndoPath(
|
|---|
| 600 | filename,
|
|---|
| 601 | compilation.outputOptions.path,
|
|---|
| 602 | false
|
|---|
| 603 | );
|
|---|
| 604 | result.push({
|
|---|
| 605 | render: () =>
|
|---|
| 606 | this.renderChunk(
|
|---|
| 607 | {
|
|---|
| 608 | chunk,
|
|---|
| 609 | chunkGraph,
|
|---|
| 610 | codeGenerationResults,
|
|---|
| 611 | uniqueName: compilation.outputOptions.uniqueName,
|
|---|
| 612 | undoPath,
|
|---|
| 613 | hash,
|
|---|
| 614 | modules,
|
|---|
| 615 | runtimeTemplate
|
|---|
| 616 | },
|
|---|
| 617 | hooks
|
|---|
| 618 | ),
|
|---|
| 619 | filename,
|
|---|
| 620 | info,
|
|---|
| 621 | identifier: `css${chunk.id}`,
|
|---|
| 622 | hash: chunk.contentHash.css
|
|---|
| 623 | });
|
|---|
| 624 | }
|
|---|
| 625 | return result;
|
|---|
| 626 | });
|
|---|
| 627 | const globalChunkLoading = compilation.outputOptions.chunkLoading;
|
|---|
| 628 | /**
|
|---|
| 629 | * Checks whether this css modules plugin is enabled for chunk.
|
|---|
| 630 | * @param {Chunk} chunk the chunk
|
|---|
| 631 | * @returns {boolean} true, when enabled
|
|---|
| 632 | */
|
|---|
| 633 | const isEnabledForChunk = (chunk) => {
|
|---|
| 634 | const options = chunk.getEntryOptions();
|
|---|
| 635 | const chunkLoading =
|
|---|
| 636 | options && options.chunkLoading !== undefined
|
|---|
| 637 | ? options.chunkLoading
|
|---|
| 638 | : globalChunkLoading;
|
|---|
| 639 | return chunkLoading === "jsonp" || chunkLoading === "import";
|
|---|
| 640 | };
|
|---|
| 641 | /** @type {WeakSet<Chunk>} */
|
|---|
| 642 | const onceForChunkSet = new WeakSet();
|
|---|
| 643 | /**
|
|---|
| 644 | * Handles the hook callback for this code path.
|
|---|
| 645 | * @param {Chunk} chunk chunk to check
|
|---|
| 646 | * @param {RuntimeRequirements} set runtime requirements
|
|---|
| 647 | */
|
|---|
| 648 | const handler = (chunk, set) => {
|
|---|
| 649 | if (onceForChunkSet.has(chunk)) return;
|
|---|
| 650 | onceForChunkSet.add(chunk);
|
|---|
| 651 | if (!isEnabledForChunk(chunk)) return;
|
|---|
| 652 |
|
|---|
| 653 | const CssLoadingRuntimeModule = getCssLoadingRuntimeModule();
|
|---|
| 654 | compilation.addRuntimeModule(chunk, new CssLoadingRuntimeModule(set));
|
|---|
| 655 | };
|
|---|
| 656 | compilation.hooks.runtimeRequirementInTree
|
|---|
| 657 | .for(RuntimeGlobals.hasCssModules)
|
|---|
| 658 | .tap(PLUGIN_NAME, handler);
|
|---|
| 659 | compilation.hooks.runtimeRequirementInTree
|
|---|
| 660 | .for(RuntimeGlobals.ensureChunkHandlers)
|
|---|
| 661 | .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
|
|---|
| 662 | if (!isEnabledForChunk(chunk)) return;
|
|---|
| 663 | if (
|
|---|
| 664 | !chunkGraph.hasModuleInGraph(
|
|---|
| 665 | chunk,
|
|---|
| 666 | (m) =>
|
|---|
| 667 | m.type === CSS_MODULE_TYPE ||
|
|---|
| 668 | m.type === CSS_MODULE_TYPE_GLOBAL ||
|
|---|
| 669 | m.type === CSS_MODULE_TYPE_MODULE ||
|
|---|
| 670 | m.type === CSS_MODULE_TYPE_AUTO
|
|---|
| 671 | )
|
|---|
| 672 | ) {
|
|---|
| 673 | return;
|
|---|
| 674 | }
|
|---|
| 675 |
|
|---|
| 676 | set.add(RuntimeGlobals.hasOwnProperty);
|
|---|
| 677 | set.add(RuntimeGlobals.publicPath);
|
|---|
| 678 | set.add(RuntimeGlobals.getChunkCssFilename);
|
|---|
| 679 | });
|
|---|
| 680 | compilation.hooks.runtimeRequirementInTree
|
|---|
| 681 | .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
|---|
| 682 | .tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
|
|---|
| 683 | if (!isEnabledForChunk(chunk)) return;
|
|---|
| 684 | if (
|
|---|
| 685 | !chunkGraph.hasModuleInGraph(
|
|---|
| 686 | chunk,
|
|---|
| 687 | (m) =>
|
|---|
| 688 | m.type === CSS_MODULE_TYPE ||
|
|---|
| 689 | m.type === CSS_MODULE_TYPE_GLOBAL ||
|
|---|
| 690 | m.type === CSS_MODULE_TYPE_MODULE ||
|
|---|
| 691 | m.type === CSS_MODULE_TYPE_AUTO
|
|---|
| 692 | )
|
|---|
| 693 | ) {
|
|---|
| 694 | return;
|
|---|
| 695 | }
|
|---|
| 696 | set.add(RuntimeGlobals.publicPath);
|
|---|
| 697 | set.add(RuntimeGlobals.getChunkCssFilename);
|
|---|
| 698 | });
|
|---|
| 699 |
|
|---|
| 700 | compilation.hooks.runtimeRequirementInTree
|
|---|
| 701 | .for(RuntimeGlobals.cssInjectStyle)
|
|---|
| 702 | .tap(PLUGIN_NAME, (chunk, set) => {
|
|---|
| 703 | // Same as above: namespace stub is enough.
|
|---|
| 704 | set.add(RuntimeGlobals.requireScope);
|
|---|
| 705 | const CssInjectStyleRuntimeModule =
|
|---|
| 706 | getCssInjectStyleRuntimeModule();
|
|---|
| 707 | compilation.addRuntimeModule(
|
|---|
| 708 | chunk,
|
|---|
| 709 | new CssInjectStyleRuntimeModule(set)
|
|---|
| 710 | );
|
|---|
| 711 | });
|
|---|
| 712 | }
|
|---|
| 713 | );
|
|---|
| 714 | }
|
|---|
| 715 |
|
|---|
| 716 | /**
|
|---|
| 717 | * Gets modules in order.
|
|---|
| 718 | * @param {Chunk} chunk chunk
|
|---|
| 719 | * @param {Iterable<Module> | undefined} modules unordered modules
|
|---|
| 720 | * @param {Compilation} compilation compilation
|
|---|
| 721 | * @returns {Module[]} ordered modules
|
|---|
| 722 | */
|
|---|
| 723 | getModulesInOrder(chunk, modules, compilation) {
|
|---|
| 724 | if (!modules) return [];
|
|---|
| 725 |
|
|---|
| 726 | /** @type {Module[]} */
|
|---|
| 727 | const modulesList = [...modules];
|
|---|
| 728 |
|
|---|
| 729 | // Get ordered list of modules per chunk group
|
|---|
| 730 | // Lists are in reverse order to allow to use Array.pop()
|
|---|
| 731 | const modulesByChunkGroup = Array.from(
|
|---|
| 732 | chunk.groupsIterable,
|
|---|
| 733 | (chunkGroup) => {
|
|---|
| 734 | const sortedModules = modulesList
|
|---|
| 735 | .map((module) => ({
|
|---|
| 736 | module,
|
|---|
| 737 | index: chunkGroup.getModulePostOrderIndex(module)
|
|---|
| 738 | }))
|
|---|
| 739 | .filter((item) => item.index !== undefined)
|
|---|
| 740 | .sort(
|
|---|
| 741 | (a, b) =>
|
|---|
| 742 | /** @type {number} */ (b.index) - /** @type {number} */ (a.index)
|
|---|
| 743 | )
|
|---|
| 744 | .map((item) => item.module);
|
|---|
| 745 |
|
|---|
| 746 | return { list: sortedModules, set: new Set(sortedModules) };
|
|---|
| 747 | }
|
|---|
| 748 | );
|
|---|
| 749 |
|
|---|
| 750 | if (modulesByChunkGroup.length === 1) {
|
|---|
| 751 | return modulesByChunkGroup[0].list.reverse();
|
|---|
| 752 | }
|
|---|
| 753 |
|
|---|
| 754 | const boundCompareModulesByFullName = compareModulesByFullName(
|
|---|
| 755 | compilation.compiler
|
|---|
| 756 | );
|
|---|
| 757 |
|
|---|
| 758 | /**
|
|---|
| 759 | * Compares module lists.
|
|---|
| 760 | * @param {{ list: Module[] }} a a
|
|---|
| 761 | * @param {{ list: Module[] }} b b
|
|---|
| 762 | * @returns {-1 | 0 | 1} result
|
|---|
| 763 | */
|
|---|
| 764 | const compareModuleLists = ({ list: a }, { list: b }) => {
|
|---|
| 765 | if (a.length === 0) {
|
|---|
| 766 | return b.length === 0 ? 0 : 1;
|
|---|
| 767 | }
|
|---|
| 768 | if (b.length === 0) return -1;
|
|---|
| 769 | return boundCompareModulesByFullName(a[a.length - 1], b[b.length - 1]);
|
|---|
| 770 | };
|
|---|
| 771 |
|
|---|
| 772 | modulesByChunkGroup.sort(compareModuleLists);
|
|---|
| 773 |
|
|---|
| 774 | /** @type {Module[]} */
|
|---|
| 775 | const finalModules = [];
|
|---|
| 776 |
|
|---|
| 777 | for (;;) {
|
|---|
| 778 | /** @type {Set<Module>} */
|
|---|
| 779 | const failedModules = new Set();
|
|---|
| 780 | const list = modulesByChunkGroup[0].list;
|
|---|
| 781 | if (list.length === 0) {
|
|---|
| 782 | // done, everything empty
|
|---|
| 783 | break;
|
|---|
| 784 | }
|
|---|
| 785 | /** @type {Module} */
|
|---|
| 786 | let selectedModule = list[list.length - 1];
|
|---|
| 787 | /** @type {undefined | false | Module} */
|
|---|
| 788 | let hasFailed;
|
|---|
| 789 | outer: for (;;) {
|
|---|
| 790 | for (const { list, set } of modulesByChunkGroup) {
|
|---|
| 791 | if (list.length === 0) continue;
|
|---|
| 792 | const lastModule = list[list.length - 1];
|
|---|
| 793 | if (lastModule === selectedModule) continue;
|
|---|
| 794 | if (!set.has(selectedModule)) continue;
|
|---|
| 795 | failedModules.add(selectedModule);
|
|---|
| 796 | if (failedModules.has(lastModule)) {
|
|---|
| 797 | // There is a conflict, try other alternatives
|
|---|
| 798 | hasFailed = lastModule;
|
|---|
| 799 | continue;
|
|---|
| 800 | }
|
|---|
| 801 | selectedModule = lastModule;
|
|---|
| 802 | hasFailed = false;
|
|---|
| 803 | continue outer; // restart
|
|---|
| 804 | }
|
|---|
| 805 | break;
|
|---|
| 806 | }
|
|---|
| 807 | if (hasFailed) {
|
|---|
| 808 | const fallbackModule = /** @type {Module} */ (hasFailed);
|
|---|
| 809 |
|
|---|
| 810 | const fallbackIssuers = [
|
|---|
| 811 | ...compilation.moduleGraph
|
|---|
| 812 | .getIncomingConnectionsByOriginModule(fallbackModule)
|
|---|
| 813 | .keys()
|
|---|
| 814 | ].filter(Boolean);
|
|---|
| 815 |
|
|---|
| 816 | const selectedIssuers = [
|
|---|
| 817 | ...compilation.moduleGraph
|
|---|
| 818 | .getIncomingConnectionsByOriginModule(selectedModule)
|
|---|
| 819 | .keys()
|
|---|
| 820 | ].filter(Boolean);
|
|---|
| 821 |
|
|---|
| 822 | const allIssuers = [
|
|---|
| 823 | ...new Set([...fallbackIssuers, ...selectedIssuers])
|
|---|
| 824 | ]
|
|---|
| 825 | .map((m) =>
|
|---|
| 826 | /** @type {Module} */ (m).readableIdentifier(
|
|---|
| 827 | compilation.requestShortener
|
|---|
| 828 | )
|
|---|
| 829 | )
|
|---|
| 830 | .sort();
|
|---|
| 831 |
|
|---|
| 832 | // There is a not resolve-able conflict with the selectedModule
|
|---|
| 833 | compilation.warnings.push(
|
|---|
| 834 | new WebpackError(
|
|---|
| 835 | `chunk ${
|
|---|
| 836 | chunk.name || chunk.id
|
|---|
| 837 | }\nConflicting order between ${fallbackModule.readableIdentifier(
|
|---|
| 838 | compilation.requestShortener
|
|---|
| 839 | )} and ${selectedModule.readableIdentifier(
|
|---|
| 840 | compilation.requestShortener
|
|---|
| 841 | )}\nCSS modules are imported in:\n - ${allIssuers.join("\n - ")}`
|
|---|
| 842 | )
|
|---|
| 843 | );
|
|---|
| 844 | selectedModule = fallbackModule;
|
|---|
| 845 | }
|
|---|
| 846 | // Insert the selected module into the final modules list
|
|---|
| 847 | finalModules.push(selectedModule);
|
|---|
| 848 | // Remove the selected module from all lists
|
|---|
| 849 | for (const { list, set } of modulesByChunkGroup) {
|
|---|
| 850 | const lastModule = list[list.length - 1];
|
|---|
| 851 | if (lastModule === selectedModule) {
|
|---|
| 852 | list.pop();
|
|---|
| 853 | } else if (hasFailed && set.has(selectedModule)) {
|
|---|
| 854 | const idx = list.indexOf(selectedModule);
|
|---|
| 855 | if (idx >= 0) list.splice(idx, 1);
|
|---|
| 856 | }
|
|---|
| 857 | }
|
|---|
| 858 | modulesByChunkGroup.sort(compareModuleLists);
|
|---|
| 859 | }
|
|---|
| 860 | return finalModules;
|
|---|
| 861 | }
|
|---|
| 862 |
|
|---|
| 863 | /**
|
|---|
| 864 | * Gets ordered chunk css modules.
|
|---|
| 865 | * @param {Chunk} chunk chunk
|
|---|
| 866 | * @param {ChunkGraph} chunkGraph chunk graph
|
|---|
| 867 | * @param {Compilation} compilation compilation
|
|---|
| 868 | * @returns {CssModule[]} ordered css modules
|
|---|
| 869 | */
|
|---|
| 870 | getOrderedChunkCssModules(chunk, chunkGraph, compilation) {
|
|---|
| 871 | /** @type {string | undefined} */
|
|---|
| 872 | let charset;
|
|---|
| 873 |
|
|---|
| 874 | const hooks = CssModulesPlugin.getCompilationHooks(compilation);
|
|---|
| 875 |
|
|---|
| 876 | /**
|
|---|
| 877 | * @param {Iterable<Module> | undefined} iter modules pre-sorted by full module name
|
|---|
| 878 | * @returns {Module[]} ordered modules
|
|---|
| 879 | */
|
|---|
| 880 | const orderModules = (iter) => {
|
|---|
| 881 | const modules = iter ? [...iter] : [];
|
|---|
| 882 | const result = hooks.orderModules.call(chunk, modules, compilation);
|
|---|
| 883 | if (result !== undefined) return result;
|
|---|
| 884 | return this.getModulesInOrder(chunk, modules, compilation);
|
|---|
| 885 | };
|
|---|
| 886 |
|
|---|
| 887 | return /** @type {CssModule[]} */ ([
|
|---|
| 888 | ...orderModules(
|
|---|
| 889 | chunkGraph.getOrderedChunkModulesIterableBySourceType(
|
|---|
| 890 | chunk,
|
|---|
| 891 | CSS_IMPORT_TYPE,
|
|---|
| 892 | compareModulesByFullName(compilation.compiler)
|
|---|
| 893 | )
|
|---|
| 894 | ),
|
|---|
| 895 | ...orderModules(
|
|---|
| 896 | chunkGraph.getOrderedChunkModulesIterableBySourceType(
|
|---|
| 897 | chunk,
|
|---|
| 898 | CSS_TYPE,
|
|---|
| 899 | compareModulesByFullName(compilation.compiler)
|
|---|
| 900 | )
|
|---|
| 901 | ).map((module) => {
|
|---|
| 902 | if (
|
|---|
| 903 | typeof (/** @type {BuildInfo} */ (module.buildInfo).charset) !==
|
|---|
| 904 | "undefined"
|
|---|
| 905 | ) {
|
|---|
| 906 | if (
|
|---|
| 907 | typeof charset !== "undefined" &&
|
|---|
| 908 | charset !== /** @type {BuildInfo} */ (module.buildInfo).charset
|
|---|
| 909 | ) {
|
|---|
| 910 | const err = new WebpackError(
|
|---|
| 911 | `Conflicting @charset at-rules detected: the module ${module.readableIdentifier(
|
|---|
| 912 | compilation.requestShortener
|
|---|
| 913 | )} (in chunk ${chunk.name || chunk.id}) specifies "${
|
|---|
| 914 | /** @type {BuildInfo} */ (module.buildInfo).charset
|
|---|
| 915 | }", but "${charset}" was expected, all modules must use the same character set`
|
|---|
| 916 | );
|
|---|
| 917 |
|
|---|
| 918 | err.chunk = chunk;
|
|---|
| 919 | err.module = module;
|
|---|
| 920 | err.hideStack = true;
|
|---|
| 921 |
|
|---|
| 922 | compilation.warnings.push(err);
|
|---|
| 923 | }
|
|---|
| 924 |
|
|---|
| 925 | if (typeof charset === "undefined") {
|
|---|
| 926 | charset = /** @type {BuildInfo} */ (module.buildInfo).charset;
|
|---|
| 927 | }
|
|---|
| 928 | }
|
|---|
| 929 |
|
|---|
| 930 | return module;
|
|---|
| 931 | })
|
|---|
| 932 | ]);
|
|---|
| 933 | }
|
|---|
| 934 |
|
|---|
| 935 | /**
|
|---|
| 936 | * Renders css module source.
|
|---|
| 937 | * @param {CssModule} module css module
|
|---|
| 938 | * @param {ChunkRenderContext} renderContext options object
|
|---|
| 939 | * @param {CompilationHooks} hooks hooks
|
|---|
| 940 | * @returns {Source | null} css module source
|
|---|
| 941 | */
|
|---|
| 942 | static renderModule(module, renderContext, hooks) {
|
|---|
| 943 | const { undoPath, hash, moduleFactoryCache, moduleSourceContent } =
|
|---|
| 944 | renderContext;
|
|---|
| 945 | const cacheEntry = moduleFactoryCache.get(moduleSourceContent);
|
|---|
| 946 |
|
|---|
| 947 | /** @type {Inheritance} */
|
|---|
| 948 | const inheritance = [[module.cssLayer, module.supports, module.media]];
|
|---|
| 949 | if (module.inheritance) {
|
|---|
| 950 | inheritance.push(...module.inheritance);
|
|---|
| 951 | }
|
|---|
| 952 |
|
|---|
| 953 | /** @type {CachedSource} */
|
|---|
| 954 | let source;
|
|---|
| 955 | if (
|
|---|
| 956 | cacheEntry &&
|
|---|
| 957 | cacheEntry.undoPath === undoPath &&
|
|---|
| 958 | cacheEntry.hash === hash &&
|
|---|
| 959 | cacheEntry.inheritance.length === inheritance.length &&
|
|---|
| 960 | cacheEntry.inheritance.every(([layer, supports, media], i) => {
|
|---|
| 961 | const item = inheritance[i];
|
|---|
| 962 | if (Array.isArray(item)) {
|
|---|
| 963 | return layer === item[0] && supports === item[1] && media === item[2];
|
|---|
| 964 | }
|
|---|
| 965 | return false;
|
|---|
| 966 | })
|
|---|
| 967 | ) {
|
|---|
| 968 | source = cacheEntry.source;
|
|---|
| 969 | } else {
|
|---|
| 970 | if (!moduleSourceContent) return null;
|
|---|
| 971 | const moduleSourceCode =
|
|---|
| 972 | /** @type {string} */
|
|---|
| 973 | (moduleSourceContent.source());
|
|---|
| 974 | const replaceSource = new ReplaceSource(moduleSourceContent);
|
|---|
| 975 |
|
|---|
| 976 | const autoPlaceholder = CssUrlDependency.PUBLIC_PATH_AUTO;
|
|---|
| 977 | const autoPlaceholderLen = autoPlaceholder.length;
|
|---|
| 978 | for (
|
|---|
| 979 | let idx = moduleSourceCode.indexOf(autoPlaceholder);
|
|---|
| 980 | idx !== -1;
|
|---|
| 981 | idx = moduleSourceCode.indexOf(
|
|---|
| 982 | autoPlaceholder,
|
|---|
| 983 | idx + autoPlaceholderLen
|
|---|
| 984 | )
|
|---|
| 985 | ) {
|
|---|
| 986 | replaceSource.replace(idx, idx + autoPlaceholderLen - 1, undoPath);
|
|---|
| 987 | }
|
|---|
| 988 |
|
|---|
| 989 | if (hash) {
|
|---|
| 990 | const hashPrefix = CssUrlDependency.PUBLIC_PATH_FULL_HASH;
|
|---|
| 991 | const hashPrefixLen = hashPrefix.length;
|
|---|
| 992 | const sourceLen = moduleSourceCode.length;
|
|---|
| 993 | let idx = moduleSourceCode.indexOf(hashPrefix);
|
|---|
| 994 | while (idx !== -1) {
|
|---|
| 995 | let digitEnd = idx + hashPrefixLen;
|
|---|
| 996 | while (digitEnd < sourceLen) {
|
|---|
| 997 | const cc = moduleSourceCode.charCodeAt(digitEnd);
|
|---|
| 998 | if (cc < 48 || cc > 57) break;
|
|---|
| 999 | digitEnd++;
|
|---|
| 1000 | }
|
|---|
| 1001 | let nextSearch;
|
|---|
| 1002 | if (
|
|---|
| 1003 | digitEnd > idx + hashPrefixLen &&
|
|---|
| 1004 | digitEnd + 1 < sourceLen &&
|
|---|
| 1005 | moduleSourceCode.charCodeAt(digitEnd) === 95 &&
|
|---|
| 1006 | moduleSourceCode.charCodeAt(digitEnd + 1) === 95
|
|---|
| 1007 | ) {
|
|---|
| 1008 | const length = Number.parseInt(
|
|---|
| 1009 | moduleSourceCode.slice(idx + hashPrefixLen, digitEnd),
|
|---|
| 1010 | 10
|
|---|
| 1011 | );
|
|---|
| 1012 | replaceSource.replace(
|
|---|
| 1013 | idx,
|
|---|
| 1014 | digitEnd + 1,
|
|---|
| 1015 | length === 0 ? hash : hash.slice(0, length)
|
|---|
| 1016 | );
|
|---|
| 1017 | nextSearch = digitEnd + 2;
|
|---|
| 1018 | } else {
|
|---|
| 1019 | nextSearch = idx + hashPrefixLen;
|
|---|
| 1020 | }
|
|---|
| 1021 | idx = moduleSourceCode.indexOf(hashPrefix, nextSearch);
|
|---|
| 1022 | }
|
|---|
| 1023 | }
|
|---|
| 1024 |
|
|---|
| 1025 | /** @type {Source} */
|
|---|
| 1026 | let moduleSource = replaceSource;
|
|---|
| 1027 |
|
|---|
| 1028 | for (let i = 0; i < inheritance.length; i++) {
|
|---|
| 1029 | const layer = inheritance[i][0];
|
|---|
| 1030 | const supports = inheritance[i][1];
|
|---|
| 1031 | const media = inheritance[i][2];
|
|---|
| 1032 |
|
|---|
| 1033 | if (media) {
|
|---|
| 1034 | moduleSource = new ConcatSource(
|
|---|
| 1035 | `@media ${media} {\n`,
|
|---|
| 1036 | new PrefixSource("\t", moduleSource),
|
|---|
| 1037 | "}\n"
|
|---|
| 1038 | );
|
|---|
| 1039 | }
|
|---|
| 1040 |
|
|---|
| 1041 | if (supports) {
|
|---|
| 1042 | moduleSource = new ConcatSource(
|
|---|
| 1043 | `@supports (${supports}) {\n`,
|
|---|
| 1044 | new PrefixSource("\t", moduleSource),
|
|---|
| 1045 | "}\n"
|
|---|
| 1046 | );
|
|---|
| 1047 | }
|
|---|
| 1048 |
|
|---|
| 1049 | // Layer can be anonymous
|
|---|
| 1050 | if (layer !== undefined && layer !== null) {
|
|---|
| 1051 | moduleSource = new ConcatSource(
|
|---|
| 1052 | `@layer${layer ? ` ${layer}` : ""} {\n`,
|
|---|
| 1053 | new PrefixSource("\t", moduleSource),
|
|---|
| 1054 | "}\n"
|
|---|
| 1055 | );
|
|---|
| 1056 | }
|
|---|
| 1057 | }
|
|---|
| 1058 |
|
|---|
| 1059 | if (moduleSource) {
|
|---|
| 1060 | moduleSource = new ConcatSource(moduleSource, "\n");
|
|---|
| 1061 | }
|
|---|
| 1062 |
|
|---|
| 1063 | source = new CachedSource(moduleSource);
|
|---|
| 1064 | moduleFactoryCache.set(moduleSourceContent, {
|
|---|
| 1065 | inheritance,
|
|---|
| 1066 | undoPath,
|
|---|
| 1067 | hash,
|
|---|
| 1068 | source
|
|---|
| 1069 | });
|
|---|
| 1070 | }
|
|---|
| 1071 |
|
|---|
| 1072 | return tryRunOrWebpackError(
|
|---|
| 1073 | () => hooks.renderModulePackage.call(source, module, renderContext),
|
|---|
| 1074 | "CssModulesPlugin.getCompilationHooks().renderModulePackage"
|
|---|
| 1075 | );
|
|---|
| 1076 | }
|
|---|
| 1077 |
|
|---|
| 1078 | /**
|
|---|
| 1079 | * Renders generated source.
|
|---|
| 1080 | * @param {RenderContext} renderContext the render context
|
|---|
| 1081 | * @param {CompilationHooks} hooks hooks
|
|---|
| 1082 | * @returns {Source} generated source
|
|---|
| 1083 | */
|
|---|
| 1084 | renderChunk(
|
|---|
| 1085 | {
|
|---|
| 1086 | undoPath,
|
|---|
| 1087 | chunk,
|
|---|
| 1088 | codeGenerationResults,
|
|---|
| 1089 | modules,
|
|---|
| 1090 | runtimeTemplate,
|
|---|
| 1091 | chunkGraph,
|
|---|
| 1092 | hash
|
|---|
| 1093 | },
|
|---|
| 1094 | hooks
|
|---|
| 1095 | ) {
|
|---|
| 1096 | const source = new ConcatSource();
|
|---|
| 1097 |
|
|---|
| 1098 | /** @type {string | undefined} */
|
|---|
| 1099 | let charset;
|
|---|
| 1100 |
|
|---|
| 1101 | for (const module of modules) {
|
|---|
| 1102 | if (
|
|---|
| 1103 | typeof (/** @type {BuildInfo} */ (module.buildInfo).charset) !==
|
|---|
| 1104 | "undefined" &&
|
|---|
| 1105 | typeof charset === "undefined"
|
|---|
| 1106 | ) {
|
|---|
| 1107 | charset = /** @type {BuildInfo} */ (module.buildInfo).charset;
|
|---|
| 1108 | }
|
|---|
| 1109 |
|
|---|
| 1110 | try {
|
|---|
| 1111 | const codeGenResult = codeGenerationResults.get(module, chunk.runtime);
|
|---|
| 1112 | const moduleSourceContent =
|
|---|
| 1113 | /** @type {Source} */
|
|---|
| 1114 | (
|
|---|
| 1115 | codeGenResult.sources.get(CSS_TYPE) ||
|
|---|
| 1116 | codeGenResult.sources.get(CSS_IMPORT_TYPE)
|
|---|
| 1117 | );
|
|---|
| 1118 | const moduleSource = CssModulesPlugin.renderModule(
|
|---|
| 1119 | module,
|
|---|
| 1120 | {
|
|---|
| 1121 | undoPath,
|
|---|
| 1122 | hash,
|
|---|
| 1123 | chunk,
|
|---|
| 1124 | chunkGraph,
|
|---|
| 1125 | codeGenerationResults,
|
|---|
| 1126 | moduleSourceContent,
|
|---|
| 1127 | moduleFactoryCache: this._moduleFactoryCache,
|
|---|
| 1128 | runtimeTemplate
|
|---|
| 1129 | },
|
|---|
| 1130 | hooks
|
|---|
| 1131 | );
|
|---|
| 1132 | if (moduleSource) {
|
|---|
| 1133 | source.add(moduleSource);
|
|---|
| 1134 | }
|
|---|
| 1135 | } catch (err) {
|
|---|
| 1136 | /** @type {Error} */
|
|---|
| 1137 | (err).message += `\nduring rendering of css ${module.identifier()}`;
|
|---|
| 1138 | throw err;
|
|---|
| 1139 | }
|
|---|
| 1140 | }
|
|---|
| 1141 |
|
|---|
| 1142 | chunk.rendered = true;
|
|---|
| 1143 |
|
|---|
| 1144 | if (charset) {
|
|---|
| 1145 | return new ConcatSource(`@charset "${charset}";\n`, source);
|
|---|
| 1146 | }
|
|---|
| 1147 |
|
|---|
| 1148 | return source;
|
|---|
| 1149 | }
|
|---|
| 1150 |
|
|---|
| 1151 | /**
|
|---|
| 1152 | * Gets chunk filename template.
|
|---|
| 1153 | * @param {Chunk} chunk chunk
|
|---|
| 1154 | * @param {OutputOptions} outputOptions output options
|
|---|
| 1155 | * @returns {ChunkFilenameTemplate} used filename template
|
|---|
| 1156 | */
|
|---|
| 1157 | static getChunkFilenameTemplate(chunk, outputOptions) {
|
|---|
| 1158 | if (chunk.cssFilenameTemplate) {
|
|---|
| 1159 | return chunk.cssFilenameTemplate;
|
|---|
| 1160 | } else if (chunk.canBeInitial()) {
|
|---|
| 1161 | return outputOptions.cssFilename;
|
|---|
| 1162 | }
|
|---|
| 1163 | return outputOptions.cssChunkFilename;
|
|---|
| 1164 | }
|
|---|
| 1165 |
|
|---|
| 1166 | /**
|
|---|
| 1167 | * Returns true, when the chunk has css.
|
|---|
| 1168 | * @param {Chunk} chunk chunk
|
|---|
| 1169 | * @param {ChunkGraph} chunkGraph chunk graph
|
|---|
| 1170 | * @returns {boolean} true, when the chunk has css
|
|---|
| 1171 | */
|
|---|
| 1172 | static chunkHasCss(chunk, chunkGraph) {
|
|---|
| 1173 | return (
|
|---|
| 1174 | Boolean(
|
|---|
| 1175 | chunkGraph.getChunkModulesIterableBySourceType(chunk, CSS_TYPE)
|
|---|
| 1176 | ) ||
|
|---|
| 1177 | Boolean(
|
|---|
| 1178 | chunkGraph.getChunkModulesIterableBySourceType(chunk, CSS_IMPORT_TYPE)
|
|---|
| 1179 | )
|
|---|
| 1180 | );
|
|---|
| 1181 | }
|
|---|
| 1182 | }
|
|---|
| 1183 |
|
|---|
| 1184 | module.exports = CssModulesPlugin;
|
|---|