function makeModuleError(template, module, cause) {
		let modules = `'${module.name}'`;

		if (isModuleError(cause)) {
			// update the chain of modules (increasing the indent)
			modules += `\n -> ${cause._modules.replace(/ -> /g, "  -> ")}`;
			// omit repeated occurrences of the same kind of error
			if ( template === cause._template ) {
				cause = cause.cause;
			}
		}

		// create the message string from the template and the cause's message
		const message =
			template.replace(/\{id\}/, modules).replace(/\{url\}/, module.url)
			+ (cause ? ": " + cause.message : "");

		const error = new Error(message);
		error.name = "ModuleError";
		error.cause = cause;
		if ( cause?.stack ) {
			error.stack = error.stack + "\nCaused by: " + cause.stack;
		}
		// the following properties are only for internal usage
		error._template = template;
		error._modules = modules;
		return error;
	}
Wraps the given 'cause' in a new error with the given message and with name 'ModuleError'.

The new message and the message of the cause are combined. The stacktrace of the
new error and of the cause are combined (with a separating 'Caused by').

Instead of the final message string, a template is provided which can contain placeholders
for the module ID ({id}) and module URL ({url}). Providing a template without concrete
values allows to detect the repeated nesting of the same error. In such a case, only
the innermost cause will be kept (affects both, stack trace as well as the cause property).
The message, however, will contain the full chain of module IDs.

@param {string} template Message string template with placeholders
@param {Module} module Module for which the error occurred
@param {Error} cause original error
@returns {Error} New module error