$
This commit is contained in:
462
node_modules/webpack/lib/css/CssModulesPlugin.js
generated
vendored
Normal file
462
node_modules/webpack/lib/css/CssModulesPlugin.js
generated
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { ConcatSource } = require("webpack-sources");
|
||||
const HotUpdateChunk = require("../HotUpdateChunk");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const SelfModuleFactory = require("../SelfModuleFactory");
|
||||
const CssExportDependency = require("../dependencies/CssExportDependency");
|
||||
const CssImportDependency = require("../dependencies/CssImportDependency");
|
||||
const CssLocalIdentifierDependency = require("../dependencies/CssLocalIdentifierDependency");
|
||||
const CssSelfLocalIdentifierDependency = require("../dependencies/CssSelfLocalIdentifierDependency");
|
||||
const CssUrlDependency = require("../dependencies/CssUrlDependency");
|
||||
const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
|
||||
const { compareModulesByIdentifier } = require("../util/comparators");
|
||||
const createSchemaValidation = require("../util/create-schema-validation");
|
||||
const createHash = require("../util/createHash");
|
||||
const memoize = require("../util/memoize");
|
||||
const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
|
||||
const CssExportsGenerator = require("./CssExportsGenerator");
|
||||
const CssGenerator = require("./CssGenerator");
|
||||
const CssParser = require("./CssParser");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../../declarations/WebpackOptions").CssExperimentOptions} CssExperimentOptions */
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
|
||||
const getCssLoadingRuntimeModule = memoize(() =>
|
||||
require("./CssLoadingRuntimeModule")
|
||||
);
|
||||
|
||||
const getSchema = name => {
|
||||
const { definitions } = require("../../schemas/WebpackOptions.json");
|
||||
return {
|
||||
definitions,
|
||||
oneOf: [{ $ref: `#/definitions/${name}` }]
|
||||
};
|
||||
};
|
||||
|
||||
const validateGeneratorOptions = createSchemaValidation(
|
||||
require("../../schemas/plugins/css/CssGeneratorOptions.check.js"),
|
||||
() => getSchema("CssGeneratorOptions"),
|
||||
{
|
||||
name: "Css Modules Plugin",
|
||||
baseDataPath: "parser"
|
||||
}
|
||||
);
|
||||
const validateParserOptions = createSchemaValidation(
|
||||
require("../../schemas/plugins/css/CssParserOptions.check.js"),
|
||||
() => getSchema("CssParserOptions"),
|
||||
{
|
||||
name: "Css Modules Plugin",
|
||||
baseDataPath: "parser"
|
||||
}
|
||||
);
|
||||
|
||||
const escapeCss = (str, omitOptionalUnderscore) => {
|
||||
const escaped = `${str}`.replace(
|
||||
// cspell:word uffff
|
||||
/[^a-zA-Z0-9_\u0081-\uffff-]/g,
|
||||
s => `\\${s}`
|
||||
);
|
||||
return !omitOptionalUnderscore && /^(?!--)[0-9_-]/.test(escaped)
|
||||
? `_${escaped}`
|
||||
: escaped;
|
||||
};
|
||||
|
||||
const plugin = "CssModulesPlugin";
|
||||
|
||||
class CssModulesPlugin {
|
||||
/**
|
||||
* @param {CssExperimentOptions} options options
|
||||
*/
|
||||
constructor({ exportsOnly = false }) {
|
||||
this._exportsOnly = exportsOnly;
|
||||
}
|
||||
/**
|
||||
* Apply the plugin
|
||||
* @param {Compiler} compiler the compiler instance
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
plugin,
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
const selfFactory = new SelfModuleFactory(compilation.moduleGraph);
|
||||
compilation.dependencyFactories.set(
|
||||
CssUrlDependency,
|
||||
normalModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
CssUrlDependency,
|
||||
new CssUrlDependency.Template()
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
CssLocalIdentifierDependency,
|
||||
new CssLocalIdentifierDependency.Template()
|
||||
);
|
||||
compilation.dependencyFactories.set(
|
||||
CssSelfLocalIdentifierDependency,
|
||||
selfFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
CssSelfLocalIdentifierDependency,
|
||||
new CssSelfLocalIdentifierDependency.Template()
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
CssExportDependency,
|
||||
new CssExportDependency.Template()
|
||||
);
|
||||
compilation.dependencyFactories.set(
|
||||
CssImportDependency,
|
||||
normalModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
CssImportDependency,
|
||||
new CssImportDependency.Template()
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
StaticExportsDependency,
|
||||
new StaticExportsDependency.Template()
|
||||
);
|
||||
normalModuleFactory.hooks.createParser
|
||||
.for("css")
|
||||
.tap(plugin, parserOptions => {
|
||||
validateParserOptions(parserOptions);
|
||||
return new CssParser();
|
||||
});
|
||||
normalModuleFactory.hooks.createParser
|
||||
.for("css/global")
|
||||
.tap(plugin, parserOptions => {
|
||||
validateParserOptions(parserOptions);
|
||||
return new CssParser({
|
||||
allowPseudoBlocks: false,
|
||||
allowModeSwitch: false
|
||||
});
|
||||
});
|
||||
normalModuleFactory.hooks.createParser
|
||||
.for("css/module")
|
||||
.tap(plugin, parserOptions => {
|
||||
validateParserOptions(parserOptions);
|
||||
return new CssParser({
|
||||
defaultMode: "local"
|
||||
});
|
||||
});
|
||||
normalModuleFactory.hooks.createGenerator
|
||||
.for("css")
|
||||
.tap(plugin, generatorOptions => {
|
||||
validateGeneratorOptions(generatorOptions);
|
||||
return this._exportsOnly
|
||||
? new CssExportsGenerator()
|
||||
: new CssGenerator();
|
||||
});
|
||||
normalModuleFactory.hooks.createGenerator
|
||||
.for("css/global")
|
||||
.tap(plugin, generatorOptions => {
|
||||
validateGeneratorOptions(generatorOptions);
|
||||
return this._exportsOnly
|
||||
? new CssExportsGenerator()
|
||||
: new CssGenerator();
|
||||
});
|
||||
normalModuleFactory.hooks.createGenerator
|
||||
.for("css/module")
|
||||
.tap(plugin, generatorOptions => {
|
||||
validateGeneratorOptions(generatorOptions);
|
||||
return this._exportsOnly
|
||||
? new CssExportsGenerator()
|
||||
: new CssGenerator();
|
||||
});
|
||||
const orderedCssModulesPerChunk = new WeakMap();
|
||||
compilation.hooks.afterCodeGeneration.tap("CssModulesPlugin", () => {
|
||||
const { chunkGraph } = compilation;
|
||||
for (const chunk of compilation.chunks) {
|
||||
if (CssModulesPlugin.chunkHasCss(chunk, chunkGraph)) {
|
||||
orderedCssModulesPerChunk.set(
|
||||
chunk,
|
||||
this.getOrderedChunkCssModules(chunk, chunkGraph, compilation)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
compilation.hooks.contentHash.tap("CssModulesPlugin", chunk => {
|
||||
const {
|
||||
chunkGraph,
|
||||
outputOptions: {
|
||||
hashSalt,
|
||||
hashDigest,
|
||||
hashDigestLength,
|
||||
hashFunction
|
||||
}
|
||||
} = compilation;
|
||||
const modules = orderedCssModulesPerChunk.get(chunk);
|
||||
if (modules === undefined) return;
|
||||
const hash = createHash(hashFunction);
|
||||
if (hashSalt) hash.update(hashSalt);
|
||||
for (const module of modules) {
|
||||
hash.update(chunkGraph.getModuleHash(module, chunk.runtime));
|
||||
}
|
||||
const digest = /** @type {string} */ (hash.digest(hashDigest));
|
||||
chunk.contentHash.css = nonNumericOnlyHash(digest, hashDigestLength);
|
||||
});
|
||||
compilation.hooks.renderManifest.tap(plugin, (result, options) => {
|
||||
const { chunkGraph } = compilation;
|
||||
const { hash, chunk, codeGenerationResults } = options;
|
||||
|
||||
if (chunk instanceof HotUpdateChunk) return result;
|
||||
|
||||
const modules = orderedCssModulesPerChunk.get(chunk);
|
||||
if (modules !== undefined) {
|
||||
result.push({
|
||||
render: () =>
|
||||
this.renderChunk({
|
||||
chunk,
|
||||
chunkGraph,
|
||||
codeGenerationResults,
|
||||
uniqueName: compilation.outputOptions.uniqueName,
|
||||
modules
|
||||
}),
|
||||
filenameTemplate: CssModulesPlugin.getChunkFilenameTemplate(
|
||||
chunk,
|
||||
compilation.outputOptions
|
||||
),
|
||||
pathOptions: {
|
||||
hash,
|
||||
runtime: chunk.runtime,
|
||||
chunk,
|
||||
contentHashType: "css"
|
||||
},
|
||||
identifier: `css${chunk.id}`,
|
||||
hash: chunk.contentHash.css
|
||||
});
|
||||
}
|
||||
return result;
|
||||
});
|
||||
const enabledChunks = new WeakSet();
|
||||
const handler = (chunk, set) => {
|
||||
if (enabledChunks.has(chunk)) {
|
||||
return;
|
||||
}
|
||||
enabledChunks.add(chunk);
|
||||
|
||||
set.add(RuntimeGlobals.publicPath);
|
||||
set.add(RuntimeGlobals.getChunkCssFilename);
|
||||
set.add(RuntimeGlobals.hasOwnProperty);
|
||||
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
|
||||
set.add(RuntimeGlobals.makeNamespaceObject);
|
||||
|
||||
const CssLoadingRuntimeModule = getCssLoadingRuntimeModule();
|
||||
compilation.addRuntimeModule(chunk, new CssLoadingRuntimeModule(set));
|
||||
};
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hasCssModules)
|
||||
.tap(plugin, handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.ensureChunkHandlers)
|
||||
.tap(plugin, handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
||||
.tap(plugin, handler);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getModulesInOrder(chunk, modules, compilation) {
|
||||
if (!modules) return [];
|
||||
|
||||
const modulesList = [...modules];
|
||||
|
||||
// Get ordered list of modules per chunk group
|
||||
// Lists are in reverse order to allow to use Array.pop()
|
||||
const modulesByChunkGroup = Array.from(chunk.groupsIterable, chunkGroup => {
|
||||
const sortedModules = modulesList
|
||||
.map(module => {
|
||||
return {
|
||||
module,
|
||||
index: chunkGroup.getModulePostOrderIndex(module)
|
||||
};
|
||||
})
|
||||
.filter(item => item.index !== undefined)
|
||||
.sort((a, b) => b.index - a.index)
|
||||
.map(item => item.module);
|
||||
|
||||
return { list: sortedModules, set: new Set(sortedModules) };
|
||||
});
|
||||
|
||||
if (modulesByChunkGroup.length === 1)
|
||||
return modulesByChunkGroup[0].list.reverse();
|
||||
|
||||
const compareModuleLists = ({ list: a }, { list: b }) => {
|
||||
if (a.length === 0) {
|
||||
return b.length === 0 ? 0 : 1;
|
||||
} else {
|
||||
if (b.length === 0) return -1;
|
||||
return compareModulesByIdentifier(a[a.length - 1], b[b.length - 1]);
|
||||
}
|
||||
};
|
||||
|
||||
modulesByChunkGroup.sort(compareModuleLists);
|
||||
|
||||
const finalModules = [];
|
||||
|
||||
for (;;) {
|
||||
const failedModules = new Set();
|
||||
const list = modulesByChunkGroup[0].list;
|
||||
if (list.length === 0) {
|
||||
// done, everything empty
|
||||
break;
|
||||
}
|
||||
let selectedModule = list[list.length - 1];
|
||||
let hasFailed = undefined;
|
||||
outer: for (;;) {
|
||||
for (const { list, set } of modulesByChunkGroup) {
|
||||
if (list.length === 0) continue;
|
||||
const lastModule = list[list.length - 1];
|
||||
if (lastModule === selectedModule) continue;
|
||||
if (!set.has(selectedModule)) continue;
|
||||
failedModules.add(selectedModule);
|
||||
if (failedModules.has(lastModule)) {
|
||||
// There is a conflict, try other alternatives
|
||||
hasFailed = lastModule;
|
||||
continue;
|
||||
}
|
||||
selectedModule = lastModule;
|
||||
hasFailed = false;
|
||||
continue outer; // restart
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (hasFailed) {
|
||||
// There is a not resolve-able conflict with the selectedModule
|
||||
if (compilation) {
|
||||
// TODO print better warning
|
||||
compilation.warnings.push(
|
||||
new Error(
|
||||
`chunk ${
|
||||
chunk.name || chunk.id
|
||||
}\nConflicting order between ${hasFailed.readableIdentifier(
|
||||
compilation.requestShortener
|
||||
)} and ${selectedModule.readableIdentifier(
|
||||
compilation.requestShortener
|
||||
)}`
|
||||
)
|
||||
);
|
||||
}
|
||||
selectedModule = hasFailed;
|
||||
}
|
||||
// Insert the selected module into the final modules list
|
||||
finalModules.push(selectedModule);
|
||||
// Remove the selected module from all lists
|
||||
for (const { list, set } of modulesByChunkGroup) {
|
||||
const lastModule = list[list.length - 1];
|
||||
if (lastModule === selectedModule) list.pop();
|
||||
else if (hasFailed && set.has(selectedModule)) {
|
||||
const idx = list.indexOf(selectedModule);
|
||||
if (idx >= 0) list.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
modulesByChunkGroup.sort(compareModuleLists);
|
||||
}
|
||||
return finalModules;
|
||||
}
|
||||
|
||||
getOrderedChunkCssModules(chunk, chunkGraph, compilation) {
|
||||
return [
|
||||
...this.getModulesInOrder(
|
||||
chunk,
|
||||
chunkGraph.getOrderedChunkModulesIterableBySourceType(
|
||||
chunk,
|
||||
"css-import",
|
||||
compareModulesByIdentifier
|
||||
),
|
||||
compilation
|
||||
),
|
||||
...this.getModulesInOrder(
|
||||
chunk,
|
||||
chunkGraph.getOrderedChunkModulesIterableBySourceType(
|
||||
chunk,
|
||||
"css",
|
||||
compareModulesByIdentifier
|
||||
),
|
||||
compilation
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
renderChunk({
|
||||
uniqueName,
|
||||
chunk,
|
||||
chunkGraph,
|
||||
codeGenerationResults,
|
||||
modules
|
||||
}) {
|
||||
const source = new ConcatSource();
|
||||
const metaData = [];
|
||||
for (const module of modules) {
|
||||
try {
|
||||
const codeGenResult = codeGenerationResults.get(module, chunk.runtime);
|
||||
|
||||
const s =
|
||||
codeGenResult.sources.get("css") ||
|
||||
codeGenResult.sources.get("css-import");
|
||||
if (s) {
|
||||
source.add(s);
|
||||
source.add("\n");
|
||||
}
|
||||
const exports =
|
||||
codeGenResult.data && codeGenResult.data.get("css-exports");
|
||||
const moduleId = chunkGraph.getModuleId(module) + "";
|
||||
metaData.push(
|
||||
`${
|
||||
exports
|
||||
? Array.from(exports, ([n, v]) => {
|
||||
const shortcutValue = `${
|
||||
uniqueName ? uniqueName + "-" : ""
|
||||
}${moduleId}-${n}`;
|
||||
return v === shortcutValue
|
||||
? `${escapeCss(n)}/`
|
||||
: v === "--" + shortcutValue
|
||||
? `${escapeCss(n)}%`
|
||||
: `${escapeCss(n)}(${escapeCss(v)})`;
|
||||
}).join("")
|
||||
: ""
|
||||
}${escapeCss(moduleId)}`
|
||||
);
|
||||
} catch (e) {
|
||||
e.message += `\nduring rendering of css ${module.identifier()}`;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
source.add(
|
||||
`head{--webpack-${escapeCss(
|
||||
(uniqueName ? uniqueName + "-" : "") + chunk.id,
|
||||
true
|
||||
)}:${metaData.join(",")};}`
|
||||
);
|
||||
return source;
|
||||
}
|
||||
|
||||
static getChunkFilenameTemplate(chunk, outputOptions) {
|
||||
if (chunk.cssFilenameTemplate) {
|
||||
return chunk.cssFilenameTemplate;
|
||||
} else if (chunk.canBeInitial()) {
|
||||
return outputOptions.cssFilename;
|
||||
} else {
|
||||
return outputOptions.cssChunkFilename;
|
||||
}
|
||||
}
|
||||
|
||||
static chunkHasCss(chunk, chunkGraph) {
|
||||
return (
|
||||
!!chunkGraph.getChunkModulesIterableBySourceType(chunk, "css") ||
|
||||
!!chunkGraph.getChunkModulesIterableBySourceType(chunk, "css-import")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CssModulesPlugin;
|
Reference in New Issue
Block a user