Error shared module is not available for eager consumption

AngularFix contains a large number of fixes for Angular, AngularJS, Typescript, HTML, CSS and Javascript related issues. Daily Updated!

Issue

I’ve read other answers and haven’t had any success implementing federated modules with Angular 13. I always get the ‘Shared module is not available for eager consumption’ message.

TL;DR:

  1. Double-check your public path in your custom webpack config — it may be missing a trailing / which WebPack may erroneously be reporting as «unavailable for eager consumption».
  2. Check the routing — your MFE/remote module will receive the child routes after the host module’s routing (so if your host is routing to the MFE when hitting the route ‘login’, your MFE will not get the ‘login’ path, it will get an empty path (see update 2 below).
  3. Bootstrapping (update 1 below) may (or may not) be required.

Host App webpack.config.ts:

export const webpackConfig: Configuration = {
  output: {
    publicPath: 'http://localhost:4200',
    uniqueName: 'host',
  },
  plugins: {
    new container.ModuleFederationPlugin({
      name: "host",
      remotes: {
        "remote-login": "login@http://localhost:4201/remoteEntry.js"
      }
      shared: [
        "@angular/core",
        "@angular/common",
        "@angular/router",
        "@angular/common/http",
      ]
    })
  ]
}

export default webpackConfig;

The remote app:

export const webpackConfig: Configuration = {
  output: {
    publicPath: 'http://localhost:4201',
  },
  optimization: { runtimeChunk: false },
  experiments: { outputModule: true },
  plugins: {
    new container.ModuleFederationPlugin({
      name: "login",
      filename: "remoteEntry.js",
      exposes: {
        LoginComponent: './projects/module1/src/app/pages/login/login.component.ts',
      },
      shared: [
        "@angular/core",
        "@angular/common",
        "@angular/router",
        "@angular/common/http",
      ]
    })
  ]
}

export default webpackConfig;

Update 1:

I’ve tried using a ‘bootstrap’ file. Using this in the main.ts file: import('bootstrap').catch(err => console.error(err)) and now see the following error in the console — which appears solely related to the new bootstrap process:
ChunkLoadError: Loading chunk projects_host_src_bootstrap_ts failed.

_Note: This error was because the public path defined in the webpack.config.ts was missing a trailing slash. Leading it to try to load the chunk from http://localhost:4200projets_host_src_bootstrap_ts (missing the / after the port number).

Update 2:

I’m now getting Error: ASSERTION ERROR: NgModule 'LoginComponent' is not a subtype of NgModuleType. So at least I’m back in ‘Angular-error-land’.

I had to set the routes in the LoginModule (home of the LoginComponent) to be:

export const routes: Routes = [
  {
    path: '', //Note: empty path, _not_ matching the app's 'login' path
    loadChildren: () => import('./login/login.component').then(m => m.LoginComponent),
  }
]

Update 3: It’s working

So I changed the MFE (the LoginModule) routing to be non-lazy and it worked!

export const routes: Routes = [
  {
    path: '', //Note: empty path, _not_ matching the app's 'login' path
    component: LoginComponent,
  }
]

I’m going to roll back the bootstrap changes and see if they are required, but it’s at least using the federated module now!

Solution

  1. Double-check your public path in your custom webpack config — it may be missing a trailing / which WebPack may erroneously be reporting as «unavailable for eager consumption».

  2. Check the routing — your MFE/remote module will receive the child routes after the host module’s routing (so if your host is routing to the MFE when hitting the route ‘login’, your MFE will not get the ‘login’ path, it will get an empty path.

  3. Bootstrapping may (or may not) be required.

Answered By — Patrick Dench

Question:

I’ve read other answers and haven’t had any success implementing federated modules with Angular 13. I always get the ‘Shared module is not available for eager consumption’ message.

TL;DR:
Double-check your public path in your custom webpack config – it may be missing a trailing / which WebPack may erroneously be reporting as «unavailable for eager consumption».
Check the routing – your MFE/remote module will receive the child routes after the host module’s routing (so if your host is routing to the MFE when hitting the route ‘login’, your MFE will not get the ‘login’ path, it will get an empty path (see update 2 below).
Bootstrapping (update 1 below) may (or may not) be required.

Host App webpack.config.ts:

export const webpackConfig: Configuration = {
  output: {
    publicPath: 'http://localhost:4200',
    uniqueName: 'host',
  },
  plugins: {
    new container.ModuleFederationPlugin({
      name: "host",
      remotes: {
        "remote-login": "login@http://localhost:4201/remoteEntry.js"
      }
      shared: [
        "@angular/core",
        "@angular/common",
        "@angular/router",
        "@angular/common/http",
      ]
    })
  ]
}

export default webpackConfig;

The remote app:

export const webpackConfig: Configuration = {
  output: {
    publicPath: 'http://localhost:4201',
  },
  optimization: { runtimeChunk: false },
  experiments: { outputModule: true },
  plugins: {
    new container.ModuleFederationPlugin({
      name: "login",
      filename: "remoteEntry.js",
      exposes: {
        LoginComponent: './projects/module1/src/app/pages/login/login.component.ts',
      },
      shared: [
        "@angular/core",
        "@angular/common",
        "@angular/router",
        "@angular/common/http",
      ]
    })
  ]
}

export default webpackConfig;

Update 1:

I’ve tried using a ‘bootstrap’ file. Using this in the main.ts file: import('bootstrap').catch(err => console.error(err)) and now see the following error in the console – which appears solely related to the new bootstrap process:
ChunkLoadError: Loading chunk projects_host_src_bootstrap_ts failed.

_Note: This error was because the public path defined in the webpack.config.ts was missing a trailing slash. Leading it to try to load the chunk from http://localhost:4200projets_host_src_bootstrap_ts (missing the / after the port number).

Update 2:

I’m now getting Error: ASSERTION ERROR: NgModule 'LoginComponent' is not a subtype of NgModuleType. So at least I’m back in ‘Angular-error-land’.

I had to set the routes in the LoginModule (home of the LoginComponent) to be:

export const routes: Routes = [
  {
    path: '', //Note: empty path, _not_ matching the app's 'login' path
    loadChildren: () => import('./login/login.component').then(m => m.LoginComponent),
  }
]

Update 3: It’s working

So I changed the MFE (the LoginModule) routing to be non-lazy and it worked!

export const routes: Routes = [
  {
    path: '', //Note: empty path, _not_ matching the app's 'login' path
    component: LoginComponent,
  }
]

I’m going to roll back the bootstrap changes and see if they are required, but it’s at least using the federated module now!

Answer:

  1. Double-check your public path in your custom webpack config – it may be missing a trailing / which WebPack may erroneously be reporting as “unavailable for eager consumption”.

  2. Check the routing – your MFE/remote module will receive the child routes after the host module’s routing (so if your host is routing to the MFE when hitting the route ‘login’, your MFE will not get the ‘login’ path, it will get an empty path.

  3. Bootstrapping may (or may not) be required.

If you have better answer, please add a comment about this, thank you!

#javascript #reactjs #webpack #webpack-5 #webpack-module-federation

#javascript #reactjs #webpack #webpack-5 #webpack-module-federation

Вопрос:

Я изучал функцию объединения модулей Webpack 5, и у меня возникли некоторые проблемы с пониманием того, почему мой код не работает. Идея очень похожа на то, что делают стандартные примеры объединения модулей:

app1 — является ли хост-приложение app2 удаленным, предоставляющим доступ всему приложению к app1

( app1 отображает заголовок и горизонтальную линию, ниже которой app2 должно быть отображено)

Оба app1 и app2 объявляют react и react-dom как их общие, одноэлементные, нетерпеливые зависимости в weback.config.js :

 // app1 webpack.config.js
module.exports = {
  entry: path.resolve(SRC_DIR, './index.js');,
  ...
  plugins: [
    new ModuleFederationPlugin({
      name: "app1",
      remotes: {
        app2: `app2@//localhost:2002/remoteEntry.js`,
      },
      shared: { react: { singleton: true, eager: true }, "react-dom": { singleton: true, eager: true } },
    }),
    ...
  ],
};
 
 // app2 webpack.config.js
module.exports = {
  entry: path.resolve(SRC_DIR, './index.js');,
  ...
  plugins: [
    new ModuleFederationPlugin({
      name: "app2",
      library: { type: "var", name: "app2" },
      filename: "remoteEntry.js",
      exposes: {
        "./App": "./src/App",
      },
      shared: { react: { singleton: true, eager: true }, "react-dom": { singleton: true, eager: true } },
    }),
    ...
  ],
};
 

В приложении 1 index.js У меня есть следующий код:

 import React from "react";
import ReactDOM from "react-dom";
import App from "./App";


ReactDOM.render(<App />, document.getElementById("root"));
 

Следующим App.js будет компонент App1:

 import React, { Suspense } from 'react';

const RemoteApp2 = React.lazy(() => import("app2/App"));

export default function App() {
  return (
    <div>
      <h1>App 1</h1>
      <p>Below will be some content</p>
      <hr/>
      <Suspense fallback={'Loading App 2'}>
        <RemoteApp2 />
      </Suspense>
    </div>
  );
}
 

Но когда я запускаю приложение, я получаю следующую ошибку:

 Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/react/react?1bb3
    at Object.__webpack_modules__.<computed> (consumes:133)
    at __webpack_require__ (bootstrap:21)
    at fn (hot module replacement:61)
    at Module../src/index.js (main.bundle.a8d89941f5dd9a37d429.js:239)
    at __webpack_require__ (bootstrap:21)
    at startup:4
    at startup:6
 

Если я извлеку все из index.js to bootstrap.js и in index.js , это будет сделано

 import('./bootstrap');
 

Все работает просто отлично.

Это меня смущает, поскольку в официальных документах и сообщениях в блоге от создателя говорится, что вы можете сделать так или bootstrap.js иначе ИЛИ объявить зависимость как нетерпеливую.

Был бы признателен за любую помощь / информацию о том, почему это не работает без bootstrap.js шаблона.

Вот ссылка на полную песочницу GitHub, которую я создавал: https://github.com/vovkvlad/webpack-module-fedaration-sandbox/tree/master/simple

Ответ №1:

Просто чтобы прояснить для тех, кто может пропустить комментарий к первоначальному ответу:

Похоже, что основной причиной первоначального сбоя было то, что remoteEntry.js файл был загружен после кода, который фактически запускает хост-приложение.

Оба bootstrap.js подхода и добавление прямого скрипта <script src="http://localhost:2002/remoteEntry.js"></script> к <head></head> тегу приводят к одному и тому же результату — они remoteEntry.js загружаются и анализируются ПЕРЕД кодом основного приложения.

В случае начальной загрузки порядок следующий:

  1. main_bundle загружается
  2. поскольку основной код извлекается в bootstrap.js файл — remoteEntry.js загружается
  3. bootstrap.js загружается, который фактически запускает основное приложение

введите описание изображения здесь

с предложенным вариантом Олега Водолазского порядок событий следующий:

  1. remoteEntry.js загружается первым, поскольку он добавляется непосредственно в html файл, а webpack main_bundle добавляется <head></head> после ссылки remoteEntry
  2. main_bundle загружается и запускает приложение

введите описание изображения здесь

и в случае, если вы просто пытаетесь запустить приложение без начальной загрузки и без жестко запрограммированного скрипта в <head></head> main_bundle загружается до remoteEntry.js и после main_bundle попытки фактического запуска приложения, оно завершается с ошибкой:

введите описание изображения здесь

Ответ №2:

Чтобы заставить его работать, вам нужно изменить способ загрузки удаленного ввода.

  1. Обновите ModuleFederationPlugin конфигурацию webpack.config.js для app1 до этого:
 ...

new ModuleFederationPlugin({
    name: "app1",
    remoteType: 'var',
    remotes: {
      app2: 'app2',
    },
    shared: {
      ...packageJsonDeps,
      react: { singleton: true, eager: true, requiredVersion: packageJsonDeps.react },
      "react-dom": { singleton: true, eager: true, requiredVersion: packageJsonDeps["react-dom"] }
    },
}),

...
 
  1. Добавьте script тег в head свой index.html in app1 :
 <script src="http://localhost:2002/remoteEntry.js"></script>
 

Хороший взгляд на дальнейший взлом!

Обновить:

Просто ради этого: я создал PR для вашего репозитория в изолированной среде с исправлениями, описанными выше: https://github.com/vovkvlad/webpack-module-fedaration-sandbox/pull/2

Комментарии:

1. Итак, чтобы прояснить ситуацию: предлагаемые вами изменения действительно работают, но, насколько я понимаю, играя с этим, суть в том, что remoteEntry.js они должны быть загружены ПЕРЕД пакетом, который фактически запускает приложение. И это в основном то, что bootstrap.js делает — это заставляет основное приложение загружаться после main_bundle и remoteEntry.js при использовании предлагаемого вами изменения, оно делает то же самое — оно загружается remoteEntry.js до main_bundle того, как as main_bundle добавляется webpack после жестко заданного тега script с remoteEntry.js

2. Вот ссылка со скриншотами всех трех ситуаций: imgur.com/a/63WTCMg

3. У меня такая же проблема. И предлагаемое решение не масштабируется, если мы говорим о разработке или POC в порядке, но когда у вас есть готовые к производству приложения со средами 3 , это решение не будет работать. Если у кого-нибудь есть решение, которое работает с динамическим импортом, мне действительно интересно, как вы решили эту проблему.

4. Есть ли какие-либо новости относительно решения без файла начальной загрузки или добавления скриптов для всех удаленных записей?

Ответ №3:

Вы можете установить зависимость как нетерпеливую внутри расширенного API объединения модулей, который не помещает модули в асинхронный блок, а предоставляет их синхронно. Это позволяет нам использовать эти общие модули в начальном блоке. Но будьте осторожны, так как все предоставленные и резервные модули всегда будут загружены. Рекомендуется предоставлять его только в одной точке вашего приложения, например, в оболочке.

Веб-сайт Webpack настоятельно рекомендует использовать асинхронную границу. Он разделит код инициализации на больший фрагмент, чтобы избежать каких-либо дополнительных обходов и повысить производительность в целом.

Например, ваша запись выглядела следующим образом:

 index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
 

Давайте создадим bootstrap.js файл и переместите в него содержимое записи, а затем импортируйте этот загрузочный файл в запись:

index.js

   import('./bootstrap');
- import React from 'react';
- import ReactDOM from 'react-dom';
- import App from './App';
- ReactDOM.render(<App />, document.getElementById('root'));
 

bootstrap.js

   import React from 'react';
  import ReactDOM from 'react-dom';
  import App from './App';
  ReactDOM.render(<App />, document.getElementById('root'));
 

Этот метод работает, но может иметь ограничения или недостатки.

Установка eager: true для зависимости через модуль ModuleFederationPlugin

webpack.config.js

 // ...
new ModuleFederationPlugin({
  shared: {
    ...deps,
    react: {
      eager: true,
    },
  },
});
 

Источник

Комментарии:

1. Кроме import(".bootstrap") того, необходимы ли остальные imports и ReactDOM.Render() в index.js файле?

2. @ChunkyChunk Нет, в этом нет необходимости. Потому что у нас есть это в файле начальной загрузки.

3. Я не заметил » » и «-«. Теперь я понимаю, что вы написали.

Ответ №4:

Я также столкнулся с проблемами при использовании приложения NextJS в качестве контейнерного приложения. Вы знаете, нам приходилось снова и снова давать заряд нетерпения.

Я пошел другим путем, чем современные методы в Интернете. Я использовал метод динамической загрузки для своей удаленной библиотеки, и, похоже, общие модули теперь не извлекаются снова и снова. Они загружаются только один раз. Кроме того, я реализовал полную систему как независимую от фреймворка, так что вы можете использовать любой фреймворк в качестве удаленного приложения (angular, vue, react, svelte …). Кроме того, я перенес логику SSR в удаленную часть приложения, так что теперь она может полностью поддерживать SSR и для любого фреймворка. Кажется, это сработало, и я хотел поделиться своим решением здесь, чтобы помочь сообществу. Я написал сообщение в блоге medium с примером ссылки на репозиторий Github. Я подробно изложил свой подход.

Вы можете найти подробный пост здесь: https://medium.com/@metinarslanturkk/how-i-implemented-dynamic-loaded-framework-agnostic-microfrontend-app-with-nextjs-and-react-which-620ff3df4298

А это пример ссылки на репо: https://github.com/MetinArslanturk/microfrontend-nextjs-ssr

Спасибо, Метин

What is Module Federation?

It is basically a JavaScript architecture. It allows a JavaScript application to dynamically load code from another application (a different Webpack build).

This is how you normally use Webpack

You would use Webpack to generate a bundle for production or development, let’s say Webpack helps you to generate a folder called dist and a file main.js within this folder. This is the result of all of your JavaScript code that you normally have in a folder called src

The more you add code into your src folder the heavier is this main.js file which Webpack generates. Remember that this is the file you take to your production environment and clients download in their browsers, if this file is heavy that means it will take longer for the users to load your page.

That means we care about the size of our bundle but we also want to keep adding new features to our projects

Is there a solution to this problem?

There is, there are strategies to break that main.js file into chunks of smaller files in order to avoid loading all your code at first render. This is called Code Splitting (https://webpack.js.org/guides/code-splitting/)

There are different techniques to accomplish this, one is defining more than one entry point into your Webpack configuration but it comes with some pitfalls, sometimes you will have duplicated modules between chunks and both chunks will include these modules so it will increase the size of your chunks.

There’s another popular and more accepted way, this consists in using the import() syntax which conforms to the ES Proposal in order to have dynamic imports in JS (https://github.com/tc39/proposal-dynamic-import)

Using this approach looks something like this:

function test() {
  import('./some-file-inside-my-project.js')
    .then(module => module.loadItemsInPage())
    .catch(error => alert('There was an error'))
}

Enter fullscreen mode

Exit fullscreen mode

We can lazy load the elements to our page using import() syntax and also this will create a new chunk which will get loaded on demand

But what if I told you that there’s another way to break this main.js file not only into different chunks but into different projects?

Here is where Module Federation comes

With Module Federation you can import remote Webpack builds to your application. Currently, you could import these chunks but they would have to come from your same project. Now, you can have these chunks (Webpack builds) from a different origin, which means, a different project!

Module Federation in action

To explain what all of this is about, we will see some code samples of a Webpack configuration using ModuleFederationPlugin and some React.js code

For this, we will use Webpack 5 which currently is on version beta. This is how the package.json file looks like:

// package.json (fragment)

...

  "scripts": {
   "start": "webpack-dev-server --open",
   "build": "webpack --mode production"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "7.10.3",
    "@babel/preset-react": "7.10.1",
    "babel-loader": "8.1.0",
    "html-webpack-plugin": "^4.3.0",
    "webpack": "5.0.0-beta.24",
    "webpack-cli": "3.3.11",
    "webpack-dev-server": "^3.11.0"
  },
  "dependencies": {
    "react": "^16.13.1",
    "react-dom": "^16.13.1"
  }

...

Enter fullscreen mode

Exit fullscreen mode

We have included all the Webpack modules to create a basic setup for a React application

This is how the webpack.config.js looks so far:

// webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  entry: './src/index',
  mode: 'development',
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    port: 3000,
  },
    output: {
    publicPath: "http://localhost:3000/",
  },
  module: {
    rules: [
      {
        test: /.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        options: {
          presets: ['@babel/preset-react'],
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

Enter fullscreen mode

Exit fullscreen mode

This is a normal configuration of Webpack

Let’s add a react component to the project:

// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';

function App() {
  return (
    <h1>Hello from React component</h1>
  )
}

ReactDOM.render(<App />, document.getElementById('root'));

Enter fullscreen mode

Exit fullscreen mode

At this point if you run this project, you will get a page which will show a message saying «Hello from React component». Until now, there’s nothing new here.

The code of this project until this step is here:https://github.com/brandonvilla21/module-federation/tree/initial-project

Creating a second project

Now, we will create a second project with the same package.json file but with some differences under the Webpack configuration:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

// Import Plugin
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  entry: './src/index',
  mode: 'development',
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    // Change port to 3001
    port: 3001,
  },
    output: {
    publicPath: "http://localhost:3001/",
  },
  module: {
    rules: [
      {
        test: /.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        options: {
          presets: ['@babel/preset-react'],
        },
      },
    ],
  },
  plugins: [
    // Use Plugin
    new ModuleFederationPlugin({
      name: 'app2',
      library: { type: 'var', name: 'app2' },
      filename: 'remoteEntry.js',
      exposes: {
        // expose each component you want 
        './Counter': './src/components/Counter',
      },
      shared: ['react', 'react-dom'],
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

Enter fullscreen mode

Exit fullscreen mode

We’re importing the ModuleFederationPlugin on top of the configuration

const { ModuleFederationPlugin } = require('webpack').container;

Enter fullscreen mode

Exit fullscreen mode

We also need to change the port since we will be running both applications at the same time

port: 3001,

Enter fullscreen mode

Exit fullscreen mode

And this is how the Plugin config looks like:

new ModuleFederationPlugin({
  name: 'app2', // We need to give it a name as an identifier
  library: { type: 'var', name: 'app2' },
  filename: 'remoteEntry.js', // Name of the remote file
  exposes: {
    './Counter': './src/components/Counter', // expose each component you want 
  },
  shared: ['react', 'react-dom'], // If the consumer application already has these libraries loaded, it won't load them twice
}),

Enter fullscreen mode

Exit fullscreen mode

This is the main piece of configuration in order to share the dependencies of this second project with the first one.

Before consuming this second application from the first one, let’s create the Counter component:

// src/components/Counter.js

import React from 'react'

function Counter(props) {
  return (
     <>
       <p>Count: {props.count}</p>
       <button onClick={props.onIncrement}>Increment</button>
       <button onClick={props.onDecrement}>Decrement</button>
     </>
  )
}

export default Counter

Enter fullscreen mode

Exit fullscreen mode

This is a very common example but the point here is to show how can we use this component and pass some props from the first application

If you try to run the second app at this point adding a basic index.js like what we did on the first application, you will likely get a message saying the following:

Uncaught Error: Shared module is not available for eager consumption

Enter fullscreen mode

Exit fullscreen mode

As the error says, you’re eagerly executing your application. In order to provide an async way to load the application we can do the following:

Create a bootstrap.js file and move all your code from index.js to this file

// src/bootstrap.js

import React from 'react';
import ReactDOM from 'react-dom';

function App() {
  return <h1>Hello from second app</h1>;
}

ReactDOM.render(<App />, document.getElementById('root'));

Enter fullscreen mode

Exit fullscreen mode

And import it in index.js like this: (notice we’re using import() syntax here)

// src/index.js

import('./bootstrap')

Enter fullscreen mode

Exit fullscreen mode

Now if you run the second project at this point, you will be able to see the message Hello from second app

Importing Counter component to the first project

We will need to update the webpack.config.js file first, in order to consume the Counter component from the second app

// webpack.config.js (fragment)

...
plugins: [
    new ModuleFederationPlugin({
      name: 'app1',
      library: { type: 'var', name: 'app1' },
      remotes: {
        app2: 'app2', // Add remote (Second project)
      },
      shared: ['react', 'react-dom'],
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
...

Enter fullscreen mode

Exit fullscreen mode

The difference between this Webpack config and the other relies on expose and remote. Where in the first app, we expose the component that we want to take from the first app, so in this app, we specify the name of the remote app

We also need to specify the remoteEntry.js file from the remote host:

<!-- public/index.html (fragment)-->

...
<body>
  <div id="root"></div>
  <script src="http://localhost:3001/remoteEntry.js"></script>
</body>
...

Enter fullscreen mode

Exit fullscreen mode

Importing React component from a remote project

Now it’s time to use the Counter component from the second project into the first project:

// src/bootstrap.js

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

const Counter = React.lazy(() => import('app2/Counter'));

function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <h1>Hello from React component</h1>
      <React.Suspense fallback='Loading Counter...'>
        <Counter
          count={count}
          onIncrement={() => setCount(count + 1)}
          onDecrement={() => setCount(count - 1)}
        />
      </React.Suspense>
    </>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

Enter fullscreen mode

Exit fullscreen mode

We will need to lazy load the Counter component and then we can use React Suspense for loading the component with a fallback

That’s it! You should be able to load the counter component from the first project

Conclusions

The possibility to load remote Webpack builds into your applications opens up a new world of possibilities for creating new Frontend architectures. It will be possible to create:

Micro Frontends

Since we can have separate bundles of JavaScript into separate projects, it gives us the possibility to have separate build processes for each application.

You will be able to have totally independent applications with the feeling of a single website. This allows big teams to break down into smaller and more efficient teams which will scale vertically from the Frontend to the Backend team.

This way we will have autonomous teams which won’t depend on others in order to deliver new features

It could be represented like this:

Vertical scaling

Source Image

Design system incorporation at runtime

Currently, there are multiple ways to implement a design system at build time (npm/yarn packages, GitHub packages, Bit.dev) but this could represent an issue for some projects. Whenever you need to update some components from your design system, you will have to re-build your application and deploy it again in order to have the latest version of your design system in production.

With a design system at runtime, you will be able to get the latest version of your design system into your application without going through the build and re-deploy process of your entire application since you will get the components from a different origin and at runtime.

These two are just a few of the possibilities with Federated Modules.

Repository of the complete example

github.com/brandonvilla21/module-federation

Понравилась статья? Поделить с друзьями:
  • Error setup script exited with error
  • Error sqlsrv connect
  • Error sqlite cantopen 14
  • Error setup file gameinfo txt doesn t exist in subdirectory hl2
  • Error sql error code 303 conversion error from string