source: frontend/node_modules/webpack/lib/sharing/ProvideSharedPlugin.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
4*/
5
6"use strict";
7
8const { parseOptions } = require("../container/options");
9const WebpackError = require("../errors/WebpackError");
10const ProvideForSharedDependency = require("./ProvideForSharedDependency");
11const ProvideSharedDependency = require("./ProvideSharedDependency");
12const ProvideSharedModuleFactory = require("./ProvideSharedModuleFactory");
13
14/** @typedef {import("../../declarations/plugins/sharing/ProvideSharedPlugin").ProvideSharedPluginOptions} ProvideSharedPluginOptions */
15/** @typedef {import("../Compilation")} Compilation */
16/** @typedef {import("../Compiler")} Compiler */
17/** @typedef {import("../NormalModuleFactory").NormalModuleCreateData} NormalModuleCreateData */
18
19/**
20 * Defines the provide options type used by this module.
21 * @typedef {object} ProvideOptions
22 * @property {string} shareKey
23 * @property {string} shareScope
24 * @property {string | undefined | false} version
25 * @property {boolean} eager
26 */
27
28/** @typedef {Map<string, { config: ProvideOptions, version: string | undefined | false }>} ResolvedProvideMap */
29
30const PLUGIN_NAME = "ProvideSharedPlugin";
31
32class ProvideSharedPlugin {
33 /**
34 * Creates an instance of ProvideSharedPlugin.
35 * @param {ProvideSharedPluginOptions} options options
36 */
37 constructor(options) {
38 this.options = options;
39 }
40
41 /**
42 * Applies the plugin by registering its hooks on the compiler.
43 * @param {Compiler} compiler the compiler instance
44 * @returns {void}
45 */
46 apply(compiler) {
47 compiler.hooks.validate.tap(PLUGIN_NAME, () => {
48 compiler.validate(
49 () => require("../../schemas/plugins/sharing/ProvideSharedPlugin.json"),
50 this.options,
51 {
52 name: "Provide Shared Plugin",
53 baseDataPath: "options"
54 },
55 (options) =>
56 require("../../schemas/plugins/sharing/ProvideSharedPlugin.check")(
57 options
58 )
59 );
60 });
61
62 /** @type {[string, ProvideOptions][]} */
63 const provides = parseOptions(
64 this.options.provides,
65 (item) => {
66 if (Array.isArray(item)) {
67 throw new Error("Unexpected array of provides");
68 }
69 /** @type {ProvideOptions} */
70 const result = {
71 shareKey: item,
72 version: undefined,
73 shareScope: this.options.shareScope || "default",
74 eager: false
75 };
76 return result;
77 },
78 (item) => ({
79 shareKey: /** @type {string} */ (item.shareKey),
80 version: item.version,
81 shareScope: item.shareScope || this.options.shareScope || "default",
82 eager: Boolean(item.eager)
83 })
84 ).sort(([a], [b]) => {
85 if (a < b) return -1;
86 if (b < a) return 1;
87 return 0;
88 });
89
90 /** @type {WeakMap<Compilation, ResolvedProvideMap>} */
91 const compilationData = new WeakMap();
92
93 compiler.hooks.compilation.tap(
94 PLUGIN_NAME,
95 (compilation, { normalModuleFactory }) => {
96 /** @type {ResolvedProvideMap} */
97 const resolvedProvideMap = new Map();
98 /** @type {Map<string, ProvideOptions>} */
99 const matchProvides = new Map();
100 /** @type {Map<string, ProvideOptions>} */
101 const prefixMatchProvides = new Map();
102 for (const [request, config] of provides) {
103 if (/^(?:\/|[A-Z]:\\|\\\\|\.\.?(?:\/|$))/i.test(request)) {
104 // relative request
105 resolvedProvideMap.set(request, {
106 config,
107 version: config.version
108 });
109 } else if (/^(?:\/|[A-Z]:\\|\\\\)/i.test(request)) {
110 // absolute path
111 resolvedProvideMap.set(request, {
112 config,
113 version: config.version
114 });
115 } else if (request.endsWith("/")) {
116 // module request prefix
117 prefixMatchProvides.set(request, config);
118 } else {
119 // module request
120 matchProvides.set(request, config);
121 }
122 }
123 compilationData.set(compilation, resolvedProvideMap);
124 /**
125 * Provide shared module.
126 * @param {string} key key
127 * @param {ProvideOptions} config config
128 * @param {NormalModuleCreateData["resource"]} resource resource
129 * @param {NormalModuleCreateData["resourceResolveData"]} resourceResolveData resource resolve data
130 */
131 const provideSharedModule = (
132 key,
133 config,
134 resource,
135 resourceResolveData
136 ) => {
137 let version = config.version;
138 if (version === undefined) {
139 let details = "";
140 if (!resourceResolveData) {
141 details = "No resolve data provided from resolver.";
142 } else {
143 const descriptionFileData =
144 resourceResolveData.descriptionFileData;
145 if (!descriptionFileData) {
146 details =
147 "No description file (usually package.json) found. Add description file with name and version, or manually specify version in shared config.";
148 } else if (!descriptionFileData.version) {
149 details = `No version in description file (usually package.json). Add version to description file ${resourceResolveData.descriptionFilePath}, or manually specify version in shared config.`;
150 } else {
151 version = /** @type {string | false | undefined} */ (
152 descriptionFileData.version
153 );
154 }
155 }
156 if (!version) {
157 const error = new WebpackError(
158 `No version specified and unable to automatically determine one. ${details}`
159 );
160 error.file = `shared module ${key} -> ${resource}`;
161 compilation.warnings.push(error);
162 }
163 }
164 resolvedProvideMap.set(resource, {
165 config,
166 version
167 });
168 };
169 normalModuleFactory.hooks.module.tap(
170 PLUGIN_NAME,
171 (module, { resource, resourceResolveData }, resolveData) => {
172 if (resolvedProvideMap.has(resource)) {
173 return module;
174 }
175 const { request } = resolveData;
176 {
177 const config = matchProvides.get(request);
178 if (config !== undefined) {
179 provideSharedModule(
180 request,
181 config,
182 resource,
183 resourceResolveData
184 );
185 resolveData.cacheable = false;
186 }
187 }
188 for (const [prefix, config] of prefixMatchProvides) {
189 if (request.startsWith(prefix)) {
190 const remainder = request.slice(prefix.length);
191 provideSharedModule(
192 resource,
193 {
194 ...config,
195 shareKey: config.shareKey + remainder
196 },
197 resource,
198 resourceResolveData
199 );
200 resolveData.cacheable = false;
201 }
202 }
203 return module;
204 }
205 );
206 }
207 );
208 compiler.hooks.finishMake.tapPromise(PLUGIN_NAME, (compilation) => {
209 const resolvedProvideMap = compilationData.get(compilation);
210 if (!resolvedProvideMap) return Promise.resolve();
211 return Promise.all(
212 Array.from(
213 resolvedProvideMap,
214 ([resource, { config, version }]) =>
215 new Promise((resolve, reject) => {
216 compilation.addInclude(
217 compiler.context,
218 new ProvideSharedDependency(
219 config.shareScope,
220 config.shareKey,
221 version || false,
222 resource,
223 config.eager
224 ),
225 {
226 name: undefined
227 },
228 (err) => {
229 if (err) return reject(err);
230 resolve(null);
231 }
232 );
233 })
234 )
235 ).then(() => {});
236 });
237
238 compiler.hooks.compilation.tap(
239 PLUGIN_NAME,
240 (compilation, { normalModuleFactory }) => {
241 compilation.dependencyFactories.set(
242 ProvideForSharedDependency,
243 normalModuleFactory
244 );
245
246 compilation.dependencyFactories.set(
247 ProvideSharedDependency,
248 new ProvideSharedModuleFactory()
249 );
250 }
251 );
252 }
253}
254
255module.exports = ProvideSharedPlugin;
Note: See TracBrowser for help on using the repository browser.