Using ES Modules Based Micro-Frontends to Enable Distributed Development

Rate this content
Bookmark

A look at the open source tooling created by the UI Engineering group at JP Morgan to streamline the developer workflow of building and deploying apps in isolation while still delivering a single unifying micro-frontend based portal to the end user, leveraging the use of native support for ES module imports in the browser.

28 min
21 Oct, 2022

Comments

Sign in or register to post your comment.

Video Summary and Transcription

JP Morgan is using modern web technologies like the UITK and Modular to address challenges in their large-scale development environment. They employ micro front-ends with ES modules for dynamic loading and sharing theming using CSS variables. The applications are built using modular, which allows for scaffolding and creating new applications from templates. They rely on an opinionated approach to app creation and use a CDN for efficient deployment and caching. The host application handles user authentication and communication between micro front-ends, while platform services like authorization and authentication are provided by the digital platform.

Available in Español

1. Introduction to JP Morgan's Web Technologies

Short description:

My name is Steve and I'm here to talk about how we're using modern web technologies at JP Morgan. We have two things to discuss: the UITK, a React component library, and Modular, an opinionated monorepo management tool. We have a large-scale development environment with thousands of applications and developers. Each development team faces the same challenges of continuous integration, continuous deployment, and quality assurance.

Good morning everyone. With that amount of videos about JPMorgan, no pressure doing this today. So, as I said, my name is Steve, and I'm here to talk a little bit about how we're using modern web technologies, JP, things like ES modules where we can use them to solve age-old problems, problems like how do we run multiple applications that have all been built and deployed independently of each other in single container portal-like applications.

So a little bit about me. I've been working in and around the fintech space for about 20 years now, and I've had the privilege to see UI technologies grow during that time. And now that I'm with JP Morgan, I'm actually no longer a core developer. But now I get to work with developers to put together our open source providing. We have two things I'm going to talk about today. One is the UITK, which is a React component library that we use to standardize the way their applications look and feel. And Modular, which is an opinionated monorepo management tool. And they're actually both on our public Github, if you want to check them out. And we have we appreciate pull requests.

So the kind of places I've worked at before, I said it's always in Fintech. Some of those organizations are really small. When I came to JP Morgan last year, I had no real idea of a sense of scale that I was going to be facing. We have across the bank as a whole is 50,000 developers, I think. 18,000 of which are in our division. And we're deploying about 5,800 applications into one of our container types, which is a desktop container. 2,000 of those are in production. They service about 200,000 daily users. There are hundreds of deployments going on every day. We have this really distributed development problem. Or joy, depending on how you look at it. Distributed development means we have loads of development teams. They all work independently. They're empowered to make their own choices about how they're going to build their applications, how they're going to deploy them, and more recently, how often do they deploy? Why are they actually sending code out? But looking at it from an organizational standpoint, what is the developer experience of that distributed development model? Well, every development team has to solve the same problems. They're all going to need to have some form of continuous integration. They're all going to need continuous deployment, and they're all going to have the same need to apply quality assurance. So they're going to need test tooling. They're going to need to choose the same products for doing their testing.

2. Consistency and Solutions in UI Engineering

Short description:

And then because we're all under the same brand umbrella, we're going to need to have the same design language. So what was our solution to that? So our solution is in UI engineering. We have what we call the Digital Platform, which is a bit like a Jamstack provider inside the bank. We have a design system that is an accessibility first design system that has a companion react-based component library. We have a new version of the React library being developed at the moment. And more finally, the modular, which is an opinionated monorepo management tool. It has a few features in it that I'll be showing today, but it's similar to create-react-app and then an opinionation on developer tooling that goes in with building the applications themselves. So we have a desktop container. When we come to deliver a web portal, users still want to have a single way of launching applications. They want to have a consistent look and feel on the apps that they're loading, and they want to be able to use their apps in all modern browsers.

And then because we're all under the same brand umbrella, we're going to need to have the same design language. So how do we add that consistency to the applications that we're deploying? Bearing in mind, there's thousands of them being pushed out. So when the applications go out as well, they're going to need to solve the same kind of problems. We need to know how they're going to authenticate their users, how they authorize them to use the apps. And because we want to have the same rich user experiences, we're thinking how are you going to be able to share the layouts you've created, how you're going to share access to your applications. Which all kind of implies that you've got the same kind of understanding of having a preferences system. How you're going to store and persist the user data.

So what was our solution to that? So our solution is in UI engineering. We have what we call the Digital Platform, which is a bit like a Jamstack provider inside the bank. So I've already mentioned we have a desktop container, but we have ways that we distribute our mobile and web apps as well. We call it Omnichannel, but we also provide more of a DevOps providing. So we have things like continuous integration, actually it's based on Jenkins. We have continuous deployment which is based on Amazon S3. And we also provide like a centralized application registry and that's where we have our developers push the versions of their code so we can determine which are going to be made available in production. And more importantly, when we need to roll things back, it simplifies our processes. And then probably more relevant to today and what I'm going to be talking about later is we have a design system. So that is actually, it's an accessibility first design system that has a companion react-based component library. We have been embracing web components and allowed for the use of Angular. There was a decision made a couple of years ago that we were going to be react focused. So we actually have a new version of the React library being developed at the moment. It will be released fairly soon. Feel free to go and have a look at it on our GitHub. And then more finally, the modular, which is an opinionated monorepo management tool. It has a few features in it that I'll be showing today, but it's similar to create-react-app and then an opinionation on developer tooling that goes in with building the applications themselves.

So we have a desktop container. The developers, when they create applications, push it through to our continuous deployment infrastructure, and tell the desktop container, which is an Electron-based app, where to fetch the URLs. When we come to deliver a web portal, what is the user experience expectation? It's actually it's almost the same as on desktop. Users still want to have a single way of launching applications. They want to have a consistent look and feel on the apps that they're loading, and they want to be able to use their apps in all modern browsers. So historically, that could have meant using iframes to load applications together, which would come with the usual drawbacks of you've got many, potentially many, instances of frameworks being loaded into one application, into one web browser window.

3. Micro Front-Ends and Application Container

Short description:

We're using micro front-ends with ES modules for dynamic loading of applications and sharing theming using CSS variables. Transpiling our applications involves rewriting imports to bundle application code separately and using an open source CDN for ES modules. We have a web application container that supports evergreen browsers and dynamic loading of imports in JavaScript.

The use of memory, things get janky. You can't share or readily share CSS and theming between the various apps that you've loaded. So what was our solution? Well, I mentioned that we're using modern technologies, so now we are focusing on having micro front-ends. The micro front-ends that we're looking at are relying on ES modules for splitting the applications and loading them dynamically. And the React library that we've created uses CSS variables to share theming across the various apps that you might be loading.

It comes with many benefits. Things like, if you're using ES modules, the way that we will be transpiling our applications is we take the source code, usually in TypeScript, rewrite imports that are in your own application to bundle your application code separately, and then rewrite all of your external dependencies onto a CDN. We use an open source CDN for ES modules, ESM.SH, have a look, it's great, but you may also be using Skypack. We actually have internal versions of these that are able to access and transpile our existing Commons.js node modules in our internal registry into ES modules. In case you're not familiar, ES modules, a current and modern standard of creating JavaScript in its simplest form, you're probably already using them in TypeScript, and it's a convenient way of just simply having your imports and exports in your code after it's been transpiled to JavaScript.

The other thing is that we have a web application container. We dropped support for Internet Explorer in the last year or so. We don't really mourn its loss, because it does mean that we're able to use evergreen browsers now, all of which are able to support dynamic loading of imports in JavaScript without any need for any plugins.

4. Building Micro Frontend and Application Templates

Short description:

Building a micro frontend. It's live demo time. I've mentioned modular, which has a way of scaffolding applications. We have a minimal monorepo with an express server and an example of creating a host app. We switched to Webpack 5 and added support for ES build. Modular also allows creating new applications from templates, either from NPM or repositories.

Okay, so, building a micro frontend. That was lots of words from me. It's live demo time, which obviously never goes wrong, so please bear with me.

So, I've mentioned, oh, good. I've mentioned modular. It does have a way of scaffolding applications. It's based very similar on your create React app, however, what we're looking at here, I'm going to use a, this is a minimal monorepo. It has a couple of packages in so far. One package is simply an express server that, mocking out the application registry that I talked about before, is gonna serve up our built content, so you can see the demo. And we also have an example of how you would create a host app.

Now, create React app would be able to serve these components, so it looks very similar to normal, using Webpack and Webpack dev server. Recently, we switched up to Webpack 5 and added support for ES build. With ES build, instead of generating a commons.js bundle, we're now creating an ES module bundle. So, what I'm gonna do in here is run a quick command to, there we go, to start up as an express server. It's also gonna start a Webpack dev server that builds this host application. It should, there we go, good. It's gonna very slowly load on localhost. My application, we'll just assume that that's the case. I'll come back to it.

So, thereafter, other things that modular has in it. Now, I mentioned this delivering of development at scale. At scale, we often have the need to create new applications and those new applications are created from templates. So, modular has a feature that can either use templates based on, that come directly from NPM or from within your repositories. So, I'm gonna use them, they're coming from my repository. So, I'm gonna add a new module into my monorepo. Gonna look at the card. Ah, I am, there we go, I can't type with people watching me. So, bringing modular commands to add a new package into my template, I've created some templates already, but just so you can see how they get added in. Why am I running through this? The templates that we add are actually, they can all be run as independent applications. So in the code view, I've now got a new application.

5. Running and Building Applications

Short description:

It doesn't do an awful lot. Fortunately it doesn't use useReact, useEffect rather. I'm gonna start using a new port. So what this is proxying is if a developer is creating the app for themselves, then, did the old one load? Good. Good. Anyway, assume that you can render those. 3000, 2001. I'll show you the video and it'll be amazing. Gonna add another one. Does it start? Good. Good, good. Who would want it to just work straight out of the box, eh? So, never mind. The idea is, we have this card view. They actually get rendered as independent applications that you can yarn. The next step is, having created a couple of packages, that I can show them running together. So, next, I would need to build them. Now, the difference in the build process is that by running through esbuild, we actually create an ES module, which is a single file that can then be pushed onto a CDN.

It doesn't do an awful lot. Fortunately it doesn't use useReact, useEffect rather. Oh, it does, is that an effective one? Maybe, okay, so pretend you haven't seen my useEffects, I did say that I don't do code for a living anymore, and now that that's created a new package, I can actually start this for myself. I'm gonna start using a new port.

So let's say that I'm gonna just run this application. So what this is proxying is if a developer is creating the app for themselves, then, did the old one load? Hello? Hello? There we go. These do load. Oh well. If it doesn't load, I'm just gonna talk for a little bit longer and then show you the video because live demos do that. Good. Good. Anyway, assume that you can render those. Nevermind. 3000, 2001. You know, I've never seen create React app just stop. Good, I knew I shouldn't have tried to do a live demo.

Okay, so I'll carry on for now, and then I'll show you the video and it'll be amazing. Gonna add another one. Okay, so trying again. Then next, I'm gonna have to just talk. Does it start? Good. Good, good. Who would want it to just work straight out of the box, eh? So, never mind. Okay, so what am I gonna talk about? So the idea is, we have this card view. They actually get rendered as independent applications that you can yarn. I'm sorry, you can start with Webpack DevServer. The next step is, having created a couple of packages, that I can show them running together. So, next, I would need to build them. Now, the difference in the build process is that by running through esbuild, we are, ah. By running through esbuild, we actually create an ES module, which is a single file that can then be pushed onto a CDN.

6. Building and Loading Dynamic Modules with ES Build

Short description:

In the example I have here, it actually runs as a local server. I'm gonna see why my modules aren't fetching from the internet. So here we've got the same code window where I did a yarn serve. This is gonna start my node server. In the host package, I created a remote view. That loading is using, it's all JavaScript that runs natively in the browser.

In the example I have here, it actually runs as a local server, and let's just see if it's magicked its way it's magicked its way through the internet. Well, turns out I'm not online. That's a shame. Because I've styled it since I've created this video. Disappointing. Oh well, you get to see what I was doing yesterday. So assume that this is running live.

I'm gonna see why my modules aren't fetching from the internet and maybe if you come find me, I can show you a real running version of this as you can get from all the videos. We have a stand out the front. I'll be there later with a working version. But I'm gonna show you the mocked up version instead.

So here we've got the same code window where I did a yarn serve. This is gonna start my node server which is like the proxy for our app registry and sets up a create React app. There's nothing on the screen so far because what I need to do is add one of those components. So this is showing you how I built one of those, run through ES build, and by running through ES build, generate my ES module, that then gets stuck on the CDM. You can see here, if we have fetched it using our portal, actually that's something I can show you, this is a JavaScript file that gets loaded dynamically.

How did we do that? In the host package, I created a remote view. The remote view is actually, it's a very simple component that just fetches a module from a URL. That module, obviously it shares its state through a context to ensure that we don't try and load these modules multiple times. Here you can see how we're actually loading the remote view. That loading is using, it's all JavaScript that runs natively in the browser. We don't need any plugins to do this. We simply have a fetch from our manifest. We actually use package JSON to define the content that describes the module. We use that, actually I can show you one of those, we use that to describe how the module has been built. So you can see including some packages, that's our design system. But also, where is the output of the JavaScript and the CSS? Those are then going to be used by this remote view to say, when we fetch that package JSON, then we know if we've got a style sheet, we can insert it to the HTML. That may not be the best way of doing it, but it worked. And if we have a manifest, now this one is where we've put the JavaScript. So see that dynamic import? That is natively supported in all browsers.

7. Dynamic Import and Module Sharing

Short description:

If you are running this through Webpack, you'll need a little escape hatch, because Webpack will try and evaluate the import statement for you. But knowing that we've done a dynamic import in the browser, that actually gives us the evaluated default content of the package itself. So we know that those are going to be views for us. So we simply use that view as a component constructor and can include it in the TypeScript TSX. By loading the modules into the same React tree, we can benefit from things like sharing of modules, sharing of dependencies, especially if you've got stateful dependencies. They actually share the same instance. Our builds are faster because we only have to actually build and transpile our own application code. They reduce the file size that we're storing on our CDN. They load faster in the browser because they share dependencies between them. I'm really excited that we get to use modern technology to solve problems that have been around for a long time.

If you are running this through Webpack, you'll need a little escape hatch, because Webpack will try and evaluate the import statement for you. But knowing that we've done a dynamic import in the browser, that actually gives us the evaluated default content of the package itself. So we know that those are going to be views for us. So we simply use that view as a component constructor and can include it in the TypeScript TSX.

I'm presuming I still haven't gone online. OK. So the next bit is I can add more. I can add more components into this, independently building them from each other. And then we can use the portal, simply because it does dynamic loading. The portal is deployed independently of the applications that it contains. And then they can, actually, in my real working demo, I was so proud, I have the grid and the card talking to each other. But there we go. There is an example that I can share that shows this running. It is a very simple thing to get up and running. I think that that was me approaching time. So there was left for me to say that we have, by loading the modules into the same React tree, we can benefit from things like sharing of modules, sharing of dependencies, especially if you've got stateful dependencies. They actually share the same instance. So we do have a system of recommending that our app developers pin at least React to the same version, which simply just uses the resolutions object in a package.json that we then use the same React version across all of our applications. And yeah, so our builds are faster because we only have to actually build and transpile our own application code. They reduce the file size that we're storing on our CDN. They load faster in the browser because they share dependencies between them. And yeah, I'm really excited that we get to use modern technology to solve problems that have been around for a long time. So apologies if the demo didn't work quite well. But honestly, come see me later and it does actually work. Cool. Thank you. Thank you. Thank you. Oh, what a treat. Please, my darling, step into the hot seat.

QnA

Managing Deployments and Opinions of Modular

Short description:

Thank you. We're going to talk about modular a little, which is a great joy for me. We have a couple of questions in the Slido already. How do you manage deployments of these distributed apps? It depends on the team. Some are containerized applications, while others are totally independent. The CDN we use treats each version as immutable, allowing for continuous deployment. We have loads of apps that depend on each other, so communication is key. I have a question about the opinions of Modular. It was designed to be very opinionated.

Thank you. We're going to talk about modular a little, which is a great joy for me. First of all, good job having a backup video that's a pro speaker tip because conference Wi-Fi is usually not great because there's hundreds of you. So good job. Phew. I know.

We have a couple of questions in the Slido already. Remember, slide.do and the code is 2124. Let's go to the live. How do you manage deployments of these distributed apps? Do you just deploy ESM bundles? What happens when you need to synchronize deployments of multiple apps? Ah, fun. It depends on the team. We have got, as a mentioning of scale, not all of those development teams know each other. Sometimes where we have things that are interlinked, we actually use a variation on a theme of Scrum of Scrums, so we can plan together. There are large programs of work. Those programs of work usually involve like the tech leads from the applications that are going to be deployed, their product managers, so we can shape actually how they're going to be deployed. The deployments themselves, we use a range of technologies. I was talking about the shiniest and the newest. Some of them are containerized applications. Some of them, they are totally independent of other apps. The CDN that I was mentioning is fairly new. That one, actually, we use, we treat each version as being immutable, so even in our continuous deployment infrastructure, each build that comes off CI gets pushed into the CDN and is, therefore, available for use as a production application. So yeah, we've got loads of apps that all depend on each other. It's down to human contact. We have to talk to each other to say when we can deploy them, really. What a concept.

I know, right? I have a question about the opinions of Modular. So I was there when Modular got created some time ago. And so I don't know what it looks like now. But I remember that the concept was it was going to be very opinionated. You mentioned that.

Benefits of Opinionated App Creator and CDN Usage

Short description:

Having a very opinionated app creator has worked for us in terms of bootstrapping new applications and providing a consistent way of setting up configuration. While modular is becoming less opinionated, it helps us scale up development and add new features to large-scale applications. We rely on ES modules, a consistent CDN, and modern tech like HTTP2 to keep micro front-ends snappy and avoid unnecessary reloading or extra downloads. Our specific CDN is heavily cached, and we pin versions for stateful components. The difference between our approach and Webpack's Module Federation or Nexus is that we don't build everything together.

What part of having a very opinionated app creator has worked for you, has worked for you at scale, and may or may not work for someone with not quite so many apps? So it has worked in some ways. When it was used to start with, it really was about bootstrapping new applications. So in the ever-changing face of UI development, it was convenient to have a consistent way of either picking tooling or setting up configuration for your tooling. The UI development space moves very quickly. So what was confusing and difficult then isn't necessarily confusing and difficult now. So while modular exists as a way of standardizing how we interact with applications, it is becoming ever less opinionated. So there's more and more escape patches to come with it. And actually, it's giving us a really unique way of helping scale up development. So we now don't just have like we aren't there at the origin of applications. We're now being included into large scale applications that are wanting to add new features. So things like the new releases of, I think we called it ghost testing, for similar to running tests on only the things that have changed in your pull request or things that depend on you. And soon we're going to have the incremental build of just building selectively. So it gets added in.

That actually relates to another question which we have, which is, how do you manage to keep it snappy between the micro front-ends, avoiding unnecessary reloading maybe, extra downloads, state management, et cetera. So there, actually, one of the things we rely on is by using ES modules and a consistent CDN. So I mean, it's not quite as elegant and seamless as I made it look. We do recommend a specific CDN. So it's always, we all use the same CDN. We pin versions for things that we know that are stateful. But the CDN that we use, we actually have an implementation of it internally so we can share our proprietary code with internal users. But the CDN itself is heavily cached. So the modules themselves do load really quickly. We also rely on HTTP2 and newer standards. So it doesn't matter having lots of connections needed, needing to fetch lots of dependencies. We'd like, that was old school. We would think that was a problem, but modern tech, it isn't really. So yeah, we try and rely on modern tech. There's a couple of questions here that I'm going to bundle, which is people asking, why not this other thing, right? Which is kind of always comes up. How is this different from Webpack's Module Federation or Nexus approach? Mm-hmm. So Module Federation, the version of using micro frontends in this way means you don't actually build everything together.

Building Host Application and Platform Services

Short description:

To build the host application, you don't need to know what modules you loaded. Being opinionated means making choices and evolving over time. User authentication and communication between micro front-ends are handled by the host application. Platform services like authorization and authentication are provided by the digital platform. Steve is available for further discussion in the speaker Q&A room.

So you don't need to know what modules you loaded in order to build your host application. I know there are a few of, why have you chosen's coming up. Because I think to be opinionated, you have to make a choice. Those choices have come around over time, and often people push back on, why did you do a thing? And now we take it case by case, and we have to evolve.

And then in the similar vein, it's How do you do specific things, such as user authentication across multiple modules, or communication between one micro front end in the deployed app, and the other if it exists? So in the version that does work, please come see me later. In the speaker room Q&A down by the lobby. I actually showed the grid talking to that card view, and they talk to each other. The answer that we've got internally is part of that digital platform is we provide platform services. So things like the authorization authentication that's done on launching the host application. There's a arcane system for authorization, but it is handled by the host application. So as an app is loaded, it can define which credentials the user must have. And then the host is responsible for ensuring that those have been fetched.

That's great. We have a ton more questions, but unfortunately not a ton more time. So let's thank Steve. And you can find him later in the speaker Q&A room. Thank you for joining us. Thank you so much. Free to go.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Scaling Up with Remix and Micro Frontends
Top Content
Do you have a large product built by many teams? Are you struggling to release often? Did your frontend turn into a massive unmaintainable monolith? If, like me, you’ve answered yes to any of those questions, this talk is for you! I’ll show you exactly how you can build a micro frontend architecture with Remix to solve those challenges.
React Advanced Conference 2022React Advanced Conference 2022
22 min
Monolith to Micro-Frontends
Top Content
Many companies worldwide are considering adopting Micro-Frontends to improve business agility and scale, however, there are many unknowns when it comes to what the migration path looks like in practice. In this talk, I will discuss the steps required to successfully migrate a monolithic React Application into a more modular decoupled frontend architecture.
React Advanced Conference 2023React Advanced Conference 2023
20 min
Micro-Frontends With React & Vite Module Federation
Top Content
From my experience one of the hardest things is to share information between microfrontends, so in this talk I would like to explain various ways on how to share a design system to ensure uniformity to the application. Another difficult thing is sharing dependencies, fortunately with module federation it can be done, but how can I use different versions of the same library and how does it work behind the scenes?
I'm the creator of module-federation/vite library, with React and this library, I'd like to show you how you can achieve these results by configuring everything correctly.
React Summit 2022React Summit 2022
23 min
Sharing is Caring: (How) Should Micro Frontends Share State?
Micro frontends architecture is extremely powerful when it comes to splitting large frontend monoliths into smaller, individually deployable blocks, each is owned by an autonomous team and is focused on a business domain. But what about State? We are often told that micro frontends shouldn't share state, as this would make them coupled to each other. However, when it comes to complex UIs, it is not rare to encounter scenarios where state management between micro frontends is necessary. This talk is about finding the sweet spot — In which scenarios it is reasonable for micro frontends to share State? and how should micro frontends share State while remaining decoupled of each other? We discuss & compare different solutions in React.
React Advanced Conference 2021React Advanced Conference 2021
27 min
Micro-Frontends Performance and Centralised Data Caching
Common myths about Micro-Frontends hold that they are bad for performance or that developers implementing this architectural style don’t care about the performance implications because they are focusing on fixing the developer experience and organizational issues rather than focusing on the user experience, however, the reality is altogether different. Micro-Frontends are not inheritably bad for performance and, as is often the case in software development, making best use of the technology depends on correct implementation. This talk will demonstrate how Micro-Frontends can make your applications faster and more resilient while keeping the benefits of independent deployments.

Workshops on related topic

JSNation Live 2021JSNation Live 2021
113 min
Micro Frontends with Module Federation and React
Workshop
Did you ever work in a monolithic Next.js app? I did and scaling a large React app so that many teams can work simultaneously is not easy. With micro frontends you can break up a frontend monolith into smaller pieces so that each team can build and deploy independently. In this workshop you'll learn how to build large React apps that scale using micro frontends.
JSNation Live 2021JSNation Live 2021
113 min
Micro-Frontends with Module Federation and Angular
Workshop
Ever more companies are choosing Micro-Frontends. However, they are anything but easy to implement. Fortunately, Module Federation introduced with webpack 5 has initiated a crucial change of direction.
In this interactive workshop, you will learn from Manfred Steyer -- Angular GDE and Trusted Collaborator in the Angular team -- how to plan and implement Micro-Frontend architectures with Angular and the brand new webpack Module Federation. We talk about sharing libraries and advanced concepts like dealing with version mismatches, dynamic Module Federation, and integration into monorepos.
After the individual exercises, you will have a case study you can use as a template for your projects. This workshop helps you evaluate the individual options for your projects.
Prerequisites:You should have some experience with Angular.