11

Webpack module federation for our feedback product @Shipup

 2 years ago
source link: https://medium.com/shipup-blog/webpack-module-federation-for-our-feedback-product-shipup-9538c1942ab7
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Webpack module federation for our feedback product @

What we had to achieve

Almost one year ago we started working on a new product at Shipup, our Feedback product. This feature helps our clients send satisfaction surveys right at delivery. It allows the customer receives a simple question embedded in the delivery email that redirects to a web page where it can provide feedback regarding the delivery. The goal is to allow our clients to create a highly customizable Feedback feature that configures directly on our platform. The merchant can then customize the branding, questions, trigger webhooks following response, and more.

To allow the best customization we needed to provide them a preview of their changes, which means what the consumer will see while answering the survey.

https://cdn-images-1.medium.com/max/1600/1*E_1CfXdGeBTGLtBYKZnZfA.png
Here you can customize the design and brandingHere is the result for the customer

Solutions we had

That said, we have multiple solutions to implement previews into our Platform.

  • Code Duplication

The simplest solution, but not the smartest for obvious reasons was to duplicate the code. In this case if we made a change to our feedback we would have to maintain the code in two places, one for the survey and one for the preview into our platform which quickly turns into a developer’s nightmare.

  • NPM package

Another solution would be to expose our feedback as a library and make it a dependency of our platform. In this case, if you update the code, you need to publish a new version of the library, bump the version into the platform, and release a new version of the platform. Because we work with polyrepo at Shipup, this solution is not as easy to set up as with a monorepo. That said you will add some extra work to the developer for an update of our codebase. Moreover, you need to make sure that you deploy on both applications, the Feedback, and our platform. In an ideal world, you should be able to update the feedback everywhere in one click.

  • Webpack Federated Module

That’s where the Webpack module federation comes to the rescue. By using Feedback as a federated module inside our platform, you can release a new version of Feedback and it’s live everywhere, awesome! If you don’t know what are federated modules, you can read this post https://medium.com/swlh/webpack-5-module-federation-a-game-changer-to-javascript-architecture-bcdd30e02669 from Zack Jackson

Module federation allows a JavaScript application to dynamically load code from another application

1*LYa-AhLhP0-3q2O9liL13w.png

Implementation of our Feedback product as a federated module

We had to expose a React component from Feedback, this preview component has some differences with the original Feedback as the context of the execution is different. We only wanted to display a step of our survey without any API call and no option to navigate into the survey

Then we added the ModuleFederation plugin to expose this component

The remote application configuration (Feedback)

new ModuleFederationPlugin({
name: 'Feedback',
filename: 'remoteEntry.js',
exposes: {
'./Preview': './src/App/Preview',
},
// ...
}

Once the Feedback product was able to expose a Preview component we needed to declare it as a federated module from our platform. We introduced a way to test it locally by changing where to load the federated module depending on an environment variable

The host application configuration (Shipup platform)

new ModuleFederationPlugin({
name: 'app',
remotes: {
Feedback: process.env.LOCAL_FEEDBACK
? 'Feedback@<http://localhost:8081/remoteEntry.js>'
: 'Feedback@<https://feedback.shipup.co/remoteEntry.js>',
},
// ...
}

Load the federated module from our platform

Now that our Preview component is accessible as a federated module it’s as simple as making an import to load our preview:

const RemoteFeedback = lazy(() => import('Feedback/Preview'));function FeedbackPreview() {
return <Suspense fallback={<Spinner />}>
<RemoteFeedback {...someProps} />
</Suspense>
}

Then if you try to load your application you will face the following error

Hooks can only be called inside the body of a function component.

https://reactjs.org/warnings/invalid-hook-call-warning.html

That means you’re currently loading React twice and it doesn’t like it at all. In fact, your host application is loading one version of React and your remote application is loading it too. To solve this issue you will need to make two things

  • Create a bootstrap.js file and move all you had from your index.js into it for both remote and host applications.
    Your index.js file will look like following:
import('./bootstrap');
  • Declare react and react-dom as shared modules in the module federation plugin:
shared: {
'react': {
singleton: true,
},
'react-dom': {
singleton: true,
},
}

If you want to have further explanations you can dive into webpack documentation

Then if you try to reload your app you will face a second issue:

No required version specified and unable to automatically determine one. Unable to find required version for "react" in description file

You will need to tell which version to use by updating your configuration

shared: {
'react': {
singleton: true,
requiredVersion: '^17.0.0',
},
'react-dom': {
singleton: true,
requiredVersion: '^17.0.0',
},
},

If you reload your app, it finally works like a charm!

By doing so we are now sure that our feedback preview always reflects what the consumer will see without any deviation

Where we are now

It’s been 6 months since we released our new Feedback product and we’re happy with our choice, we were able to release several versions without any issues.

Recently we took it a step further by sharing our design system as federated modules and creating our ShipupFederationPlugin over the ModuleFederationPlugin.

This plugin introduces cool stuff such as:

  • Automatic detection of a local federated module over production when your federated module is started locally.
  • Versioning as a fallback in case one project is not able to use the latest version of a federated module.
  • Possibility to access a federated module using a query string from a branch pushed to Github, to create a smooth Quality Assurance experience. The developer only has to share a specific url and him and everyone involved into the process can test his improvements.
  • Manage multiple env (local / staging/production) to load federated modules from the corresponding env. For example, when you’re on a staging env it will also load federated modules from staging.

But that could be the subject of a dedicated post …

Interested to start a new challenge at Shipup ? We’re hiring! Check out our job openings at careers.shipup.co


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK