| | |
| | | const CssModule = require("../CssModule"); |
| | | const { tryRunOrWebpackError } = require("../HookWebpackError"); |
| | | const HotUpdateChunk = require("../HotUpdateChunk"); |
| | | const { CSS_IMPORT_TYPE, CSS_TYPE } = require("../ModuleSourceTypeConstants"); |
| | | const { |
| | | CSS_MODULE_TYPE, |
| | | CSS_MODULE_TYPE_AUTO, |
| | |
| | | } = require("../ModuleTypeConstants"); |
| | | const NormalModule = require("../NormalModule"); |
| | | const RuntimeGlobals = require("../RuntimeGlobals"); |
| | | const SelfModuleFactory = require("../SelfModuleFactory"); |
| | | const Template = require("../Template"); |
| | | const WebpackError = require("../WebpackError"); |
| | | const CssIcssExportDependency = require("../dependencies/CssIcssExportDependency"); |
| | | const CssIcssFromIdentifierDependency = require("../dependencies/CssIcssFromIdentifierDependency"); |
| | | const CssIcssGlobalIdentifierDependency = require("../dependencies/CssIcssGlobalIdentifierDependency"); |
| | | const CssIcssImportDependency = require("../dependencies/CssIcssImportDependency"); |
| | | const CssIcssLocalIdentifierDependency = require("../dependencies/CssIcssLocalIdentifierDependency"); |
| | | const CssIcssSelfLocalIdentifierDependency = require("../dependencies/CssIcssSelfLocalIdentifierDependency"); |
| | | const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency"); |
| | | const CssImportDependency = require("../dependencies/CssImportDependency"); |
| | | const CssUrlDependency = require("../dependencies/CssUrlDependency"); |
| | | const StaticExportsDependency = require("../dependencies/StaticExportsDependency"); |
| | | const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin"); |
| | | const { compareModulesByIdOrIdentifier } = require("../util/comparators"); |
| | | const createSchemaValidation = require("../util/create-schema-validation"); |
| | | const { compareModulesByFullName } = require("../util/comparators"); |
| | | const createHash = require("../util/createHash"); |
| | | const { getUndoPath } = require("../util/identifier"); |
| | | const memoize = require("../util/memoize"); |
| | | const nonNumericOnlyHash = require("../util/nonNumericOnlyHash"); |
| | | const removeBOM = require("../util/removeBOM"); |
| | | const CssGenerator = require("./CssGenerator"); |
| | | const CssMergeStyleSheetsRuntimeModule = require("./CssMergeStyleSheetsRuntimeModule"); |
| | | const CssParser = require("./CssParser"); |
| | | |
| | | const publicPathAutoRegex = new RegExp(CssUrlDependency.PUBLIC_PATH_AUTO, "g"); |
| | | |
| | | /** @typedef {import("webpack-sources").Source} Source */ |
| | | /** @typedef {import("../config/defaults").OutputNormalizedWithDefaults} OutputOptions */ |
| | |
| | | /** @typedef {import("../Module").BuildMeta} BuildMeta */ |
| | | |
| | | /** |
| | | * Defines the render context type used by this module. |
| | | * @typedef {object} RenderContext |
| | | * @property {Chunk} chunk the chunk |
| | | * @property {ChunkGraph} chunkGraph the chunk graph |
| | |
| | | */ |
| | | |
| | | /** |
| | | * Defines the chunk render context type used by this module. |
| | | * @typedef {object} ChunkRenderContext |
| | | * @property {Chunk=} chunk the chunk |
| | | * @property {ChunkGraph=} chunkGraph the chunk graph |
| | |
| | | */ |
| | | |
| | | /** |
| | | * Defines the compilation hooks type used by this module. |
| | | * @typedef {object} CompilationHooks |
| | | * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModulePackage |
| | | * @property {SyncHook<[Chunk, Hash, ChunkHashContext]>} chunkHash |
| | | */ |
| | | |
| | | /** |
| | | * Defines the module factory cache entry type used by this module. |
| | | * @typedef {object} ModuleFactoryCacheEntry |
| | | * @property {string} undoPath - The undo path to the CSS file |
| | | * @property {Inheritance} inheritance - The inheritance chain |
| | |
| | | const getCssLoadingRuntimeModule = memoize(() => |
| | | require("./CssLoadingRuntimeModule") |
| | | ); |
| | | const getCssMergeStyleSheetsRuntimeModule = memoize(() => |
| | | require("./CssMergeStyleSheetsRuntimeModule") |
| | | ); |
| | | const getCssInjectStyleRuntimeModule = memoize(() => |
| | | require("./CssInjectStyleRuntimeModule") |
| | | ); |
| | | |
| | | /** |
| | | * Returns ], definitions: import("../../schemas/WebpackOptions.json")["definitions"] }} schema. |
| | | * @param {string} name name |
| | | * @returns {{ oneOf: [{ $ref: string }], definitions: import("../../schemas/WebpackOptions.json")["definitions"] }} schema |
| | | */ |
| | |
| | | }; |
| | | }; |
| | | |
| | | const generatorValidationOptions = { |
| | | name: "Css Modules Plugin", |
| | | baseDataPath: "generator" |
| | | }; |
| | | const validateGeneratorOptions = { |
| | | css: createSchemaValidation( |
| | | require("../../schemas/plugins/css/CssGeneratorOptions.check"), |
| | | () => getSchema("CssGeneratorOptions"), |
| | | generatorValidationOptions |
| | | ), |
| | | "css/auto": createSchemaValidation( |
| | | require("../../schemas/plugins/css/CssAutoGeneratorOptions.check"), |
| | | () => getSchema("CssAutoGeneratorOptions"), |
| | | generatorValidationOptions |
| | | ), |
| | | "css/module": createSchemaValidation( |
| | | require("../../schemas/plugins/css/CssModuleGeneratorOptions.check"), |
| | | () => getSchema("CssModuleGeneratorOptions"), |
| | | generatorValidationOptions |
| | | ), |
| | | "css/global": createSchemaValidation( |
| | | require("../../schemas/plugins/css/CssGlobalGeneratorOptions.check"), |
| | | () => getSchema("CssGlobalGeneratorOptions"), |
| | | generatorValidationOptions |
| | | ) |
| | | }; |
| | | |
| | | const parserValidationOptions = { |
| | | name: "Css Modules Plugin", |
| | | baseDataPath: "parser" |
| | | }; |
| | | const validateParserOptions = { |
| | | css: createSchemaValidation( |
| | | require("../../schemas/plugins/css/CssParserOptions.check"), |
| | | () => getSchema("CssParserOptions"), |
| | | parserValidationOptions |
| | | ), |
| | | "css/auto": createSchemaValidation( |
| | | require("../../schemas/plugins/css/CssAutoParserOptions.check"), |
| | | () => getSchema("CssAutoParserOptions"), |
| | | parserValidationOptions |
| | | ), |
| | | "css/module": createSchemaValidation( |
| | | require("../../schemas/plugins/css/CssModuleParserOptions.check"), |
| | | () => getSchema("CssModuleParserOptions"), |
| | | parserValidationOptions |
| | | ), |
| | | "css/global": createSchemaValidation( |
| | | require("../../schemas/plugins/css/CssGlobalParserOptions.check"), |
| | | () => getSchema("CssGlobalParserOptions"), |
| | | parserValidationOptions |
| | | ) |
| | | |
| | | const generatorValidationOptions = { |
| | | name: "Css Modules Plugin", |
| | | baseDataPath: "generator" |
| | | }; |
| | | |
| | | /** @type {WeakMap<Compilation, CompilationHooks>} */ |
| | |
| | | |
| | | class CssModulesPlugin { |
| | | /** |
| | | * Returns the attached hooks. |
| | | * @param {Compilation} compilation the compilation |
| | | * @returns {CompilationHooks} the attached hooks |
| | | */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * Apply the plugin |
| | | * Applies the plugin by registering its hooks on the compiler. |
| | | * @param {Compiler} compiler the compiler instance |
| | | * @returns {void} |
| | | */ |
| | |
| | | PLUGIN_NAME, |
| | | (compilation, { normalModuleFactory }) => { |
| | | const hooks = CssModulesPlugin.getCompilationHooks(compilation); |
| | | const selfFactory = new SelfModuleFactory(compilation.moduleGraph); |
| | | compilation.dependencyFactories.set( |
| | | CssImportDependency, |
| | | normalModuleFactory |
| | |
| | | CssUrlDependency, |
| | | new CssUrlDependency.Template() |
| | | ); |
| | | compilation.dependencyTemplates.set( |
| | | CssIcssLocalIdentifierDependency, |
| | | new CssIcssLocalIdentifierDependency.Template() |
| | | ); |
| | | compilation.dependencyFactories.set( |
| | | CssIcssSelfLocalIdentifierDependency, |
| | | selfFactory |
| | | ); |
| | | compilation.dependencyTemplates.set( |
| | | CssIcssSelfLocalIdentifierDependency, |
| | | new CssIcssSelfLocalIdentifierDependency.Template() |
| | | ); |
| | | compilation.dependencyFactories.set( |
| | | CssIcssImportDependency, |
| | | normalModuleFactory |
| | |
| | | compilation.dependencyTemplates.set( |
| | | CssIcssImportDependency, |
| | | new CssIcssImportDependency.Template() |
| | | ); |
| | | compilation.dependencyFactories.set( |
| | | CssIcssFromIdentifierDependency, |
| | | normalModuleFactory |
| | | ); |
| | | compilation.dependencyTemplates.set( |
| | | CssIcssFromIdentifierDependency, |
| | | new CssIcssFromIdentifierDependency.Template() |
| | | ); |
| | | compilation.dependencyFactories.set( |
| | | CssIcssGlobalIdentifierDependency, |
| | | normalModuleFactory |
| | | ); |
| | | compilation.dependencyTemplates.set( |
| | | CssIcssGlobalIdentifierDependency, |
| | | new CssIcssGlobalIdentifierDependency.Template() |
| | | ); |
| | | compilation.dependencyTemplates.set( |
| | | CssIcssExportDependency, |
| | |
| | | normalModuleFactory.hooks.createParser |
| | | .for(type) |
| | | .tap(PLUGIN_NAME, (parserOptions) => { |
| | | validateParserOptions[type](parserOptions); |
| | | const { |
| | | url, |
| | | import: importOption, |
| | | namedExports, |
| | | exportType |
| | | } = parserOptions; |
| | | /** @type {undefined | "global" | "local" | "auto"} */ |
| | | let defaultMode; |
| | | |
| | | switch (type) { |
| | | case CSS_MODULE_TYPE: |
| | | return new CssParser({ |
| | | importOption, |
| | | url, |
| | | namedExports, |
| | | exportType |
| | | }); |
| | | case CSS_MODULE_TYPE_GLOBAL: |
| | | return new CssParser({ |
| | | defaultMode: "global", |
| | | importOption, |
| | | url, |
| | | namedExports, |
| | | exportType |
| | | }); |
| | | case CSS_MODULE_TYPE_MODULE: |
| | | return new CssParser({ |
| | | defaultMode: "local", |
| | | importOption, |
| | | url, |
| | | namedExports, |
| | | exportType |
| | | }); |
| | | case CSS_MODULE_TYPE_AUTO: |
| | | return new CssParser({ |
| | | defaultMode: "auto", |
| | | importOption, |
| | | url, |
| | | namedExports, |
| | | exportType |
| | | }); |
| | | case CSS_MODULE_TYPE: { |
| | | compiler.validate( |
| | | () => getSchema("CssParserOptions"), |
| | | parserOptions, |
| | | parserValidationOptions, |
| | | (options) => |
| | | require("../../schemas/plugins/css/CssParserOptions.check")( |
| | | options |
| | | ) |
| | | ); |
| | | |
| | | break; |
| | | } |
| | | case CSS_MODULE_TYPE_GLOBAL: { |
| | | defaultMode = "global"; |
| | | compiler.validate( |
| | | () => getSchema("CssModuleParserOptions"), |
| | | parserOptions, |
| | | parserValidationOptions, |
| | | (options) => |
| | | require("../../schemas/plugins/css/CssModuleParserOptions.check")( |
| | | options |
| | | ) |
| | | ); |
| | | break; |
| | | } |
| | | case CSS_MODULE_TYPE_MODULE: { |
| | | defaultMode = "local"; |
| | | compiler.validate( |
| | | () => getSchema("CssModuleParserOptions"), |
| | | parserOptions, |
| | | parserValidationOptions, |
| | | (options) => |
| | | require("../../schemas/plugins/css/CssModuleParserOptions.check")( |
| | | options |
| | | ) |
| | | ); |
| | | break; |
| | | } |
| | | case CSS_MODULE_TYPE_AUTO: { |
| | | defaultMode = "auto"; |
| | | compiler.validate( |
| | | () => getSchema("CssModuleParserOptions"), |
| | | parserOptions, |
| | | parserValidationOptions, |
| | | (options) => |
| | | require("../../schemas/plugins/css/CssModuleParserOptions.check")( |
| | | options |
| | | ) |
| | | ); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return new CssParser({ |
| | | defaultMode, |
| | | ...parserOptions |
| | | }); |
| | | }); |
| | | normalModuleFactory.hooks.createGenerator |
| | | .for(type) |
| | | .tap(PLUGIN_NAME, (generatorOptions) => { |
| | | validateGeneratorOptions[type](generatorOptions); |
| | | switch (type) { |
| | | case CSS_MODULE_TYPE: { |
| | | compiler.validate( |
| | | () => getSchema("CssGeneratorOptions"), |
| | | generatorOptions, |
| | | generatorValidationOptions, |
| | | (options) => |
| | | require("../../schemas/plugins/css/CssGeneratorOptions.check")( |
| | | options |
| | | ) |
| | | ); |
| | | |
| | | break; |
| | | } |
| | | case CSS_MODULE_TYPE_GLOBAL: { |
| | | compiler.validate( |
| | | () => getSchema("CssModuleGeneratorOptions"), |
| | | generatorOptions, |
| | | generatorValidationOptions, |
| | | (options) => |
| | | require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")( |
| | | options |
| | | ) |
| | | ); |
| | | |
| | | break; |
| | | } |
| | | case CSS_MODULE_TYPE_MODULE: { |
| | | compiler.validate( |
| | | () => getSchema("CssModuleGeneratorOptions"), |
| | | generatorOptions, |
| | | generatorValidationOptions, |
| | | (options) => |
| | | require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")( |
| | | options |
| | | ) |
| | | ); |
| | | |
| | | break; |
| | | } |
| | | case CSS_MODULE_TYPE_AUTO: { |
| | | compiler.validate( |
| | | () => getSchema("CssModuleGeneratorOptions"), |
| | | generatorOptions, |
| | | generatorValidationOptions, |
| | | (options) => |
| | | require("../../schemas/plugins/css/CssModuleGeneratorOptions.check")( |
| | | options |
| | | ) |
| | | ); |
| | | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return new CssGenerator( |
| | | generatorOptions, |
| | |
| | | normalModuleFactory.hooks.createModuleClass |
| | | .for(type) |
| | | .tap(PLUGIN_NAME, (createData, resolveData) => { |
| | | const exportType = |
| | | /** @type {CssParser} */ |
| | | (createData.parser).options.exportType; |
| | | if (resolveData.dependencies.length > 0) { |
| | | // When CSS is imported from CSS there is only one dependency |
| | | const dependency = resolveData.dependencies[0]; |
| | |
| | | (compilation.moduleGraph.getParentModule(dependency)); |
| | | |
| | | if (parent instanceof CssModule) { |
| | | /** @type {import("../CssModule").Inheritance | undefined} */ |
| | | /** @type {Inheritance | undefined} */ |
| | | let inheritance; |
| | | |
| | | if ( |
| | |
| | | cssLayer: dependency.layer, |
| | | supports: dependency.supports, |
| | | media: dependency.media, |
| | | inheritance |
| | | inheritance, |
| | | exportType: parent.exportType || exportType |
| | | }) |
| | | ); |
| | | } |
| | |
| | | ...createData, |
| | | cssLayer: dependency.layer, |
| | | supports: dependency.supports, |
| | | media: dependency.media |
| | | media: dependency.media, |
| | | exportType |
| | | }) |
| | | ); |
| | | } |
| | |
| | | |
| | | return new CssModule( |
| | | /** @type {CSSModuleCreateData} */ |
| | | (createData) |
| | | ( |
| | | /** @type {unknown} */ ({ |
| | | ...createData, |
| | | exportType |
| | | }) |
| | | ) |
| | | ); |
| | | }); |
| | | |
| | |
| | | compilation |
| | | ).renderModuleContent.tap(PLUGIN_NAME, (source, module) => { |
| | | if (module instanceof CssModule && module.hot) { |
| | | const exportType = module.exportType; |
| | | // When exportType !== "link", modules behave like JavaScript modules |
| | | if (exportType && !["link", "style"].includes(exportType)) { |
| | | return source; |
| | | } |
| | | // For exportType === "link", we can optimize with self-acceptance |
| | | const cssData = /** @type {BuildInfo} */ (module.buildInfo).cssData; |
| | | if (!cssData) { |
| | | return source; |
| | | } |
| | | const exports = cssData.exports; |
| | | /** @type {Record<string, string>} */ |
| | | const exportsObj = {}; |
| | | for (const [key, value] of exports) { |
| | | exportsObj[key] = value; |
| | | } |
| | | const stringifiedExports = JSON.stringify( |
| | | JSON.stringify( |
| | | [...exports].reduce((obj, [key, value]) => { |
| | | obj[key] = value; |
| | | return obj; |
| | | }, /** @type {Record<string, string>} */ ({})) |
| | | ) |
| | | JSON.stringify(exportsObj) |
| | | ); |
| | | |
| | | const hmrCode = Template.asString([ |
| | |
| | | "} else {", |
| | | Template.indent("module.hot.accept();"), |
| | | "}", |
| | | "module.hot.dispose(function(data) { data.__webpack_css_exports__ = __webpack_css_exports__; });" |
| | | "module.hot.dispose(function(data) {", |
| | | Template.indent([ |
| | | "data.__webpack_css_exports__ = __webpack_css_exports__;" |
| | | ]), |
| | | "});" |
| | | ]); |
| | | |
| | | return new ConcatSource(source, "\n", new RawSource(hmrCode)); |
| | |
| | | |
| | | return source; |
| | | }); |
| | | /** @type {WeakMap<Chunk, CssModule[]>} */ |
| | | const orderedCssModulesPerChunk = new WeakMap(); |
| | | compilation.hooks.afterCodeGeneration.tap(PLUGIN_NAME, () => { |
| | | const { chunkGraph } = compilation; |
| | |
| | | }); |
| | | const globalChunkLoading = compilation.outputOptions.chunkLoading; |
| | | /** |
| | | * Checks whether this css modules plugin is enabled for chunk. |
| | | * @param {Chunk} chunk the chunk |
| | | * @returns {boolean} true, when enabled |
| | | */ |
| | |
| | | : globalChunkLoading; |
| | | return chunkLoading === "jsonp" || chunkLoading === "import"; |
| | | }; |
| | | /** @type {WeakSet<Chunk>} */ |
| | | const onceForChunkSet = new WeakSet(); |
| | | /** |
| | | * Handles the hook callback for this code path. |
| | | * @param {Chunk} chunk chunk to check |
| | | * @param {RuntimeRequirements} set runtime requirements |
| | | */ |
| | |
| | | compilation.hooks.runtimeRequirementInTree |
| | | .for(RuntimeGlobals.cssMergeStyleSheets) |
| | | .tap(PLUGIN_NAME, (chunk) => { |
| | | const CssMergeStyleSheetsRuntimeModule = |
| | | getCssMergeStyleSheetsRuntimeModule(); |
| | | compilation.addRuntimeModule( |
| | | chunk, |
| | | new CssMergeStyleSheetsRuntimeModule() |
| | | ); |
| | | }); |
| | | |
| | | compilation.hooks.runtimeRequirementInTree |
| | | .for(RuntimeGlobals.cssInjectStyle) |
| | | .tap(PLUGIN_NAME, (chunk, set) => { |
| | | const CssInjectStyleRuntimeModule = |
| | | getCssInjectStyleRuntimeModule(); |
| | | compilation.addRuntimeModule( |
| | | chunk, |
| | | new CssInjectStyleRuntimeModule(set) |
| | | ); |
| | | }); |
| | | } |
| | |
| | | } |
| | | |
| | | /** |
| | | * Gets modules in order. |
| | | * @param {Chunk} chunk chunk |
| | | * @param {Iterable<Module>} modules unordered modules |
| | | * @param {Iterable<Module> | undefined} modules unordered modules |
| | | * @param {Compilation} compilation compilation |
| | | * @returns {Module[]} ordered modules |
| | | */ |
| | |
| | | return modulesByChunkGroup[0].list.reverse(); |
| | | } |
| | | |
| | | const boundCompareModulesByIdOrIdentifier = compareModulesByIdOrIdentifier( |
| | | compilation.chunkGraph |
| | | const boundCompareModulesByFullName = compareModulesByFullName( |
| | | compilation.compiler |
| | | ); |
| | | |
| | | /** |
| | | * Compares module lists. |
| | | * @param {{ list: Module[] }} a a |
| | | * @param {{ list: Module[] }} b b |
| | | * @returns {-1 | 0 | 1} result |
| | |
| | | return b.length === 0 ? 0 : 1; |
| | | } |
| | | if (b.length === 0) return -1; |
| | | return boundCompareModulesByIdOrIdentifier( |
| | | a[a.length - 1], |
| | | b[b.length - 1] |
| | | ); |
| | | return boundCompareModulesByFullName(a[a.length - 1], b[b.length - 1]); |
| | | }; |
| | | |
| | | modulesByChunkGroup.sort(compareModuleLists); |
| | |
| | | const finalModules = []; |
| | | |
| | | for (;;) { |
| | | /** @type {Set<Module>} */ |
| | | const failedModules = new Set(); |
| | | const list = modulesByChunkGroup[0].list; |
| | | if (list.length === 0) { |
| | |
| | | } |
| | | /** @type {Module} */ |
| | | let selectedModule = list[list.length - 1]; |
| | | /** @type {undefined | false | Module} */ |
| | | let hasFailed; |
| | | outer: for (;;) { |
| | | for (const { list, set } of modulesByChunkGroup) { |
| | |
| | | break; |
| | | } |
| | | if (hasFailed) { |
| | | const fallbackModule = /** @type {Module} */ (hasFailed); |
| | | |
| | | const fallbackIssuers = [ |
| | | ...compilation.moduleGraph |
| | | .getIncomingConnectionsByOriginModule(fallbackModule) |
| | | .keys() |
| | | ].filter(Boolean); |
| | | |
| | | const selectedIssuers = [ |
| | | ...compilation.moduleGraph |
| | | .getIncomingConnectionsByOriginModule(selectedModule) |
| | | .keys() |
| | | ].filter(Boolean); |
| | | |
| | | const allIssuers = [ |
| | | ...new Set([...fallbackIssuers, ...selectedIssuers]) |
| | | ] |
| | | .map((m) => |
| | | /** @type {Module} */ (m).readableIdentifier( |
| | | compilation.requestShortener |
| | | ) |
| | | ) |
| | | .sort(); |
| | | |
| | | // There is a not resolve-able conflict with the selectedModule |
| | | // TODO print better warning |
| | | compilation.warnings.push( |
| | | new WebpackError( |
| | | `chunk ${chunk.name || chunk.id}\nConflicting order between ${ |
| | | /** @type {Module} */ |
| | | (hasFailed).readableIdentifier(compilation.requestShortener) |
| | | } and ${selectedModule.readableIdentifier( |
| | | `chunk ${ |
| | | chunk.name || chunk.id |
| | | }\nConflicting order between ${fallbackModule.readableIdentifier( |
| | | compilation.requestShortener |
| | | )}` |
| | | )} and ${selectedModule.readableIdentifier( |
| | | compilation.requestShortener |
| | | )}\nCSS modules are imported in:\n - ${allIssuers.join("\n - ")}` |
| | | ) |
| | | ); |
| | | selectedModule = /** @type {Module} */ (hasFailed); |
| | | selectedModule = fallbackModule; |
| | | } |
| | | // Insert the selected module into the final modules list |
| | | finalModules.push(selectedModule); |
| | |
| | | } |
| | | |
| | | /** |
| | | * Gets ordered chunk css modules. |
| | | * @param {Chunk} chunk chunk |
| | | * @param {ChunkGraph} chunkGraph chunk graph |
| | | * @param {Compilation} compilation compilation |
| | | * @returns {Module[]} ordered css modules |
| | | * @returns {CssModule[]} ordered css modules |
| | | */ |
| | | getOrderedChunkCssModules(chunk, chunkGraph, compilation) { |
| | | return [ |
| | | /** @type {string | undefined} */ |
| | | let charset; |
| | | |
| | | return /** @type {CssModule[]} */ ([ |
| | | ...this.getModulesInOrder( |
| | | chunk, |
| | | /** @type {Iterable<Module>} */ |
| | | ( |
| | | chunkGraph.getOrderedChunkModulesIterableBySourceType( |
| | | chunk, |
| | | "css-import", |
| | | compareModulesByIdOrIdentifier(chunkGraph) |
| | | ) |
| | | CSS_IMPORT_TYPE, |
| | | compareModulesByFullName(compilation.compiler) |
| | | ), |
| | | compilation |
| | | ), |
| | | ...this.getModulesInOrder( |
| | | chunk, |
| | | /** @type {Iterable<Module>} */ |
| | | ( |
| | | chunkGraph.getOrderedChunkModulesIterableBySourceType( |
| | | chunk, |
| | | "css", |
| | | compareModulesByIdOrIdentifier(chunkGraph) |
| | | ) |
| | | CSS_TYPE, |
| | | compareModulesByFullName(compilation.compiler) |
| | | ), |
| | | compilation |
| | | ) |
| | | ]; |
| | | ).map((module) => { |
| | | if ( |
| | | typeof (/** @type {BuildInfo} */ (module.buildInfo).charset) !== |
| | | "undefined" |
| | | ) { |
| | | if ( |
| | | typeof charset !== "undefined" && |
| | | charset !== /** @type {BuildInfo} */ (module.buildInfo).charset |
| | | ) { |
| | | const err = new WebpackError( |
| | | `Conflicting @charset at-rules detected: the module ${module.readableIdentifier( |
| | | compilation.requestShortener |
| | | )} (in chunk ${chunk.name || chunk.id}) specifies "${ |
| | | /** @type {BuildInfo} */ (module.buildInfo).charset |
| | | }", but "${charset}" was expected, all modules must use the same character set` |
| | | ); |
| | | |
| | | err.chunk = chunk; |
| | | err.module = module; |
| | | err.hideStack = true; |
| | | |
| | | compilation.warnings.push(err); |
| | | } |
| | | |
| | | if (typeof charset === "undefined") { |
| | | charset = /** @type {BuildInfo} */ (module.buildInfo).charset; |
| | | } |
| | | } |
| | | |
| | | return module; |
| | | }) |
| | | ]); |
| | | } |
| | | |
| | | /** |
| | | * Renders css module source. |
| | | * @param {CssModule} module css module |
| | | * @param {ChunkRenderContext} renderContext options object |
| | | * @param {CompilationHooks} hooks hooks |
| | |
| | | inheritance.push(...module.inheritance); |
| | | } |
| | | |
| | | /** @type {CachedSource} */ |
| | | let source; |
| | | if ( |
| | | cacheEntry && |
| | | cacheEntry.undoPath === undoPath && |
| | | cacheEntry.inheritance.length === inheritance.length && |
| | | cacheEntry.inheritance.every(([layer, supports, media], i) => { |
| | | const item = inheritance[i]; |
| | | if (Array.isArray(item)) { |
| | |
| | | const moduleSourceCode = |
| | | /** @type {string} */ |
| | | (moduleSourceContent.source()); |
| | | const publicPathAutoRegex = new RegExp( |
| | | CssUrlDependency.PUBLIC_PATH_AUTO, |
| | | "g" |
| | | ); |
| | | publicPathAutoRegex.lastIndex = 0; |
| | | /** @type {Source} */ |
| | | let moduleSource = new ReplaceSource(moduleSourceContent); |
| | | /** @type {null | RegExpExecArray} */ |
| | | let match; |
| | | while ((match = publicPathAutoRegex.exec(moduleSourceCode))) { |
| | | /** @type {ReplaceSource} */ (moduleSource).replace( |
| | | match.index, |
| | | (match.index += match[0].length - 1), |
| | | match.index + match[0].length - 1, |
| | | undoPath |
| | | ); |
| | | } |
| | |
| | | } |
| | | |
| | | /** |
| | | * Renders generated source. |
| | | * @param {RenderContext} renderContext the render context |
| | | * @param {CompilationHooks} hooks hooks |
| | | * @returns {Source} generated source |
| | |
| | | hooks |
| | | ) { |
| | | const source = new ConcatSource(); |
| | | |
| | | /** @type {string | undefined} */ |
| | | let charset; |
| | | |
| | | for (const module of modules) { |
| | | if ( |
| | | typeof (/** @type {BuildInfo} */ (module.buildInfo).charset) !== |
| | | "undefined" && |
| | | typeof charset === "undefined" |
| | | ) { |
| | | charset = /** @type {BuildInfo} */ (module.buildInfo).charset; |
| | | } |
| | | |
| | | try { |
| | | const codeGenResult = codeGenerationResults.get(module, chunk.runtime); |
| | | const moduleSourceContent = |
| | | /** @type {Source} */ |
| | | ( |
| | | codeGenResult.sources.get("css") || |
| | | codeGenResult.sources.get("css-import") |
| | | codeGenResult.sources.get(CSS_TYPE) || |
| | | codeGenResult.sources.get(CSS_IMPORT_TYPE) |
| | | ); |
| | | const moduleSource = CssModulesPlugin.renderModule( |
| | | module, |
| | |
| | | throw err; |
| | | } |
| | | } |
| | | |
| | | chunk.rendered = true; |
| | | |
| | | if (charset) { |
| | | return new ConcatSource(`@charset "${charset}";\n`, source); |
| | | } |
| | | |
| | | return source; |
| | | } |
| | | |
| | | /** |
| | | * Gets chunk filename template. |
| | | * @param {Chunk} chunk chunk |
| | | * @param {OutputOptions} outputOptions output options |
| | | * @returns {TemplatePath} used filename template |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns true, when the chunk has css. |
| | | * @param {Chunk} chunk chunk |
| | | * @param {ChunkGraph} chunkGraph chunk graph |
| | | * @returns {boolean} true, when the chunk has css |
| | | */ |
| | | static chunkHasCss(chunk, chunkGraph) { |
| | | return ( |
| | | Boolean(chunkGraph.getChunkModulesIterableBySourceType(chunk, "css")) || |
| | | Boolean( |
| | | chunkGraph.getChunkModulesIterableBySourceType(chunk, "css-import") |
| | | chunkGraph.getChunkModulesIterableBySourceType(chunk, CSS_TYPE) |
| | | ) || |
| | | Boolean( |
| | | chunkGraph.getChunkModulesIterableBySourceType(chunk, CSS_IMPORT_TYPE) |
| | | ) |
| | | ); |
| | | } |