webpack/lib/RecordIdsPlugin.js

213 lines
6.0 KiB
JavaScript
Raw Normal View History

2013-05-31 18:22:40 +08:00
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2018-07-30 23:08:51 +08:00
2017-02-21 22:13:09 +08:00
"use strict";
const { compareNumbers } = require("./util/comparators");
const identifierUtils = require("./util/identifier");
2018-06-06 22:37:23 +08:00
/** @typedef {import("./Chunk")} Chunk */
2018-07-30 23:08:51 +08:00
/** @typedef {import("./Compiler")} Compiler */
2018-06-06 22:37:23 +08:00
/** @typedef {import("./Module")} Module */
/**
2024-06-11 21:09:50 +08:00
* @typedef {object} RecordsChunks
2018-06-06 22:37:23 +08:00
* @property {Record<string, number>=} byName
* @property {Record<string, number>=} bySource
* @property {number[]=} usedIds
*/
/**
2024-06-11 21:09:50 +08:00
* @typedef {object} RecordsModules
2018-06-06 22:37:23 +08:00
* @property {Record<string, number>=} byIdentifier
* @property {number[]=} usedIds
2018-06-06 22:37:23 +08:00
*/
/**
2024-06-11 21:09:50 +08:00
* @typedef {object} Records
2018-06-06 22:37:23 +08:00
* @property {RecordsChunks=} chunks
* @property {RecordsModules=} modules
*/
/**
* @typedef {object} RecordIdsPluginOptions
* @property {boolean=} portableIds true, when ids need to be portable
*/
2025-04-23 20:03:37 +08:00
const PLUGIN_NAME = "RecordIdsPlugin";
class RecordIdsPlugin {
2018-06-06 22:37:23 +08:00
/**
2025-04-16 22:04:11 +08:00
* @param {RecordIdsPluginOptions=} options object
2018-06-06 22:37:23 +08:00
*/
constructor(options) {
this.options = options || {};
}
2018-06-06 22:37:23 +08:00
/**
* @param {Compiler} compiler the Compiler
* @returns {void}
*/
2017-02-21 22:13:09 +08:00
apply(compiler) {
const portableIds = this.options.portableIds;
2020-04-17 16:54:27 +08:00
2021-05-11 15:31:46 +08:00
const makePathsRelative =
identifierUtils.makePathsRelative.bindContextCache(
compiler.context,
compiler.root
);
2020-04-17 16:54:27 +08:00
/**
* @param {Module} module the module
* @returns {string} the (portable) identifier
*/
const getModuleIdentifier = module => {
if (portableIds) {
return makePathsRelative(module.identifier());
}
return module.identifier();
};
2025-04-23 20:03:37 +08:00
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
compilation.hooks.recordModules.tap(PLUGIN_NAME, (modules, records) => {
const chunkGraph = compilation.chunkGraph;
if (!records.modules) records.modules = {};
if (!records.modules.byIdentifier) records.modules.byIdentifier = {};
/** @type {Set<number>} */
const usedIds = new Set();
for (const module of modules) {
const moduleId = chunkGraph.getModuleId(module);
if (typeof moduleId !== "number") continue;
const identifier = getModuleIdentifier(module);
records.modules.byIdentifier[identifier] = moduleId;
usedIds.add(moduleId);
}
records.modules.usedIds = Array.from(usedIds).sort(compareNumbers);
});
compilation.hooks.reviveModules.tap(PLUGIN_NAME, (modules, records) => {
if (!records.modules) return;
if (records.modules.byIdentifier) {
const chunkGraph = compilation.chunkGraph;
/** @type {Set<number>} */
const usedIds = new Set();
2018-02-25 09:00:20 +08:00
for (const module of modules) {
const moduleId = chunkGraph.getModuleId(module);
2025-04-23 20:03:37 +08:00
if (moduleId !== null) continue;
2020-04-17 16:54:27 +08:00
const identifier = getModuleIdentifier(module);
2025-04-23 20:03:37 +08:00
const id = records.modules.byIdentifier[identifier];
if (id === undefined) continue;
if (usedIds.has(id)) continue;
usedIds.add(id);
chunkGraph.setModuleId(module, id);
2018-02-25 09:00:20 +08:00
}
2018-01-22 20:52:43 +08:00
}
2025-04-23 20:03:37 +08:00
if (Array.isArray(records.modules.usedIds)) {
compilation.usedModuleIds = new Set(records.modules.usedIds);
2017-02-21 22:13:09 +08:00
}
2025-04-23 20:03:37 +08:00
});
2015-04-24 05:55:50 +08:00
2018-06-06 22:37:23 +08:00
/**
* @param {Chunk} chunk the chunk
* @returns {string[]} sources of the chunk
*/
const getChunkSources = chunk => {
2018-06-06 22:37:23 +08:00
/** @type {string[]} */
const sources = [];
2018-02-25 09:00:20 +08:00
for (const chunkGroup of chunk.groupsIterable) {
const index = chunkGroup.chunks.indexOf(chunk);
if (chunkGroup.name) {
sources.push(`${index} ${chunkGroup.name}`);
} else {
for (const origin of chunkGroup.origins) {
if (origin.module) {
if (origin.request) {
sources.push(
`${index} ${getModuleIdentifier(origin.module)} ${
origin.request
}`
);
} else if (typeof origin.loc === "string") {
sources.push(
`${index} ${getModuleIdentifier(origin.module)} ${
origin.loc
}`
);
} else if (
origin.loc &&
typeof origin.loc === "object" &&
"start" in origin.loc
) {
sources.push(
`${index} ${getModuleIdentifier(
origin.module
)} ${JSON.stringify(origin.loc.start)}`
);
}
}
}
}
2017-02-21 22:13:09 +08:00
}
return sources;
2017-11-08 18:32:05 +08:00
};
2025-04-23 20:03:37 +08:00
compilation.hooks.recordChunks.tap(PLUGIN_NAME, (chunks, records) => {
if (!records.chunks) records.chunks = {};
if (!records.chunks.byName) records.chunks.byName = {};
if (!records.chunks.bySource) records.chunks.bySource = {};
/** @type {Set<number>} */
const usedIds = new Set();
for (const chunk of chunks) {
if (typeof chunk.id !== "number") continue;
const name = chunk.name;
if (name) records.chunks.byName[name] = chunk.id;
const sources = getChunkSources(chunk);
for (const source of sources) {
records.chunks.bySource[source] = chunk.id;
}
usedIds.add(chunk.id);
}
records.chunks.usedIds = Array.from(usedIds).sort(compareNumbers);
});
compilation.hooks.reviveChunks.tap(PLUGIN_NAME, (chunks, records) => {
if (!records.chunks) return;
/** @type {Set<number>} */
const usedIds = new Set();
if (records.chunks.byName) {
2018-02-25 09:00:20 +08:00
for (const chunk of chunks) {
2025-04-23 20:03:37 +08:00
if (chunk.id !== null) continue;
if (!chunk.name) continue;
const id = records.chunks.byName[chunk.name];
if (id === undefined) continue;
if (usedIds.has(id)) continue;
usedIds.add(id);
chunk.id = id;
chunk.ids = [id];
2018-01-22 20:52:43 +08:00
}
2017-02-21 22:13:09 +08:00
}
2025-04-23 20:03:37 +08:00
if (records.chunks.bySource) {
for (const chunk of chunks) {
if (chunk.id !== null) continue;
const sources = getChunkSources(chunk);
for (const source of sources) {
const id = records.chunks.bySource[source];
2018-02-25 09:00:20 +08:00
if (id === undefined) continue;
if (usedIds.has(id)) continue;
usedIds.add(id);
chunk.id = id;
2018-09-05 20:22:10 +08:00
chunk.ids = [id];
2025-04-23 20:03:37 +08:00
break;
}
2018-01-22 20:52:43 +08:00
}
2017-02-21 22:13:09 +08:00
}
2025-04-23 20:03:37 +08:00
if (Array.isArray(records.chunks.usedIds)) {
compilation.usedChunkIds = new Set(records.chunks.usedIds);
}
});
2013-05-31 18:22:40 +08:00
});
2017-02-21 22:13:09 +08:00
}
}
2017-02-21 22:13:09 +08:00
module.exports = RecordIdsPlugin;