Projekt

Obecné

Profil

Stáhnout (8.57 KB) Statistiky
| Větev: | Revize:
1
/*
2
	MIT License http://www.opensource.org/licenses/mit-license.php
3
	Author Tobias Koppers @sokra
4
*/
5
"use strict";
6

    
7
const { ConcatSource, OriginalSource } = require("webpack-sources");
8
const Template = require("./Template");
9

    
10
/** @typedef {import("../declarations/WebpackOptions").LibraryCustomUmdObject} LibraryCustomUmdObject */
11
/** @typedef {import("./Compilation")} Compilation */
12

    
13
/**
14
 * @param {string[]} accessor the accessor to convert to path
15
 * @returns {string} the path
16
 */
17
const accessorToObjectAccess = accessor => {
18
	return accessor.map(a => `[${JSON.stringify(a)}]`).join("");
19
};
20

    
21
/**
22
 * @param {string=} base the path prefix
23
 * @param {string|string[]} accessor the accessor
24
 * @param {string=} joinWith the element separator
25
 * @returns {string} the path
26
 */
27
const accessorAccess = (base, accessor, joinWith = ", ") => {
28
	const accessors = Array.isArray(accessor) ? accessor : [accessor];
29
	return accessors
30
		.map((_, idx) => {
31
			const a = base
32
				? base + accessorToObjectAccess(accessors.slice(0, idx + 1))
33
				: accessors[0] + accessorToObjectAccess(accessors.slice(1, idx + 1));
34
			if (idx === accessors.length - 1) return a;
35
			if (idx === 0 && base === undefined)
36
				return `${a} = typeof ${a} === "object" ? ${a} : {}`;
37
			return `${a} = ${a} || {}`;
38
		})
39
		.join(joinWith);
40
};
41

    
42
/** @typedef {string | string[] | LibraryCustomUmdObject} UmdMainTemplatePluginName */
43

    
44
/**
45
 * @typedef {Object} AuxiliaryCommentObject
46
 * @property {string} root
47
 * @property {string} commonjs
48
 * @property {string} commonjs2
49
 * @property {string} amd
50
 */
51

    
52
/**
53
 * @typedef {Object} UmdMainTemplatePluginOption
54
 * @property {boolean=} optionalAmdExternalAsGlobal
55
 * @property {boolean} namedDefine
56
 * @property {string | AuxiliaryCommentObject} auxiliaryComment
57
 */
58

    
59
class UmdMainTemplatePlugin {
60
	/**
61
	 * @param {UmdMainTemplatePluginName} name the name of the UMD library
62
	 * @param {UmdMainTemplatePluginOption} options the plugin option
63
	 */
64
	constructor(name, options) {
65
		if (typeof name === "object" && !Array.isArray(name)) {
66
			this.name = name.root || name.amd || name.commonjs;
67
			this.names = name;
68
		} else {
69
			this.name = name;
70
			this.names = {
71
				commonjs: name,
72
				root: name,
73
				amd: name
74
			};
75
		}
76
		this.optionalAmdExternalAsGlobal = options.optionalAmdExternalAsGlobal;
77
		this.namedDefine = options.namedDefine;
78
		this.auxiliaryComment = options.auxiliaryComment;
79
	}
80

    
81
	/**
82
	 * @param {Compilation} compilation the compilation instance
83
	 * @returns {void}
84
	 */
85
	apply(compilation) {
86
		const { mainTemplate, chunkTemplate, runtimeTemplate } = compilation;
87

    
88
		const onRenderWithEntry = (source, chunk, hash) => {
89
			let externals = chunk
90
				.getModules()
91
				.filter(
92
					m =>
93
						m.external &&
94
						(m.externalType === "umd" || m.externalType === "umd2")
95
				);
96
			const optionalExternals = [];
97
			let requiredExternals = [];
98
			if (this.optionalAmdExternalAsGlobal) {
99
				for (const m of externals) {
100
					if (m.optional) {
101
						optionalExternals.push(m);
102
					} else {
103
						requiredExternals.push(m);
104
					}
105
				}
106
				externals = requiredExternals.concat(optionalExternals);
107
			} else {
108
				requiredExternals = externals;
109
			}
110

    
111
			const replaceKeys = str => {
112
				return mainTemplate.getAssetPath(str, {
113
					hash,
114
					chunk
115
				});
116
			};
117

    
118
			const externalsDepsArray = modules => {
119
				return `[${replaceKeys(
120
					modules
121
						.map(m =>
122
							JSON.stringify(
123
								typeof m.request === "object" ? m.request.amd : m.request
124
							)
125
						)
126
						.join(", ")
127
				)}]`;
128
			};
129

    
130
			const externalsRootArray = modules => {
131
				return replaceKeys(
132
					modules
133
						.map(m => {
134
							let request = m.request;
135
							if (typeof request === "object") request = request.root;
136
							return `root${accessorToObjectAccess([].concat(request))}`;
137
						})
138
						.join(", ")
139
				);
140
			};
141

    
142
			const externalsRequireArray = type => {
143
				return replaceKeys(
144
					externals
145
						.map(m => {
146
							let expr;
147
							let request = m.request;
148
							if (typeof request === "object") {
149
								request = request[type];
150
							}
151
							if (request === undefined) {
152
								throw new Error(
153
									"Missing external configuration for type:" + type
154
								);
155
							}
156
							if (Array.isArray(request)) {
157
								expr = `require(${JSON.stringify(
158
									request[0]
159
								)})${accessorToObjectAccess(request.slice(1))}`;
160
							} else {
161
								expr = `require(${JSON.stringify(request)})`;
162
							}
163
							if (m.optional) {
164
								expr = `(function webpackLoadOptionalExternalModule() { try { return ${expr}; } catch(e) {} }())`;
165
							}
166
							return expr;
167
						})
168
						.join(", ")
169
				);
170
			};
171

    
172
			const externalsArguments = modules => {
173
				return modules
174
					.map(
175
						m =>
176
							`__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__`
177
					)
178
					.join(", ");
179
			};
180

    
181
			const libraryName = library => {
182
				return JSON.stringify(replaceKeys([].concat(library).pop()));
183
			};
184

    
185
			let amdFactory;
186
			if (optionalExternals.length > 0) {
187
				const wrapperArguments = externalsArguments(requiredExternals);
188
				const factoryArguments =
189
					requiredExternals.length > 0
190
						? externalsArguments(requiredExternals) +
191
						  ", " +
192
						  externalsRootArray(optionalExternals)
193
						: externalsRootArray(optionalExternals);
194
				amdFactory =
195
					`function webpackLoadOptionalExternalModuleAmd(${wrapperArguments}) {\n` +
196
					`			return factory(${factoryArguments});\n` +
197
					"		}";
198
			} else {
199
				amdFactory = "factory";
200
			}
201

    
202
			const auxiliaryComment = this.auxiliaryComment;
203

    
204
			const getAuxilaryComment = type => {
205
				if (auxiliaryComment) {
206
					if (typeof auxiliaryComment === "string")
207
						return "\t//" + auxiliaryComment + "\n";
208
					if (auxiliaryComment[type])
209
						return "\t//" + auxiliaryComment[type] + "\n";
210
				}
211
				return "";
212
			};
213

    
214
			return new ConcatSource(
215
				new OriginalSource(
216
					"(function webpackUniversalModuleDefinition(root, factory) {\n" +
217
						getAuxilaryComment("commonjs2") +
218
						"	if(typeof exports === 'object' && typeof module === 'object')\n" +
219
						"		module.exports = factory(" +
220
						externalsRequireArray("commonjs2") +
221
						");\n" +
222
						getAuxilaryComment("amd") +
223
						"	else if(typeof define === 'function' && define.amd)\n" +
224
						(requiredExternals.length > 0
225
							? this.names.amd && this.namedDefine === true
226
								? "		define(" +
227
								  libraryName(this.names.amd) +
228
								  ", " +
229
								  externalsDepsArray(requiredExternals) +
230
								  ", " +
231
								  amdFactory +
232
								  ");\n"
233
								: "		define(" +
234
								  externalsDepsArray(requiredExternals) +
235
								  ", " +
236
								  amdFactory +
237
								  ");\n"
238
							: this.names.amd && this.namedDefine === true
239
							? "		define(" +
240
							  libraryName(this.names.amd) +
241
							  ", [], " +
242
							  amdFactory +
243
							  ");\n"
244
							: "		define([], " + amdFactory + ");\n") +
245
						(this.names.root || this.names.commonjs
246
							? getAuxilaryComment("commonjs") +
247
							  "	else if(typeof exports === 'object')\n" +
248
							  "		exports[" +
249
							  libraryName(this.names.commonjs || this.names.root) +
250
							  "] = factory(" +
251
							  externalsRequireArray("commonjs") +
252
							  ");\n" +
253
							  getAuxilaryComment("root") +
254
							  "	else\n" +
255
							  "		" +
256
							  replaceKeys(
257
									accessorAccess("root", this.names.root || this.names.commonjs)
258
							  ) +
259
							  " = factory(" +
260
							  externalsRootArray(externals) +
261
							  ");\n"
262
							: "	else {\n" +
263
							  (externals.length > 0
264
									? "		var a = typeof exports === 'object' ? factory(" +
265
									  externalsRequireArray("commonjs") +
266
									  ") : factory(" +
267
									  externalsRootArray(externals) +
268
									  ");\n"
269
									: "		var a = factory();\n") +
270
							  "		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n" +
271
							  "	}\n") +
272
						`})(${
273
							runtimeTemplate.outputOptions.globalObject
274
						}, function(${externalsArguments(externals)}) {\nreturn `,
275
					"webpack/universalModuleDefinition"
276
				),
277
				source,
278
				";\n})"
279
			);
280
		};
281

    
282
		for (const template of [mainTemplate, chunkTemplate]) {
283
			template.hooks.renderWithEntry.tap(
284
				"UmdMainTemplatePlugin",
285
				onRenderWithEntry
286
			);
287
		}
288

    
289
		mainTemplate.hooks.globalHashPaths.tap("UmdMainTemplatePlugin", paths => {
290
			if (this.names.root) paths = paths.concat(this.names.root);
291
			if (this.names.amd) paths = paths.concat(this.names.amd);
292
			if (this.names.commonjs) paths = paths.concat(this.names.commonjs);
293
			return paths;
294
		});
295

    
296
		mainTemplate.hooks.hash.tap("UmdMainTemplatePlugin", hash => {
297
			hash.update("umd");
298
			hash.update(`${this.names.root}`);
299
			hash.update(`${this.names.amd}`);
300
			hash.update(`${this.names.commonjs}`);
301
		});
302
	}
303
}
304

    
305
module.exports = UmdMainTemplatePlugin;
(128-128/144)