Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
September 14, 2021 07:09 pm GMT

Better React Micro Frontends w/ Nx

One of the first articles we covered in tech book club was Micro Frontends, an approach to scaling frontend development across many independent and autonomous teams.

Although the content of the article is well-articulated, the accompanying example is lacking. It hacks create-react-app with an extra package to enable Webpack builds and offers no mechanism to run all of the micro frontend applications in tandem. The example is easy to follow, but inspires no confidence for a real-world scenario.

After experimenting with different tools and approaches, I think I've constructed a better scaffold for micro frontends that improves the overall developer experience. This article walks you through that approach.

You can find the complete example here.

Monorepos with Nx

One of the major disadvantages to micro frontends is complexity. Rather than maintaining all of your application code in one place, that code is now spread across multiple applications and managed by separate teams. This can make collaboration on shared assets difficult and tedious.

Keeping each micro frontend within the same repository (monorepo) is one easy way to help manage this complexity. Google famously uses this technique to manage its billion-line codebase, relying on automation and tools to manage the trade-offs.

Rather than using create-react-app to bootstrap micro frontends, turn instead to Nx. Nx is a build framework that offers tools to manage a multi-application monorepo, a perfect fit for micro frontends.

Here are a few ways Nx helps manage micro frontends:

  • Script orchestration: run servers/builds for multiple micro frontends concurrently with a single command.
  • Share common components and code libraries conveniently without introducing lots of Webpack overhead.
  • Manage consistent dependency versions.
  • Run builds and tests for affected changes across micro frontends based on dependency graphs.

Nx is certainly not the only tool that supports monorepos, but Ive found it to be a great fit for micro frontends thanks to its built-in React support and batteries-included functionality. Lerna is noteworthy alternative that offers less built-in functionality at the advantage of flexibility.

Detailed example

Nx requires only a few configuration changes to support micro frontends and you wont need the help of an ejection tool like react-app-rewired.

  1. Create a new Nx workspace with two React applications (one container, one micro frontend).
  2. Extend Nxs default React Webpack configuration to disable chunking and generate an asset manifest.
  3. Implement conventional micro frontend components as described in the Thoughtworks article.
  4. Tie it all together with a single npm start script.

1. Create the Nx workspace

Begin by creating a new Nx workspace:

npx create-nx-workspace@latest micronx? What to create in the new workspace...> emptyUse Nx Cloud?> No

Navigate into the new micronx directory and create two React applications, one container and one micro frontend. Its important to select styled-components (or another CSS-in-JS solution) so that your component CSS is included in the micro frontends JS bundle.

cd ./micronxnpm install --also=dev @nrwl/react# Container applicationnx g @nrwl/react:app container> styled-components> No# Micro frontendnx g @nrwl/react:app dashboard> No

So far you've created a monorepo with two separate React applications: container and dashboard. Either React application can be served independently via its respective nx run <app>:serve script, but there's nothing yet in place to have them work together.

The next step sprinkles in some configuration changes that allow you to dynamically load the dashboard application as a micro frontend.

2. Modify micro frontend Webpack configuration

Nx stores most of its relevant configuration in the workspace.json file stored at the project's root.

You need to modify workspace.json to point the micro frontends Webpack configuration to a new file, webpack.config.js. This new file contains the configuration updates necessary to support dynamically loading the micro frontend.

Note that you dont need to do this for the container, since the container is not a micro frontend.

// workspace.json"projects": {  "dashboard": {    "targets": {      "build": {        // ...        "webpackConfig": "webpack.config.js"      }    }  }}

Now you need to create that file, webpack.config.js, at the root directory of the project.

This modified Webpack configuration extends the default code from @nrwl/react to avoid losing any functionality. Following the Thoughtworks example, two modifications are needed to support conventional micro frontends:

  1. Disable chunking so the container application loads one bundle per micro frontend.
  2. Add WebpackManifestPlugin to map the generated JS output to an easy import path (taken from react-scripts webpack configuration).
npm install --also=dev webpack-manifest-plugin
// webpack.config.jsconst reactWebpackConfig = require('@nrwl/react/plugins/webpack')const { WebpackManifestPlugin } = require('webpack-manifest-plugin')function getWebpackConfig(config) {  config = reactWebpackConfig(config)  // Disable chunking  config.optimization = {    ...config.optimization,    runtimeChunk: false,    splitChunks: {      chunks(chunk) {        return false      },    },  }  // Enable asset-manifest  config.plugins.push(    new WebpackManifestPlugin({      fileName: 'asset-manifest.json',      publicPath: '/',      generate: (seed, files, entrypoints) => {        const manifestFiles = files.reduce((manifest, file) => {          manifest[file.name] = file.path          return manifest        }, seed)        const entrypointFiles = entrypoints.main.filter(          fileName => !fileName.endsWith('.map'),        )        return {          files: manifestFiles,          entrypoints: entrypointFiles,        }      },    }),  )  return config}module.exports = getWebpackConfig

Run nx run dashboard:serve and visit http://localhost:4200/asset-manifest.json. Note that the dashboard application now only has one entry point: main.js.

{  "files": {    "main.js": "/main.js",    "main.js.map": "/main.js.map",    "polyfills.js": "/polyfills.js",    "polyfills.js.map": "/polyfills.js.map",    "assets/.gitkeep": "/assets/.gitkeep",    "favicon.ico": "/favicon.ico",    "index.html": "/index.html"  },  "entrypoints": ["main.js"]}

3. Add in micro frontend components

With Nx configured properly, the next step is to follow Thoughtworks example and introduce all of the micro frontend functionality.

The following links don't deviate from the article, but are included for completeness.

  1. Create a new component, MicroFrontend, in the container.

  2. Use the MicroFrontend component to load the dashboard micro frontend in the container.

  3. Export render functions so the dashboard micro frontend no longer renders itself to the DOM.

  4. Update the dashboard's index.html so it can still be served independently.

4. Tie everything together

The last step is to serve the micro frontend and container together. Add concurrently and modify your start script to serve the dashboard on a specific port.

"start": "concurrently \"nx run container:serve\" \"nx run dashboard:serve --port=3001\""

Run npm start and you've got micro frontends.

Working with Nx

Serving micro frontends

Nx doesn't have out-of-the-box functionality for serving multiple applications simultaneously, which is why I resorted to concurrently in the above example. That said, running individual micro frontends is made easy with the Nx CLI.

  • Develop micro frontends independently via nx run <project>:serve.
  • See how they fit into the whole application via npm start.

Generators

Nx ships with a handful of generators that help scaffold your application. In particular, the library generator makes it really easy to share React components:

nx g lib common

This creates a new React library in your project's libs/ directory with a bunch of pre-configured build settings. Included is a convenient TypeScript path alias that makes importing the library straightforward:

// apps/dashboard/src/app/app.tsximport { ComponentA, ComponentB } from '@micronx/common'

Nx provides additional benefits to sharing code this way by keeping track of your project's dependency graph. The relationships between your various code libraries and each dependent application can be illustrated by running nx dep-graph.

Internally, Nx uses this dependency graph to reduce the number of builds/tests that need to be run when changes are introduced. If you make a change to apps/dashboard/ and run nx affected:test, Nx will only run tests for the Dashboard micro frontend. This becomes very powerful as the dependency graph of your project grows in complexity.

Optimizations

Something unique to the micro frontend strategy is the duplication of common vendor dependencies and shared code libraries in the production JS bundles.

The Thoughwork's article touches on this in the "Common Content" section, advocating for tagging common dependencies as Webpack externals to prevent them from being included in each application's final bundle.

module.exports = (config, env) => {  config.externals = {    react: 'React',    'react-dom': 'ReactDOM',  }  return config}

Once Nx upgrades its React tools to Webpack 5, a new method of code optimization will be available for micro frontend projects via Module Federation. This strategy enables building shared code libraries (libs/) into the container application, removing yet another common dependency from the micro frontend bundles.


Original Link: https://dev.to/mgmarlow/better-react-micro-frontends-w-nx-5gnm

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To