Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F118072248
CssModulesPlugin.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Jun 17, 12:40
Size
13 KB
Mime Type
text/x-c++
Expires
Thu, Jun 19, 12:40 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
26818598
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
CssModulesPlugin.js
View Options
/*
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;
Event Timeline
Log In to Comment