feat: refactoring project

This commit is contained in:
Carlos
2024-11-23 14:56:07 -05:00
parent f0c2a50c18
commit 1c6db5818d
2351 changed files with 39323 additions and 60326 deletions

View File

@@ -5,13 +5,16 @@
"use strict";
const { SyncWaterfallHook, SyncHook } = require("tapable");
const {
ConcatSource,
PrefixSource,
ReplaceSource,
CachedSource
} = require("webpack-sources");
const Compilation = require("../Compilation");
const CssModule = require("../CssModule");
const { tryRunOrWebpackError } = require("../HookWebpackError");
const HotUpdateChunk = require("../HotUpdateChunk");
const {
CSS_MODULE_TYPE,
@@ -39,17 +42,49 @@ const CssGenerator = require("./CssGenerator");
const CssParser = require("./CssParser");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../../declarations/WebpackOptions").Output} OutputOptions */
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../CssModule").Inheritance} Inheritance */
/** @typedef {import("../DependencyTemplate").CssExportsData} CssExportsData */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../Template").RuntimeTemplate} RuntimeTemplate */
/** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
/** @typedef {import("../util/Hash")} Hash */
/** @typedef {import("../util/createHash").Algorithm} Algorithm */
/** @typedef {import("../util/memoize")} Memoize */
/**
* @typedef {object} RenderContext
* @property {Chunk} chunk the chunk
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {CodeGenerationResults} codeGenerationResults results of code generation
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {string} uniqueName the unique name
* @property {boolean} cssHeadDataCompression need compress
* @property {string} undoPath undo path to css file
* @property {CssModule[]} modules modules
*/
/**
* @typedef {object} ChunkRenderContext
* @property {Chunk} chunk the chunk
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {CodeGenerationResults} codeGenerationResults results of code generation
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {string[]} metaData meta data for runtime
* @property {string} undoPath undo path to css file
*/
/**
* @typedef {object} CompilationHooks
* @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModulePackage
* @property {SyncHook<[Chunk, Hash, ChunkHashContext]>} chunkHash
*/
const getCssLoadingRuntimeModule = memoize(() =>
require("./CssLoadingRuntimeModule")
);
@@ -120,6 +155,9 @@ const validateParserOptions = {
)
};
/** @type {WeakMap<Compilation, CompilationHooks>} */
const compilationHooksMap = new WeakMap();
/**
* @param {string} str string
* @param {boolean=} omitOptionalUnderscore if true, optional underscore is not added
@@ -128,7 +166,7 @@ const validateParserOptions = {
const escapeCss = (str, omitOptionalUnderscore) => {
const escaped = `${str}`.replace(
// cspell:word uffff
/[^a-zA-Z0-9_\u0081-\uffff-]/g,
/[^a-zA-Z0-9_\u0081-\uFFFF-]/g,
s => `\\${s}`
);
return !omitOptionalUnderscore && /^(?!--)[0-9_-]/.test(escaped)
@@ -140,13 +178,13 @@ const escapeCss = (str, omitOptionalUnderscore) => {
* @param {string} str string
* @returns {string} encoded string
*/
const LZWEncode = str => {
const lzwEncode = str => {
/** @type {Map<string, string>} */
const map = new Map();
let encoded = "";
let phrase = str[0];
let code = 256;
let maxCode = "\uffff".charCodeAt(0);
const maxCode = "\uFFFF".charCodeAt(0);
for (let i = 1; i < str.length; i++) {
const c = str[i];
if (map.has(phrase + c)) {
@@ -165,9 +203,34 @@ const LZWEncode = str => {
return encoded;
};
const plugin = "CssModulesPlugin";
const PLUGIN_NAME = "CssModulesPlugin";
class CssModulesPlugin {
/**
* @param {Compilation} compilation the compilation
* @returns {CompilationHooks} the attached hooks
*/
static getCompilationHooks(compilation) {
if (!(compilation instanceof Compilation)) {
throw new TypeError(
"The 'compilation' argument must be an instance of Compilation"
);
}
let hooks = compilationHooksMap.get(compilation);
if (hooks === undefined) {
hooks = {
renderModulePackage: new SyncWaterfallHook([
"source",
"module",
"renderContext"
]),
chunkHash: new SyncHook(["chunk", "hash", "context"])
};
compilationHooksMap.set(compilation, hooks);
}
return hooks;
}
constructor() {
/** @type {WeakMap<Source, { undoPath: string, inheritance: Inheritance, source: CachedSource }>} */
this._moduleCache = new WeakMap();
@@ -180,8 +243,9 @@ class CssModulesPlugin {
*/
apply(compiler) {
compiler.hooks.compilation.tap(
plugin,
PLUGIN_NAME,
(compilation, { normalModuleFactory }) => {
const hooks = CssModulesPlugin.getCompilationHooks(compilation);
const selfFactory = new SelfModuleFactory(compilation.moduleGraph);
compilation.dependencyFactories.set(
CssUrlDependency,
@@ -227,19 +291,18 @@ class CssModulesPlugin {
]) {
normalModuleFactory.hooks.createParser
.for(type)
.tap(plugin, parserOptions => {
.tap(PLUGIN_NAME, parserOptions => {
validateParserOptions[type](parserOptions);
const { namedExports } = parserOptions;
switch (type) {
case CSS_MODULE_TYPE_GLOBAL:
case CSS_MODULE_TYPE_AUTO:
case CSS_MODULE_TYPE:
return new CssParser({
namedExports
});
case CSS_MODULE_TYPE:
case CSS_MODULE_TYPE_GLOBAL:
return new CssParser({
allowModeSwitch: false,
defaultMode: "global",
namedExports
});
case CSS_MODULE_TYPE_MODULE:
@@ -247,11 +310,16 @@ class CssModulesPlugin {
defaultMode: "local",
namedExports
});
case CSS_MODULE_TYPE_AUTO:
return new CssParser({
defaultMode: "auto",
namedExports
});
}
});
normalModuleFactory.hooks.createGenerator
.for(type)
.tap(plugin, generatorOptions => {
.tap(PLUGIN_NAME, generatorOptions => {
validateGeneratorOptions[type](generatorOptions);
return generatorOptions.exportsOnly
@@ -268,7 +336,7 @@ class CssModulesPlugin {
});
normalModuleFactory.hooks.createModuleClass
.for(type)
.tap(plugin, (createData, resolveData) => {
.tap(PLUGIN_NAME, (createData, resolveData) => {
if (resolveData.dependencies.length > 0) {
// When CSS is imported from CSS there is only one dependency
const dependency = resolveData.dependencies[0];
@@ -283,8 +351,7 @@ class CssModulesPlugin {
let inheritance;
if (
(parent.cssLayer !== null &&
parent.cssLayer !== undefined) ||
parent.cssLayer !== undefined ||
parent.supports ||
parent.media
) {
@@ -340,9 +407,18 @@ class CssModulesPlugin {
}
}
});
compilation.hooks.chunkHash.tap(
"CssModulesPlugin",
(chunk, hash, context) => {
hooks.chunkHash.call(chunk, hash, context);
}
);
compilation.hooks.contentHash.tap("CssModulesPlugin", chunk => {
const {
chunkGraph,
codeGenerationResults,
moduleGraph,
runtimeTemplate,
outputOptions: {
hashSalt,
hashDigest,
@@ -350,19 +426,31 @@ class CssModulesPlugin {
hashFunction
}
} = compilation;
const modules = orderedCssModulesPerChunk.get(chunk);
if (modules === undefined) return;
const hash = createHash(hashFunction);
const hash = createHash(/** @type {Algorithm} */ (hashFunction));
if (hashSalt) hash.update(hashSalt);
for (const module of modules) {
hash.update(chunkGraph.getModuleHash(module, chunk.runtime));
hooks.chunkHash.call(chunk, hash, {
chunkGraph,
codeGenerationResults,
moduleGraph,
runtimeTemplate
});
const modules = orderedCssModulesPerChunk.get(chunk);
if (modules) {
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);
chunk.contentHash.css = nonNumericOnlyHash(
digest,
/** @type {number} */
(hashDigestLength)
);
});
compilation.hooks.renderManifest.tap(plugin, (result, options) => {
compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
const { chunkGraph } = compilation;
const { hash, chunk, codeGenerationResults } = options;
const { hash, chunk, codeGenerationResults, runtimeTemplate } =
options;
if (chunk instanceof HotUpdateChunk) return result;
@@ -383,21 +471,26 @@ class CssModulesPlugin {
);
const undoPath = getUndoPath(
filename,
compilation.outputOptions.path,
/** @type {string} */
(compilation.outputOptions.path),
false
);
result.push({
render: () =>
this.renderChunk({
chunk,
chunkGraph,
codeGenerationResults,
uniqueName: compilation.outputOptions.uniqueName,
cssHeadDataCompression:
compilation.outputOptions.cssHeadDataCompression,
undoPath,
modules
}),
this.renderChunk(
{
chunk,
chunkGraph,
codeGenerationResults,
uniqueName: compilation.outputOptions.uniqueName,
cssHeadDataCompression:
compilation.outputOptions.cssHeadDataCompression,
undoPath,
modules,
runtimeTemplate
},
hooks
),
filename,
info,
identifier: `css${chunk.id}`,
@@ -429,9 +522,6 @@ class CssModulesPlugin {
onceForChunkSet.add(chunk);
if (!isEnabledForChunk(chunk)) return;
set.add(RuntimeGlobals.publicPath);
set.add(RuntimeGlobals.getChunkCssFilename);
set.add(RuntimeGlobals.hasOwnProperty);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
set.add(RuntimeGlobals.makeNamespaceObject);
@@ -440,13 +530,48 @@ class CssModulesPlugin {
};
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.hasCssModules)
.tap(plugin, handler);
.tap(PLUGIN_NAME, handler);
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.ensureChunkHandlers)
.tap(plugin, handler);
.tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
if (!isEnabledForChunk(chunk)) return;
if (
!chunkGraph.hasModuleInGraph(
chunk,
m =>
m.type === CSS_MODULE_TYPE ||
m.type === CSS_MODULE_TYPE_GLOBAL ||
m.type === CSS_MODULE_TYPE_MODULE ||
m.type === CSS_MODULE_TYPE_AUTO
)
) {
return;
}
set.add(RuntimeGlobals.hasOwnProperty);
set.add(RuntimeGlobals.publicPath);
set.add(RuntimeGlobals.getChunkCssFilename);
});
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
.tap(plugin, handler);
.tap(PLUGIN_NAME, (chunk, set, { chunkGraph }) => {
if (!isEnabledForChunk(chunk)) return;
if (
!chunkGraph.hasModuleInGraph(
chunk,
m =>
m.type === CSS_MODULE_TYPE ||
m.type === CSS_MODULE_TYPE_GLOBAL ||
m.type === CSS_MODULE_TYPE_MODULE ||
m.type === CSS_MODULE_TYPE_AUTO
)
) {
return;
}
set.add(RuntimeGlobals.publicPath);
set.add(RuntimeGlobals.getChunkCssFilename);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
});
}
);
}
@@ -467,12 +592,10 @@ class CssModulesPlugin {
// 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)
};
})
.map(module => ({
module,
index: chunkGroup.getModulePostOrderIndex(module)
}))
.filter(item => item.index !== undefined)
.sort(
(a, b) =>
@@ -486,13 +609,17 @@ class CssModulesPlugin {
if (modulesByChunkGroup.length === 1)
return modulesByChunkGroup[0].list.reverse();
/**
* @param {{ list: Module[] }} a a
* @param {{ list: Module[] }} b b
* @returns {-1 | 0 | 1} result
*/
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]);
}
if (b.length === 0) return -1;
return compareModulesByIdentifier(a[a.length - 1], b[b.length - 1]);
};
modulesByChunkGroup.sort(compareModuleLists);
@@ -509,7 +636,7 @@ class CssModulesPlugin {
}
/** @type {Module} */
let selectedModule = list[list.length - 1];
let hasFailed = undefined;
let hasFailed;
outer: for (;;) {
for (const { list, set } of modulesByChunkGroup) {
if (list.length === 0) continue;
@@ -595,23 +722,14 @@ class CssModulesPlugin {
}
/**
* @param {object} options options
* @param {string[]} options.metaData meta data
* @param {string} options.undoPath undo path for public path auto
* @param {Chunk} options.chunk chunk
* @param {ChunkGraph} options.chunkGraph chunk graph
* @param {CodeGenerationResults} options.codeGenerationResults code generation results
* @param {CssModule} options.module css module
* @param {CssModule} module css module
* @param {ChunkRenderContext} renderContext options object
* @param {CompilationHooks} hooks hooks
* @returns {Source} css module source
*/
renderModule({
metaData,
undoPath,
chunk,
chunkGraph,
codeGenerationResults,
module
}) {
renderModule(module, renderContext, hooks) {
const { codeGenerationResults, chunk, undoPath, chunkGraph, metaData } =
renderContext;
const codeGenResult = codeGenerationResults.get(module, chunk.runtime);
const moduleSourceContent =
/** @type {Source} */
@@ -623,7 +741,7 @@ class CssModulesPlugin {
const cacheEntry = this._moduleCache.get(moduleSourceContent);
/** @type {Inheritance} */
let inheritance = [[module.cssLayer, module.supports, module.media]];
const inheritance = [[module.cssLayer, module.supports, module.media]];
if (module.inheritance) {
inheritance.push(...module.inheritance);
}
@@ -707,7 +825,7 @@ class CssModulesPlugin {
codeGenResult.data && codeGenResult.data.get("css-exports");
const exports = cssExportsData && cssExportsData.exports;
const esModule = cssExportsData && cssExportsData.esModule;
let moduleId = chunkGraph.getModuleId(module) + "";
let moduleId = String(chunkGraph.getModuleId(module));
// When `optimization.moduleIds` is `named` the module id is a path, so we need to normalize it between platforms
if (typeof moduleId === "string") {
@@ -724,72 +842,77 @@ class CssModulesPlugin {
: ""
}${esModule ? "&" : ""}${escapeCss(moduleId)}`
);
return source;
return tryRunOrWebpackError(
() => hooks.renderModulePackage.call(source, module, renderContext),
"CssModulesPlugin.getCompilationHooks().renderModulePackage"
);
}
/**
* @param {object} options options
* @param {string | undefined} options.uniqueName unique name
* @param {boolean | undefined} options.cssHeadDataCompression compress css head data
* @param {string} options.undoPath undo path for public path auto
* @param {Chunk} options.chunk chunk
* @param {ChunkGraph} options.chunkGraph chunk graph
* @param {CodeGenerationResults} options.codeGenerationResults code generation results
* @param {CssModule[]} options.modules ordered css modules
* @param {RenderContext} renderContext the render context
* @param {CompilationHooks} hooks hooks
* @returns {Source} generated source
*/
renderChunk({
uniqueName,
cssHeadDataCompression,
undoPath,
chunk,
chunkGraph,
codeGenerationResults,
modules
}) {
renderChunk(
{
uniqueName,
cssHeadDataCompression,
undoPath,
chunk,
chunkGraph,
codeGenerationResults,
modules,
runtimeTemplate
},
hooks
) {
const source = new ConcatSource();
/** @type {string[]} */
const metaData = [];
for (const module of modules) {
try {
const moduleSource = this.renderModule({
metaData,
undoPath,
chunk,
chunkGraph,
codeGenerationResults,
module
});
const moduleSource = this.renderModule(
module,
{
metaData,
undoPath,
chunk,
chunkGraph,
codeGenerationResults,
runtimeTemplate
},
hooks
);
source.add(moduleSource);
} catch (e) {
} catch (err) {
/** @type {Error} */
(e).message += `\nduring rendering of css ${module.identifier()}`;
throw e;
(err).message += `\nduring rendering of css ${module.identifier()}`;
throw err;
}
}
const metaDataStr = metaData.join(",");
source.add(
`head{--webpack-${escapeCss(
(uniqueName ? uniqueName + "-" : "") + chunk.id,
(uniqueName ? `${uniqueName}-` : "") + chunk.id,
true
)}:${cssHeadDataCompression ? LZWEncode(metaDataStr) : metaDataStr};}`
)}:${cssHeadDataCompression ? lzwEncode(metaDataStr) : metaDataStr};}`
);
chunk.rendered = true;
return source;
}
/**
* @param {Chunk} chunk chunk
* @param {OutputOptions} outputOptions output options
* @returns {Chunk["cssFilenameTemplate"] | OutputOptions["cssFilename"] | OutputOptions["cssChunkFilename"]} used filename template
* @returns {TemplatePath} used filename template
*/
static getChunkFilenameTemplate(chunk, outputOptions) {
if (chunk.cssFilenameTemplate) {
return chunk.cssFilenameTemplate;
} else if (chunk.canBeInitial()) {
return outputOptions.cssFilename;
} else {
return outputOptions.cssChunkFilename;
return /** @type {TemplatePath} */ (outputOptions.cssFilename);
}
return /** @type {TemplatePath} */ (outputOptions.cssChunkFilename);
}
/**
@@ -799,8 +922,10 @@ class CssModulesPlugin {
*/
static chunkHasCss(chunk, chunkGraph) {
return (
!!chunkGraph.getChunkModulesIterableBySourceType(chunk, "css") ||
!!chunkGraph.getChunkModulesIterableBySourceType(chunk, "css-import")
Boolean(chunkGraph.getChunkModulesIterableBySourceType(chunk, "css")) ||
Boolean(
chunkGraph.getChunkModulesIterableBySourceType(chunk, "css-import")
)
);
}
}