Repository: webpack/webpack (JavaScript)

Issue:
Module Federation deps strictVersion mismatch source in error message
<!-- Please don't delete this template or we'll close your issue -->

## Feature request

<!-- Issues that contain questions or support requests will be closed. -->
<!-- Before creating an issue please make sure you are using the latest version of webpack. -->
<!-- Check if this feature needs to be implemented in a plugin or loader instead -->
<!-- If yes: file the issue on the plugin/loader repo -->
<!-- Features related to the development server should be filed on this repo instead -->

**What is the expected behavior?**
`getStrictSingletonVersion` throws more detailed error.
Also will be great get all errors at once (not one per step)

This dramatically decrease spent time on module federation integration process.


**What is motivation or use case for adding/changing the behavior?**
Adding module federation to huge porject i'm facing following problem:
I'm unable do determine package, which declare mismatched strict version dependency, because only clue i've get is 
```
Unsatisfied version 11.0.3 of shared singleton module @angular/core (required ^10.0.0)
```

Digging deeper i've found this (but it still don't help me):
![image](https://user-images.githubusercontent.com/1610882/112955615-4a96c600-9148-11eb-8d8d-7aa08ed995ac.png)
There are is a lot of older angular dependencies version, but - i can't determine which package bring them there.

**How should this be implemented in your opinion?**

This:
```
Unsatisfied version 11.0.3 of shared singleton module @angular/core (required ^10.0.0)
```

Will be good to expanded to this:
```
Unsatisfied versions detected:
@angular/core (current 11.0.3)
   10.0.0 (by @ngrx/core)
   6.0.3 (by ngx-quicklinks)
```
**Are you willing to work on this yourself?**
I'm not sure i can handle it, but i can try, if you give me few design clues.



Hints:
That too baaaaad(
Digging into all packages to find exact package which add own peerDependencies and mess the bundle
Try `yarn why @angular/core`. I guess that will print the information you are looking for. Otherwise you can use the stack trace of the error.
Ofcourse i tried, it was in peerDependency of installed packages and not displayed by `yarn why` (because of peerDependencies).

Stack trace also doesn't work, because it is `eager` module, and eager dependency list defined right in previous line of code (it don't traced up to parent call)

I found all mismatched peerDependencies by:
```bash
grep -nri '@angular' --include="package.json" node_modules
```

But it looks not about good DX. So that's why i file that issue

@glebmachine Maybe you can provide example?
@alexander-akait Sure!
https://github.com/glebmachine/module-federation-version-mismatch-repro

Steps to reproduce:
1. `git clone git@github.com:glebmachine/module-federation-version-mismatch-repro.git` 
2. `cd module-federation-version-mismatch-repro`
3. `yarn`
4. `./node_modules/.bin/ng run shell:serve`


Kindly reminder
```
warning " > ngx-sub-form@5.1.2" has incorrect peer dependency "@angular/common@^9.0.0".
warning " > ngx-sub-form@5.1.2" has incorrect peer dependency "@angular/core@^9.0.0".
warning " > ngx-sub-form@5.1.2" has incorrect peer dependency "tslib@^1.10.0".
```

You have mixed version of `@angular/core`, only one `@angular/core` package allowed to use. It is configured by `@angular/cli`

Nothing to fix here, sorry
You can comment and change code:
```
// import { Controls, NgxAutomaticRootFormComponent } from 'ngx-sub-form';
```

and all works fine
@alexander-akait Ваш комментарий выглядит как издевательство, честно

Это репро, я наглядно здесь иллюстрирую скупые сообщения об ошибках
Вот скриншот ошибки:
![image](https://user-images.githubusercontent.com/1610882/114544836-d9850180-9c63-11eb-8eae-65b93c33a0c3.png)

В сообщении не сказано, какой модуль принес зависимость с несовместимой версией
И `ngx-sub-form` это как раз та самая зависимость, не надо ее комментировать. Это вопроc DX, который дает webpack.

Единственный способ ее найти, это грепать по зависимостям
Если нужны комментарии, мы можем вживую с вами пообщаться: t.me/glebmikheev

@glebmachine

> Ваш комментарий выглядит как издевательство, честно
> Это вопроc DX, который дает webpack.

Пожалуйста не будьте токсичны, это настройка лежит внутри `@angular/cli` и именно там `angular-cli` должен вам сообщить о несовместимости, мы это описываем достаточно хорошо в документации. Что вы здесь ожидаете? Мы сообщили о несовместимой версии и в какой модуле проблема. Некоторые пакеты можно использовать много раз, некоторые нет, мы не можем проанализировать код каждого пакеты на совместимость, все что мы можем - вывести ошибку на основании используемых модулей и их настроект при федерации модулей.

К слову говоря даже пакетный менеджер вам об этом сообщает. Даже более при использовании yarn PnP или pnpm вы не сможете установить ваши зависимости из-за этой проблемы без хаков. И даже ещё более - использовать разных версий angular скорее всего сломает ваш проект.  
@alexander-akait сейчас принесу чистое репро, где только js
Я понимаю ваш вопрос и желание, я помечу это как улучшение, но это может быт не так легко решить как кажется, так как сборка может происходить независимо и имена могут в production может быть сжаты, хотя это имеет смысл для development режима
Вот, пожалуйста, репро:

https://github.com/glebmachine/module-federation-pure-demo/tree/error-message

Тут чистый пример, где нет angular-специфики
Как запустить репро:

1. `git clone git@github.com:glebmachine/module-federation-pure-demo.git`
2. `git checkout error-message`
3. `npm i`
4. `npm run serve:shell`

И при запуске приложения мы получаем вот такую ошибку:
![image](https://user-images.githubusercontent.com/1610882/114548541-95483000-9c68-11eb-9309-516ce67da9bb.png)

### Подробности:
В общих зависимостях стоит `has-value: 2.0.2` (`package.json`)
В шереном модуле стоит зависимость `has-value: 0.0.1` (`app\package.json`)

В итоге генерится вот такой код:
![image](https://user-images.githubusercontent.com/1610882/114548858-ff60d500-9c68-11eb-9980-732ddeb8ff17.png)
Тут регистрируются фабрики для зависимостей, где указаны версии.

В случае если strictVersion зависимость, то генерится ошибка:
![image](https://user-images.githubusercontent.com/1610882/114549078-3fc05300-9c69-11eb-80be-15f9d92610a6.png)

И вот в этом контексте не хватает информации в _каком_ модуле, была определена версия зависимости.
Что в свою очередь не позволяет разработчику проанализировать проблему. Только понять и признать сам факт.

Мы можем дать более качественный DX, если подскажем _какой_ файл ему принес эту зависимость.
Может хотя-бы alias отсюда протащить до этого исключения, взяв название из этого конфига:
![image](https://user-images.githubusercontent.com/1610882/114549383-9c237280-9c69-11eb-8aed-1609d3fd9253.png)


Спасибо!)
Это действительно важная штука, потому что это то, что делает вебпак крутым, либо усложняет его использование
Module Federation одна из самых важных вещей, которая случилась с вебпаком после Tree Shaking'a. Хотелось бы, чтобы порог входа был как можно более низким.

Я сейчас перевожу большое банковское приложение, и это невероятно усложняет ежедневную поддержку кодовой базы
Могу посодействовать, чем смогу
Можешь послать PR если у тебя есть желание быстрее это улучшить :+1: 
> Можешь послать PR если у тебя есть желание быстрее это улучшить 👍

Я за, я готов

Но мне нужно помочь с дизайном, от того, кто шарит за архитектуру.
Пару подсказок, типа "посмотри сюда" "видишь вот тут"

Это и сократит вход в кодовую базу, и даст мне правильный дизайн, что уменьшит суету на ревью =)

Можешь дать подобные подсказочки, пожалуйста ?)
Пожалуйста, используйте английский в будущем
You can improve it here https://github.com/webpack/webpack/blob/master/lib/sharing/ConsumeSharedRuntimeModule.js, we have helpers like `findVersion`/`findSingletonVersionKey` https://github.com/webpack/webpack/blob/master/lib/sharing/ConsumeSharedRuntimeModule.js#L98, I think we need return not only versions, but also packages where this versions were used so it allows to improve error message
@snitin315 sure, thank you!
@alexander-akait thanks for some clues, will back soon)

Patch:
diff --git a/lib/sharing/ConsumeSharedRuntimeModule.js b/lib/sharing/ConsumeSharedRuntimeModule.js
--- a/lib/sharing/ConsumeSharedRuntimeModule.js
+++ b/lib/sharing/ConsumeSharedRuntimeModule.js
@@ -103,9 +103,9 @@ class ConsumeSharedRuntimeModule extends RuntimeModule {
 				]
 			)};`,
 			`var getInvalidSingletonVersionMessage = ${runtimeTemplate.basicFunction(
-				"key, version, requiredVersion",
+				"scope, key, version, requiredVersion",
 				[
-					`return "Unsatisfied version " + version + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"`
+					`return "Unsatisfied version " + version + " from " + (version && scope[key][version].from) + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"`
 				]
 			)};`,
 			`var getSingletonVersion = ${runtimeTemplate.basicFunction(
@@ -113,7 +113,7 @@ class ConsumeSharedRuntimeModule extends RuntimeModule {
 				[
 					"var version = findSingletonVersionKey(scope, key);",
 					"if (!satisfy(requiredVersion, version)) " +
-						'typeof console !== "undefined" && console.warn && console.warn(getInvalidSingletonVersionMessage(key, version, requiredVersion));',
+						'typeof console !== "undefined" && console.warn && console.warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));',
 					"return get(scope[key][version]);"
 				]
 			)};`,
@@ -122,7 +122,7 @@ class ConsumeSharedRuntimeModule extends RuntimeModule {
 				[
 					"var version = findSingletonVersionKey(scope, key);",
 					"if (!satisfy(requiredVersion, version)) " +
-						"throw new Error(getInvalidSingletonVersionMessage(key, version, requiredVersion));",
+						"throw new Error(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));",
 					"return get(scope[key][version]);"
 				]
 			)};`,


Test patch:
diff --git a/test/configCases/container/1-container-full/webpack.config.js b/test/configCases/container/1-container-full/webpack.config.js
--- a/test/configCases/container/1-container-full/webpack.config.js
+++ b/test/configCases/container/1-container-full/webpack.config.js
@@ -7,7 +7,8 @@ module.exports = {
 		bundle0: "./index.js"
 	},
 	output: {
-		filename: "[name].js"
+		filename: "[name].js",
+		uniqueName: "1-container-full"
 	},
 	plugins: [
 		new ModuleFederationPlugin({
diff --git a/test/configCases/container/2-container-full/index.js b/test/configCases/container/2-container-full/index.js
--- a/test/configCases/container/2-container-full/index.js
+++ b/test/configCases/container/2-container-full/index.js
@@ -30,7 +30,7 @@ const expectWarning = regexp => {
 it("should load the component from container", () => {
 	return import("./App").then(({ default: App }) => {
 		expectWarning(
-			/Unsatisfied version 8 of shared singleton module react \(required \^2\)/
+			/Unsatisfied version 8 from 2-container-full of shared singleton module react \(required \^2\)/
 		);
 		const rendered = App();
 		expect(rendered).toBe(
diff --git a/test/configCases/container/2-container-full/webpack.config.js b/test/configCases/container/2-container-full/webpack.config.js
--- a/test/configCases/container/2-container-full/webpack.config.js
+++ b/test/configCases/container/2-container-full/webpack.config.js
@@ -3,6 +3,9 @@ const { ModuleFederationPlugin } = require("../../../../").container;
 
 /** @type {import("../../../../").Configuration} */
 module.exports = {
+	output: {
+		uniqueName: "2-container-full"
+	},
 	plugins: [
 		new ModuleFederationPlugin({
 			name: "main",
diff --git a/test/configCases/sharing/consume-module/index.js b/test/configCases/sharing/consume-module/index.js
--- a/test/configCases/sharing/consume-module/index.js
+++ b/test/configCases/sharing/consume-module/index.js
@@ -193,7 +193,8 @@ it("should handle version matching correctly in strict and singleton mode", asyn
 		},
 		singleton: {
 			"1.1.1": {
-				get: () => () => "shared singleton"
+				get: () => () => "shared singleton",
+				from: 'container-a'
 			}
 		}
 	};
@@ -230,7 +231,7 @@ it("should handle version matching correctly in strict and singleton mode", asyn
 		const result = await import("singleton");
 		expect(result.default).toBe("shared singleton");
 		expectWarning(
-			/Unsatisfied version 1\.1\.1 of shared singleton module singleton \(required =1\.1\.0\)/
+			/Unsatisfied version 1\.1\.1 from container-a of shared singleton module singleton \(required =1\.1\.0\)/
 		);
 	}
 });