Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a Micro Frontend bundle with Webpack that shares libraries with the container application?

I have a task.

To have Micro Frontends with single-spa framework.

  1. portal/main application (which load all other js code by url)
  2. Micro Frontend 1 (react based)
  3. Micro Frontend 2 (react based)

So my problem just one: I don't want to duplicate vendor libraries like react, react-dom (any others). And I want to make them shared among other Micro Frontends (which is bundled with webpack)

I know what is the bad practice to have some global stuff (it's violate the whole idea of bundeling with webpack). But how to solve the problem of duplication of vendor libraries?

I found one solution just load decencies with SystemJs like separated tags in html, but I just wonder maybe there is another solutuion for that.

Thank you.

SystemJs approach to load dependencies by demand but from CDN, I just want do the same but load all dependencies from "shared" webpack bundle with react and other stuff.

window.SystemJS = window.System

function insertNewImportMap(newMapJSON) {
  const newScript = document.createElement('script')
  newScript.type = 'systemjs-importmap'
  newScript.text = JSON.stringify(newMapJSON)
  const allMaps = document.querySelectorAll('script[type="systemjs-importmap"]')

  allMaps[allMaps.length - 1].insertAdjacentElement(
    'afterEnd',
    newScript
  )
}

const devDependencies = {
  imports: {
    react: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.development.js',
    'react-dom': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.development.js',
    'react-dom/server': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom-server.browser.development.js',
    'single-spa': 'https://unpkg.com/[email protected]/lib/umd/single-spa.min.js',
    lodash: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js',
    rxjs: 'https://unpkg.com/[email protected]/bundles/rxjs.umd.js',
  }
}

const prodDependencies = {
  imports: {
    react: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js',
    'react-dom': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js',
    'react-dom/server': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom-server.browser.production.min.js',
    'single-spa': 'https://unpkg.com/[email protected]/lib/umd/single-spa.min.js',
    lodash: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js',
    rxjs: 'https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js',
  }
}

const devMode = true // you will need to figure out a way to use a set of production dependencies instead
if (devMode) {
  insertNewImportMap(devDependencies)
} else {
  insertNewImportMap(prodDependencies)
}

like image 656
e.bezdomnikov Avatar asked Aug 06 '19 06:08

e.bezdomnikov


People also ask

What is Webpack micro frontend?

One application can dynamically run code from another bundle or build, on the client and the server. This is the foundation of micro frontends. Each webpack build can be a host, which is a container to load other builds. It can also serve as a remote, which is a micro frontend to be loaded.

What is the Webpack module Federation plugin?

The module federation plugin is introduced in Webpack 5.0 that enables the development of micro frontend applications with runtime federation by dynamically loading code from micro frontend apps (aka remote apps) into the container app (aka host app).

What is a Webpack module bundler?

This article will explore a module bundler called Webpack, share with you how to bundle up an application with Webpack. Webpack supports CommonJs, AMD, and ES6 module formatting systems. Webpack takes your Javascript files, dependencies as input, bundles them, and then outputs compressed optimised files.

What are the different configuration options in Webpack?

Other Webpack configuration options to be aware of include: Output: Enables you to set your public path and the unique name for the build. This is useful when you load multiple modules from different remotes. Learn More. Experiments: The ‘experiments’ feature was also introduced in Webpack 5.


Video Answer


2 Answers

Update:

Just realized, that your question is directed at Micro Frontends (not only micro services) and therefore is not about sharing libraries with Webpack in general. Added Micro Frontend to your tags/title and updated the answer to be more focused on this topic.


So my problem just one: I don't want to duplicate vendor libraries like react, react-dom (any others). And I want to make them shared among other [Micro Frontends] (which is bundled with webpack)

What you can do is exclude dependencies from the output bundle of your Micro Frontends by adding a Webpack externals property to the config.

webpack config of your Micro Frontends:

module.exports = {
  ...
  externals = {
    react: 'React',
    'react-dom': 'ReactDOM'
  }
}

Above config would exclude react and react-dom and expect them in the global variables React and ReactDOM. You can then share those dependencies by including the libraries in a script inside index.html of your root applicationn aka stitching layer:

<html>
  ...
  <body>
    ...
    <script src="<your-host>/react.prod-16.9.0.min.js"></script>
    <script src="<your-host>/react-dom.prod-16.9.0.min.js"></script>
  </body>
</html>

If you have other common components to share, you can also integrate the library scripts in a component library.

The reason for the include as script is: We do not want that our container has to require/import the Micro Frontends at build time in order to avoid a coupling of build/release/version management between all apps. Instead one purpose of Micro Frontends is to achieve fully independent deployment of the parts, which include continuous delivery steps from build, test to release.

I know what is the bad practice to have some global stuff (it's violate the whole idea of bundeling with webpack).

Of course, you create some form of coupling between the apps. But if you have a mature, stable and common library shared by all parts, it is a reasonable decision.

Hope, it helps (now)!

like image 88
ford04 Avatar answered Oct 22 '22 18:10

ford04


The best way to achieve this today is using Webpack's new Module Federation technology released in v5. This approach does not use SystemJS but rather the internals of Webpack. We tried several different micro frontend approaches, but this one outshines them all & is currently running successfully for us in production. There are definitely some challenges to setting it up but it was worth the developer productivity gains.

Here is the info site produced by the creator Zack Jackson which should provide all the resources you need: https://module-federation.github.io/

Here is the link to webpack docs which deal more with technicalities rather than how to practically set up a full micro frontend architecture: https://webpack.js.org/concepts/module-federation/

like image 41
protoEvangelion Avatar answered Oct 22 '22 17:10

protoEvangelion