module-federation-plugin-example's Issues
Dynamic Module Federation with Angular Universal
Thanks for your wonderful approach!!!. Right now I made it work with relative path to consume remote plugins.
Is there any way to load dynamically how its loading for browser module? Currently creating script tag using "document" object but same thing is not working when I do for Server side rendering. Any help would be more for us to proceed further.
Basically remote entry location may vary so the we cannot create static server bundle with relative path
Server Side Rendering
I clone the repo and follow Trying it out secion, I disable async module federation as a first step after that once I run the following
ng add @nguniversal/common --project shell
I face the following error
Collection "C:\POC\module-federation-plugin-example\node_modules\@nguniversal\common\schematics\collection.json" cannot be resolved.
I tried to run the command with a project that doesn't have Module Federation and the same error raised.
Angular CLI proxy for configure several microApps
Hi Manfred,
Thank you for provide this kind of open source plugins that will help to the community.
Based in the example of the implementation of the MicroApp and Host/Shell App, the idea it's great as you have described below.
For Host/Shell App, is that possible to use Angular proxy CLI instead?
<some-element-ui microApp="/some-element-ui/main.js">
<some-element-ui/>
Host/Shell
Angular CLI proxy configuration
const PROXY_CONFIG = [
{
context: [
"/some-element-ui"
],
target: "http://localhost:3000",
pathRewrite: {
"^/some-element-ui" : ""
},
secure: false,
changeOrigin: true
}
]
module.exports = PROXY_CONFIG;
Thanks,
Edgar
How can i share a component instead of a module
Hi, this is just a question instead of an issue.
All the examples and documentation that i read about federation in angular are related to modules and all the modules are loaded using router´s lazy load, so they are all linked to an url.
My question is how can i share a component or a module that are not related to an url but to just a shared module/component/service with just a bunch of code?
Use service from remote microfrontend in shell app.
Hey everybody!
Don't judge for my english, please.
I need a help, because cannot find solution on my question.
I have two separate application, host and remote. It isn't monorepo, and I want use Services and Components from remote app in host app not as page in router.
For example in host app was created TestModule, and in template of this module I want use component from remote.
Is it possible? Or I should create monorepo and create some shared libs and declare it in tsconfig?
BrowserAnimationsModule doesn't work with Module Federation
I am working on a module-federation prototype with webpack5 and nrwl12(monorepo).
Basically, I have a host application, that loads a shared module from page b. That shared module should be used in the host then. It sets up a RouterModule.forChild() and is exposed via webpack. That works.
Now I added one of our components, which uses animation inside and things are breaking. With the BrowserAnimationsModule imported in my shared module, the host app will not work anymore. The router will just add a new copy of my shared content underneath one another every time I navigate to it. I assume it creates a new platform everytime it loads the module, but how can I prevent that?
I have also tried to share the @angular/platform-browser/animations across app and host, but without luck.
ng test error: flights.module.ts is missing from the TypeScript compilation
Hi, thanks for providing this sample.
When I run ng test, I get the following error:
PS C:\Code\Repos\Git\module-federation-plugin-example-starter> ng test --browsers ChromeHeadless
- Generating browser application bundles...(node:71312) [DEP_WEBPACK_WATCH_WITHOUT_CALLBACK] DeprecationWarning: A 'callback' argument need to be provided to the 'webpack(options, callback)' function when the 'watch' option is set. There is no way to handle the 'watch' option without a callback.
\ Generating browser application bundles (phase: building)...26 02 2021 11:44:10.726:WARN [karma]: No captured browser, open http://localhost:9877/
26 02 2021 11:44:10.753:INFO [karma-server]: Karma v5.2.3 server started at http://localhost:9877/
26 02 2021 11:44:10.755:INFO [launcher]: Launching browsers ChromeHeadless with concurrency unlimited
26 02 2021 11:44:10.766:INFO [launcher]: Starting browser ChromeHeadless
\ Generating browser application bundles (phase: sealing)...
./projects/mfe1/src/app/flights/flights.module.ts - Error: Module build failed (from ./node_modules/@ngtools/webpack/src/index.js):
Error: C:\Code\Repos\Git\module-federation-plugin-example-starter\projects\mfe1\src\app\flights\flights.module.ts is missing from the TypeScript compilation. Please make sure it is in your tsconfig via the 'files' or 'include' property.
at AngularCompilerPlugin.getCompiledFile (C:\Code\Repos\Git\module-federation-plugin-example-starter\node_modules@ngtools\webpack\src\angular_compiler_plugin.js:957:23)
at plugin.done.then (C:\Code\Repos\Git\module-federation-plugin-example-starter\node_modules@ngtools\webpack\src\loader.js:43:31)
I haven't managed to fix the issue so just checking to see if you had any ideas.
Load Remote Module
Hi,
can I use the (loadRemoteModule) function to load a component from React project?
i try this :
const r = await loadRemoteModule({
type: 'script',
remoteName:'react',
remoteEntry: 'http://localhost:4204/remoteEntry.js',
exposedModule: './web-components'
});
const ref2 = this.reactContainer.createComponent(r.react);
but it not work,
or any way to dynamic load React component and pass parameter to it ?
Question: Reload the module if there is some change without refreshing the window
Hi,
I need to reload the application module without refreshing the page.
For Ex. If I run all the application at first and later when I stopped any one of the application and when I redirect to that path its should show module not found which I am getting only if I refresh the page I need the page to get updated without refreshing the window.
const module = await loadRemoteModule({
remoteEntry: 'http://localhost:4205/remoteEntry.js',
remoteName: 'encrypt',
exposedModule: './Module'
});
// Trigger initialization of federated module when the route is navigated to
initFederation('/assets/mf.manifest.json')
.catch(err => console.error(err))
.then(_res => {
console.log(_res);
import('../bootstrap')
})
.catch(err => console.error(err));
I tried with loading remote module and also initFederation when route is navigated but its not updating
ng serve not working with module federation and angular 11
ng serve does not work when i use multiple lines of styles or scripts inside angular .json like below. However, if include only single line there, it works fluently.... your help shall be highly appreciated...
.... styles:[ "node_modules/bootstrap/dist/css/bootstrap.min.css", "projects/shell/src/styles.css" ] ....
Build Docker image separately for each projects in angular module federation
Hi,
How to build a docker image for all the projects inside angular module federation separately each projects should contain its own docker image
module federation doesn't work without sharing
in your example, if I remove sharing from remote and host like this
const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack');
module.exports = withModuleFederationPlugin({
shared: {
},
});
const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack');
module.exports = withModuleFederationPlugin({
name: 'mfe1',
exposes: {
'./Module': './projects/mfe1/src/app/flights/flights.module.ts',
},
shared: {
},
});
I get this error:
ERROR Error: Uncaught (in promise): Error: NG0203: inject() must be called from an injection context (a constructor, a factory function or a field initializer). Find more at https://angular.io/errors/NG0203
RuntimeError@http://localhost:3000/projects_mfe1_src_app_flights_flights_module_ts.js:11570:5
injectInjectorOnly@http://localhost:3000/projects_mfe1_src_app_flights_flights_module_ts.js:17038:11
ɵɵinject@http://localhost:3000/projects_mfe1_src_app_flights_flights_module_ts.js:17049:59
RouterModule_Factory@http://localhost:3000/projects_mfe1_src_app_flights_flights_module_ts.js:56820:77
factory@http://localhost:5000/projects_shell_src_bootstrap_ts.js:25988:32
hydrate@http://localhost:5000/projects_shell_src_bootstrap_ts.js:25880:29
get@http://localhost:5000/projects_shell_src_bootstrap_ts.js:25762:23
injectInjectorOnly@http://localhost:5000/projects_shell_src_bootstrap_ts.js:20526:29
ɵɵinject@http://localhost:5000/projects_shell_src_bootstrap_ts.js:20531:59
useValue@http://localhost:5000/projects_shell_src_bootstrap_ts.js:25481:33
resolveInjectorInitializers@http://localhost:5000/projects_shell_src_bootstrap_ts.js:25805:9
NgModuleRef@http://localhost:5000/projects_shell_src_bootstrap_ts.js:40872:22
create@http://localhost:5000/projects_shell_src_bootstrap_ts.js:40907:12
loadChildren/loadRunner<@http://localhost:5000/projects_shell_src_bootstrap_ts.js:67153:36
_next@http://localhost:5000/projects_shell_src_bootstrap_ts.js:2819:29
next@http://localhost:5000/projects_shell_src_bootstrap_ts.js:1272:12
notifyNext@http://localhost:5000/projects_shell_src_bootstrap_ts.js:2989:22
_next@http://localhost:5000/projects_shell_src_bootstrap_ts.js:1727:17
next@http://localhost:5000/projects_shell_src_bootstrap_ts.js:1272:12
subscribeToPromise/</<@http://localhost:5000/projects_shell_src_bootstrap_ts.js:4470:18
3484/</Zone$1</ZoneDelegate</ZoneDelegate.prototype.invoke@http://localhost:5000/polyfills.js:8113:160
onInvoke@http://localhost:5000/projects_shell_src_bootstrap_ts.js:45573:25
3484/</Zone$1</ZoneDelegate</ZoneDelegate.prototype.invoke@http://localhost:5000/polyfills.js:8113:48
3484/</Zone$1</Zone</Zone.prototype.run@http://localhost:5000/polyfills.js:7839:37
scheduleResolveOrReject/<@http://localhost:5000/polyfills.js:9259:28
3484/</Zone$1</ZoneDelegate</ZoneDelegate.prototype.invokeTask@http://localhost:5000/polyfills.js:8146:173
onInvokeTask@http://localhost:5000/projects_shell_src_bootstrap_ts.js:45561:25
3484/</Zone$1</ZoneDelegate</ZoneDelegate.prototype.invokeTask@http://localhost:5000/polyfills.js:8146:56
3484/</Zone$1</Zone</Zone.prototype.runTask@http://localhost:5000/polyfills.js:7896:39
drainMicroTaskQueue@http://localhost:5000/polyfills.js:8362:25
how can I make it work without sharing components?
Module Not Found when trying to share a service .
@angular-architects/module-federation version 14.3.0 unhandled exception occurred with webpack.config.js
When upgrading from @angular-architects/module-federation 14.2.3 to 14.3.0 I am seeing an error (pasted below) when trying to serve the application now.
Generating browser application bundles (phase: setup)...An unhandled exception occurred: The "path" argument must be of type string. Received an instance of Object See "C:\Users\...\AppData\Local\Temp\ng-1b2NOF\angular-errors.log" for further details.
Inside the error log it contains a stack that seems to point to our webpack.config.js as the cause of the error. I pasted what is inside the error log file below:
[error] TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Object
at new NodeError (node:internal/errors:388:5)
at validateString (node:internal/validators:114:11)
at Object.join (node:path:429:7)
at readConfiguredSecondaries (C:\code\client\node_modules\@angular-architects\module-federation\src\utils\share-utils.js:126:94)
at getSecondaries (C:\code\client\node_modules\@angular-architects\module-federation\src\utils\share-utils.js:96:24)
at Object.share (C:\code\client\node_modules\@angular-architects\module-federation\src\utils\share-utils.js:175:33)
at shareAll (C:\code\client\node_modules\@angular-architects\module-federation\src\utils\share-utils.js:143:27)
at Object.<anonymous> (C:\code\client\webpack.config.js:50:10)
at Module._compile (node:internal/modules/cjs/loader:1112:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1166:10)
at Module.load (node:internal/modules/cjs/loader:988:32)
at Module._load (node:internal/modules/cjs/loader:834:12)
at Module.require (node:internal/modules/cjs/loader:1012:19)
at require (node:internal/modules/cjs/helpers:102:18)
at transforms.<computed> [as webpackConfiguration] (C:\code\client\node_modules\ngx-build-plus\src\utils\index.js:56:38)
at setup (C:\code\client\node_modules\@angular-devkit\build-angular\src\builders\dev-server\index.js:168:46)
I also pasted what I have in my webpack.config.js below. This error showed up with no changes being made to the webpack.config.js. It just started once we saw the upgrade to the @angular-architects/module-federation 14.3.0 version
const { share, withModuleFederationPlugin, = require('@angular-architects/module-federation/webpack');
module.exports = withModuleFederationPlugin({
remotes: { },
shared: share({
'@angular/core': { singleton: true, strictVersion: true, requiredVersion: 'auto', },
'@angular/common': { singleton: true, strictVersion: true, requiredVersion: 'auto', },
'@angular/common/http': { singleton: true, strictVersion: true, requiredVersion: 'auto', },
'@angular/router': { singleton: true, strictVersion: true, requiredVersion: 'auto', },
'@okta/okta-angular': { singleton: true, strictVersion: true, requiredVersion: 'auto', },
'@okta/okta-auth-js': { singleton: true, strictVersion: true, requiredVersion: 'auto', },
}),
sharedMappings: ['auth-lib'],
});
I'm following this article because we want a solution where we don't need to hardcode the URL for the remoteEntry.js file.
To fix this error do we need to adjust how the webpack.config.js file is configured?
Angular Dependency Injection: Singleton Service gets instantiated twice
I have build a minimal setup based on the branch nf-standalone-solutions where a singleton service gets instantiated twice under certain circumstances. The Problem does not occure in a pure angular project.:
Changes:
- added File "projects/auth/src/lib/test.all.ts" (component+service+module in one file; it is not important if splitted in multiple files)
- added * library export for test.all.ts
- imported TestModule in AppModule of the shell app
- added test component to app component html and injected the test service into the app component
If you start the shell app, the Service "ComponentTestService" gets instantiated twice (console output in the constructor of the service). In a similar workspace generated with angular, the service only gets instantiated once (without the native module federation).
I could also isolate the error:
If the service is not used in the library which defines it, the service gets initialized once even if used in multiple other libraries. The only case i could reproduce this error is if the service is injected in the library itself and outside of the library.
I was not sure where to put this issue. It is a replika of:
angular-architects/module-federation-plugin#433
Keycloak initialization error: TypeError: keycloak_js__WEBPACK_IMPORTED_MODULE_5__ is not a constructor
Hi I have been trying to implement keycloak in angular module federation I have followed the https://github.com/manfredsteyer/module-federation-plugin-example/tree/static repo for building the application but once I used keycloak I am getting error as shown below I have followed this https://www.npmjs.com/package/keycloak-angular/v/15.1.0 to implement keycloak in angular.
Project fails with error: expected hoisted manifest
Env:
node -v ==> v16.16.0
npm -v ==> 8.11.0
yarn -v ==> 1.22.18
git clone https://github.com/manfredsteyer/module-federation-plugin-example.git --branch starter
cd module-federation-plugin-example.git
yarn
Results in:
error An unexpected error occurred: "expected hoisted manifest for "ngx-build-plus#@angular-devkit/build-angular#webpack-dev-server#webpack-dev-middleware#webpack"".
➜ module-federation-plugin-example git:(starter) cat yarn-error.log
Arguments:
/usr/local/Cellar/node@16/16.16.0/bin/node /usr/local/Cellar/yarn/1.22.18/libexec/bin/yarn.js
PATH:
Yarn version:
1.22.18
Node version:
16.16.0
Platform:
darwin x64
Trace:
Invariant Violation: expected hoisted manifest for "ngx-build-plus#@angular-devkit/build-angular#webpack-dev-server#webpack-dev-middleware#webpack"
at invariant (/usr/local/Cellar/yarn/1.22.18/libexec/lib/cli.js:2314:15)
at _loop2 (/usr/local/Cellar/yarn/1.22.18/libexec/lib/cli.js:91022:9)
at PackageHoister.init (/usr/local/Cellar/yarn/1.22.18/libexec/lib/cli.js:91092:19)
at PackageLinker.getFlatHoistedTree (/usr/local/Cellar/yarn/1.22.18/libexec/lib/cli.js:48541:20)
at PackageLinker. (/usr/local/Cellar/yarn/1.22.18/libexec/lib/cli.js:48552:27)
at Generator.next ()
at step (/usr/local/Cellar/yarn/1.22.18/libexec/lib/cli.js:310:30)
at /usr/local/Cellar/yarn/1.22.18/libexec/lib/cli.js:328:14
at new Promise ()
at new F (/usr/local/Cellar/yarn/1.22.18/libexec/lib/cli.js:5301:28)
npm manifest:
{
"name": "mf-demo",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "npm run start:shell",
"start:shell": "ng serve shell -o --port 5000",
"start:mfe1": "ng serve mfe1 -o --port 3000",
"start:all": "concurrently "npm run start:shell" "npm run start:mfe1" ",
"build:shell": "ng build shell --prod",
"build:mfe1": "ng build mfe1 --prod",
"serve:dist": "concurrently "serve dist/shell -l 5000 -s" "serve dist/mfe1 -l 3000 -s" ",
"build": "npm run build:shell && npm run build:mfe1",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular-architects/module-federation": "^14.3.0",
"@angular/animations": "14.0.0",
"@angular/common": "14.0.0",
"@angular/compiler": "14.0.0",
"@angular/core": "14.0.0",
"@angular/forms": "14.0.0",
"@angular/platform-browser": "14.0.0",
"@angular/platform-browser-dynamic": "14.0.0",
"@angular/router": "14.0.0",
"@nrwl/workspace": "^10.3.0",
"concurrently": "^5.3.0",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/architect": "^0.1400.0",
"@angular-devkit/build-angular": "14.0.0",
"@angular/cli": "14.0.0",
"@angular/compiler-cli": "14.0.0",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^12.11.1",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~6.3.9",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"ngx-build-plus": "^14.0.0",
"protractor": "~7.0.0",
"serve": "^11.3.2",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~4.7.3"
}
}
yarn manifest:
No manifest
Lockfile:
No lockfile
Images used by remotes not found in the shell
Hi Manfred,
in your example I can't load images belonging to the remote app from the shell.
Your specific case works because the angular.png image exist also in the shell app and is that one that is downloaded and used by the app.
I've tried to substitute the image with anoter one that exist in the remote app only and the result is this one below.
It try to reach the image on the host app, but it doesn't exist there. If the remote app it' s run as standalone everything it's ok
How can be fixed? (without using absolute path for all the images used in the remotes)
Thank you!
Navigation between micro frontends with web-components does not work
While testing the ng-web-component-mixed
branch, I found failures in the navigation between microfrontends, but the navigation from shell to microfrontend works correctly.
Initially to be able to navigate from the host to the microfrontends I had to share the remoteEntry to the WrapperComponent:
If the remoteEntry is not added, the following error is generated:
Well, with the remoteEntry added and trying to navigate between microfrontends, the URL changes but the component does not load, it seems that the navigation is trying to resolve to the origin microfrontend (I also made use of the connectRouter function that Mandred Steyer shares with us):
According to the analysis carried out, navigation from a microfrontend without web-component to the host or to another microfrontend with web-component works well, but navigation from a microfrontend with web-component to an external route (host or another microfrontend) does not work.
Has anyone been able to solve this problem with navigation to external routes using microfrontends with web-component? Thank you
Internal dependency does not emmited to separated chunk
module not found error
I am using "@angular-architects/module-federation": "^14.3.14" version in angular application with a library named test and application named host. I used path mapping in angular tsconfig as below.
"paths": {
"test/": [
"projects/test/",
"dist/test"
]
}
i am trying to access a module like import { TestModule } from 'test/first';
in my app.module and trying to render the library component in app.html.
Error: Module not found: Error: Can't resolve 'test/*' in 'E:\mfe\projects\host\src\app'.
I encountered this error only after introducing the webpack file. I suspect the webpack is not resolving the my path alias
module federation does not work in mobile browsers
Unexpected token "export"
Hello Manfred
I'm trying out this project, but I'm not able to start the shell (host).
yarn ng serve shell -o
yarn run v1.22.4
$ ng serve shell -o
Unknown error: SyntaxError: Unexpected token 'export'
error Command failed with exit code 127.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
The micro frontend is working as expected. Any ideas?
Error loading AOT remote app
I use your (@manfredsteyer) example module-federation-plugin-example from main branch.
I run script build
and then serve:dist
. When I try to load mfe1, there is an error:
Angular ngzone relations
Hi!
Your article mentions that to avoid problems, one should share NgZone between angular microfrontends. What are those problems that could arise?
Would it be a good alternative to fork the host's zone, and make the remote use that? I imagine that the host's wrapper component could inject ngZone, call run, inside the run callback fork the zone and then append the angular element running in that zone. Looking through the code I see that NgZone of the mfe would just fork the current zone - which is itself a fork of the host's zone.
(Sadly I have a browser API to decorate for remotes only)
How to structure CI/CD pipeline with this approach?
Hey @manfredsteyer,
first of all - thank you for this module federation repository!
I was wondering how you would handle this setup in a pipeline? How can you still build individual microfrontends when working in one repository?
Do you use tags to trigger the pipeline?
Love to hear your thoughts on that!
Kind regards,
Thomas
Webpack.config.js files not generated Angular 12 module federation
Webpack.config.js files not generated and giving error saying cannot set property 'extraWebpack config' of undefined I run module federation plugin ( ng add @angular-architects/module-federation). App is using Angular 12. Please help.
Module Not Found when trying to share a service .
Issue Report .
I am trying to share a service's singleton instance across projects but I am getting Module not found Error .
I followed step by step tutorial .
tsconfig.json app level
{
"compileOnSave": false,
"compilerOptions": {
"paths": {
"astrapay-library": [
"dist/astrapay-library/astrapay-library",
"dist/astrapay-library"
// "projects/astrapay-library/src/project.ts"
]
},
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"module": "es2020",
"lib": [
"es2018",
"dom"
]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
// "strictTemplates" : true
}
}
Shell app's webpack.config.json
[...]
const sharedMappings = new mf.SharedMappings();
sharedMappings.register(
path.join(__dirname, '../../tsconfig.json'),
[
/* mapped paths to share */
"astrapay-library" // <-- This is my shared library's name
]);
module.exports = {
output: {
uniqueName: "shell"
},
optimization: {
// Only needed to bypass a temporary bug
runtimeChunk: false
},
plugins: [
new ModuleFederationPlugin({
// For remotes (please adjust)
// name: "shell",
// filename: "remoteEntry.js",
// exposes: {
// './Component': './projects/shell/src/app/app.component.ts',
// },
// For hosts (please adjust)
remotes: {
"payment": "payment@http://localhost:3000/remoteEntry.js",
},
shared: {
"@angular/core": { singleton: true, strictVersion: true },
"@angular/common": { singleton: true, strictVersion: true },
"@angular/router": { singleton: true, strictVersion: true },
"ngx-toastr" : {singleton: true, strictVersion: true},
...sharedMappings.getDescriptors()
}
}),
sharedMappings.getPlugin(),
],
};
payment app's webpack.config.json
[...]
const sharedMappings = new mf.SharedMappings();
sharedMappings.register(
path.join(__dirname, '../../tsconfig.json'),
[
/* mapped paths to share */
"astrapay-library"
]);
module.exports = {
output: {
uniqueName: "payment"
},
optimization: {
// Only needed to bypass a temporary bug
runtimeChunk: false
},
plugins: [
new ModuleFederationPlugin({
// For remotes (please adjust)
name: "payment",
filename: "remoteEntry.js",
exposes: {
'./BankManagememt': './projects/payment/src/modules/bank-management/bank-management.module.ts',
},
// For hosts (please adjust)
// remotes: {
// "shell": "shell@http://localhost:5000/remoteEntry.js",
// },
shared: {
"@angular/core": { singleton: true, strictVersion: true },
"@angular/common": { singleton: true, strictVersion: true },
"@angular/router": { singleton: true, strictVersion: true },
"ngx-toastr" : {singleton: true, strictVersion: true},
...sharedMappings.getDescriptors()
}
}),
sharedMappings.getPlugin(),
],
};
When running ng serve payment
and ng serve shell
I get this error :
Meanwhile if I dont specify the library in sharedMappings.register( "dirpath", --here--)
and specify the library in shared
object like this :
shared: {
"@angular/core": { singleton: true, strictVersion: true },
"@angular/common": { singleton: true, strictVersion: true },
"@angular/router": { singleton: true, strictVersion: true },
"astrapay-library" : {
singleton: true,
import : "projects/astrapay-library/src/project"
},
"ngx-toastr" : {singleton: true, strictVersion: true},
...sharedMappings.getDescriptors()
}
It works but the service is not singleton .
Why am I getting this issue ?
Update to angular 13
The example works perfectly with angular 12 but with angular 13 it ends up in following error: "Cannot use 'import.meta' outside a module"
Is there a way to fix this issue?
"dependencies": {
"@angular-architects/module-federation": "^13.0.1",
"@angular-architects/module-federation-tools": "^13.0.1",
"@angular/animations": "^13.0.2",
"@angular/common": "^13.0.2",
"@angular/compiler": "^13.0.2",
"@angular/core": "^13.0.2",
"@angular/forms": "^13.0.2",
"@angular/platform-browser": "^13.0.2",
"@angular/platform-browser-dynamic": "^13.0.2",
"@angular/router": "^13.0.2",
"concurrently": "^6.4.0",
"rxjs": "~7.4.0",
"tslib": "^2.3.1",
"word-wrap": "^1.2.3",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^13.0.3",
"@angular/cli": "^13.0.3",
"@angular/compiler-cli": "^13.0.2",
"@types/jasmine": "~3.10.2",
"@types/jasminewd2": "~2.0.10",
"@types/node": "^16.11.9",
"codelyzer": "^6.0.2",
"jasmine-core": "~3.10.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~5.2.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"ng-packagr": "^12.0.0-rc.0",
"protractor": "~7.0.0",
"serve": "^11.3.2",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~4.4.4"
}
Thanks.
Automatic publicPath is not supported in this browser
i'm using nx workspace to generate my mfe and shell apps.
everyhting works fine on nx serve
but when i run nx build and serve my app i have this error :
Automatic publicPath is not supported in this browser
at main.77eeac4ea562bbf8.js:1:4808
at main.77eeac4ea562bbf8.js:1:4968
does anyone knows how to fix it ?
Shared monorepo lib duplicated and not shared on new mfe build
Our Setup
We have some Angular 14.x
applications in a NX Monorepo
using @angular-architects/module-federation": "^14.3.0"
.
We have a shared library added to the sharedMappings
array, as we want to share it across all mfes. This shared library exports some services, e.g. LoginService
, where the shell app sets the user data and the different remote mfes read it.
Current Issue
When we deploy all mfes together, everything works fine.
But if we build one mfe individually and deploy only this one to leverage the mfes architecture, we notice that a new bundle is created for the shared library and added to the newly built mfe (this is not the case when we make a build all). This breaks our logic, as a new service instance is created without the user data set by the shell.
In the screenshot below, it is possible to see the duplicate bundle for the shared lib b2b-mfe-shared
created for the dashboard mfe:
Expected behavior
We would expect that even for partial builds/deployments the same shared library instance is used. We migrated from Angular 12 and the previous @angular-architects/module-federation version and individual builds/deployments worked fine with that version. We followed the provided tutorial and all seems correctly configured, therefore not sure why we get this behavior.
Build commands used:
# Individual builds
"build:shell": "ng build shell --configuration production && cp apps/shell/scripts/mime.types apps/shell/scripts/.profile apps/shell/scripts/nginx.conf apps/shell/scripts/resolvers.conf dist/apps/shell/",
"build:dashboard": "ng build dashboard --configuration production && cp apps/dashboard/scripts/mime.types apps/dashboard/scripts/nginx.conf dist/apps/dashboard/",
# builds for all mfes
"build:all": "nx run-many --target=build --configuration production --all --parallel --maxParallel=3 && npm run copy:all",
"copy:all": "cp apps/shell/scripts/mime.types apps/shell/scripts/.profile apps/shell/scripts/nginx.conf apps/shell/scripts/resolvers.conf dist/apps/shell/ && cp apps/dashboard/scripts/mime.types apps/dashboard/scripts/nginx.conf dist/apps/dashboard/",
Our shell web.config.js
:
const webpackConfiguration = withModuleFederationPlugin({
name: 'shell',
filename: 'shell.js',
sharedMappings: ['@b2b-frontend/b2b-mfe-shared'], <-- This is our shared monorepo lib
exposes: {
'./Module': 'apps/shell/src/app/app.module.ts',
},
remotes: {},
shared: share({
'@angular/core': { singleton: true, strictVersion: true, requiredVersion: '14.2.12' },
'@angular/common': { singleton: true, strictVersion: true, requiredVersion: '14.2.12' }
...
}),
});
One remote mfe (dashboard) web.config.js
:
module.exports = withModuleFederationPlugin({
name: 'dashboard',
filename: 'dashboard.js',
sharedMappings: ['@b2b-frontend/b2b-mfe-shared'],
exposes: {
'./Module': 'apps/dashboard/src/app/app.module.ts',
},
shared: share({
'@angular/core': { singleton: true, strictVersion: true, requiredVersion: '14.2.12' },
'@angular/common': { singleton: true, strictVersion: true, requiredVersion: '14.2.12' },
...
}),
});
One of the shared service from lib:
@Injectable({
providedIn: 'root', <-- We also tried with 'platform' but without any success
})
export class LoginService implements Resolve<LoginService> {
private userInfo: UserInfo;
// When a mfe is newly deployed, this method returns undefined,
// as a new instance of this service is created and not the shared one is used.
getUserInfo(): UserInfo {
return this.userInfo;
}
setUserInfo(userInfo: UserInfo): void {
this.userInfo = userInfo;
}
resolve(): Observable<LoginService> {
...
}
}
Shell routes for remote mfes:
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () => loadRemoteModule('./mfedashboard/dashboard.js').then((m) => m.AppModule),
...
];
@NgModule({
imports: [
RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload',
relativeLinkResolution: 'legacy',
paramsInheritanceStrategy: 'always' }),
],
exports: [RouterModule],
})
export class AppRoutingModule {}
tsconfig.base.json
"paths": {
"@b2b-frontend/b2b-mfe-shared": ["libs/b2b-mfe-shared/src/index.ts"],
...
}
No support for CSS
In this example (using main
branch), if we add a styleUrls
attribute in the shell app.component:
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
then ng serve shell
does not work anymore.
I imagine there is something missing in the webpack config, but I do not know what.
Note: it only happens when we put 'auth-lib'
in the shared mappings. So combination of CSS in app component + shared library breaks the build, but if we remove any of these, it works.
Question : Efficient dependency management
Hello @manfredsteyer ,
I have some doubts related to your repository.
You are using a global package.json instead of individual application-level package.json files. Assuming the number of applications increases in the future, how will you manage your packages across the applications? Additionally, how will you handle your webpack.config.js?
root-project/
│
├── package.json
├── node_modules/
│
└── projects/
├── MFE1/
│ ├── package.json
│ └── ...
├── MFE2/
│ ├── package.json
│ └── ...
├── MFE3/
│ ├── package.json
│ └── ...
.
.
.
.
├── MFEn/
│ ├── package.json
│ └── ...
└── ...
Workers in remote (CORS problems)
After spending a day testing various solutions where workers are in a remote I was left without a solution (not monorepo, can't directly access from shell).
Currently, if remote app sets up a Worker:
new Worker(new URL('./test.worker', import.meta.url), {type: 'module'});
It gets blocked by CORS since the remote runs on a different port (or possibly domain in prod deployments).
And even if you could solve it in prod, running on the same domain on a webserver but a different path - local development will still be impossible with dev servers/ng serve.
I tried a few approaches (corsworker, dynamic scripts/fetch) to "preload" as a Blob.
However, these do not work with import.meta.url. The URL does not get correctly replaced in runtime (you get file:/// which is not available and also blocked by cors).
One option I could think of is if we could expose/share files to shell URL so you could use:
this.worker = new Worker('./remote-shared-path/test.worker', {type: 'module'});
MFE and PWA
PWA / ServiceWorkers for cache and update management are increasingly common with many advantages.
Micro frontends with separately deployable and isolated modules are equally impactful.
But both together become suddenly quite a mess.
You can easily do the shell/host - and cache/update anything changed there - and even serve it as a PWA. But remotes are essentially uncovered.
Dynamic remotes are unknown during build time - their files are unknown and they do not get a unique hash for change detection.
Remotes may load additional dependencies.
Browser caching of files and assets is extremely unreliable. But you can't use service worker for remote projects either - they are only served through shell.
And the second major issue is lack of update notifications - since the worker is not aware that a new version of a remote is available.
How would you approach this issue?
Deployment to cloud
Hi, how can I deploy those microfrontends to f eg. azure, should i use webservice and run it with npm run run:all?
(angular 12) missing module @angular-devkit/architect and how to "fix" :)
When i try to serve the apps, i got this message right here:
Require stack:
- C:\ng10-app\node_modules\ngx-build-plus\src\plus-dev-server\index.js
- C:\ng10-app\node_modules\@angular\cli\node_modules\@angular-devkit\architect\node\node-modules-architect-host.js
- C:\ng10-app\node_modules\@angular\cli\node_modules\@angular-devkit\architect\node\index.js
- C:\ng10-app\node_modules\@angular\cli\models\architect-command.js
- C:\ng10-app\node_modules\@angular\cli\commands\serve-impl.js
- C:\ng10-app\node_modules\@angular\cli\node_modules\@angular-devkit\schematics\tools\export-ref.js
- C:\ng10-app\node_modules\@angular\cli\node_modules\@angular-devkit\schematics\tools\index.js
- C:\ng10-app\node_modules\@angular\cli\utilities\json-schema.js
- C:\ng10-app\node_modules\@angular\cli\models\command-runner.js
- C:\ng10-app\node_modules\@angular\cli\lib\cli\index.js
- C:\ng10-app\node_modules\@angular\cli\lib\init.js
- C:\ng10-app\node_modules\@angular\cli\bin\ng
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
at Function.Module._load (internal/modules/cjs/loader.js:725:27)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (C:\ng10-app\node_modules\ngx-build-plus\src\plus-dev-server\index.js:4:21)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)```
After installing the development package `@angular-devkit/architect@^0.1200.0`, everything works fine :)
ng serve mfe1 -o probem
hello
cmd ng serve mfe1 -o return Cannot GET / and also any other routes in angular 11.2.
so http://localhost:3000/remoteEntry.js also give me Cannot GET /remoteEntry.js
Question: Aboud deploy the apps to Cloudflare or to other site,
Hi Manfred,
Could you please explain to me how can I deployed to Cloudflare, or which will be that site where I can deploy your example more easily?
I tried to deploy to Cloudflare but the routing not works, and not generate index.html into dist folder based on esbuild.
This is what I tries.
Thank you.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.