joeldenning / coexisting-angular-microfrontends

Multiple angular applications, coexisting in one page via single-spa.
MIT License
225 stars 154 forks source link

Sharing dependencies between Angular 8 single-spa applications #31

Open Antarus66 opened 4 years ago

Antarus66 commented 4 years ago

Could someone share their experience of sharing Angular deps between several single-spa applications?

I made a recommended setup like in this repo: https://github.com/polyglot-microfrontends/shared-dependencies

It works for some libs but doesn't work for Angular.

What I've done for the moment:

  1. Additional set of imports for the root application:
{
  "imports": {
    "single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.0.0-beta.1/lib/system/single-spa.min.js",
    "single-spa-angular": "https://cdn.jsdelivr.net/npm/single-spa-angular@3.1.0/lib/browser-lib/single-spa-angular.min.js",
    "zone.js": "https://cdn.jsdelivr.net/npm/zone.js@0.9.1/dist/zone.min.js",
    "rxjs": "https://unpkg.com/@esm-bundle/rxjs/system/rxjs.min.js",
    "rxjs/operators": "https://unpkg.com/@esm-bundle/rxjs/system/rxjs-operators.min.js",
    "@angular/core": "https://cdn.jsdelivr.net/npm/@angular/core@8.2.14/bundles/core.umd.js",
    "@angular/common": "https://cdn.jsdelivr.net/npm/@angular/common@8.2.14/bundles/common.umd.min.js",
    "@angular/compiler": "https://cdn.jsdelivr.net/npm/@angular/compiler@8.2.14/bundles/compiler.umd.js",
    "@angular/forms": "https://cdn.jsdelivr.net/npm/@angular/forms@8.2.14/bundles/forms.umd.min.js",
    "@angular/platform-browser": "https://cdn.jsdelivr.net/npm/@angular/platform-browser@8.2.14/bundles/platform-browser.umd.min.js",
    "@angular/platform-browser-dynamic": "https://cdn.jsdelivr.net/npm/@angular/platform-browser-dynamic@8.2.14/bundles/platform-browser-dynamic.umd.min.js",
    "@angular/animations": "https://cdn.jsdelivr.net/npm/@angular/animations@8.2.14/bundles/animations.umd.min.js",
    "@angular/router": "https://cdn.jsdelivr.net/npm/@angular/router@8.2.14/bundles/router.umd.min.js",
    "moment": "https://cdn.jsdelivr.net/npm/moment@2.24.0/moment.min.js"
  }
}
  1. Added externals to the extra-webpack-config.js
const singleSpaAngularWebpack = require('single-spa-angular/lib/webpack').default;
const webpackMerge = require("webpack-merge");

module.exports = (angularWebpackConfig, options) => {
  const singleSpaWebpackConfig = singleSpaAngularWebpack(angularWebpackConfig, options);

  const externalsConfig = {
    externals: {
      'zone.js': 'Zone',
      "rxjs": "rxjs",
      'moment': 'moment',
      "@angular/core": "@angular/core",
      "@angular/common": "@angular/common",
      "@angular/compiler": "@angular/compiler",
      "@angular/forms": "@angular/forms",
      "@angular/platform-browser": "@angular/platform-browser",
      "@angular/platform-browser-dynamic": "@angular/platform-browser-dynamic",
      "@angular/animations": "@angular/animations",
      "@angular/router": "@angular/router"
    },
  };
  const mergedConfig = webpackMerge.smart(singleSpaWebpackConfig, externalsConfig);

  console.log(mergedConfig);

  return mergedConfig;
}

It works fine for dependencies except of @angular/* On application loading I see:

image

joeldenning commented 4 years ago

This is something that people have done before, and I hope to create an example showing it at some point in the future. If you join our slack workspace there are several people there who can guide you on this.

steve-todorov commented 4 years ago

@Antarus66 you might be interested inhttps://indepth.dev/webpack-5-module-federation-a-game-changer-in-javascript-architecture/ :)

cihy2 commented 4 years ago

@Antarus66 did you solve this problem? I have the same.

kapiladiyecha commented 4 years ago

@joeldenning I'm facing a similar issue. Any example of sharing dependencies between angular apps? tried searching, couldn't get much information on this. TIA :)

joeldenning commented 4 years ago

Angular's Ivy Compiler forbids runtime sharing of dependencies, which is why this example does not use it. If you use View Engine, you can do runtime sharing. More info about Ivy compiler at https://twitter.com/Joelbdenning/status/1253781652486017024

kapiladiyecha commented 4 years ago

Understand. Thanks for sharing the detailed information :)

Antarus66 commented 4 years ago

Works when I removed @ at the beginning of the angular dependencies names:

const singleSpaAngularWebpack = require('single-spa-angular/lib/webpack').default
const webpackMerge = require("webpack-merge");

module.exports = (angularWebpackConfig, options) => {
  const singleSpaWebpackConfig = singleSpaAngularWebpack(angularWebpackConfig, options);

  const externalsConfig = {
    externals: {
      "zone.js": "Zone",
      "rxjs": "rxjs",
      "rxjs/operators": "rxjs/operators",
      "moment": "moment",
      "angular/core": "@angular/core",
      "angular/common": "@angular/common",
      "angular/compiler": "@angular/compiler",
      "angular/forms": "@angular/forms",
      "angular/platform-browser": "@angular/platform-browser",
      "angular/platform-browser-dynamic": "@angular/platform-browser-dynamic",
      "angular/animations": "@angular/animations",
      "angular/router": "@angular/router"
    },
  };

  const mergedConfig = webpackMerge.smart(singleSpaWebpackConfig, externalsConfig);

  return mergedConfig;
}
horlabyc commented 3 years ago

I am wondering, if i have some import like this for moment

import 'moment' I have added moment's cdn to my import map

How do I use methods in moment like moment.now(). It currently says "moment cannot be found"

zalito12 commented 3 years ago

I keep getting this error when trying to share angular dependencies like rxjs or @angular/core: Cannot use import statement outside a module

I have tried to disable Ivy but no changes, I'm using angular 9