UNPKG

6.51 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5"use strict";
6
7const identifierUtils = require("./util/identifier");
8
9/** @typedef {import("./Compiler")} Compiler */
10/** @typedef {import("./Chunk")} Chunk */
11/** @typedef {import("./Module")} Module */
12
13/**
14 * @typedef {Object} RecordsChunks
15 * @property {Record<string, number>=} byName
16 * @property {Record<string, number>=} bySource
17 * @property {number[]=} usedIds
18 */
19
20/**
21 * @typedef {Object} RecordsModules
22 * @property {Record<string, number>=} byIdentifier
23 * @property {Record<string, number>=} bySource
24 * @property {Record<number, number>=} usedIds
25 */
26
27/**
28 * @typedef {Object} Records
29 * @property {RecordsChunks=} chunks
30 * @property {RecordsModules=} modules
31 */
32
33class RecordIdsPlugin {
34 /**
35 * @param {Object} options Options object
36 * @param {boolean=} options.portableIds true, when ids need to be portable
37 */
38 constructor(options) {
39 this.options = options || {};
40 }
41
42 /**
43 * @param {Compiler} compiler the Compiler
44 * @returns {void}
45 */
46 apply(compiler) {
47 const portableIds = this.options.portableIds;
48 compiler.hooks.compilation.tap("RecordIdsPlugin", compilation => {
49 compilation.hooks.recordModules.tap(
50 "RecordIdsPlugin",
51 /**
52 * @param {Module[]} modules the modules array
53 * @param {Records} records the records object
54 * @returns {void}
55 */
56 (modules, records) => {
57 if (!records.modules) records.modules = {};
58 if (!records.modules.byIdentifier) records.modules.byIdentifier = {};
59 if (!records.modules.usedIds) records.modules.usedIds = {};
60 for (const module of modules) {
61 if (typeof module.id !== "number") continue;
62 const identifier = portableIds
63 ? identifierUtils.makePathsRelative(
64 compiler.context,
65 module.identifier(),
66 compilation.cache
67 )
68 : module.identifier();
69 records.modules.byIdentifier[identifier] = module.id;
70 records.modules.usedIds[module.id] = module.id;
71 }
72 }
73 );
74 compilation.hooks.reviveModules.tap(
75 "RecordIdsPlugin",
76 /**
77 * @param {Module[]} modules the modules array
78 * @param {Records} records the records object
79 * @returns {void}
80 */
81 (modules, records) => {
82 if (!records.modules) return;
83 if (records.modules.byIdentifier) {
84 /** @type {Set<number>} */
85 const usedIds = new Set();
86 for (const module of modules) {
87 if (module.id !== null) continue;
88 const identifier = portableIds
89 ? identifierUtils.makePathsRelative(
90 compiler.context,
91 module.identifier(),
92 compilation.cache
93 )
94 : module.identifier();
95 const id = records.modules.byIdentifier[identifier];
96 if (id === undefined) continue;
97 if (usedIds.has(id)) continue;
98 usedIds.add(id);
99 module.id = id;
100 }
101 }
102 if (Array.isArray(records.modules.usedIds)) {
103 compilation.usedModuleIds = new Set(records.modules.usedIds);
104 }
105 }
106 );
107
108 /**
109 * @param {Module} module the module
110 * @returns {string} the (portable) identifier
111 */
112 const getModuleIdentifier = module => {
113 if (portableIds) {
114 return identifierUtils.makePathsRelative(
115 compiler.context,
116 module.identifier(),
117 compilation.cache
118 );
119 }
120 return module.identifier();
121 };
122
123 /**
124 * @param {Chunk} chunk the chunk
125 * @returns {string[]} sources of the chunk
126 */
127 const getChunkSources = chunk => {
128 /** @type {string[]} */
129 const sources = [];
130 for (const chunkGroup of chunk.groupsIterable) {
131 const index = chunkGroup.chunks.indexOf(chunk);
132 for (const origin of chunkGroup.origins) {
133 if (origin.module) {
134 if (origin.request) {
135 sources.push(
136 `${index} ${getModuleIdentifier(origin.module)} ${
137 origin.request
138 }`
139 );
140 } else if (typeof origin.loc === "string") {
141 sources.push(
142 `${index} ${getModuleIdentifier(origin.module)} ${origin.loc}`
143 );
144 } else if (
145 origin.loc &&
146 typeof origin.loc === "object" &&
147 origin.loc.start
148 ) {
149 sources.push(
150 `${index} ${getModuleIdentifier(
151 origin.module
152 )} ${JSON.stringify(origin.loc.start)}`
153 );
154 }
155 }
156 }
157 }
158 return sources;
159 };
160
161 compilation.hooks.recordChunks.tap(
162 "RecordIdsPlugin",
163 /**
164 * @param {Chunk[]} chunks the chunks array
165 * @param {Records} records the records object
166 * @returns {void}
167 */
168 (chunks, records) => {
169 if (!records.chunks) records.chunks = {};
170 if (!records.chunks.byName) records.chunks.byName = {};
171 if (!records.chunks.bySource) records.chunks.bySource = {};
172 /** @type {Set<number>} */
173 const usedIds = new Set();
174 for (const chunk of chunks) {
175 if (typeof chunk.id !== "number") continue;
176 const name = chunk.name;
177 if (name) records.chunks.byName[name] = chunk.id;
178 const sources = getChunkSources(chunk);
179 for (const source of sources) {
180 records.chunks.bySource[source] = chunk.id;
181 }
182 usedIds.add(chunk.id);
183 }
184 records.chunks.usedIds = Array.from(usedIds).sort();
185 }
186 );
187 compilation.hooks.reviveChunks.tap(
188 "RecordIdsPlugin",
189 /**
190 * @param {Chunk[]} chunks the chunks array
191 * @param {Records} records the records object
192 * @returns {void}
193 */
194 (chunks, records) => {
195 if (!records.chunks) return;
196 /** @type {Set<number>} */
197 const usedIds = new Set();
198 if (records.chunks.byName) {
199 for (const chunk of chunks) {
200 if (chunk.id !== null) continue;
201 if (!chunk.name) continue;
202 const id = records.chunks.byName[chunk.name];
203 if (id === undefined) continue;
204 if (usedIds.has(id)) continue;
205 usedIds.add(id);
206 chunk.id = id;
207 }
208 }
209 if (records.chunks.bySource) {
210 for (const chunk of chunks) {
211 const sources = getChunkSources(chunk);
212 for (const source of sources) {
213 const id = records.chunks.bySource[source];
214 if (id === undefined) continue;
215 if (usedIds.has(id)) continue;
216 usedIds.add(id);
217 chunk.id = id;
218 break;
219 }
220 }
221 }
222 if (Array.isArray(records.chunks.usedIds)) {
223 compilation.usedChunkIds = new Set(records.chunks.usedIds);
224 }
225 }
226 );
227 });
228 }
229}
230module.exports = RecordIdsPlugin;