SlideShare a Scribd company logo
Building Micro-Frontends: Scaling Teams and
Projects Empowering Developers 1st Edition Luca
Mezzalira install download
https://ebookmeta.com/product/building-micro-frontends-scaling-
teams-and-projects-empowering-developers-1st-edition-luca-
mezzalira/
Download more ebook from https://ebookmeta.com
We believe these products will be a great fit for you. Click
the link to download now, or visit ebookmeta.com
to discover even more!
Building Games with Ethereum Smart Contracts:
Intermediate Projects for Solidity Developers Kedar
Iyer
https://ebookmeta.com/product/building-games-with-ethereum-smart-
contracts-intermediate-projects-for-solidity-developers-kedar-
iyer/
Front-End Reactive Architectures: Explore the Future of
the Front-End using Reactive JavaScript Frameworks and
Libraries 1st Edition Luca Mezzalira
https://ebookmeta.com/product/front-end-reactive-architectures-
explore-the-future-of-the-front-end-using-reactive-javascript-
frameworks-and-libraries-1st-edition-luca-mezzalira/
Primary Mathematics 3A Hoerst
https://ebookmeta.com/product/primary-mathematics-3a-hoerst/
A New Vision for Center Based Engineering Research 1st
Edition And Medicine Engineering National Academies Of
Sciences
https://ebookmeta.com/product/a-new-vision-for-center-based-
engineering-research-1st-edition-and-medicine-engineering-
national-academies-of-sciences/
Security Council Sanctions Governance The Power and
Limits of Rules 1st Edition Thomas Dörfler
https://ebookmeta.com/product/security-council-sanctions-
governance-the-power-and-limits-of-rules-1st-edition-thomas-
dorfler/
Math Is Everything Bliss Green
https://ebookmeta.com/product/math-is-everything-bliss-green/
Fundamentals of Data Engineering 1st Edition Joe Reis
https://ebookmeta.com/product/fundamentals-of-data-
engineering-1st-edition-joe-reis/
Logic Computation and Rigorous Methods Essays Dedicated
to Egon Börger on the Occasion of His 75th Birthday
Lecture Notes in Computer Science 12750 Alexander
Raschke (Editor)
https://ebookmeta.com/product/logic-computation-and-rigorous-
methods-essays-dedicated-to-egon-borger-on-the-occasion-of-
his-75th-birthday-lecture-notes-in-computer-
science-12750-alexander-raschke-editor/
Modern Architecture 1st Edition Frank Lloyd Wright
https://ebookmeta.com/product/modern-architecture-1st-edition-
frank-lloyd-wright/
Psychoanalysis as an Ethical Process 1st Edition Robert
P. Drozek
https://ebookmeta.com/product/psychoanalysis-as-an-ethical-
process-1st-edition-robert-p-drozek/
Building Micro-Frontends: Scaling Teams and Projects Empowering Developers 1st Edition Luca Mezzalira
Chapter 4. Discovering Micro-
Frontend Architectures
In the previous chapter, we learned about decisions framework, the
foundation of any micro-frontend architecture. In this chapter, we will
review the different architecture choices, applying what we have learned so
far.
Micro-Frontend Decisions Framework
Applied
The decisions framework helps you to choose the right approach for your
micro-frontend project based on its characteristics (see Figure 4-1). Your
first decision will be between a horizontal and vertical split.
Figure 4-1. The micro-frontends decisions framework
TIP
The micro-frontends decisions framework helps you determine the best architecture for
a project.
Vertical Split
A vertical split offers fewer choices, and because they are likely well
known by frontend developers who are used to writing single-page
applications (SPAs), only the client-side choice is shown in Figure 4-1.
You’ll find a vertical split helpful when your project requires a consistent
user interface evolution and a fluid user experience across multiple views.
That’s because a vertical split provides the closest developer experience to
an SPA, and therefore the tools, best practices, and patterns can be used for
the development of a micro-frontend.
Although technically you can serve vertical-split micro-frontends with any
composition, so far all the explored implementations have a client-side
composition in which an application shell is responsible for mounting and
unmounting micro-frontends, leaving us with one composition method to
choose from. The relation between a micro-frontend and the application
shell is always one to one, so therefore the application shell loads only one
micro-frontend at a time. You’ll also want to use client-side routing. The
routing is usually split in two parts, with a global routing used for loading
different micro-frontends being handled by the application shell (see
Figure 4-2).
Figure 4-2. The application shell is responsible for global routing between micro-frontends
Although the local routing between views inside the same micro-frontend is
managed by the micro-frontend itself, you’ll have full control of the
implementation and evolution of the views present inside it since the team
responsible for a micro-frontend is also the subject-matter expert on that
business domain of the application (Figure 4-3).
Figure 4-3. A micro-frontend is responsible for routing between views available inside the micro-
frontend itself
Finally, for implementing an architecture with a vertical-split micro-
frontend, the application shell loads HTML or JavaScript as the entry point.
The application shell shouldn’t share any business domain logic with the
other micro-frontends and should be technology agnostic to allow future
system evolution, so you don’t want to use any specific UI framework for
building an application shell. Try Vanilla JavaScript if you built your own
implementation.
The application shell is always present during users’ sessions because it’s
responsible for orchestrating the web application as well as exposing some
life cycle APIs for micro-frontends in order to react when they are fully
mounted or unmounted.
When vertical-split micro-frontends have to share information with other
micro-frontends, such as tokens or user preferences, we can use query
strings for volatile data, or web storages for tokens or user preferences,
similar to how the horizontal split ones do between different views.
Horizontal Split
A horizontal split works well when a business subdomain should be
presented across several views and therefore reusability of the subdomain
becomes key for the project; when search engine optimization is a key
requirement of your project and you want to use a server-side rendering
approach; when your frontend application requires tens if not hundreds of
developers working together and you have to split more granular our
subdomains; or when you have a multitenant project with customer
customizations in specific parts of your software.
The next decision you’ll make is between client-side, edge-side, and server-
side compositions. Client side is a good choice when your teams are more
familiar with the frontend ecosystem or when your project is subject to high
traffic with significant spikes, for instance. You’ll avoid dealing with
scalability challenges on the frontend layer because you can easily cache
your micro-frontends, leveraging a content delivery network (CDN).
You can use edge-side composition for a project with static content and
high traffic in order to delegate the scalability challenge to the CDN
provider instead of having to deal with it in your infrastructure. As we
discussed in Chapter 3, embracing this architecture style has some
challenges, such as its complicated developer experience and the fact that
not all CDNs support it. But projects like online catalog with no
personalized content may be a good candidate for this approach.
Server-side composition gives us the most control of our output, which is
great for highly indexed websites, such as news sites or ecommerce. It’s
also a good choice for websites that require great performance metrics,
similar to PayPal and American Express, both of which use server-side
composition.
Next is your routing strategy. While you can technically apply any routing
to any composition, it’s common to use the routing strategy associated with
your chosen composition pattern. If you choose a client-side composition,
for example, most of the time, routing will happen at the client-side level.
You might use computation logic at the edge (using Lambda@Edge in case
of AWS or Workers in CloudFlare) to avoid polluting the application shell’s
code with canary releases or to provide an optimized version of your web
application to search engine crawlers leveraging the dynamic rendering
capability.
On the other hand, an edge-side composition will have an HTML page
associated with each view, so every time a user loads a new page, a new
page will be composed in the CDN, which will retrieve multiple micro-
frontends to create that final view. Finally, with server-side routing, the
application server will know which HTML template is associated with a
specific route; routing and composition happen on the server side.
Your composition choice will also help narrow your technical solutions for
building a micro-frontends project. When you use client-side composition
and routing, your best implementation choice is an application shell loading
multiple micro-frontends in the same view with the webpack plug-in called
Module Federation, with iframes, or with web components, for instance.
For the edge-side composition, the only solution available is using edge-
side includes (ESI). We are seeing hints that this may change in the future,
as cloud providers extend their edge services to provide more
computational and storage resources. For now, though, ESI is the only
option. And when you decide to use server-side composition, you can use
server-side includes (SSI) or one of the many SSR frameworks for your
micro-frontend applications. Note that SSRs will give you greater flexibility
and control over your implementation.
Missing from the decisions framework is the final pillar: how the micro-
frontends will communicate when they are in the same or different views.
This is mainly because when you select a horizontal split, you have to avoid
sharing any state across micro-frontends; this approach is an antipattern.
Instead, you’ll use the techniques mentioned in Chapter 3, such as an event
emitter, custom events, or reactive streams using an implementation of the
publish/subscribe (pub/sub) pattern for decoupling the micro-frontends and
maintaining their independent nature. When you have to communicate
between different views, you’ll use a query string parameter to share
volatile data, such as product identifiers, and web storage/cookies for
persistent data, such as users’ tokens or local users’ settings.
OBSERVER PATTERN
The observer pattern (also known as publish/subscribe pattern) is a
behavioral design pattern that defines a one-to-many relationship
between objects such that, when one object changes its state, all
dependent objects are notified and updated automatically. An object
with a one-to-many relationship with other objects that are interested in
its state is called the subject or publisher. Its dependent objects are
called observers or subscribers. The observers are notified whenever the
state of the subject changes, and then they act accordingly. The subject
can have any number of dependent observers.
Architecture Analysis
To help you better choose the right architecture for your project, we’ll now
analyze the technical implementations, looking at challenges and benefits.
We’ll review the different implementations in detail and then assess the
characteristics for each architecture. The characteristics we’ll analyze for
every implementation:
Deployability
Reliability and ease of deploying a micro-frontend in an environment.
Modularity
Ease of adding or removing micro-frontends and ease of integrating
with shared components hosted by micro-frontends.
Simplicity
Ease of being able to understand or do. If a piece of software is
considered simple, it has likely been found to be easy to understand and
to reason about.
Testability
Degree to which a software artifact supports testing in a given test
context. If the testability of the software artifact is high, then finding
faults in the system by means of testing is easier.
Performance
Indicator of how well a micro-frontend would meet the quality of user
experience described by web vitals, essential metrics for a healthy site.
Developer experience
The experience developers are exposed to when they use your product,
be it client libraries, SDKs, frameworks, open source code, tools, API,
technology, or services.
Scalability
The ability of a process, network, software, or organization to grow and
manage increased demand.
Coordination
Unification, integration, or synchronization of group members’ efforts
in order to provide unity of action in the pursuit of common goals.
Characteristics are rated on a five-point scale, with one point indicating that
the specific architecture characteristic isn’t well supported and five points
indicating that the architecture characteristic is one of the strongest features
in the architectural pattern. The score indicates which architecture
characteristic shines better with every approach described. It’s almost
impossible having all the characteristics working perfectly in an
architecture due to the tension they exercise with each other. Our role would
be to find the trade-off suitable for the application we have to build, hence
the decision to create a score mechanism to evaluate all of these
architectural approaches.
Architecture and Trade-offs
As I pointed out elsewhere in this book, I firmly believe that the perfect
architecture doesn’t exist; it’s always a trade-off. The trade-offs are not only
technical but also based on business requirements and organizational
structure. Modern architecture considers other forces that contribute to the
final outcome as well as technical aspects. We must recognize the
sociotechnical aspects and optimize for the context we operate in instead of
searching for the “perfect architecture” (which doesn’t exist) or borrowing
the architecture from another context without researching whether it would
be appropriate for our context.
In Fundamentals of Software Architecture, Neal Ford and Mark Richards
highlight very well these new architecture practices and invite the readers to
optimize for the “least worst” architecture. As they state, “Never shoot for
the best architecture, but rather the least worst architecture.”
Before settling on a final architecture, take the time to understand the
context you operate in, your teams’ structures, and the communication
flows between teams. When we ignore these aspects, we risk creating a
great technical proposition that’s completely unsuitable for our company.
It’s the same when we read case studies from other companies embracing
specific architectures. We need to understand how the company works and
how that compares to how our company works. Often the case studies focus
on how a company solved a specific problem, which may or may not
overlap with your challenges and goals. It’s up to you to find out if the case
study’s challenges match your own.
Read widely and talk with different people in the community to understand
the forces behind certain decisions. Taking the time to research will help
you avoid making wrong assumptions and become more aware of the
environment you are working in.
Every architecture is optimized for solving specific technical and
organizational challenges, which is why we see so many approaches to
micro-frontends. Remember: there isn’t right or wrong in architecture, just
the best trade-off for your own context.
Vertical-Split Architectures
For a vertical-split architecture, a client-side composition, client-side
routing, and an application shell, as described above, are fantastic for teams
with a solid background of building SPAs for their first foray into micro-
frontends, because the development experience will be mostly familiar. This
is probably also the easiest way to enter the micro-frontend world for
developers with a frontend background.
Application Shell
A persistent part of a micro-frontend application, the application shell is the
first thing downloaded when an application is requested. It will shepherd a
user session from the beginning to the end, loading and unloading micro-
frontends based on the endpoint the user requests. The main reasons to load
micro-frontends inside an application shell include:
Handling the initial user state (if any)
If a user tries to access an authenticated route via a deep link but the
user token is invalid, the application shell redirects the user to the sign-
in view or a landing page. This process is needed only for the first load,
however. After that, every micro-frontend in an authenticated area of a
web application should manage the logic for keeping the user
authenticated or redirecting them to an unauthenticated page.
Retrieving global configurations
When needed, the application shell should first fetch a configuration
that contains any information used across the entire user sessions, such
as the user’s country if the application provides different experiences
based on country.
Fetching the available routes and associated micro-frontends to load
To avoid needlessly deploying the application shell, the route
configurations should be loaded at runtime with the associated micro-
frontends. This will guarantee control of the routing system without
deploying the application shell multiple times.
Setting logging, observability, or marketing libraries
Because these libraries are usually applied to the entire application, it’s
best to instantiate them at the application shell level.
Handling errors if a micro-frontend cannot be loaded
Sometimes micro-frontends are unreachable due to a network issue or
bug in the system. It’s wise to add an error message (a 404 page, for
instance) to the application shell or load a highly available micro-
frontend to display errors and suggest possible solutions to the user, like
suggesting similar products or asking them to come back later.
You could achieve similar results by using libraries in every micro-frontend
rather than using an orchestrator like the application shell. However, ideally
you want just one place to manage these things from. Having multiple
libraries means ensuring they are always in sync between micro-frontends,
which requires more coordination and adds complexity to the entire
process. Having multiple libraries also creates risk in the deployment phase,
where there are breaking changes, compared to centralizing libraries inside
the application shell.
Never use the application shell as a layer to interact constantly with micro-
frontends during a user session. The application shell should only be used
for edge cases or initialization. Using it as a shared layer for micro-
frontends risks having a logical coupling between micro-frontends and the
application shell, forcing testing and/or redeployment of all micro-frontends
available in an application. This situation is also called a distributed
monolith and is a developer’s worst nightmare.
In this pattern, the application shell loads only one micro-frontend at a time.
That means you don’t need to create a mechanism for encapsulating
conflicting dependencies between micro-frontends because there won’t be
any clash between libraries or CSS styles (see Figure 4-4), as long as both
are removed from the window object when a micro-frontend is unloaded.
The application shell is nothing more than a simple HTML page with logic
wrapped in a JavaScript file. Some CSS styles may or may not be included
in the application shell for the initial loading experience, such as for
showing a loading animation like a spinner. Every micro-frontend entry
point is represented by a single HTML page containing the logic and style
of a single view or a small SPA containing several routes that include all the
logic needed to allow a user to consume an entire subdomain of the
application without a new micro-frontend needing to load. A JavaScript file
could be loaded instead as a micro-frontend entry point, but in this case we
are limited by the initial customer experience, because we have to wait until
the JavaScript file is interpreted before it can add new elements into the
domain object model (DOM).
Figure 4-4. Vertical-split architecture with client-side composition and routing using the application
shell
The vertical split works well when we want to create a consistent user
experience while providing full control to a single team. A clear sign that
this may be the right approach for your application is when you don’t have
many repetitions of business subdomains across multiple views but every
part of the application may be represented by an application itself.
Identifying micro-frontends becomes easy when we have a clear
understanding of how users interact with the application. If you use an
analytics tool like Google Analytics, you’ll have access to this information.
If you don’t have this information, you’ll need to get it before you can
determine how to structure the architecture, business domains, and your
organization. With this architecture, there isn’t a high reusability of micro-
frontends, so it’s unlikely that a vertical-split micro-frontend will be reused
in the same application multiple times.
However, inside every micro-frontend we can reuse components (think
about a design system), generating a modularity that helps avoid too much
duplication. It’s more likely, though, that micro-frontends will be reused in
different applications maintained by the same company. Imagine that in a
multitenant environment, you have to develop multiple platforms and you
want to have a similar user interface with some customizations for part of
every platform. You will be able to reuse vertical-split micro-frontends,
reducing code fragmentation and evolving the system independently based
on the business requirements.
Challenges
Of course, there will be some challenges during the implementation phase,
as with any architecture pattern. Apart from domain-specific ones, we’ll
have common challenges, some of which have an immediate answer, while
others will depend more on context. Let’s look at four major challenges: a
sharing state, the micro-frontends composition, a multiframework approach,
and the evolution of your architecture.
Sharing state
The first challenge we face when we work with micro-frontends in general
is how to share states between micro-frontends. While we don’t need to
share information as much with a vertical-split architecture, the need still
exists.
Some of the information that we may need to share across multiple micro-
frontends are fine when stored via web storage, such as the audio volume
level for media the user played or the fonts recently used to edit a
document.
When information is more sensitive, such as personal user data or an
authentication token, we need a way to retrieve this information from a
public API and then share across all the micro-frontends interested in this
information. In this case, the first micro-frontend loaded at the beginning of
the user’s session would retrieve this data, stored in a web storage with a
retrieval time stamp. Then every micro-frontend that requires this data can
retrieve it directly from the web storage, and if the time stamp is older than
a preset amount of time, the micro-frontend can request the data again. And
because the application loads only one micro-frontend at a time and every
micro-frontend will have access to the selected web storage, there is no
strong requirement to pass through the application shell for storing data in
the web storage.
However, let’s say that your application relies heavily on the web storage,
and you decide to implement security checks to validate the space available
or type of message stored. In this scenario, you may want to instead create
an abstraction via the application shell that will expose an API for storing
and retrieving data. This will centralize where the data validation happens,
providing meaningful errors to every micro-frontend in case a validation
fails.
Composing micro-frontends
You have several options for composing vertical-split micro-frontends
inside an application shell. Remember, however, that vertical-split micro-
frontends are composed and routed on the client side only, so we are limited
to what the browser’s standards offer us. There are four techniques for
composing micro-frontends on the client side:
ES modules
JavaScript modules can be used to split our applications into smaller
files to be loaded at compile time or at runtime, fully implemented in
modern browsers. This can be a solid mechanism for composing micro-
frontends at runtime using standards. To implement an ES module, we
simply define the module attribute in our script tag and the browser will
interpret it as a module:
<script type="module" src="catalogMFE.js"></script>
This module will be always deferred and can implement cross-origin
resource sharing (CORS) authentication. ES modules can also be
defined for the entire application inside an import map, allowing us to
use the syntax to import a module inside the application. As of
publication time, the main problem with import maps is that they are not
supported by all the browsers. You’ll be limited to Google Chrome,
Microsoft Edge (with Chromium engine), and recent versions of Opera,
limiting this solution’s viability.
SystemJS
This module loader supports import maps specifications, which are not
natively available inside the browser. This allows them to be used inside
the SystemJS implementation, where the module loader library makes
the implementation compatible with all the browsers. This is a handy
solution when we want our micro-frontends to load at runtime, because
it uses a syntax similar to import maps and allows SystemJS to take care
of the browser’s API fragmentation.
Module Federation
This is a plug-in introduced in webpack 5 used for loading external
modules, libraries, or even entire applications inside another one. The
plug-in takes care of the undifferentiated heavy lifting needed for
composing micro-frontends, wrapping the micro-frontends’ scope and
sharing dependencies between different micro-frontends or handling
different versions of the same library without runtime errors. The
developer experience and the implementation are so slick that it would
seem like writing a normal SPA. Every micro-frontend is imported as a
module and then implemented in the same way as a component of a UI
framework. The abstraction made by this plug-in makes the entire
composition challenge almost completely painless.
HTML parsing
When a micro-frontend has an entry point represented by an HTML
page, we can use JavaScript for parsing the DOM elements and append
the nodes needed inside the application shell’s DOM. At its simplest, an
HTML document is really just an XML document with its own defined
schema. Given that, we can treat the micro-frontend as an XML
document and append the relevant nodes inside the shell’s DOM using
the DOMParser object. After parsing the micro-frontend DOM, we then
append the DOM nodes using adoptNode or cloneNode methods.
However, using cloneNode or adoptNode doesn’t work with the script
element, because the browser doesn’t evaluate the script element, so in
this case we create a new one, passing the source file found in the
micro-frontend’s HTML page. Creating a new script element will
trigger the browser to fully evaluate the JavaScript file associated with
this element. In this way, you can even simplify the micro-frontend
developer experience because your team will provide the final results
knowing how the initial DOM will look. This technique is used by some
frameworks, such as qiankun, which allows HTML documents to be
micro-frontend entry points.
All the major frameworks composed on the client side implement these
techniques, and sometimes you even have options to pick from. For
example, with single SPA you can use ES modules, SystemJS with import
maps, or Module Federation.
All these techniques allow you to implement static or dynamic routes. In the
case of static routes, you just need to hardcode the path in your code. With
dynamic path, you can retrieve all the routes from a static JSON file to load
at the beginning of the application or create something more dynamic by
developing an endpoint that can be consumed by the application shell and
where you apply logic based on the user’s country or language for returning
the final routing list.
Multiframework approach
Using micro-frontends for a multiframework approach is a controversial
decision, because many people think that this forces them to use multiple
UI frameworks, like React, Angular, Vue, or Svelte. But what is true for
frontend applications written in a monolithic way is also true for micro-
frontends.
Although technically you can implement multiple UI frameworks in an
SPA, it creates performance issues and potential dependency clashes. This
applies to micro-frontends as well, so using a multiframework
implementation for this architecture style isn’t recommended.
Instead, follow best practices like reducing external dependencies as much
as you can, importing only what you use rather than entire packages that
may increase the final JavaScript bundle. Many JavaScript tools implement
a tree-shaking mechanism to help achieve smaller bundle sizes.
There are some use cases in which the benefits of having a multiframework
approach with micro-frontends outweigh the challenges, such as when we
can create a healthy flywheel for developers, reducing the time to market of
their business logic without affecting production traffic.
Imagine you start porting a frontend application from an SPA to micro-
frontends. Working on a micro-frontend and deploying the SPA codebase
alongside it would help you to provide value for your business and users.
First, we would have a team finding best practices for approaching the
porting (such as identifying libraries to reuse across micro-frontends),
setting up the automation pipeline, sharing code between micro-frontends,
and so on. Second, after creating the minimum viable product (MVP), the
micro-frontend can be shipped to the final user, retrieving metrics and
comparing with the older version. In a situation like this, asking a user to
download multiple UI frameworks is less problematic than developing the
new architecture for several months without understanding if the direction
is leading to a better result. Validating your assumptions is crucial for
generating the best practices shared by different teams inside your
organization. Improving the feedback loop and deploying code to
production as fast as possible demonstrates the best approach for
overcoming future challenges with microarchitectures in general.
You can apply the same reasoning to other libraries in the same application
but with different versions, such as when you have a project with an old
version of Angular and you want to upgrade to the latest version.
Remember, the goal is creating the muscles for moving at speed with
confidence and reducing the potential mistakes automating what is possible
and fostering the right mindset across the teams. Finally, these
considerations are applicable to all the micro-frontend architecture shared in
this book.
Architecture evolution and code encapsulation
Perfectly defining the subdomains on the first try isn’t always feasible. In
particular, using a vertical-split approach may result in coarse-grained
micro-frontends that become complicated after several months of work
because of broadening project scope as the team’s capabilities grow. Also,
we can have new insights into assumptions we made at the beginning of the
process. Fear not! This architecture’s modular nature helps you face these
challenges and provides a clear path for evolving it alongside the business.
When your team’s cognitive load starts to become unsustainable, it may be
time to split your micro-frontend. One of the many best practices for
splitting a micro-frontend is code encapsulation, which is based on a
specific user flow. Let’s explore it!
The concept of encapsulation comes from object-oriented programming
(OOP) and is associated with classes and how to handle data. Encapsulation
binds together the attributes (data) and the methods (functions and
procedures) that manipulate the data in order to protect the data. The
general rule, enforced by many languages, is that attributes should only be
accessed (that is, retrieved or modified) using methods that are contained
(encapsulated) within the class definition.
Imagine your micro-frontend is composed of several views, such as a
payment form, sign-up form, sign-in form, and email and password retrieval
form, as shown in Figure 4-5.
Figure 4-5. Authentication micro-frontend composed of several views that may create a high
cognitive load for the team responsible for this micro-frontend
An existing user accessing this micro-frontend is more likely to sign in to
the authenticated area or want to retrieve their account email or password,
while a new user is likely to sign up or make a payment. A natural split for
this micro-frontend, then, could be one micro-frontend for authentication
and another for subscription. In this way, you’ll separate the two according
to business logic without having to ask the users to download more code
than the flow would require (see Figure 4-6).
Figure 4-6. Splitting the authentication micro-frontend to reduce the cognitive load, following
customer experience more than technical constraints
This isn’t the only way to split this micro-frontend, but however you split it,
be sure you’re prioritizing a business outcome rather than a technical one.
Prioritizing the customer experience is the best way to provide a final
output that your users will enjoy.
Encapsulation helps with these situations. For instance, avoid having a
unique state representing the entire micro-frontend. Instead, prefer state
management libraries that allow composition of state, like MobX-State-
Tree does. The data will be expressed in tree structure, which you can
compose at will. Spend the time evaluating how to implement the
application state, and you may save time later while also reducing your
cognitive load. It is always easier to think when the code is well identified
inside some boundaries than when it’s spread across multiple parts of the
application.
When libraries or even logic are used in multiple domains, such as in a form
validation library, you have a few options:
Duplicate the code
Code duplication isn’t always a bad practice; it depends on what you are
optimizing for and overall impact of the duplicated code. Let’s say that
you have a component that has different states based on user status and
the view where it’s hosted, and that this component is subject to new
requirements more often in one domain than in others. You may want to
centralize it. Keep in mind, though, that every time you have a
centralized library or component, you have to build a solid governance
for making sure that when this shared code is updated, it also gets
updated in every micro-frontend that uses this shared code as well.
When this happens, you also have to make sure the new version doesn’t
break anything inside each micro-frontend and you need to coordinate
the activity across multiple teams. In this case, the component isn’t
difficult to implement and it will become easier to build for every team
that uses it, because there are fewer states to take care of. That allows
every implementation to evolve independently at its own speed. Here,
we’re optimizing for speed of delivery and reducing the external
dependencies for every team. This approach works best when you have
a limited amount of duplication. When you have dozens of similar
components, this reasoning doesn’t scale anymore; you’ll want to
abstract into a library instead.
Abstract your code into a shared library
In some situations, you really want to centralize the business logic to
ensure that every micro-frontend is using the same implementation, as
with integrating payment methods. Imagine implementing in your
checkout form multiple payment methods with their validation logic,
handling errors, and so on. Duplicating such a complex and delicate part
of the system isn’t wise. Creating a shared library instead will help
maintain consistency and simplify the integration across the entire
platform. Within the automation pipelines, you’ll want to add a version
check on every micro-frontend to review the latest library version.
Unfortunately, while dealing with distributed systems helps you scale
the organization and deliver with speed, sometimes you need to enforce
certain practices for the greater good.
Delegate to a backend API
The third option is to delegate the common part to be served to all your
vertical-split micro-frontends by the backend, thus providing some
configuration and implementation of the business logic to each micro-
frontend. Imagine you have multiple micro-frontends that are
implementing an input field with specific validation that is simple
enough to represent with a regular expression. You might be tempted to
centralize the logic in a common library, but this would mean enforcing
the update of this dependency every time something changes.
Considering the logic is easy enough to represent and the common part
would be using the same regular expression, you can provide this
information as a configuration field when the application loads and
make it available to all the micro-frontends via the web storage. That
way, if you want to change the regular expression, you won’t need to
redeploy every micro-frontend implementing it. You’ll just change the
regular expression in the configuration, and all the micro-frontends will
automatically use the latest implementation.
CODE DUPLICATION OVER WRONG ABSTRACTIONS
Many well-known people in the industry have started to realize that
abstracting code is not always a benefit, especially in the long run. In
certain cases, code duplication brings more benefits to a premature or a
hasty abstraction. Moreover, duplicated code can be easily abstracted if
and when needed; it’s more challenging to try to move away from
abstractions once they’re present in the code. If you are interested in
this topic, read “The Wrong Abstraction”, a 2016 blog post by Sandi
Metz. Kent Dodds’s AHA programming or “Avoid Hasty Abstractions”
concept is strongly inspired by the work Metz describes in his blog and
talk. Also, the well-known DRY principle (don’t repeat yourself)
appears to be misapplied by many developers, who just looked in the
code for duplicated lines of code and abstracted them. In the second
edition of Pragmatic Programmer (Addison-Wesley), where the DRY
principle was first introduced, the authors provide a great explanation of
this point:
In the first edition of this book we did a poor job of explaining just
what we meant by Don’t Repeat Yourself. Many people took it to refer
to code only: they thought that DRY means “don’t copy-and-paste
lines of source.”
That is part of DRY, but it’s a tiny and fairly trivial part. DRY is
about the duplication of knowledge, of intent. It’s about expressing
the same thing in two different places, possibly in two totally different
ways. [emphasis added]
It’s important to understand that no solution fits everything. Consider the
context your implementation should represent and choose the best trade-off
in the guardrails you are operating with. Could you have designed the
micro-frontends in this way from the beginning? Potentially, you could
have, but the whole point of this architecture is to avoid premature
abstractions, optimize for fast delivery, and evolve the architecture when it
is required due to complexity or just a change of direction.
Implementing a Design System
In a distributed architecture like micro-frontends, design systems may seem
a difficult feature to achieve, but in reality the technical implementation
doesn’t differ too much from that of a design system in an SPA. When
thinking about a design system applied to micro-frontends, imagine a
layered system composed of design tokens, basic components, user
interface library, and the micro-frontends that host all these parts together,
as shown in Figure 4-7.
Figure 4-7. How a design system fits inside a micro-frontends architecture
The first layer, design tokens, allows you to capture low-level values to then
create the styles for your product, such as font families, text colors, text
size, and many other characteristics used inside our final user interface.
Generally, design tokens are listed in JSON or YAML files, expressing
every detail of our design system.
We don’t usually distribute design tokens across different micro-frontends
because each team will implement them in their own way, risking the
introduction of bugs in some areas of the application and not in others,
increasing the code duplication across the system, and, in general, slowing
down the maintenance of a design system. However, there are situations
when design tokens can be an initial step for creating a level of consistency
for iterating later on, with basic components shared across all the micro-
frontends. Often, teams do not have enough space for implementing the
final design system components inside every micro-frontend. Therefore,
make sure if you go down this path that you have the time and space for
iterating on the design system.
The next layer is basic components. Usually, these components don’t hold
the application business logic and are completely unaware of where they
will be used. As a result, they should be as generic as can be, such as a label
or button, which will provide the consistency we are looking for and the
flexibility to be used in any part of the application.
This is the perfect stage for centralizing the code that will be used across
multiple micro-frontends. In this way, we create the consistency needed in
the UI to allow every team to use components at the level they need.
The third layer is a UI components library, usually a composition of basic
components that contain some business logic that is reusable inside a given
domain. We may be tempted to share these components as well, but be
cautious in doing so. The governance to maintain and the organization
structure may cause many external dependencies across teams, creating
more frustration than efficiencies. One exception is when there are complex
UI components that require a lot of iterations and there is a centralized team
responsible for them. Imagine, for instance, building a complex component
such as a video player with several functionalities, such as closed captions,
a volume bar, and trick play. Duplicating these components is a waste of
time and effort; centralizing and abstracting your code is by far more
efficient.
Note, though, that shared components are often not reused as much as we
expect, resulting in a wasted effort. Therefore, think twice before
centralizing a component. When in doubt, start duplicating the component
and, after a few iterations, review whether these components need to be
abstracted. The wrong abstraction is way more expensive than duplicated
code.
The final layer is the micro-frontend that is hosting the UI components
library. Keep in mind the importance of a micro-frontend’s independence.
The moment we get more than three or four external dependencies, we are
heading toward a distributed monolith. That’s the worst place to be because
we are treating a distributed architecture like a monolith that we wanted to
move away from, no longer creating independent teams across the
organization.
To ensure we are finding the right trade-offs between development speed
and independent teams and UI consistency, consider validating the
dependencies monthly or every two months throughout the project life
cycle. In the past, I’ve worked at companies where this exercise was done
every two weeks at the end of every sprint, and it helped many teams
postpone tasks that may not have been achievable during a sprint due to
blocks from external dependencies. In this way, you’ll reduce your teams’
frustration and increase their performance.
On the technical side, the best investment you can make for creating a
design system is in web components. Since you can use web components
with any UI framework, should you decide to change the UI framework
later, the design system will remain the same, saving you time and effort.
There are some situations in which using web components is not viable,
such as projects that have to target old browsers. Chances are, though, you
won’t have such strong requirements and you can target modern browsers,
allowing you to leverage web components with your micro-frontend
architecture.
While getting the design system ready to be implemented is half the work,
to accomplish the delivery inside your micro-frontends architecture, you’ll
need a solid governance to maintain that initial investment. Remember,
dealing with a distributed architecture is not as straightforward as you can
imagine. Usually, the first implementation happens quite smoothly because
there is time allocated to that. The problems come with subsequent updates.
Especially when you deal with distributed teams, the best approach is to
automate the system design version validation in the continuous integration
(CI) phase. Every time a micro-frontend is built, the package.json file
should check that the design system library is up to date with the latest
version.
Implementing this check in CI allows you to be as strict as needed. You
may decide to provide a warning in the logs, asking to update the version as
soon as possible, or prevent artifact creation if the micro-frontend is one or
more major versions behind.
Some companies have custom dashboards for dealing with this problem, not
only for design systems but also for other libraries, such as logging or
authentication. In this way, every team can check in real time whether their
micro-frontend implements the latest versions.
Finally, let’s consider the team’s structure. Traditionally, in enterprise
companies, the design team is centralized, taking care of all the aspects of
the design system, from ideation to delivery, and the developers just
implement the library the design team provides. However, some companies
implement a distributed model wherein the design team is a central
authority that provides the core components and direction for the entire
design system, but other teams populate the design system with new
components or new functionalities of existing ones. In this second
approach, we reduce potential bottlenecks by allowing the development
teams to contribute to the global design system. Meanwhile, we keep
guardrails in place to ensure every component respects the overall plan,
such as regular meetings between design and development, office hours
during which the design team can guide development teams, or even
collaborative sessions where the design team sets the direction but the
developers actually implement the code inside the design system.
Developer Experience
For vertical-split micro-frontends, the developer’s experience is very
similar to SPAs. However, there are a couple of suggestions that you may
find useful to think about up front. First of all, create a command line tool
for scaffolding micro-frontends with a basic implementation and common
libraries you would like to share in all the micro-frontends such as a logging
library. While not an essential tool to have from day one, it’s definitely
helpful in the long term, especially for new team members. Also, create a
dashboard that summarizes the micro-frontend version you have in different
environments. In general, all the tools you are using for developing an SPA
are still relevant for a vertical-split micro-frontend architecture. We will
discuss this topic more in depth in Chapter 7, where we review how to
create automation pipelines for micro-frontend applications.
Search Engine Optimization
Some projects require a strong SEO strategy, including micro-frontend
projects. Let’s look at two major options for a good SEO strategy with
vertical-split micro-frontends. The first one involves optimizing the
application code in a way that is easily indexable by crawlers. In this case,
the developer’s job is implementing as many best practices as possible for
rendering the entire DOM in a timely manner (usually under five seconds).
Time matters with crawlers, because they have to index all the data in a
view and also structure the UI in a way that exposes all the meaningful
information without hiding behind user interactions. Another option is to
create an HTML markup that is meaningful for crawlers to extract the
content and categorize it properly. While this isn’t impossible, in the long
run, this option may require a bit of effort to maintain for every new feature
and project enhancement.
Another option would be using dynamic rendering to provide an optimized
version of your web application for all the crawlers trying to index your
content. Google introduced dynamic rendering to allow you to redirect
crawler requests to an optimized version of your website, usually
prerendered, without penalizing the positioning of your website in the
search engine results (see Figure 4-8).
Figure 4-8. When a crawler requests a specific page, the application server should retrieve the user-
agent and serve the crawler’s requests to a prerendered version of the website, otherwise serving the
micro-frontend implementation
There are a couple of solutions for serving a prerendered version of your
application to a crawler. First, for the prerendering phase, you can create a
customized version of your website that fetches the same data of the
website your users will consume. For instance, you can create a server-side
rendering output stored in an objects storage that translates a template into
static HTML pages at compile time, maintaining the same user-facing URL
structure. Amazon S3 is a good choice for this. You can also decide to
server-side render at runtime, eliminating the need to store the static pages
and serving the crawlers a just-in-time version created ad hoc for them.
Although this solution requires some effort to implement, it allows you the
best customization and optimization for improving the final output to the
crawler.
A second option would be using an open source solution like Puppeteer or
Rendertron to scrape the code from the website created for the users and
then deploy a web server that generates static pages regularly.
After generating the static version of your website, you need to know when
the request is coming from a browser and when from a crawler. A basic
implementation would be using a regular expression that identifies the
crawler’s user-agents. A good Node.js library for that is crawler-user-
agents. In this case, after identifying the user-agent header, the application
server can respond with the correct implementation. This solution can be
applied at the edge using technologies like AWS Lambda@Edge or
Cloudflare Workers. In this case, CDNs of some cloud providers allow a
computation layer after receiving a request. Because there are some
constraints on the maximum execution time of these containers, the user-
agent identification represents a good reason for using these edge
technologies. Moreover, they can be used for additional logic, introducing
canary releases or blue-green deployment, as we will see in Chapter 6.
Performance and Micro-Frontends
Is good performance achievable in a micro-frontend architecture?
Definitely! Performance of a micro-frontend architecture, like in any other
frontend architecture, is key for the success of a web application. And a
vertical-split architecture can achieve good performance thanks to the split
of domains and, therefore, the code to be shared with a client.
Think for a moment about an SPA. Typically, the user has to download all
the code specifically related to the application, the business logic, and the
libraries used in the entire application. For simplicity, let’s imagine that an
entire application code is 500 KB. The unauthenticated area, composed of
sign-in, sign-up, the landing page, customer support, and few other views,
requires 100 KB of business logic, while the authenticated area requires 150
KB of business logic. Both use the same bundled dependencies that are
each 250 KB (see Figure 4-9).
A new user has to download all 500 KB, despite the action having to fulfill
inside the SPA. Maybe one user just wants to understand the business
proposition and visits just the landing page, another user wants to see the
payment methods available, or an authenticated user is interested mainly in
the authenticated area where the service or products are available. No
matter what users are trying to achieve, they are forced to download the
entire application.
Figure 4-9. Any user of an SPA has to download the entire application regardless of the action they
intend to perform in the application
In a vertical-split architecture, however, our unauthenticated user who
wants to see the business proposition on the landing page will be able to
download the code just for that micro-frontend, while the authenticated user
will download only the codebase for the authenticated area. We often don’t
realize that our users’ behaviors are different from the way we interpret the
application, because we often optimize the application’s performance as a
whole rather than by how users interact with the site. Optimizing our site
according to user experiences results in a better outcome.
Applying the previous example to a vertical-split architecture, a user
interested only in the unauthenticated area will download less than 100 KB
of business logic plus the shared dependencies, while an authenticated user
will download only the 250 KB plus the shared dependencies.
Clearly a new user who moves beyond the landing page will download
almost 500 KB, but this approach will still save some kilobytes if we have
properly identified the application boundaries because it’s unlikely a new
user will go through every single application view. In the worst-case
scenario, the user will download 500 KB as they would for the SPA, but this
time not everything up front. Certainly, there is additional logic to
download due to the application shell, but usually the size is only in the
double digits, making it meaningless for this example. Figure 4-10 shows
the advantages of a vertical-split micro-frontend in terms of performance.
A good practice for managing performance on a vertical-split architecture is
introducing a performance budget. A performance budget is a limit for
micro-frontends that a team is not allowed to exceed. The performance
budget includes the final bundle size, multimedia content to load, and even
CSS files. Setting a performance budget is an important part of making sure
every team optimizes its own micro-frontend properly and can even be
enforced during the CI process. You won’t set a performance budget until
later in the project, but it should be updated every time there is a
meaningful refactoring or additional features introduced in the micro-
frontend codebase.
Figure 4-10. A vertical-split micro-frontend enables the user to download only the application code
needed to accomplish the action the user is looking for
Time to display the final result to the user is a key performance indicator,
and metrics to track include time-to-interactive or first contentful paint, the
size of the final artifact, font size, and JavaScript bundle size, as well as
metrics like accessibility and SEO. A tool like Lighthouse is useful for
analyzing these metrics and is available in a command-line version to be
used in the continuous integration process. Although these metrics have
been discussed extensively for SPA optimization, bundle size may be
trickier when it comes to micro-frontends.
With vertical-split architectures, you can decide either to bundle all the
shared libraries together or to bundle the libraries for each micro-frontend.
The former can provide greater performance because the user downloads
the bundle only once, but you’ll need to coordinate the libraries to update
for every change across all the micro-frontends. While this may sound like
an easy task, it can be more complicated than you think when it happens
regularly. Imagine you have a breaking change on a specific shared UI
framework; you can’t update the new version until all the micro-frontends
have done extensive tests on the new framework version. So while we gain
in performance in this scenario, we must first overcome some
organizational challenges. The latter solution—maintaining every micro-
frontend independently—reduces the communication overhead for
coordinating the shared dependencies but might increase the content the
user must download. As seen before, however, a user may decide to stay
within the same micro-frontend for the entire session, resulting in the exact
same kilobytes downloaded.
Once again, there isn’t right or wrong in any of these strategies. Make a
decision on the requirements to fulfill and the context you operate in. Don’t
be afraid to make a call and monitor how users interact with your
application. You may discover that, overall, the solution you picked, despite
some pitfalls, is the right one for the project. Remember, you can easily
reverse this decision, so spend the right amount of time thinking which path
your project requires, but be aware that you can change direction if a new
requirement arises or the decision causes more harm than benefits.
Available Frameworks
There are some frameworks available for embracing this architecture.
However, building an application shell on your own won’t require too much
effort, as long as you keep the application shell decoupled from any micro-
frontend business logic. Polluting the application shell codebase with
domain logic is not only a bad practice but also may invalidate all effort and
investment of using micro-frontends in the long run due to code and logic
coupling.
Two frameworks that are fully embracing this architecture are single-spa
and qiankun. The concept behind single-spa is very simple: it’s a
lightweight library that provides undifferentiated heavy lifting for the
following:
Registration of micro-frontends
The library provides a root configuration to associate a micro-frontend
to a specific path of your system.
Life cycle methods
Every micro-frontend is exposed to many stages when mounted. Single-
spa allows a micro-frontend to perform the right task for the life cycle
method. For instance, when a micro-frontend is mounted, we can apply
logic for fetching an API. When unmounted, we should remove all the
listeners and clean up all DOM elements.
Single-spa is a mature library, with years of refinement and many
integrations in production. It’s open source and actively maintained and has
a great community behind it. In the latest version of the library, you can
develop horizontal-split micro-frontends, too, including server-side
rendering ones. Qiankun is built on top of single-spa, adding some
functionality from the latest releases of single-spa.
Module Federation may also be a good alternative for implementing a
vertical-split architecture, considering that the mounting and unmounting
mechanism, dependencies management, orchestration between micro-
frontends, and many other features are already available to use. Module
Federation is typically used for composing multiple micro-frontends in the
same view (horizontal split). However, nothing is preventing us from using
it for handling vertical-split micro-frontends. Moreover, it’s a webpack
plug-in. If your projects are already using webpack, it may help you avoid
learning new frameworks for composing and orchestrating your project’s
micro-frontends. In the next chapter, we will explore the Module Federation
for implementing vertical and horizontal split architectures.
Use Cases
The vertical-split architecture is a good solution when your frontend
developers have experience with SPA development. It will also scale up to a
certain extent, but if you have hundreds of frontend developers working on
the same frontend application, a horizontal split may suit your project
better, because you can modularize your application even further.
Vertical-split architecture is also great when you want UI and UX
consistency. In this situation, every team is responsible for a specific
business domain, and a vertical split will allow them to develop an end-to-
end experience without the need to coordinate with other teams.
Another reason to choose this architecture pattern is the level of reusability
you want to have across multiple micro-frontends. For instance, if you reuse
mainly components of your design system and some libraries, like logging
or payments, a vertical split may be a great architecture fit. However, if part
of your micro-frontend is replicated in multiple views, a horizontal split
may be a better solution. Again, let the context drive the decision for your
project.
Finally, this architecture is my first recommendation when you start
embracing micro-frontends because it doesn’t introduce too much
complexity. It has a smooth learning curve for frontend developers, it
distributes the business domains to dozens of frontend developers without
any problem, and it doesn’t require huge upfront investment in tools but
more in general in the entire developer experience.
Architecture Characteristics
Deployability (5/5)
Because every micro-frontend is a single HTML page or an SPA, we
can easily deploy our artifacts on a cloud storage or an application
server and stick a CDN in front of it. It’s a well-known approach, used
for several years by many frontend developers for delivering their web
applications. Even better, when we apply a multi-CDN strategy, our
content will always be served to our user no matter which fault a CDN
provider may have.
Modularity (2/5)
This architecture is not the most modular. While we have a certain
degree of modularization and reusability, it’s more at the code level,
sharing components or libraries but less on the features side. For
instance, it’s unlikely a team responsible for the development of the
catalog micro-frontend shares it with another micro-frontend. Moreover,
when we have to split a vertical-split micro-frontend in two or more
parts because of new features, a bigger effort will be required for
decoupling all the shared dependencies implemented, since it was
designed as a unique logical unit.
Simplicity (4/5)
Taking into account that the primary aim of this approach is reducing
the team’s cognitive load and creating domain experts using well-known
practices for frontend developers, the simplicity is intrinsic. There aren’t
too many mindset shifts or new techniques to learn to embrace this
architecture. The overhead for starting with single-spa or Module
Federation should be minimal for a frontend developer.
Testability (4/5)
Compared to SPAs, this approach shows some weakness in the
application shell’s end-to-end testing. Apart from that edge case,
however, testing vertical-split micro-frontends doesn’t represent a
challenge with existing knowledge of unit, integration, or end-to-end
testing.
Performance (4/5)
You can share the common libraries for a vertical-split architecture,
though it requires a minimum of coordination across teams. Since it’s
very unlikely that you’ll have hundreds of micro-frontends with this
approach, you can easily create a deployment strategy that decouples
the common libraries from the micro-frontend business logic and
maintains the commonalities in sync across multiple micro-frontends.
Compared to other approaches, such as server-side rendering, there is a
delay on downloading the code of a micro-frontend because the
application shell should initialize the application with some logic. This
may impact the load of a micro-frontend when it’s too complex or
makes many roundtrips to the server.
Developer experience (4/5)
A team familiar with SPA tools won’t need to shift their mindset to
embrace the vertical split. There may be some challenges during end-to-
end testing, but all the other engineering practices, as well as tools,
remain the same. Not all the tools available for SPA projects are suitable
for this architecture, so your developers may need to build some internal
tools to fill the gaps. However, the out-of-the-box tools available should
be enough to start development, allowing your team to defer the
decisions to build new tools.
Scalability (5/5)
The scalability aspect of this architecture is so great that we can even
forget about it when we serve our static content via a CDN. We can also
configure the time-to-live according to the assets we are serving, setting
a higher time for assets that don’t change often, like fonts or vendor
libraries, and a lower time for assets that change often, like the business
logic of our micro-frontends. This architecture can scale almost
indefinitely based on CDN capacity, which is usually great enough to
serve billions of users simultaneously. In certain cases, when you
absolutely must avoid a single point of failure, you can even create a
multiple-CDN strategy, where your micro-frontends are served by
multiple CDN providers. Despite being more complicated, it solves the
problem elegantly without investing too much time creating custom
solutions.
Coordination (4/5)
This architecture, compared to others, enables a strong decentralization
of decision making, as well as autonomy of each team. Usually, the
touching points between micro-frontends are minimal when the domain
boundaries are well defined. Therefore, there isn’t too much
coordination needed, apart from an initial investment for defining the
application shell APIs and keeping them as domain unaware as possible.
Table 4-1 gathers the architecture characteristics and its associated score for
this micro-frontend architecture.
T
a
b
l
e
4
-
1
.
A
r
c
h
i
t
e
c
t
u
r
e
c
h
a
r
a
c
t
e
r
i
s
t
i
c
s
s
u
m
m
a
r
y
f
o
r
d
e
v
e
l
o
p
i
n
g
a
m
i
c
r
o
-
f
r
o
n
t
e
n
d
s
a
r
c
h
i
t
e
c
t
u
r
e
u
s
i
n
g
v
e
r
t
i
c
a
l
s
p
l
i
t
a
n
d
a
p
p
l
i
c
a
t
i
o
n
s
h
e
l
l
a
s
c
o
m
p
o
s
i
t
i
o
n
a
n
d
o
r
c
h
Exploring the Variety of Random
Documents with Different Content
auspicious moment passed away exactly as they intended, and
another great opportunity was lost. The French reinforcements
arrived, and having been the weaker became the stronger force.
Nothing more could be done for the rest of the campaign, but to
level the French lines from the Demer to the Mehaigne.
Thus for the third time a brilliant campaign was spoilt by the
Dutch generals and deputies. Fortunately the public indignation both
in England and in Holland was too strong for them, and
Slangenberg, though not indeed hanged as he deserved, was
deprived of all further command. Jealousy, timidity, ignorance,
treachery, and flat imbecility seem to have been the motives that
inspired these men, whose conduct has never been reprobated
according to its demerit. It was they who were responsible for the
prolongation of the war, for the burden that it laid on England, and
for the untold misery that it wrought in France. Left to himself
Marlborough would have forced the French to peace in three
campaigns, and the war would not have been ended in shame and
disgrace by the Treaty of Utrecht.[323]
Consolation for the disappointment in Flanders came from an
unexpected quarter. In Portugal, indeed, comparatively little was
done. An army was made up of about three thousand British[324]
under Lord Galway, two thousand Dutch under General Fagel, and
twelve thousand Portuguese under the Spanish General de Corsana;
and to avoid friction it was arranged that these three generals
should hold command alternately for a week at a time. In such
circumstances it was surprising that they should even have
accomplished the siege and capture of three weak fortresses,
Valenza, Albuquerque, and Badajoz, with which achievements the
campaign came to an end.[325]
June 9
20
.
August 12
23
.
But in Catalonia the operations were of a more brilliant kind.
The Catalans were known to favour the Austrian side; and it was
accordingly resolved in this year to send a fleet and an army to back
them under Admiral Leake and Lord Peterborough, the latter to be
joint admiral at sea as well as commander-in-chief ashore. The
character of Peterborough is one of the riddles of history. He was
now forty years of age, and had so far distinguished himself chiefly
by general eccentricity, not always of a harmless kind, and, in
common with most prominent men of his age, by remarkable pliancy
of principle. His experience of active service was slight and had been
gained afloat rather than ashore, and though he had long held the
colonelcy of a regiment, he had never commanded in war nor in
peace. His force consisted of six British[326] and four Dutch
battalions, or about six thousand five hundred men in all. The
expedition arrived at Lisbon early in June, when after some delay it
was decided that the fleet should proceed to Barcelona. Galway lent
his two regiments of dragoons, the Royals and the Eighth; and with
them Peterborough sailed to Gibraltar, where he picked up the eight
battalions[327] of the garrison, leaving two of his own in their place,
and proceeded to his destination. On the way up the Spanish coast a
detachment was landed to capture Denia, and on the 23rd of August
the main force was disembarked before Barcelona and took up a
position to the north-east of the town with its left flank resting on
the sea.
Sept. 2
13
.
The reports sent to England had represented Barcelona as ill-
fortified and ill-garrisoned. Ill-fortified it may have been if compared
with a creation of Vauban or Cohorn, but it was none the less a
formidable fortress, well stocked with supplies and garrisoned by
seven thousand troops under an energetic governor, by name
Velasco. Peterborough, who grasped the situation, wished to
abandon the project of a regular siege for operations of a livelier
kind, but was prevailed upon to give it a trial for eighteen days, at
the close of which he ordered the re-embarkation of the army. He
was, however, again induced to change his mind, and then suddenly,
on the evening of the 13th of September, he produced an original
scheme of his own.
About three-quarters of a mile to south-west of Barcelona stood
the small fort of Montjuich, crowning a hill seven hundred feet above
the fortress, strong by nature and strengthened still further by
outworks, which though incomplete were none the less formidable.
This Peterborough resolved to capture by escalade. Not a word was
said to the men of the work before them. No further orders were
issued than that twelve hundred English and two hundred Dutch
should be ready in the afternoon to march towards Tarragona, while
thirteen hundred men under Brigadier Stanhope were secretly
detailed to cover the rear of the assaulting columns from any attack
from Barcelona. At six o'clock the attacking force moved off under
Lord Charlemont towards the north-west, continuing the march in
this false direction for four hours, till Peterborough at last gave the
order to turn about to southward. The night was dark, and much of
the ground so rocky as to show no track, so that when the columns
at length came up before Montjuich one complete body of two
hundred was found to be missing, having evidently strayed away
from the path of the remainder.
Sept. 3
14
.
Half the force however was told off for simultaneous assault on
the eastern and western extremities of the fort, Peterborough and
Prince George of Hessen-Darmstadt accompanying the eastern
column, which, since it was expected to meet with the sternest of
the work, was made the stronger. The other moiety of the troops
was held in reserve between the two columns. A little after daybreak
the signal was given; the storming parties dashed up the glacis
under a heavy and destructive fire, and plunging in among the
enemy drove them headlong from the outworks. Following the
fugitives in hot pursuit Peterborough and Prince George captured the
eastern bastion of the fort itself, threw up a barricade of loose
stones in the gorge and entrenched themselves behind it. The
western attack had met with equal success, and had likewise
entrenched itself in a demi-bastion in that flank of the fort. Both
parties being thus under cover the fire ceased, and Peterborough
sent orders to Stanhope to bring up his reserve.
Meanwhile the Governor of Barcelona, being in communication
with Montjuich, had at the sound of the firing despatched four
hundred dragoons in all haste to reinforce the garrison. As they
entered the fort they were received with loud shouts of welcome by
the Spanish. Prince George, mistaking the sound for a cry of
surrender, at once started up and advanced with all his men into the
inner works. They were no sooner in the ditch than the Spaniards
swept round them to cut them off. Two hundred were taken
prisoners, Prince George fell mortally wounded, and the rest fell
back in confusion. This was a severe blow; but worse was to come.
Peterborough hearing that fresh reinforcements were on their way to
the enemy from Barcelona, rode out of the bastion to look for
himself, and no sooner was he gone than the troops were seized
with panic. Lord Charlemont was powerless to check it; and in a few
minutes the whole of the men, with Charlemont at their head, came
running with unseemly haste out of the captured position.
They had not run far when up galloped Peterborough in a frenzy
of rage. What he said no writer has dared to set down; but he
snatched Charlemont's half-pike from his hand and waved the men
back to the fort with a torrent of rebuke. Rallying instantly they
regained their post without the loss of a man before the enemy had
discovered their retreat; and the appearance of Stanhope with the
reserve presently banished all further idea of panic. Meanwhile the
Spanish reinforcements from Barcelona had met the English
prisoners, and learning from them that Peterborough and Prince
George were present in person before Montjuich, assumed that the
British were attacking in overwhelming force. They therefore
returned to Barcelona, leaving the fort to its fate. Three days of
bombardment sufficed to overcome the resistance of the weakened
garrison; and thus by a singular chapter of accidents Peterborough's
design proved to be a success, and Montjuich was taken.
Sept. 28
October 9.
The siege of Barcelona was then pushed forward in form, aided
by the guns of the fleet; and on the 9th of October the garrison
capitulated with the honours of war. A fortnight later King Charles
the Third made his public entry into the city; Peterborough scattered
dollars with a liberal hand, and all was merriment and rejoicing. The
picture would not be complete without the figure of a drunken
English grenadier, whose vagaries afforded inexhaustible amusement
to the populace;[328] but Peterborough was a disciplinarian, and the
troops as a whole behaved remarkably well. Stanhope was at once
sent home with the good news, and England awoke to the fact that
she possessed a second officer who, though not to be named in the
same breath with Marlborough, possessed a natural, if eccentric,
genius for war.
To face page 462
BARCELONA
1705.
The capture of Barcelona, and the subsequent reduction of
Tarragona by the fleet, brought practically the whole of Catalonia to
the side of King Charles. But now further operations were checked
by lack of money and supplies. Peterborough, who saw the difficulty
of supporting a large force in the field, was for dividing his little army
into flying columns, and making good the deficiency of numbers by
extreme mobility; but he could not gain acceptance for his views. He
wrote piteous letters of his state of destitution, reviling, as his
custom was, all his colleagues and subordinates with astonishing
freedom. Very soon the troops in Barcelona became so sickly that he
was compelled to distribute them in the fortresses of Catalonia,
leaving further operations to the Catalan guerillas. By the exertions
of these last the close of the year saw not only Catalonia but
Valencia gained over, though on no very certain footing, to the side
of King Charles. So ended the first serious campaign of the first
Peninsular war.
Building Micro-Frontends: Scaling Teams and Projects Empowering Developers 1st Edition Luca Mezzalira
C H A P T E R V
1706.
It is now time to revert to England and to the preparations for the
campaign of 1706. Marlborough, as usual, directly that the military
operations were concluded, had been deputed to visit the courts of
Vienna and of sundry German states in order to keep the Allies up to
the necessary pitch of unity and energy. These duties detained him
in Germany and at the Hague until January 1706, when he was at
last able to return to England. There he met with far less obstruction
than in former years, but none the less with an increasing burden of
work. The vast extension of operations in the Peninsula, and the
general sickliness of the troops in that quarter, demanded the
enlistment of an usually large number of recruits. One new regiment
of dragoons and eleven new battalions of foot were formed in the
course of the spring, to which it was necessary to add yet another
battalion before the close of the year.[329] Again the epidemic
sickness among the horses in Flanders had caused an extraordinary
demand for horses. The Dutch, after their wonted manner, had
actually taken pains to prevent the supply of horses to the British,
[330] though, even if they had not, the Duke had a prejudice in
favour of English horses, as of English men, as superior to any other.
Finally, the stores of the Ordnance were unequal to the constant
drain of small arms, and it was necessary to make good the
deficiency by purchases from abroad. All these difficulties and a
thousand more were of course referred for solution to Marlborough.
April 14
25
.
When in April he crossed once more to the Hague he found a
most discouraging state of affairs. The Dutch were backward in their
preparations; Prussia and Hanover were recalcitrant over the
furnishing of their contingents; Prince Lewis of Baden was sulking
within his lines, refusing to communicate a word of his intentions to
any one; and everybody was ready with a separate plan of
campaign. The Emperor of course desired further operations in the
Moselle for his own relief; but after the experience of the last
campaign the Duke had wisely resolved never again to move
eastward to co-operate with the forces of the Empire. The Dutch for
their part wished to keep Marlborough in Flanders, where he should
be under the control of their deputies; but the imbecile caprice of
these worthies was little more to his taste than the sullen jealousy of
Baden. Marlborough himself was anxious to lead a force to the help
of Eugene in Italy, a scheme which, if executed, would have carried
the British to a great fighting ground with which they are unfamiliar,
the plains of Lombardy. He had almost persuaded the States-General
to approve of this plan, when all was changed by Marshal Villars,
who surprised Prince Lewis of Baden in his lines on the Motter, and
captured two important magazines. The Dutch at once took fright
and, in their anxiety to keep Marlborough for their own defence,
agreed to appoint deputies who should receive rather than issue
orders. So to the Duke's great disappointment it was settled that the
main theatre of war should once again be Flanders.
May 8
19
.
May 9
20
.
May 11
22
.
Villeroy meanwhile lay safely entrenched in his position of the
preceding year behind the Dyle, from which Marlborough saw little
hope of enticing him. It is said that an agent was employed to rouse
Villeroy by telling him that the Duke, knowing that the French were
afraid to leave their entrenchments, would take advantage of their
inaction to capture Namur.[331] Be that as it may, Villeroy resolved to
quit the Dyle. He knew that the Prussian and Hanoverian
contingents had not yet joined Marlborough, and that the Danish
cavalry had refused to march to him until their wages were paid; so
that interest as well as injured pride prompted the hazard of a
general action. On the 19th of May, therefore, he left his lines for
Tirlemont on the Great Geete. Marlborough, who was at Maestricht,
saw with delight that the end, for which he had not dared to hope,
was accomplished. Hastily making arrangements for the payment of
the Danish troops, he concentrated the Dutch and British at Bilsen
on the Upper Demer, and moved southward to Borchloen. Here the
arrival of the Danes raised his total force to sixty thousand men, a
number but little inferior to that of the enemy. On the very same day
came the intelligence that Villeroy had crossed the Great Geete and
was moving on Judoigne. The Duke resolved to advance forthwith
and attack him there.
May 12
23
.
At one o'clock in the morning, of Whitsunday the 23rd of May,
Quartermaster-General Cadogan rode forward from the headquarters
at Corswarem with six hundred horse and the camp-colours towards
the head of the Great Geete, to mark out a camp by the village of
Ramillies. The morning was wet and foggy, and it was not until eight
o'clock that, on ascending the heights of Merdorp, they dimly
descried troops in motion on the rolling ground before them. The
allied army had not marched until two hours later than Cadogan, but
Marlborough, who had ridden on in advance of it, presently came up
and pushed the cavalry forward through the mist. Then at ten
o'clock the clouds rolled away, revealing the whole of the French
army in full march towards them.
Villeroy's eyes were rudely opened, for he had not expected
Marlborough before the following day; but he knew the ground well,
for he had been over it before with Luxemburg, and he proceeded to
take up a position which he had seen Luxemburg deliberately reject.
The table-land whereon he stood is the highest point in the plains of
Brabant. To his right flowed the Mehaigne; in his rear ran the Great
Geete; across his centre and left the Little Geete rose and crept
away sluggishly in marsh and swamp.[332] In his front lay four
villages: Taviers on the Mehaigne to his right, Ramillies, less
advanced than Taviers, on the source of the Little Geete to his right
centre, Offus parallel to Ramillies but lower down the stream to his
left centre, Autréglise or Anderkirch between two branches of the
Little Geete and parallel to Taviers to his left. Along the concave line
formed by these villages Villeroy drew up his army in two lines facing
due east.
The Mehaigne, on which his right rested, is at ordinary times a
rapid stream little more than twelve feet wide, with a muddy bottom,
but is bordered by swampy meadows on both sides, which are
flooded after heavy rain. From this stream the ground rises
northward in a steady wave for about half a mile, sinks gradually
and rises into a higher wave at Ramillies, sinks once more to
northward of that village and rolls downward in a gentler undulation
to Autréglise. Between the Mehaigne and Ramillies, a distance of
about a mile and a half, the ground east and west is broken by
sundry hollows of sufficient inclination to offer decided advantage or
disadvantage in a combat of cavalry. A single high knoll rises in the
midst of these hollows, offering a place of vantage from which
Marlborough must almost certainly have reconnoitred the disposition
of the French right. The access to Ramillies itself is steep and broken
both to north and south, but on the eastern front the ground rises to
it for half a mile in a gentle, unbroken slope, which modern rifles
would make impassable by the bravest troops. In rear, or to
westward of the French position, the table-land is clear and
unbroken, and to the right rear or south-west stands a mound or
barrow called the tomb of Ottomond, still conspicuous and still
valuable as a key to the actions of the day.[333] The full extent of the
French front from Taviers to Autréglise covered something over four
miles.
Having chosen his position, Villeroy lost no time in setting his
troops in order. His left, consisting of infantry backed by cavalry,[334]
extended from Autréglise to Offus, both of which villages were
strongly occupied. His centre from Offus to Ramillies was likewise
composed of infantry. On his right, in the expanse of sound ground
which stretches for a mile and a half from the marshes of the Geete
at Ramillies to those of the Mehaigne, were massed more than one
hundred and twenty squadrons of cavalry with some battalions of
infantry interlined with them, the famous French Household Cavalry
(Maison du Roi), being in the first line. The left flank of this expanse
was covered by the village of Ramillies, which was surrounded by a
ditch and defended by twenty battalions and twenty-four guns. On
the right flank not only Taviers but Franquinay, a village still further
in advance, were occupied by detachments of infantry, while Taviers
was further defended by cannon.
Marlborough quickly perceived the defects of Villeroy's
dispositions, which were not unlike those of Tallard at Blenheim.
Taviers was too remote from Ramillies for the maintenance of a
cross-fire of artillery. Again, the cavalry of the French left was
doubtless secure against attack behind the marshes of the Geete,
but for this very reason it was incapable of aggressive action. The
French right could therefore be turned, provided that it were not
further reinforced; and accordingly the Duke opened his manœuvres
by a demonstration against the French left.
Presently the infantry of the allied right moved forward in two
lines towards Offus and Autréglise, marching in all the pomp and
circumstance of war, Dutch, Germans, and British, with the red coats
conspicuous on the extreme right flank. Striding forward to the river
they halted and seemed to be very busy in laying their pontoons.
Villeroy marked the mass of scarlet, and remembering its usual place
in the battlefield, instantly began to withdraw several battalions from
his right and centre to his left. Marlborough watched the white coats
streaming away to their new positions, and after a time ordered the
infantry of his right to fall back to some heights in their rear. The two
lines faced about and retired accordingly over the height until the
first line was out of sight. Then the second line halted and faced
about once more, crowning the ascent with the well-known scarlet,
while the first marched away with all speed, under cover of the hill
and unseen by the French, to the opposite flank. Many British
battalions[335] stood on that height all day without moving a step or
firing a shot, but none the less paralysing the French left wing.
About half-past one the guns of both armies opened fire, and
shortly afterwards four Dutch battalions were ordered forward to
carry Franquinay and Taviers, and twelve more to attack Ramillies,
while Overkirk advanced slowly on the left with the cavalry.
Franquinay was soon cleared; Taviers resisted stoutly for a time but
was carried, and a strong reinforcement on its way to the village was
intercepted and cut to pieces. Then Overkirk, his left flank being now
cleared, pushed forward his horse and charged. The Dutch routed
the first French line, but were driven back in confusion by the
second; and the victorious French were only checked by the advance
of fresh squadrons under Marlborough himself. Even so the Allies
were at a decided disadvantage; and Marlborough, after despatching
messengers to bring up every squadron, except the British, to the
left, plunged into the thick of the melée to rally the broken horse. He
was recognised by some French dragoons, who left their ranks to
surround him, and in the general confusion he was borne to the
ground and in imminent danger of capture. His aide-de-camp,
Captain Molesworth, dismounted at once, and giving him his own
horse enabled him to escape. The cavalry, however, encouraged by
the Duke's example, recovered themselves, and Marlborough took
the opportunity to shift from Molesworth's horse to his own. Colonel
Bringfield, his equerry, held the stirrup while he mounted, but
Marlborough was hardly in the saddle before the hand that held the
stirrup relaxed its hold, and the equerry fell to the ground, his head
carried away by a round shot.[336]
Meanwhile the attack of the infantry on Ramillies was fully
developed, and relieved the horse from the fire of the village.
Twenty fresh squadrons came galloping up at the top of their speed
and ranged themselves in rear of the reforming lines. But before
they could come into action the Duke of Würtemberg pushed his
Danish horse along the Mehaigne upon the right flank of the French,
and the Dutch guards advancing still further fell upon their rear.
These now emerged upon the table-land by the tomb of Ottomond,
and the rest of the Allied horse dashed themselves once against the
French front. The famous Maison du Roi after a hard fight was cut to
pieces, and the whole of the French horse, despite Villeroy's efforts
to stay them, were driven in headlong flight across the rear of their
line of battle, leaving the battalions of infantry helpless and alone to
be ridden over and trampled out of existence.
Villeroy made frantic efforts to bring forward the cavalry of his
left to cover their retreat, but the ground was encumbered by his
baggage, which he had carelessly posted too close in his rear. The
French troops in Ramillies now gave way, and Marlborough ordered
the whole of the infantry that was massed before the village to
advance across the morass upon Offus, with the Third and Sixth
Dragoon Guards in support. The French broke and fled at their
approach; and meanwhile the Buffs and Twenty-first, which had so
far remained inactive on the right, forced their way through the
swamps before them, and taking Autréglise in rear swept away the
last vestige of the French line on the left. Five British squadrons
followed them up and captured the entire King's Regiment
(Regiment du Roi). The Third and Sixth Dragoon Guards also
pressed on, and coming upon the Spanish and Bavarian horse-
guards, who were striving to cover the retreat of the French artillery,
charged them and swept them away, only narrowly missing the
capture of the Elector himself, who was at their head.[337] On this
the whole French army, which so far had struggled to effect an
orderly retreat, broke up in panic and fled in all directions.
The mass of the fugitives made for Judoigne, but the ways were
blocked by broken-down baggage-waggons and abandoned guns,
and the crush and confusion was appalling. The British cavalry, being
quite fresh, quickly took up the pursuit over the table-land. The guns
and baggage fell an easy prey, but these were left to others, while
the red-coated troopers, not without memories of Landen, pressed
on, like hounds running for blood, after the beaten enemy. The
chase lay northwards to Judoigne and beyond it towards the refuge
of Louvain. Not until two o'clock in the morning did the cavalry
pause, having by that time reached Meldert, fifteen miles from the
battlefield; nay, even then Lord Orkney with some few squadrons
spurred on to Louvain itself, rekindled the panic and set the unhappy
French once more in flight across the Dyle.
May 13
24
.
May 14
25
.
May 15
26
.
May 16
27
.
Nor was the main army far behind the horse. Marching far into
the night, the men slept under arms for two or three hours, started
again at three o'clock, and before the next noon had also reached
Meldert and were preparing to force the passage of the Dyle.
Marlborough, who had been in the saddle with little intermission for
nearly twenty-eight hours, here wrote to the Queen that he intended
to march again that same night, but, through the desertion of the
lines of the Dyle by the French, the army gained some respite. The
next day he crossed the Dyle at Louvain and encamped at Betlehem,
the next he advanced to Dieghem, a few miles north of Brussels, the
next he passed the Senne at Vilvorde and encamped at
Grimberghen, and here at last, after six days of incessant marching,
the Duke granted his weary troops a halt, while the French,
hopelessly beaten and demoralised, retired with all haste to Ghent.
To face page 472
RAMILLIES
May 12th
" 23rd
1706.
So ended the fight and pursuit of Ramillies, which effectually
disposed of the taunt levelled at Marlborough after Blenheim, that
he did not know how to improve a victory. The loss of the French in
killed, wounded, and prisoners was thirteen thousand men, swelled
by desertion during the pursuit to full two thousand more. The
trophies of the victors were eighty standards and colours, fifty guns,
and a vast quantity of baggage. The loss of the Allies was from four
to five thousand killed and wounded, which fell almost entirely on
the Dutch and Danes, the British, owing to their position on the
extreme right, being but little engaged until the close of the day. The
chief service of the British, therefore, was rendered in the pursuit,
which they carried forward with relentless thoroughness and vigour.
The Dutch were delighted that their troops should have done the
heaviest of the work in such an action, and the British could console
themselves with the performance of their cavalry, and above all, with
the reflection that the whole of the success was due to their
incomparable chief.
May-June.
The effect of the victory and of the rapid advance that followed
it was instantaneous. Louvain and the whole line of Dyle fell into
Marlborough's hands on the day after the battle; Brussels, Malines,
and Lierre surrendered before the first halt, and gave him the line of
the Senne and the key of the French entrenchments about Antwerp;
and one day later, the surrender of Alost delivered to him one of the
strongholds on the Dender. Never pausing for a moment, he sent
forward a party to lay bridges on the Scheldt below Oudenarde in
order to cut off the French retreat into France, a movement which
obliged Villeroy forthwith to abandon the lines about Ghent and to
retire up the Lys to Courtrai. Ghent, Bruges, and Damme thereupon
surrendered on the spot; Oudenarde followed them, and after a few
days Antwerp itself. Thus within a fortnight after the victory the
whole of Flanders and Brabant, with the exception of Dendermond
and one or two places of minor importance, had succumbed to the
Allies, and the French had fallen back to their own frontier.
June.
Nor was even this all. A contribution of two million livres levied
in French Flanders brought home to the Grand Monarch that the war
was now knocking at his own gates. Villars, with the greater part of
his army, was recalled from the Rhine to the Lys, and a number of
French troops were withdrawn to the same quarter from Italy. Baden
had thus the game in his own hand on the Rhine, and though he
was too sulky and incapable to turn the advantage to account, yet
his inaction was no fault of Marlborough's. We are hardly surprised
to find that in the middle of this fortnight the Duke made urgent
request for fresh stores of champagne; he may well have needed the
stimulant amid such pressure of work and fatigue.[338]
June 6
17
.
He now detached Overkirk to besiege Ostend and another party
to blockade Dendermond, at the same time sending off five British
battalions, which we shall presently meet again, for a descent on the
Charente which was then contemplated in England. This done he
took post with the rest of the Army at Rouslers, to westward of the
Lys, whence he could at once cover the siege of Ostend and menace
Menin and Ypres. The operations at Ostend were delayed for some
time through want of artillery and the necessity of waiting for the
co-operation of the Fleet; but the trenches were finally opened on
the 17th of June, and a few weeks later the town surrendered.
June 27
July 8.
Aug. 11
22
.
Three days after this the army was reassembled for the siege of
Menin. This fortress was of peculiar strength, being esteemed one of
Vauban's masterpieces, and was garrisoned by five thousand men.
Moreover, the French, being in command of the upper sluices of the
Lys, were able greatly to impede the operations by cutting off the
water from the lower stream, and thus rendering it less useful for
purposes of transport. But all this availed it little; for three weeks
after the opening of the trenches Menin surrendered. The British
battalions[339] which had been kept inactive at Ramillies took a
leading share in the work, and some of them suffered very heavily,
but had the satisfaction of recapturing four of the British guns that
had been taken at Landen.
Aug. 25
Sept. 5.
Sept. 12
23
.
Sept. 21
Oct. 2.
A few days later Dendermond was attacked in earnest and was
likewise taken, after which Marlborough fell back across the Scheldt
to secure the whole line of the Dender by the capture of Ath. Ten
days sufficed for the work, after which Ath also fell into the hands of
the Allies. The apathy of the French throughout these operations
sufficiently show their discouragement. Owing to the supineness of
Prince Lewis of Baden Villars had been able to bring up thirty-five
thousand men to the assistance of Marshal Vendôme, who had now
superseded Villeroy, but even with this reinforcement the two
commanders only looked on helplessly while Marlborough reduced
fortress after fortress before their eyes. They were, indeed, more
anxious to strengthen the defences of Mons and Charleroi, lest the
Duke should break into France by that line, than to approach him in
the field. Nor were they not wholly unreasonable in their anxiety, for
Marlborough's next move was upon the Sambre; but incessant rain
and tempestuous weather forbade any further operations, so that
Ath proved to be the last conquest of the year. Thus ended the
campaign of Ramillies, one of the most brilliant in the annals of war,
wherein Marlborough in a single month carried his arms triumphant
from the Meuse to the sea.
Building Micro-Frontends: Scaling Teams and Projects Empowering Developers 1st Edition Luca Mezzalira
C H A P T E R V I
1706.
From Flanders it is necessary to return to the Peninsula, where we
left Peterborough bewailing his enforced inaction. Nothing is more
remarkable in the story of these Peninsular campaigns than the utter
want of unity in design between the forces of the Allies in Catalonia
and in Portugal. Even in England the British troops in these two
quarters were treated, for purposes of administration, as two distinct
establishments, which might have been divided by the whole
breadth of the Atlantic instead of by twice the breadth of England.
Yet the fault could hardly be attributed to any English functionary,
civil or military. Galway was as anxious as Peterborough to advance
to Madrid; but the Portuguese were terrified at the prospect of
moving far from their frontier, while the eyes of King Charles ever
rested anxiously on the passes by which French reinforcements
might advance into Catalonia. In such circumstances it was not easy
to accomplish an effective campaign.
Dec. 26,
1705.
Jan. 6,
1706.
The Spaniards of the Austrian party, as has been told, had by
the winter of 1705 gained a precarious hold on the whole province
of Valencia. Just before the close of the year came intelligence that
the Spanish General de las Torres had crossed the northern frontier
from Arragon into Valencia and had laid siege to San Mateo. The
town was important, inasmuch as it commanded the
communications between Catalonia and Valencia, but it was held by
no stronger garrison than thirty of the Royal Dragoons and a
thousand Spanish irregular infantry under Colonel Jones. This officer
defended himself as well as he could, but at once begged urgently
for reinforcements. King Charles thereupon appealed for help to
Peterborough, who forthwith ordered General Killigrew to march with
his garrison from Tortosa and cross the Ebro, while he himself, riding
night and day from Barcelona, caught up the column at the close of
the first day's march. King Charles had represented the force of Las
Torres as but two thousand strong, and had added that thousands of
peasants were up in arms against it. Peterborough now discovered
that the Spaniards numbered four thousand foot and three thousand
horse, while the thousands of armed peasantry were wholly
imaginary. His own force consisted of three weak British battalions,
the Thirteenth, Thirty-fifth, and Mountjoy's Foot, together with one
hundred and seventy of the Royal Dragoons, in all thirteen hundred
men. With such a handful his only hope of success must lie in
stratagem.
Dec. 28,
1705.
Jan. 8,
1706.
Advancing southward with all speed he split up his minute army
into a number of small detachments, and pushing them forward by
different routes arrived early in the morning, unseen and
unsuspected, at Traguera, within six miles of the enemy's camp.
That same day a spy was captured by the enemy and brought
before Las Torres. On him was found a letter from Peterborough to
Colonel Jones, written in the frankest and easiest style. "I am at
Traguera," so it ran in effect, "with six thousand men and artillery.
You may wonder how I collected them; but for transport and secrecy
nothing equals the sea. Now, be ready to pursue Las Torres over the
plain. It is his only line of retreat, for I have occupied all the passes
over the hills. You will see us on the hill-tops between nine and ten.
Prove yourself a true dragoon, and have your miquelets (irregulars)
ready for their favourite plunder and chase." The spy, being
threatened with death, offered to betray another messenger of
Peterborough's who was lying concealed in the hills. This second spy
was captured, and a duplicate of the same letter was found on him.

More Related Content

PDF
Building Micro-Frontends: Scaling Teams and Projects Empowering Developers 1s...
PPTX
Web Application Development-Ultimate Guide To Web Application Architecture
PDF
5 Best Frontend Frameworks For Web & Software Development
PDF
How to choose the best frontend framework in 2022
PDF
Web Application Architecture: A Comprehensive Guide for Success in 2023
PDF
Components of a Generic Web Application Architecture
PDF
A Comprehensive Guide to Web Application Architecture
DOCX
Top 10 Javascript Frameworks For Easy Web Development
Building Micro-Frontends: Scaling Teams and Projects Empowering Developers 1s...
Web Application Development-Ultimate Guide To Web Application Architecture
5 Best Frontend Frameworks For Web & Software Development
How to choose the best frontend framework in 2022
Web Application Architecture: A Comprehensive Guide for Success in 2023
Components of a Generic Web Application Architecture
A Comprehensive Guide to Web Application Architecture
Top 10 Javascript Frameworks For Easy Web Development

Similar to Building Micro-Frontends: Scaling Teams and Projects Empowering Developers 1st Edition Luca Mezzalira (20)

PPTX
Web application framework
DOCX
COMP6210 Web Services And Design Methodologies.docx
PDF
Top 12 Front End Technologies to Use In 2024.pdf
PDF
Frontend Developer Roadmap PDF By Scholarhat
PDF
How to Maximize User Experience with Effective Front-End Technology Choices
PPTX
Top 5 backend frameworks for web development in.pptx
PDF
Important Backend Frameworks To Remember For Businesses In 2023
PDF
Angular JS Basics
PDF
5 Front End Frameworks to Master in Web Development.pdf
PDF
Word press with react – implementing headless wordpress with reactjs converted
PDF
Web application architecture guide how it works types, components, best pract...
PDF
A Brief Note On Asp.Net And Cloud Computing Essay
PDF
Learn Programming Languages & Get Programming Assignment Sample Solutions PDF...
PDF
Navigating the Hype and Realities of Web Development Frameworks
PDF
10 Best Front-end Frameworks for Web Development
PPTX
Front End Development | Introduction
PPTX
Web-Development-Services-in-Pakistan.pptx
PDF
Why You Should Use MERN Stack for Startup Apps?
PDF
Top 12 Front End Technologies to Use In 2023.pdf
PDF
Best Frameworks for SaaS Product Development
Web application framework
COMP6210 Web Services And Design Methodologies.docx
Top 12 Front End Technologies to Use In 2024.pdf
Frontend Developer Roadmap PDF By Scholarhat
How to Maximize User Experience with Effective Front-End Technology Choices
Top 5 backend frameworks for web development in.pptx
Important Backend Frameworks To Remember For Businesses In 2023
Angular JS Basics
5 Front End Frameworks to Master in Web Development.pdf
Word press with react – implementing headless wordpress with reactjs converted
Web application architecture guide how it works types, components, best pract...
A Brief Note On Asp.Net And Cloud Computing Essay
Learn Programming Languages & Get Programming Assignment Sample Solutions PDF...
Navigating the Hype and Realities of Web Development Frameworks
10 Best Front-end Frameworks for Web Development
Front End Development | Introduction
Web-Development-Services-in-Pakistan.pptx
Why You Should Use MERN Stack for Startup Apps?
Top 12 Front End Technologies to Use In 2023.pdf
Best Frameworks for SaaS Product Development
Ad

Recently uploaded (20)

PDF
O7-L3 Supply Chain Operations - ICLT Program
PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PPTX
Microbial diseases, their pathogenesis and prophylaxis
PPTX
school management -TNTEU- B.Ed., Semester II Unit 1.pptx
PDF
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
PPTX
Final Presentation General Medicine 03-08-2024.pptx
PDF
RMMM.pdf make it easy to upload and study
PDF
FourierSeries-QuestionsWithAnswers(Part-A).pdf
PDF
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
PDF
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
PDF
Classroom Observation Tools for Teachers
PDF
Anesthesia in Laparoscopic Surgery in India
PDF
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
PPTX
Renaissance Architecture: A Journey from Faith to Humanism
PDF
Sports Quiz easy sports quiz sports quiz
PPTX
1st Inaugural Professorial Lecture held on 19th February 2020 (Governance and...
PPTX
PPT- ENG7_QUARTER1_LESSON1_WEEK1. IMAGERY -DESCRIPTIONS pptx.pptx
PDF
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
PPTX
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
PDF
STATICS OF THE RIGID BODIES Hibbelers.pdf
O7-L3 Supply Chain Operations - ICLT Program
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
Microbial diseases, their pathogenesis and prophylaxis
school management -TNTEU- B.Ed., Semester II Unit 1.pptx
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
Final Presentation General Medicine 03-08-2024.pptx
RMMM.pdf make it easy to upload and study
FourierSeries-QuestionsWithAnswers(Part-A).pdf
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
Classroom Observation Tools for Teachers
Anesthesia in Laparoscopic Surgery in India
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
Renaissance Architecture: A Journey from Faith to Humanism
Sports Quiz easy sports quiz sports quiz
1st Inaugural Professorial Lecture held on 19th February 2020 (Governance and...
PPT- ENG7_QUARTER1_LESSON1_WEEK1. IMAGERY -DESCRIPTIONS pptx.pptx
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
STATICS OF THE RIGID BODIES Hibbelers.pdf
Ad

Building Micro-Frontends: Scaling Teams and Projects Empowering Developers 1st Edition Luca Mezzalira

  • 1. Building Micro-Frontends: Scaling Teams and Projects Empowering Developers 1st Edition Luca Mezzalira install download https://ebookmeta.com/product/building-micro-frontends-scaling- teams-and-projects-empowering-developers-1st-edition-luca- mezzalira/ Download more ebook from https://ebookmeta.com
  • 2. We believe these products will be a great fit for you. Click the link to download now, or visit ebookmeta.com to discover even more! Building Games with Ethereum Smart Contracts: Intermediate Projects for Solidity Developers Kedar Iyer https://ebookmeta.com/product/building-games-with-ethereum-smart- contracts-intermediate-projects-for-solidity-developers-kedar- iyer/ Front-End Reactive Architectures: Explore the Future of the Front-End using Reactive JavaScript Frameworks and Libraries 1st Edition Luca Mezzalira https://ebookmeta.com/product/front-end-reactive-architectures- explore-the-future-of-the-front-end-using-reactive-javascript- frameworks-and-libraries-1st-edition-luca-mezzalira/ Primary Mathematics 3A Hoerst https://ebookmeta.com/product/primary-mathematics-3a-hoerst/ A New Vision for Center Based Engineering Research 1st Edition And Medicine Engineering National Academies Of Sciences https://ebookmeta.com/product/a-new-vision-for-center-based- engineering-research-1st-edition-and-medicine-engineering- national-academies-of-sciences/
  • 3. Security Council Sanctions Governance The Power and Limits of Rules 1st Edition Thomas Dörfler https://ebookmeta.com/product/security-council-sanctions- governance-the-power-and-limits-of-rules-1st-edition-thomas- dorfler/ Math Is Everything Bliss Green https://ebookmeta.com/product/math-is-everything-bliss-green/ Fundamentals of Data Engineering 1st Edition Joe Reis https://ebookmeta.com/product/fundamentals-of-data- engineering-1st-edition-joe-reis/ Logic Computation and Rigorous Methods Essays Dedicated to Egon Börger on the Occasion of His 75th Birthday Lecture Notes in Computer Science 12750 Alexander Raschke (Editor) https://ebookmeta.com/product/logic-computation-and-rigorous- methods-essays-dedicated-to-egon-borger-on-the-occasion-of- his-75th-birthday-lecture-notes-in-computer- science-12750-alexander-raschke-editor/ Modern Architecture 1st Edition Frank Lloyd Wright https://ebookmeta.com/product/modern-architecture-1st-edition- frank-lloyd-wright/
  • 4. Psychoanalysis as an Ethical Process 1st Edition Robert P. Drozek https://ebookmeta.com/product/psychoanalysis-as-an-ethical- process-1st-edition-robert-p-drozek/
  • 6. Chapter 4. Discovering Micro- Frontend Architectures In the previous chapter, we learned about decisions framework, the foundation of any micro-frontend architecture. In this chapter, we will review the different architecture choices, applying what we have learned so far. Micro-Frontend Decisions Framework Applied The decisions framework helps you to choose the right approach for your micro-frontend project based on its characteristics (see Figure 4-1). Your first decision will be between a horizontal and vertical split. Figure 4-1. The micro-frontends decisions framework
  • 7. TIP The micro-frontends decisions framework helps you determine the best architecture for a project. Vertical Split A vertical split offers fewer choices, and because they are likely well known by frontend developers who are used to writing single-page applications (SPAs), only the client-side choice is shown in Figure 4-1. You’ll find a vertical split helpful when your project requires a consistent user interface evolution and a fluid user experience across multiple views. That’s because a vertical split provides the closest developer experience to an SPA, and therefore the tools, best practices, and patterns can be used for the development of a micro-frontend. Although technically you can serve vertical-split micro-frontends with any composition, so far all the explored implementations have a client-side composition in which an application shell is responsible for mounting and unmounting micro-frontends, leaving us with one composition method to choose from. The relation between a micro-frontend and the application shell is always one to one, so therefore the application shell loads only one micro-frontend at a time. You’ll also want to use client-side routing. The routing is usually split in two parts, with a global routing used for loading different micro-frontends being handled by the application shell (see Figure 4-2).
  • 8. Figure 4-2. The application shell is responsible for global routing between micro-frontends Although the local routing between views inside the same micro-frontend is managed by the micro-frontend itself, you’ll have full control of the implementation and evolution of the views present inside it since the team responsible for a micro-frontend is also the subject-matter expert on that business domain of the application (Figure 4-3). Figure 4-3. A micro-frontend is responsible for routing between views available inside the micro- frontend itself
  • 9. Finally, for implementing an architecture with a vertical-split micro- frontend, the application shell loads HTML or JavaScript as the entry point. The application shell shouldn’t share any business domain logic with the other micro-frontends and should be technology agnostic to allow future system evolution, so you don’t want to use any specific UI framework for building an application shell. Try Vanilla JavaScript if you built your own implementation. The application shell is always present during users’ sessions because it’s responsible for orchestrating the web application as well as exposing some life cycle APIs for micro-frontends in order to react when they are fully mounted or unmounted. When vertical-split micro-frontends have to share information with other micro-frontends, such as tokens or user preferences, we can use query strings for volatile data, or web storages for tokens or user preferences, similar to how the horizontal split ones do between different views. Horizontal Split A horizontal split works well when a business subdomain should be presented across several views and therefore reusability of the subdomain becomes key for the project; when search engine optimization is a key requirement of your project and you want to use a server-side rendering approach; when your frontend application requires tens if not hundreds of developers working together and you have to split more granular our subdomains; or when you have a multitenant project with customer customizations in specific parts of your software. The next decision you’ll make is between client-side, edge-side, and server- side compositions. Client side is a good choice when your teams are more familiar with the frontend ecosystem or when your project is subject to high traffic with significant spikes, for instance. You’ll avoid dealing with scalability challenges on the frontend layer because you can easily cache your micro-frontends, leveraging a content delivery network (CDN).
  • 10. You can use edge-side composition for a project with static content and high traffic in order to delegate the scalability challenge to the CDN provider instead of having to deal with it in your infrastructure. As we discussed in Chapter 3, embracing this architecture style has some challenges, such as its complicated developer experience and the fact that not all CDNs support it. But projects like online catalog with no personalized content may be a good candidate for this approach. Server-side composition gives us the most control of our output, which is great for highly indexed websites, such as news sites or ecommerce. It’s also a good choice for websites that require great performance metrics, similar to PayPal and American Express, both of which use server-side composition. Next is your routing strategy. While you can technically apply any routing to any composition, it’s common to use the routing strategy associated with your chosen composition pattern. If you choose a client-side composition, for example, most of the time, routing will happen at the client-side level. You might use computation logic at the edge (using Lambda@Edge in case of AWS or Workers in CloudFlare) to avoid polluting the application shell’s code with canary releases or to provide an optimized version of your web application to search engine crawlers leveraging the dynamic rendering capability. On the other hand, an edge-side composition will have an HTML page associated with each view, so every time a user loads a new page, a new page will be composed in the CDN, which will retrieve multiple micro- frontends to create that final view. Finally, with server-side routing, the application server will know which HTML template is associated with a specific route; routing and composition happen on the server side. Your composition choice will also help narrow your technical solutions for building a micro-frontends project. When you use client-side composition and routing, your best implementation choice is an application shell loading multiple micro-frontends in the same view with the webpack plug-in called Module Federation, with iframes, or with web components, for instance.
  • 11. For the edge-side composition, the only solution available is using edge- side includes (ESI). We are seeing hints that this may change in the future, as cloud providers extend their edge services to provide more computational and storage resources. For now, though, ESI is the only option. And when you decide to use server-side composition, you can use server-side includes (SSI) or one of the many SSR frameworks for your micro-frontend applications. Note that SSRs will give you greater flexibility and control over your implementation. Missing from the decisions framework is the final pillar: how the micro- frontends will communicate when they are in the same or different views. This is mainly because when you select a horizontal split, you have to avoid sharing any state across micro-frontends; this approach is an antipattern. Instead, you’ll use the techniques mentioned in Chapter 3, such as an event emitter, custom events, or reactive streams using an implementation of the publish/subscribe (pub/sub) pattern for decoupling the micro-frontends and maintaining their independent nature. When you have to communicate between different views, you’ll use a query string parameter to share volatile data, such as product identifiers, and web storage/cookies for persistent data, such as users’ tokens or local users’ settings. OBSERVER PATTERN The observer pattern (also known as publish/subscribe pattern) is a behavioral design pattern that defines a one-to-many relationship between objects such that, when one object changes its state, all dependent objects are notified and updated automatically. An object with a one-to-many relationship with other objects that are interested in its state is called the subject or publisher. Its dependent objects are called observers or subscribers. The observers are notified whenever the state of the subject changes, and then they act accordingly. The subject can have any number of dependent observers.
  • 12. Architecture Analysis To help you better choose the right architecture for your project, we’ll now analyze the technical implementations, looking at challenges and benefits. We’ll review the different implementations in detail and then assess the characteristics for each architecture. The characteristics we’ll analyze for every implementation: Deployability Reliability and ease of deploying a micro-frontend in an environment. Modularity Ease of adding or removing micro-frontends and ease of integrating with shared components hosted by micro-frontends. Simplicity Ease of being able to understand or do. If a piece of software is considered simple, it has likely been found to be easy to understand and to reason about. Testability Degree to which a software artifact supports testing in a given test context. If the testability of the software artifact is high, then finding faults in the system by means of testing is easier. Performance Indicator of how well a micro-frontend would meet the quality of user experience described by web vitals, essential metrics for a healthy site. Developer experience
  • 13. The experience developers are exposed to when they use your product, be it client libraries, SDKs, frameworks, open source code, tools, API, technology, or services. Scalability The ability of a process, network, software, or organization to grow and manage increased demand. Coordination Unification, integration, or synchronization of group members’ efforts in order to provide unity of action in the pursuit of common goals. Characteristics are rated on a five-point scale, with one point indicating that the specific architecture characteristic isn’t well supported and five points indicating that the architecture characteristic is one of the strongest features in the architectural pattern. The score indicates which architecture characteristic shines better with every approach described. It’s almost impossible having all the characteristics working perfectly in an architecture due to the tension they exercise with each other. Our role would be to find the trade-off suitable for the application we have to build, hence the decision to create a score mechanism to evaluate all of these architectural approaches. Architecture and Trade-offs As I pointed out elsewhere in this book, I firmly believe that the perfect architecture doesn’t exist; it’s always a trade-off. The trade-offs are not only technical but also based on business requirements and organizational structure. Modern architecture considers other forces that contribute to the final outcome as well as technical aspects. We must recognize the sociotechnical aspects and optimize for the context we operate in instead of searching for the “perfect architecture” (which doesn’t exist) or borrowing
  • 14. the architecture from another context without researching whether it would be appropriate for our context. In Fundamentals of Software Architecture, Neal Ford and Mark Richards highlight very well these new architecture practices and invite the readers to optimize for the “least worst” architecture. As they state, “Never shoot for the best architecture, but rather the least worst architecture.” Before settling on a final architecture, take the time to understand the context you operate in, your teams’ structures, and the communication flows between teams. When we ignore these aspects, we risk creating a great technical proposition that’s completely unsuitable for our company. It’s the same when we read case studies from other companies embracing specific architectures. We need to understand how the company works and how that compares to how our company works. Often the case studies focus on how a company solved a specific problem, which may or may not overlap with your challenges and goals. It’s up to you to find out if the case study’s challenges match your own. Read widely and talk with different people in the community to understand the forces behind certain decisions. Taking the time to research will help you avoid making wrong assumptions and become more aware of the environment you are working in. Every architecture is optimized for solving specific technical and organizational challenges, which is why we see so many approaches to micro-frontends. Remember: there isn’t right or wrong in architecture, just the best trade-off for your own context. Vertical-Split Architectures For a vertical-split architecture, a client-side composition, client-side routing, and an application shell, as described above, are fantastic for teams with a solid background of building SPAs for their first foray into micro- frontends, because the development experience will be mostly familiar. This
  • 15. is probably also the easiest way to enter the micro-frontend world for developers with a frontend background. Application Shell A persistent part of a micro-frontend application, the application shell is the first thing downloaded when an application is requested. It will shepherd a user session from the beginning to the end, loading and unloading micro- frontends based on the endpoint the user requests. The main reasons to load micro-frontends inside an application shell include: Handling the initial user state (if any) If a user tries to access an authenticated route via a deep link but the user token is invalid, the application shell redirects the user to the sign- in view or a landing page. This process is needed only for the first load, however. After that, every micro-frontend in an authenticated area of a web application should manage the logic for keeping the user authenticated or redirecting them to an unauthenticated page. Retrieving global configurations When needed, the application shell should first fetch a configuration that contains any information used across the entire user sessions, such as the user’s country if the application provides different experiences based on country. Fetching the available routes and associated micro-frontends to load To avoid needlessly deploying the application shell, the route configurations should be loaded at runtime with the associated micro- frontends. This will guarantee control of the routing system without deploying the application shell multiple times.
  • 16. Setting logging, observability, or marketing libraries Because these libraries are usually applied to the entire application, it’s best to instantiate them at the application shell level. Handling errors if a micro-frontend cannot be loaded Sometimes micro-frontends are unreachable due to a network issue or bug in the system. It’s wise to add an error message (a 404 page, for instance) to the application shell or load a highly available micro- frontend to display errors and suggest possible solutions to the user, like suggesting similar products or asking them to come back later. You could achieve similar results by using libraries in every micro-frontend rather than using an orchestrator like the application shell. However, ideally you want just one place to manage these things from. Having multiple libraries means ensuring they are always in sync between micro-frontends, which requires more coordination and adds complexity to the entire process. Having multiple libraries also creates risk in the deployment phase, where there are breaking changes, compared to centralizing libraries inside the application shell. Never use the application shell as a layer to interact constantly with micro- frontends during a user session. The application shell should only be used for edge cases or initialization. Using it as a shared layer for micro- frontends risks having a logical coupling between micro-frontends and the application shell, forcing testing and/or redeployment of all micro-frontends available in an application. This situation is also called a distributed monolith and is a developer’s worst nightmare. In this pattern, the application shell loads only one micro-frontend at a time. That means you don’t need to create a mechanism for encapsulating conflicting dependencies between micro-frontends because there won’t be
  • 17. any clash between libraries or CSS styles (see Figure 4-4), as long as both are removed from the window object when a micro-frontend is unloaded. The application shell is nothing more than a simple HTML page with logic wrapped in a JavaScript file. Some CSS styles may or may not be included in the application shell for the initial loading experience, such as for showing a loading animation like a spinner. Every micro-frontend entry point is represented by a single HTML page containing the logic and style of a single view or a small SPA containing several routes that include all the logic needed to allow a user to consume an entire subdomain of the application without a new micro-frontend needing to load. A JavaScript file could be loaded instead as a micro-frontend entry point, but in this case we are limited by the initial customer experience, because we have to wait until the JavaScript file is interpreted before it can add new elements into the domain object model (DOM).
  • 18. Figure 4-4. Vertical-split architecture with client-side composition and routing using the application shell The vertical split works well when we want to create a consistent user experience while providing full control to a single team. A clear sign that this may be the right approach for your application is when you don’t have many repetitions of business subdomains across multiple views but every part of the application may be represented by an application itself.
  • 19. Identifying micro-frontends becomes easy when we have a clear understanding of how users interact with the application. If you use an analytics tool like Google Analytics, you’ll have access to this information. If you don’t have this information, you’ll need to get it before you can determine how to structure the architecture, business domains, and your organization. With this architecture, there isn’t a high reusability of micro- frontends, so it’s unlikely that a vertical-split micro-frontend will be reused in the same application multiple times. However, inside every micro-frontend we can reuse components (think about a design system), generating a modularity that helps avoid too much duplication. It’s more likely, though, that micro-frontends will be reused in different applications maintained by the same company. Imagine that in a multitenant environment, you have to develop multiple platforms and you want to have a similar user interface with some customizations for part of every platform. You will be able to reuse vertical-split micro-frontends, reducing code fragmentation and evolving the system independently based on the business requirements. Challenges Of course, there will be some challenges during the implementation phase, as with any architecture pattern. Apart from domain-specific ones, we’ll have common challenges, some of which have an immediate answer, while others will depend more on context. Let’s look at four major challenges: a sharing state, the micro-frontends composition, a multiframework approach, and the evolution of your architecture. Sharing state The first challenge we face when we work with micro-frontends in general is how to share states between micro-frontends. While we don’t need to share information as much with a vertical-split architecture, the need still exists.
  • 20. Some of the information that we may need to share across multiple micro- frontends are fine when stored via web storage, such as the audio volume level for media the user played or the fonts recently used to edit a document. When information is more sensitive, such as personal user data or an authentication token, we need a way to retrieve this information from a public API and then share across all the micro-frontends interested in this information. In this case, the first micro-frontend loaded at the beginning of the user’s session would retrieve this data, stored in a web storage with a retrieval time stamp. Then every micro-frontend that requires this data can retrieve it directly from the web storage, and if the time stamp is older than a preset amount of time, the micro-frontend can request the data again. And because the application loads only one micro-frontend at a time and every micro-frontend will have access to the selected web storage, there is no strong requirement to pass through the application shell for storing data in the web storage. However, let’s say that your application relies heavily on the web storage, and you decide to implement security checks to validate the space available or type of message stored. In this scenario, you may want to instead create an abstraction via the application shell that will expose an API for storing and retrieving data. This will centralize where the data validation happens, providing meaningful errors to every micro-frontend in case a validation fails. Composing micro-frontends You have several options for composing vertical-split micro-frontends inside an application shell. Remember, however, that vertical-split micro- frontends are composed and routed on the client side only, so we are limited to what the browser’s standards offer us. There are four techniques for composing micro-frontends on the client side: ES modules
  • 21. JavaScript modules can be used to split our applications into smaller files to be loaded at compile time or at runtime, fully implemented in modern browsers. This can be a solid mechanism for composing micro- frontends at runtime using standards. To implement an ES module, we simply define the module attribute in our script tag and the browser will interpret it as a module: <script type="module" src="catalogMFE.js"></script> This module will be always deferred and can implement cross-origin resource sharing (CORS) authentication. ES modules can also be defined for the entire application inside an import map, allowing us to use the syntax to import a module inside the application. As of publication time, the main problem with import maps is that they are not supported by all the browsers. You’ll be limited to Google Chrome, Microsoft Edge (with Chromium engine), and recent versions of Opera, limiting this solution’s viability. SystemJS This module loader supports import maps specifications, which are not natively available inside the browser. This allows them to be used inside the SystemJS implementation, where the module loader library makes the implementation compatible with all the browsers. This is a handy solution when we want our micro-frontends to load at runtime, because it uses a syntax similar to import maps and allows SystemJS to take care of the browser’s API fragmentation. Module Federation
  • 22. This is a plug-in introduced in webpack 5 used for loading external modules, libraries, or even entire applications inside another one. The plug-in takes care of the undifferentiated heavy lifting needed for composing micro-frontends, wrapping the micro-frontends’ scope and sharing dependencies between different micro-frontends or handling different versions of the same library without runtime errors. The developer experience and the implementation are so slick that it would seem like writing a normal SPA. Every micro-frontend is imported as a module and then implemented in the same way as a component of a UI framework. The abstraction made by this plug-in makes the entire composition challenge almost completely painless. HTML parsing When a micro-frontend has an entry point represented by an HTML page, we can use JavaScript for parsing the DOM elements and append the nodes needed inside the application shell’s DOM. At its simplest, an HTML document is really just an XML document with its own defined schema. Given that, we can treat the micro-frontend as an XML document and append the relevant nodes inside the shell’s DOM using the DOMParser object. After parsing the micro-frontend DOM, we then append the DOM nodes using adoptNode or cloneNode methods. However, using cloneNode or adoptNode doesn’t work with the script element, because the browser doesn’t evaluate the script element, so in this case we create a new one, passing the source file found in the micro-frontend’s HTML page. Creating a new script element will trigger the browser to fully evaluate the JavaScript file associated with
  • 23. this element. In this way, you can even simplify the micro-frontend developer experience because your team will provide the final results knowing how the initial DOM will look. This technique is used by some frameworks, such as qiankun, which allows HTML documents to be micro-frontend entry points. All the major frameworks composed on the client side implement these techniques, and sometimes you even have options to pick from. For example, with single SPA you can use ES modules, SystemJS with import maps, or Module Federation. All these techniques allow you to implement static or dynamic routes. In the case of static routes, you just need to hardcode the path in your code. With dynamic path, you can retrieve all the routes from a static JSON file to load at the beginning of the application or create something more dynamic by developing an endpoint that can be consumed by the application shell and where you apply logic based on the user’s country or language for returning the final routing list. Multiframework approach Using micro-frontends for a multiframework approach is a controversial decision, because many people think that this forces them to use multiple UI frameworks, like React, Angular, Vue, or Svelte. But what is true for frontend applications written in a monolithic way is also true for micro- frontends. Although technically you can implement multiple UI frameworks in an SPA, it creates performance issues and potential dependency clashes. This applies to micro-frontends as well, so using a multiframework implementation for this architecture style isn’t recommended. Instead, follow best practices like reducing external dependencies as much as you can, importing only what you use rather than entire packages that
  • 24. may increase the final JavaScript bundle. Many JavaScript tools implement a tree-shaking mechanism to help achieve smaller bundle sizes. There are some use cases in which the benefits of having a multiframework approach with micro-frontends outweigh the challenges, such as when we can create a healthy flywheel for developers, reducing the time to market of their business logic without affecting production traffic. Imagine you start porting a frontend application from an SPA to micro- frontends. Working on a micro-frontend and deploying the SPA codebase alongside it would help you to provide value for your business and users. First, we would have a team finding best practices for approaching the porting (such as identifying libraries to reuse across micro-frontends), setting up the automation pipeline, sharing code between micro-frontends, and so on. Second, after creating the minimum viable product (MVP), the micro-frontend can be shipped to the final user, retrieving metrics and comparing with the older version. In a situation like this, asking a user to download multiple UI frameworks is less problematic than developing the new architecture for several months without understanding if the direction is leading to a better result. Validating your assumptions is crucial for generating the best practices shared by different teams inside your organization. Improving the feedback loop and deploying code to production as fast as possible demonstrates the best approach for overcoming future challenges with microarchitectures in general. You can apply the same reasoning to other libraries in the same application but with different versions, such as when you have a project with an old version of Angular and you want to upgrade to the latest version. Remember, the goal is creating the muscles for moving at speed with confidence and reducing the potential mistakes automating what is possible and fostering the right mindset across the teams. Finally, these considerations are applicable to all the micro-frontend architecture shared in this book. Architecture evolution and code encapsulation
  • 25. Perfectly defining the subdomains on the first try isn’t always feasible. In particular, using a vertical-split approach may result in coarse-grained micro-frontends that become complicated after several months of work because of broadening project scope as the team’s capabilities grow. Also, we can have new insights into assumptions we made at the beginning of the process. Fear not! This architecture’s modular nature helps you face these challenges and provides a clear path for evolving it alongside the business. When your team’s cognitive load starts to become unsustainable, it may be time to split your micro-frontend. One of the many best practices for splitting a micro-frontend is code encapsulation, which is based on a specific user flow. Let’s explore it! The concept of encapsulation comes from object-oriented programming (OOP) and is associated with classes and how to handle data. Encapsulation binds together the attributes (data) and the methods (functions and procedures) that manipulate the data in order to protect the data. The general rule, enforced by many languages, is that attributes should only be accessed (that is, retrieved or modified) using methods that are contained (encapsulated) within the class definition. Imagine your micro-frontend is composed of several views, such as a payment form, sign-up form, sign-in form, and email and password retrieval form, as shown in Figure 4-5. Figure 4-5. Authentication micro-frontend composed of several views that may create a high cognitive load for the team responsible for this micro-frontend
  • 26. An existing user accessing this micro-frontend is more likely to sign in to the authenticated area or want to retrieve their account email or password, while a new user is likely to sign up or make a payment. A natural split for this micro-frontend, then, could be one micro-frontend for authentication and another for subscription. In this way, you’ll separate the two according to business logic without having to ask the users to download more code than the flow would require (see Figure 4-6). Figure 4-6. Splitting the authentication micro-frontend to reduce the cognitive load, following customer experience more than technical constraints This isn’t the only way to split this micro-frontend, but however you split it, be sure you’re prioritizing a business outcome rather than a technical one. Prioritizing the customer experience is the best way to provide a final output that your users will enjoy. Encapsulation helps with these situations. For instance, avoid having a unique state representing the entire micro-frontend. Instead, prefer state management libraries that allow composition of state, like MobX-State- Tree does. The data will be expressed in tree structure, which you can compose at will. Spend the time evaluating how to implement the application state, and you may save time later while also reducing your cognitive load. It is always easier to think when the code is well identified inside some boundaries than when it’s spread across multiple parts of the application. When libraries or even logic are used in multiple domains, such as in a form validation library, you have a few options:
  • 27. Duplicate the code Code duplication isn’t always a bad practice; it depends on what you are optimizing for and overall impact of the duplicated code. Let’s say that you have a component that has different states based on user status and the view where it’s hosted, and that this component is subject to new requirements more often in one domain than in others. You may want to centralize it. Keep in mind, though, that every time you have a centralized library or component, you have to build a solid governance for making sure that when this shared code is updated, it also gets updated in every micro-frontend that uses this shared code as well. When this happens, you also have to make sure the new version doesn’t break anything inside each micro-frontend and you need to coordinate the activity across multiple teams. In this case, the component isn’t difficult to implement and it will become easier to build for every team that uses it, because there are fewer states to take care of. That allows every implementation to evolve independently at its own speed. Here, we’re optimizing for speed of delivery and reducing the external dependencies for every team. This approach works best when you have a limited amount of duplication. When you have dozens of similar components, this reasoning doesn’t scale anymore; you’ll want to abstract into a library instead. Abstract your code into a shared library In some situations, you really want to centralize the business logic to ensure that every micro-frontend is using the same implementation, as with integrating payment methods. Imagine implementing in your
  • 28. checkout form multiple payment methods with their validation logic, handling errors, and so on. Duplicating such a complex and delicate part of the system isn’t wise. Creating a shared library instead will help maintain consistency and simplify the integration across the entire platform. Within the automation pipelines, you’ll want to add a version check on every micro-frontend to review the latest library version. Unfortunately, while dealing with distributed systems helps you scale the organization and deliver with speed, sometimes you need to enforce certain practices for the greater good. Delegate to a backend API The third option is to delegate the common part to be served to all your vertical-split micro-frontends by the backend, thus providing some configuration and implementation of the business logic to each micro- frontend. Imagine you have multiple micro-frontends that are implementing an input field with specific validation that is simple enough to represent with a regular expression. You might be tempted to centralize the logic in a common library, but this would mean enforcing the update of this dependency every time something changes. Considering the logic is easy enough to represent and the common part would be using the same regular expression, you can provide this information as a configuration field when the application loads and make it available to all the micro-frontends via the web storage. That way, if you want to change the regular expression, you won’t need to redeploy every micro-frontend implementing it. You’ll just change the
  • 29. regular expression in the configuration, and all the micro-frontends will automatically use the latest implementation. CODE DUPLICATION OVER WRONG ABSTRACTIONS Many well-known people in the industry have started to realize that abstracting code is not always a benefit, especially in the long run. In certain cases, code duplication brings more benefits to a premature or a hasty abstraction. Moreover, duplicated code can be easily abstracted if and when needed; it’s more challenging to try to move away from abstractions once they’re present in the code. If you are interested in this topic, read “The Wrong Abstraction”, a 2016 blog post by Sandi Metz. Kent Dodds’s AHA programming or “Avoid Hasty Abstractions” concept is strongly inspired by the work Metz describes in his blog and talk. Also, the well-known DRY principle (don’t repeat yourself) appears to be misapplied by many developers, who just looked in the code for duplicated lines of code and abstracted them. In the second edition of Pragmatic Programmer (Addison-Wesley), where the DRY principle was first introduced, the authors provide a great explanation of this point: In the first edition of this book we did a poor job of explaining just what we meant by Don’t Repeat Yourself. Many people took it to refer to code only: they thought that DRY means “don’t copy-and-paste lines of source.” That is part of DRY, but it’s a tiny and fairly trivial part. DRY is about the duplication of knowledge, of intent. It’s about expressing the same thing in two different places, possibly in two totally different ways. [emphasis added] It’s important to understand that no solution fits everything. Consider the context your implementation should represent and choose the best trade-off in the guardrails you are operating with. Could you have designed the
  • 30. micro-frontends in this way from the beginning? Potentially, you could have, but the whole point of this architecture is to avoid premature abstractions, optimize for fast delivery, and evolve the architecture when it is required due to complexity or just a change of direction. Implementing a Design System In a distributed architecture like micro-frontends, design systems may seem a difficult feature to achieve, but in reality the technical implementation doesn’t differ too much from that of a design system in an SPA. When thinking about a design system applied to micro-frontends, imagine a layered system composed of design tokens, basic components, user interface library, and the micro-frontends that host all these parts together, as shown in Figure 4-7. Figure 4-7. How a design system fits inside a micro-frontends architecture The first layer, design tokens, allows you to capture low-level values to then create the styles for your product, such as font families, text colors, text size, and many other characteristics used inside our final user interface. Generally, design tokens are listed in JSON or YAML files, expressing every detail of our design system.
  • 31. We don’t usually distribute design tokens across different micro-frontends because each team will implement them in their own way, risking the introduction of bugs in some areas of the application and not in others, increasing the code duplication across the system, and, in general, slowing down the maintenance of a design system. However, there are situations when design tokens can be an initial step for creating a level of consistency for iterating later on, with basic components shared across all the micro- frontends. Often, teams do not have enough space for implementing the final design system components inside every micro-frontend. Therefore, make sure if you go down this path that you have the time and space for iterating on the design system. The next layer is basic components. Usually, these components don’t hold the application business logic and are completely unaware of where they will be used. As a result, they should be as generic as can be, such as a label or button, which will provide the consistency we are looking for and the flexibility to be used in any part of the application. This is the perfect stage for centralizing the code that will be used across multiple micro-frontends. In this way, we create the consistency needed in the UI to allow every team to use components at the level they need. The third layer is a UI components library, usually a composition of basic components that contain some business logic that is reusable inside a given domain. We may be tempted to share these components as well, but be cautious in doing so. The governance to maintain and the organization structure may cause many external dependencies across teams, creating more frustration than efficiencies. One exception is when there are complex UI components that require a lot of iterations and there is a centralized team responsible for them. Imagine, for instance, building a complex component such as a video player with several functionalities, such as closed captions, a volume bar, and trick play. Duplicating these components is a waste of time and effort; centralizing and abstracting your code is by far more efficient.
  • 32. Note, though, that shared components are often not reused as much as we expect, resulting in a wasted effort. Therefore, think twice before centralizing a component. When in doubt, start duplicating the component and, after a few iterations, review whether these components need to be abstracted. The wrong abstraction is way more expensive than duplicated code. The final layer is the micro-frontend that is hosting the UI components library. Keep in mind the importance of a micro-frontend’s independence. The moment we get more than three or four external dependencies, we are heading toward a distributed monolith. That’s the worst place to be because we are treating a distributed architecture like a monolith that we wanted to move away from, no longer creating independent teams across the organization. To ensure we are finding the right trade-offs between development speed and independent teams and UI consistency, consider validating the dependencies monthly or every two months throughout the project life cycle. In the past, I’ve worked at companies where this exercise was done every two weeks at the end of every sprint, and it helped many teams postpone tasks that may not have been achievable during a sprint due to blocks from external dependencies. In this way, you’ll reduce your teams’ frustration and increase their performance. On the technical side, the best investment you can make for creating a design system is in web components. Since you can use web components with any UI framework, should you decide to change the UI framework later, the design system will remain the same, saving you time and effort. There are some situations in which using web components is not viable, such as projects that have to target old browsers. Chances are, though, you won’t have such strong requirements and you can target modern browsers, allowing you to leverage web components with your micro-frontend architecture. While getting the design system ready to be implemented is half the work, to accomplish the delivery inside your micro-frontends architecture, you’ll
  • 33. need a solid governance to maintain that initial investment. Remember, dealing with a distributed architecture is not as straightforward as you can imagine. Usually, the first implementation happens quite smoothly because there is time allocated to that. The problems come with subsequent updates. Especially when you deal with distributed teams, the best approach is to automate the system design version validation in the continuous integration (CI) phase. Every time a micro-frontend is built, the package.json file should check that the design system library is up to date with the latest version. Implementing this check in CI allows you to be as strict as needed. You may decide to provide a warning in the logs, asking to update the version as soon as possible, or prevent artifact creation if the micro-frontend is one or more major versions behind. Some companies have custom dashboards for dealing with this problem, not only for design systems but also for other libraries, such as logging or authentication. In this way, every team can check in real time whether their micro-frontend implements the latest versions. Finally, let’s consider the team’s structure. Traditionally, in enterprise companies, the design team is centralized, taking care of all the aspects of the design system, from ideation to delivery, and the developers just implement the library the design team provides. However, some companies implement a distributed model wherein the design team is a central authority that provides the core components and direction for the entire design system, but other teams populate the design system with new components or new functionalities of existing ones. In this second approach, we reduce potential bottlenecks by allowing the development teams to contribute to the global design system. Meanwhile, we keep guardrails in place to ensure every component respects the overall plan, such as regular meetings between design and development, office hours during which the design team can guide development teams, or even collaborative sessions where the design team sets the direction but the developers actually implement the code inside the design system.
  • 34. Developer Experience For vertical-split micro-frontends, the developer’s experience is very similar to SPAs. However, there are a couple of suggestions that you may find useful to think about up front. First of all, create a command line tool for scaffolding micro-frontends with a basic implementation and common libraries you would like to share in all the micro-frontends such as a logging library. While not an essential tool to have from day one, it’s definitely helpful in the long term, especially for new team members. Also, create a dashboard that summarizes the micro-frontend version you have in different environments. In general, all the tools you are using for developing an SPA are still relevant for a vertical-split micro-frontend architecture. We will discuss this topic more in depth in Chapter 7, where we review how to create automation pipelines for micro-frontend applications. Search Engine Optimization Some projects require a strong SEO strategy, including micro-frontend projects. Let’s look at two major options for a good SEO strategy with vertical-split micro-frontends. The first one involves optimizing the application code in a way that is easily indexable by crawlers. In this case, the developer’s job is implementing as many best practices as possible for rendering the entire DOM in a timely manner (usually under five seconds). Time matters with crawlers, because they have to index all the data in a view and also structure the UI in a way that exposes all the meaningful information without hiding behind user interactions. Another option is to create an HTML markup that is meaningful for crawlers to extract the content and categorize it properly. While this isn’t impossible, in the long run, this option may require a bit of effort to maintain for every new feature and project enhancement. Another option would be using dynamic rendering to provide an optimized version of your web application for all the crawlers trying to index your content. Google introduced dynamic rendering to allow you to redirect crawler requests to an optimized version of your website, usually
  • 35. prerendered, without penalizing the positioning of your website in the search engine results (see Figure 4-8). Figure 4-8. When a crawler requests a specific page, the application server should retrieve the user- agent and serve the crawler’s requests to a prerendered version of the website, otherwise serving the micro-frontend implementation There are a couple of solutions for serving a prerendered version of your application to a crawler. First, for the prerendering phase, you can create a customized version of your website that fetches the same data of the website your users will consume. For instance, you can create a server-side rendering output stored in an objects storage that translates a template into static HTML pages at compile time, maintaining the same user-facing URL structure. Amazon S3 is a good choice for this. You can also decide to server-side render at runtime, eliminating the need to store the static pages and serving the crawlers a just-in-time version created ad hoc for them. Although this solution requires some effort to implement, it allows you the best customization and optimization for improving the final output to the crawler. A second option would be using an open source solution like Puppeteer or Rendertron to scrape the code from the website created for the users and then deploy a web server that generates static pages regularly. After generating the static version of your website, you need to know when the request is coming from a browser and when from a crawler. A basic
  • 36. implementation would be using a regular expression that identifies the crawler’s user-agents. A good Node.js library for that is crawler-user- agents. In this case, after identifying the user-agent header, the application server can respond with the correct implementation. This solution can be applied at the edge using technologies like AWS Lambda@Edge or Cloudflare Workers. In this case, CDNs of some cloud providers allow a computation layer after receiving a request. Because there are some constraints on the maximum execution time of these containers, the user- agent identification represents a good reason for using these edge technologies. Moreover, they can be used for additional logic, introducing canary releases or blue-green deployment, as we will see in Chapter 6. Performance and Micro-Frontends Is good performance achievable in a micro-frontend architecture? Definitely! Performance of a micro-frontend architecture, like in any other frontend architecture, is key for the success of a web application. And a vertical-split architecture can achieve good performance thanks to the split of domains and, therefore, the code to be shared with a client. Think for a moment about an SPA. Typically, the user has to download all the code specifically related to the application, the business logic, and the libraries used in the entire application. For simplicity, let’s imagine that an entire application code is 500 KB. The unauthenticated area, composed of sign-in, sign-up, the landing page, customer support, and few other views, requires 100 KB of business logic, while the authenticated area requires 150 KB of business logic. Both use the same bundled dependencies that are each 250 KB (see Figure 4-9). A new user has to download all 500 KB, despite the action having to fulfill inside the SPA. Maybe one user just wants to understand the business proposition and visits just the landing page, another user wants to see the payment methods available, or an authenticated user is interested mainly in the authenticated area where the service or products are available. No matter what users are trying to achieve, they are forced to download the entire application.
  • 37. Figure 4-9. Any user of an SPA has to download the entire application regardless of the action they intend to perform in the application In a vertical-split architecture, however, our unauthenticated user who wants to see the business proposition on the landing page will be able to download the code just for that micro-frontend, while the authenticated user will download only the codebase for the authenticated area. We often don’t realize that our users’ behaviors are different from the way we interpret the
  • 38. application, because we often optimize the application’s performance as a whole rather than by how users interact with the site. Optimizing our site according to user experiences results in a better outcome. Applying the previous example to a vertical-split architecture, a user interested only in the unauthenticated area will download less than 100 KB of business logic plus the shared dependencies, while an authenticated user will download only the 250 KB plus the shared dependencies. Clearly a new user who moves beyond the landing page will download almost 500 KB, but this approach will still save some kilobytes if we have properly identified the application boundaries because it’s unlikely a new user will go through every single application view. In the worst-case scenario, the user will download 500 KB as they would for the SPA, but this time not everything up front. Certainly, there is additional logic to download due to the application shell, but usually the size is only in the double digits, making it meaningless for this example. Figure 4-10 shows the advantages of a vertical-split micro-frontend in terms of performance. A good practice for managing performance on a vertical-split architecture is introducing a performance budget. A performance budget is a limit for micro-frontends that a team is not allowed to exceed. The performance budget includes the final bundle size, multimedia content to load, and even CSS files. Setting a performance budget is an important part of making sure every team optimizes its own micro-frontend properly and can even be enforced during the CI process. You won’t set a performance budget until later in the project, but it should be updated every time there is a meaningful refactoring or additional features introduced in the micro- frontend codebase.
  • 39. Figure 4-10. A vertical-split micro-frontend enables the user to download only the application code needed to accomplish the action the user is looking for Time to display the final result to the user is a key performance indicator, and metrics to track include time-to-interactive or first contentful paint, the size of the final artifact, font size, and JavaScript bundle size, as well as metrics like accessibility and SEO. A tool like Lighthouse is useful for analyzing these metrics and is available in a command-line version to be used in the continuous integration process. Although these metrics have been discussed extensively for SPA optimization, bundle size may be trickier when it comes to micro-frontends. With vertical-split architectures, you can decide either to bundle all the shared libraries together or to bundle the libraries for each micro-frontend. The former can provide greater performance because the user downloads the bundle only once, but you’ll need to coordinate the libraries to update for every change across all the micro-frontends. While this may sound like an easy task, it can be more complicated than you think when it happens
  • 40. regularly. Imagine you have a breaking change on a specific shared UI framework; you can’t update the new version until all the micro-frontends have done extensive tests on the new framework version. So while we gain in performance in this scenario, we must first overcome some organizational challenges. The latter solution—maintaining every micro- frontend independently—reduces the communication overhead for coordinating the shared dependencies but might increase the content the user must download. As seen before, however, a user may decide to stay within the same micro-frontend for the entire session, resulting in the exact same kilobytes downloaded. Once again, there isn’t right or wrong in any of these strategies. Make a decision on the requirements to fulfill and the context you operate in. Don’t be afraid to make a call and monitor how users interact with your application. You may discover that, overall, the solution you picked, despite some pitfalls, is the right one for the project. Remember, you can easily reverse this decision, so spend the right amount of time thinking which path your project requires, but be aware that you can change direction if a new requirement arises or the decision causes more harm than benefits. Available Frameworks There are some frameworks available for embracing this architecture. However, building an application shell on your own won’t require too much effort, as long as you keep the application shell decoupled from any micro- frontend business logic. Polluting the application shell codebase with domain logic is not only a bad practice but also may invalidate all effort and investment of using micro-frontends in the long run due to code and logic coupling. Two frameworks that are fully embracing this architecture are single-spa and qiankun. The concept behind single-spa is very simple: it’s a lightweight library that provides undifferentiated heavy lifting for the following: Registration of micro-frontends
  • 41. The library provides a root configuration to associate a micro-frontend to a specific path of your system. Life cycle methods Every micro-frontend is exposed to many stages when mounted. Single- spa allows a micro-frontend to perform the right task for the life cycle method. For instance, when a micro-frontend is mounted, we can apply logic for fetching an API. When unmounted, we should remove all the listeners and clean up all DOM elements. Single-spa is a mature library, with years of refinement and many integrations in production. It’s open source and actively maintained and has a great community behind it. In the latest version of the library, you can develop horizontal-split micro-frontends, too, including server-side rendering ones. Qiankun is built on top of single-spa, adding some functionality from the latest releases of single-spa. Module Federation may also be a good alternative for implementing a vertical-split architecture, considering that the mounting and unmounting mechanism, dependencies management, orchestration between micro- frontends, and many other features are already available to use. Module Federation is typically used for composing multiple micro-frontends in the same view (horizontal split). However, nothing is preventing us from using it for handling vertical-split micro-frontends. Moreover, it’s a webpack plug-in. If your projects are already using webpack, it may help you avoid learning new frameworks for composing and orchestrating your project’s micro-frontends. In the next chapter, we will explore the Module Federation for implementing vertical and horizontal split architectures. Use Cases The vertical-split architecture is a good solution when your frontend developers have experience with SPA development. It will also scale up to a
  • 42. certain extent, but if you have hundreds of frontend developers working on the same frontend application, a horizontal split may suit your project better, because you can modularize your application even further. Vertical-split architecture is also great when you want UI and UX consistency. In this situation, every team is responsible for a specific business domain, and a vertical split will allow them to develop an end-to- end experience without the need to coordinate with other teams. Another reason to choose this architecture pattern is the level of reusability you want to have across multiple micro-frontends. For instance, if you reuse mainly components of your design system and some libraries, like logging or payments, a vertical split may be a great architecture fit. However, if part of your micro-frontend is replicated in multiple views, a horizontal split may be a better solution. Again, let the context drive the decision for your project. Finally, this architecture is my first recommendation when you start embracing micro-frontends because it doesn’t introduce too much complexity. It has a smooth learning curve for frontend developers, it distributes the business domains to dozens of frontend developers without any problem, and it doesn’t require huge upfront investment in tools but more in general in the entire developer experience. Architecture Characteristics Deployability (5/5) Because every micro-frontend is a single HTML page or an SPA, we can easily deploy our artifacts on a cloud storage or an application server and stick a CDN in front of it. It’s a well-known approach, used for several years by many frontend developers for delivering their web applications. Even better, when we apply a multi-CDN strategy, our
  • 43. content will always be served to our user no matter which fault a CDN provider may have. Modularity (2/5) This architecture is not the most modular. While we have a certain degree of modularization and reusability, it’s more at the code level, sharing components or libraries but less on the features side. For instance, it’s unlikely a team responsible for the development of the catalog micro-frontend shares it with another micro-frontend. Moreover, when we have to split a vertical-split micro-frontend in two or more parts because of new features, a bigger effort will be required for decoupling all the shared dependencies implemented, since it was designed as a unique logical unit. Simplicity (4/5) Taking into account that the primary aim of this approach is reducing the team’s cognitive load and creating domain experts using well-known practices for frontend developers, the simplicity is intrinsic. There aren’t too many mindset shifts or new techniques to learn to embrace this architecture. The overhead for starting with single-spa or Module Federation should be minimal for a frontend developer. Testability (4/5) Compared to SPAs, this approach shows some weakness in the application shell’s end-to-end testing. Apart from that edge case, however, testing vertical-split micro-frontends doesn’t represent a
  • 44. challenge with existing knowledge of unit, integration, or end-to-end testing. Performance (4/5) You can share the common libraries for a vertical-split architecture, though it requires a minimum of coordination across teams. Since it’s very unlikely that you’ll have hundreds of micro-frontends with this approach, you can easily create a deployment strategy that decouples the common libraries from the micro-frontend business logic and maintains the commonalities in sync across multiple micro-frontends. Compared to other approaches, such as server-side rendering, there is a delay on downloading the code of a micro-frontend because the application shell should initialize the application with some logic. This may impact the load of a micro-frontend when it’s too complex or makes many roundtrips to the server. Developer experience (4/5) A team familiar with SPA tools won’t need to shift their mindset to embrace the vertical split. There may be some challenges during end-to- end testing, but all the other engineering practices, as well as tools, remain the same. Not all the tools available for SPA projects are suitable for this architecture, so your developers may need to build some internal tools to fill the gaps. However, the out-of-the-box tools available should be enough to start development, allowing your team to defer the decisions to build new tools. Scalability (5/5)
  • 45. The scalability aspect of this architecture is so great that we can even forget about it when we serve our static content via a CDN. We can also configure the time-to-live according to the assets we are serving, setting a higher time for assets that don’t change often, like fonts or vendor libraries, and a lower time for assets that change often, like the business logic of our micro-frontends. This architecture can scale almost indefinitely based on CDN capacity, which is usually great enough to serve billions of users simultaneously. In certain cases, when you absolutely must avoid a single point of failure, you can even create a multiple-CDN strategy, where your micro-frontends are served by multiple CDN providers. Despite being more complicated, it solves the problem elegantly without investing too much time creating custom solutions. Coordination (4/5) This architecture, compared to others, enables a strong decentralization of decision making, as well as autonomy of each team. Usually, the touching points between micro-frontends are minimal when the domain boundaries are well defined. Therefore, there isn’t too much coordination needed, apart from an initial investment for defining the application shell APIs and keeping them as domain unaware as possible. Table 4-1 gathers the architecture characteristics and its associated score for this micro-frontend architecture.
  • 50. Exploring the Variety of Random Documents with Different Content
  • 51. auspicious moment passed away exactly as they intended, and another great opportunity was lost. The French reinforcements arrived, and having been the weaker became the stronger force. Nothing more could be done for the rest of the campaign, but to level the French lines from the Demer to the Mehaigne. Thus for the third time a brilliant campaign was spoilt by the Dutch generals and deputies. Fortunately the public indignation both in England and in Holland was too strong for them, and Slangenberg, though not indeed hanged as he deserved, was deprived of all further command. Jealousy, timidity, ignorance, treachery, and flat imbecility seem to have been the motives that inspired these men, whose conduct has never been reprobated according to its demerit. It was they who were responsible for the prolongation of the war, for the burden that it laid on England, and for the untold misery that it wrought in France. Left to himself Marlborough would have forced the French to peace in three campaigns, and the war would not have been ended in shame and disgrace by the Treaty of Utrecht.[323] Consolation for the disappointment in Flanders came from an unexpected quarter. In Portugal, indeed, comparatively little was done. An army was made up of about three thousand British[324] under Lord Galway, two thousand Dutch under General Fagel, and twelve thousand Portuguese under the Spanish General de Corsana; and to avoid friction it was arranged that these three generals should hold command alternately for a week at a time. In such circumstances it was surprising that they should even have accomplished the siege and capture of three weak fortresses, Valenza, Albuquerque, and Badajoz, with which achievements the campaign came to an end.[325] June 9 20 . August 12 23 .
  • 52. But in Catalonia the operations were of a more brilliant kind. The Catalans were known to favour the Austrian side; and it was accordingly resolved in this year to send a fleet and an army to back them under Admiral Leake and Lord Peterborough, the latter to be joint admiral at sea as well as commander-in-chief ashore. The character of Peterborough is one of the riddles of history. He was now forty years of age, and had so far distinguished himself chiefly by general eccentricity, not always of a harmless kind, and, in common with most prominent men of his age, by remarkable pliancy of principle. His experience of active service was slight and had been gained afloat rather than ashore, and though he had long held the colonelcy of a regiment, he had never commanded in war nor in peace. His force consisted of six British[326] and four Dutch battalions, or about six thousand five hundred men in all. The expedition arrived at Lisbon early in June, when after some delay it was decided that the fleet should proceed to Barcelona. Galway lent his two regiments of dragoons, the Royals and the Eighth; and with them Peterborough sailed to Gibraltar, where he picked up the eight battalions[327] of the garrison, leaving two of his own in their place, and proceeded to his destination. On the way up the Spanish coast a detachment was landed to capture Denia, and on the 23rd of August the main force was disembarked before Barcelona and took up a position to the north-east of the town with its left flank resting on the sea. Sept. 2 13 . The reports sent to England had represented Barcelona as ill- fortified and ill-garrisoned. Ill-fortified it may have been if compared with a creation of Vauban or Cohorn, but it was none the less a formidable fortress, well stocked with supplies and garrisoned by seven thousand troops under an energetic governor, by name Velasco. Peterborough, who grasped the situation, wished to abandon the project of a regular siege for operations of a livelier kind, but was prevailed upon to give it a trial for eighteen days, at
  • 53. the close of which he ordered the re-embarkation of the army. He was, however, again induced to change his mind, and then suddenly, on the evening of the 13th of September, he produced an original scheme of his own. About three-quarters of a mile to south-west of Barcelona stood the small fort of Montjuich, crowning a hill seven hundred feet above the fortress, strong by nature and strengthened still further by outworks, which though incomplete were none the less formidable. This Peterborough resolved to capture by escalade. Not a word was said to the men of the work before them. No further orders were issued than that twelve hundred English and two hundred Dutch should be ready in the afternoon to march towards Tarragona, while thirteen hundred men under Brigadier Stanhope were secretly detailed to cover the rear of the assaulting columns from any attack from Barcelona. At six o'clock the attacking force moved off under Lord Charlemont towards the north-west, continuing the march in this false direction for four hours, till Peterborough at last gave the order to turn about to southward. The night was dark, and much of the ground so rocky as to show no track, so that when the columns at length came up before Montjuich one complete body of two hundred was found to be missing, having evidently strayed away from the path of the remainder. Sept. 3 14 . Half the force however was told off for simultaneous assault on the eastern and western extremities of the fort, Peterborough and Prince George of Hessen-Darmstadt accompanying the eastern column, which, since it was expected to meet with the sternest of the work, was made the stronger. The other moiety of the troops was held in reserve between the two columns. A little after daybreak the signal was given; the storming parties dashed up the glacis under a heavy and destructive fire, and plunging in among the enemy drove them headlong from the outworks. Following the fugitives in hot pursuit Peterborough and Prince George captured the
  • 54. eastern bastion of the fort itself, threw up a barricade of loose stones in the gorge and entrenched themselves behind it. The western attack had met with equal success, and had likewise entrenched itself in a demi-bastion in that flank of the fort. Both parties being thus under cover the fire ceased, and Peterborough sent orders to Stanhope to bring up his reserve. Meanwhile the Governor of Barcelona, being in communication with Montjuich, had at the sound of the firing despatched four hundred dragoons in all haste to reinforce the garrison. As they entered the fort they were received with loud shouts of welcome by the Spanish. Prince George, mistaking the sound for a cry of surrender, at once started up and advanced with all his men into the inner works. They were no sooner in the ditch than the Spaniards swept round them to cut them off. Two hundred were taken prisoners, Prince George fell mortally wounded, and the rest fell back in confusion. This was a severe blow; but worse was to come. Peterborough hearing that fresh reinforcements were on their way to the enemy from Barcelona, rode out of the bastion to look for himself, and no sooner was he gone than the troops were seized with panic. Lord Charlemont was powerless to check it; and in a few minutes the whole of the men, with Charlemont at their head, came running with unseemly haste out of the captured position. They had not run far when up galloped Peterborough in a frenzy of rage. What he said no writer has dared to set down; but he snatched Charlemont's half-pike from his hand and waved the men back to the fort with a torrent of rebuke. Rallying instantly they regained their post without the loss of a man before the enemy had discovered their retreat; and the appearance of Stanhope with the reserve presently banished all further idea of panic. Meanwhile the Spanish reinforcements from Barcelona had met the English prisoners, and learning from them that Peterborough and Prince George were present in person before Montjuich, assumed that the British were attacking in overwhelming force. They therefore returned to Barcelona, leaving the fort to its fate. Three days of bombardment sufficed to overcome the resistance of the weakened
  • 55. garrison; and thus by a singular chapter of accidents Peterborough's design proved to be a success, and Montjuich was taken. Sept. 28 October 9. The siege of Barcelona was then pushed forward in form, aided by the guns of the fleet; and on the 9th of October the garrison capitulated with the honours of war. A fortnight later King Charles the Third made his public entry into the city; Peterborough scattered dollars with a liberal hand, and all was merriment and rejoicing. The picture would not be complete without the figure of a drunken English grenadier, whose vagaries afforded inexhaustible amusement to the populace;[328] but Peterborough was a disciplinarian, and the troops as a whole behaved remarkably well. Stanhope was at once sent home with the good news, and England awoke to the fact that she possessed a second officer who, though not to be named in the same breath with Marlborough, possessed a natural, if eccentric, genius for war.
  • 56. To face page 462 BARCELONA 1705. The capture of Barcelona, and the subsequent reduction of Tarragona by the fleet, brought practically the whole of Catalonia to
  • 57. the side of King Charles. But now further operations were checked by lack of money and supplies. Peterborough, who saw the difficulty of supporting a large force in the field, was for dividing his little army into flying columns, and making good the deficiency of numbers by extreme mobility; but he could not gain acceptance for his views. He wrote piteous letters of his state of destitution, reviling, as his custom was, all his colleagues and subordinates with astonishing freedom. Very soon the troops in Barcelona became so sickly that he was compelled to distribute them in the fortresses of Catalonia, leaving further operations to the Catalan guerillas. By the exertions of these last the close of the year saw not only Catalonia but Valencia gained over, though on no very certain footing, to the side of King Charles. So ended the first serious campaign of the first Peninsular war.
  • 59. C H A P T E R V 1706. It is now time to revert to England and to the preparations for the campaign of 1706. Marlborough, as usual, directly that the military operations were concluded, had been deputed to visit the courts of Vienna and of sundry German states in order to keep the Allies up to the necessary pitch of unity and energy. These duties detained him in Germany and at the Hague until January 1706, when he was at last able to return to England. There he met with far less obstruction than in former years, but none the less with an increasing burden of work. The vast extension of operations in the Peninsula, and the general sickliness of the troops in that quarter, demanded the enlistment of an usually large number of recruits. One new regiment of dragoons and eleven new battalions of foot were formed in the course of the spring, to which it was necessary to add yet another battalion before the close of the year.[329] Again the epidemic sickness among the horses in Flanders had caused an extraordinary demand for horses. The Dutch, after their wonted manner, had actually taken pains to prevent the supply of horses to the British, [330] though, even if they had not, the Duke had a prejudice in favour of English horses, as of English men, as superior to any other. Finally, the stores of the Ordnance were unequal to the constant drain of small arms, and it was necessary to make good the deficiency by purchases from abroad. All these difficulties and a thousand more were of course referred for solution to Marlborough. April 14 25 . When in April he crossed once more to the Hague he found a most discouraging state of affairs. The Dutch were backward in their preparations; Prussia and Hanover were recalcitrant over the furnishing of their contingents; Prince Lewis of Baden was sulking
  • 60. within his lines, refusing to communicate a word of his intentions to any one; and everybody was ready with a separate plan of campaign. The Emperor of course desired further operations in the Moselle for his own relief; but after the experience of the last campaign the Duke had wisely resolved never again to move eastward to co-operate with the forces of the Empire. The Dutch for their part wished to keep Marlborough in Flanders, where he should be under the control of their deputies; but the imbecile caprice of these worthies was little more to his taste than the sullen jealousy of Baden. Marlborough himself was anxious to lead a force to the help of Eugene in Italy, a scheme which, if executed, would have carried the British to a great fighting ground with which they are unfamiliar, the plains of Lombardy. He had almost persuaded the States-General to approve of this plan, when all was changed by Marshal Villars, who surprised Prince Lewis of Baden in his lines on the Motter, and captured two important magazines. The Dutch at once took fright and, in their anxiety to keep Marlborough for their own defence, agreed to appoint deputies who should receive rather than issue orders. So to the Duke's great disappointment it was settled that the main theatre of war should once again be Flanders. May 8 19 . May 9 20 . May 11 22 . Villeroy meanwhile lay safely entrenched in his position of the preceding year behind the Dyle, from which Marlborough saw little hope of enticing him. It is said that an agent was employed to rouse Villeroy by telling him that the Duke, knowing that the French were afraid to leave their entrenchments, would take advantage of their inaction to capture Namur.[331] Be that as it may, Villeroy resolved to quit the Dyle. He knew that the Prussian and Hanoverian contingents had not yet joined Marlborough, and that the Danish cavalry had refused to march to him until their wages were paid; so
  • 61. that interest as well as injured pride prompted the hazard of a general action. On the 19th of May, therefore, he left his lines for Tirlemont on the Great Geete. Marlborough, who was at Maestricht, saw with delight that the end, for which he had not dared to hope, was accomplished. Hastily making arrangements for the payment of the Danish troops, he concentrated the Dutch and British at Bilsen on the Upper Demer, and moved southward to Borchloen. Here the arrival of the Danes raised his total force to sixty thousand men, a number but little inferior to that of the enemy. On the very same day came the intelligence that Villeroy had crossed the Great Geete and was moving on Judoigne. The Duke resolved to advance forthwith and attack him there. May 12 23 . At one o'clock in the morning, of Whitsunday the 23rd of May, Quartermaster-General Cadogan rode forward from the headquarters at Corswarem with six hundred horse and the camp-colours towards the head of the Great Geete, to mark out a camp by the village of Ramillies. The morning was wet and foggy, and it was not until eight o'clock that, on ascending the heights of Merdorp, they dimly descried troops in motion on the rolling ground before them. The allied army had not marched until two hours later than Cadogan, but Marlborough, who had ridden on in advance of it, presently came up and pushed the cavalry forward through the mist. Then at ten o'clock the clouds rolled away, revealing the whole of the French army in full march towards them. Villeroy's eyes were rudely opened, for he had not expected Marlborough before the following day; but he knew the ground well, for he had been over it before with Luxemburg, and he proceeded to take up a position which he had seen Luxemburg deliberately reject. The table-land whereon he stood is the highest point in the plains of Brabant. To his right flowed the Mehaigne; in his rear ran the Great Geete; across his centre and left the Little Geete rose and crept away sluggishly in marsh and swamp.[332] In his front lay four
  • 62. villages: Taviers on the Mehaigne to his right, Ramillies, less advanced than Taviers, on the source of the Little Geete to his right centre, Offus parallel to Ramillies but lower down the stream to his left centre, Autréglise or Anderkirch between two branches of the Little Geete and parallel to Taviers to his left. Along the concave line formed by these villages Villeroy drew up his army in two lines facing due east. The Mehaigne, on which his right rested, is at ordinary times a rapid stream little more than twelve feet wide, with a muddy bottom, but is bordered by swampy meadows on both sides, which are flooded after heavy rain. From this stream the ground rises northward in a steady wave for about half a mile, sinks gradually and rises into a higher wave at Ramillies, sinks once more to northward of that village and rolls downward in a gentler undulation to Autréglise. Between the Mehaigne and Ramillies, a distance of about a mile and a half, the ground east and west is broken by sundry hollows of sufficient inclination to offer decided advantage or disadvantage in a combat of cavalry. A single high knoll rises in the midst of these hollows, offering a place of vantage from which Marlborough must almost certainly have reconnoitred the disposition of the French right. The access to Ramillies itself is steep and broken both to north and south, but on the eastern front the ground rises to it for half a mile in a gentle, unbroken slope, which modern rifles would make impassable by the bravest troops. In rear, or to westward of the French position, the table-land is clear and unbroken, and to the right rear or south-west stands a mound or barrow called the tomb of Ottomond, still conspicuous and still valuable as a key to the actions of the day.[333] The full extent of the French front from Taviers to Autréglise covered something over four miles. Having chosen his position, Villeroy lost no time in setting his troops in order. His left, consisting of infantry backed by cavalry,[334] extended from Autréglise to Offus, both of which villages were strongly occupied. His centre from Offus to Ramillies was likewise
  • 63. composed of infantry. On his right, in the expanse of sound ground which stretches for a mile and a half from the marshes of the Geete at Ramillies to those of the Mehaigne, were massed more than one hundred and twenty squadrons of cavalry with some battalions of infantry interlined with them, the famous French Household Cavalry (Maison du Roi), being in the first line. The left flank of this expanse was covered by the village of Ramillies, which was surrounded by a ditch and defended by twenty battalions and twenty-four guns. On the right flank not only Taviers but Franquinay, a village still further in advance, were occupied by detachments of infantry, while Taviers was further defended by cannon. Marlborough quickly perceived the defects of Villeroy's dispositions, which were not unlike those of Tallard at Blenheim. Taviers was too remote from Ramillies for the maintenance of a cross-fire of artillery. Again, the cavalry of the French left was doubtless secure against attack behind the marshes of the Geete, but for this very reason it was incapable of aggressive action. The French right could therefore be turned, provided that it were not further reinforced; and accordingly the Duke opened his manœuvres by a demonstration against the French left. Presently the infantry of the allied right moved forward in two lines towards Offus and Autréglise, marching in all the pomp and circumstance of war, Dutch, Germans, and British, with the red coats conspicuous on the extreme right flank. Striding forward to the river they halted and seemed to be very busy in laying their pontoons. Villeroy marked the mass of scarlet, and remembering its usual place in the battlefield, instantly began to withdraw several battalions from his right and centre to his left. Marlborough watched the white coats streaming away to their new positions, and after a time ordered the infantry of his right to fall back to some heights in their rear. The two lines faced about and retired accordingly over the height until the first line was out of sight. Then the second line halted and faced about once more, crowning the ascent with the well-known scarlet, while the first marched away with all speed, under cover of the hill and unseen by the French, to the opposite flank. Many British
  • 64. battalions[335] stood on that height all day without moving a step or firing a shot, but none the less paralysing the French left wing. About half-past one the guns of both armies opened fire, and shortly afterwards four Dutch battalions were ordered forward to carry Franquinay and Taviers, and twelve more to attack Ramillies, while Overkirk advanced slowly on the left with the cavalry. Franquinay was soon cleared; Taviers resisted stoutly for a time but was carried, and a strong reinforcement on its way to the village was intercepted and cut to pieces. Then Overkirk, his left flank being now cleared, pushed forward his horse and charged. The Dutch routed the first French line, but were driven back in confusion by the second; and the victorious French were only checked by the advance of fresh squadrons under Marlborough himself. Even so the Allies were at a decided disadvantage; and Marlborough, after despatching messengers to bring up every squadron, except the British, to the left, plunged into the thick of the melée to rally the broken horse. He was recognised by some French dragoons, who left their ranks to surround him, and in the general confusion he was borne to the ground and in imminent danger of capture. His aide-de-camp, Captain Molesworth, dismounted at once, and giving him his own horse enabled him to escape. The cavalry, however, encouraged by the Duke's example, recovered themselves, and Marlborough took the opportunity to shift from Molesworth's horse to his own. Colonel Bringfield, his equerry, held the stirrup while he mounted, but Marlborough was hardly in the saddle before the hand that held the stirrup relaxed its hold, and the equerry fell to the ground, his head carried away by a round shot.[336] Meanwhile the attack of the infantry on Ramillies was fully developed, and relieved the horse from the fire of the village. Twenty fresh squadrons came galloping up at the top of their speed and ranged themselves in rear of the reforming lines. But before they could come into action the Duke of Würtemberg pushed his Danish horse along the Mehaigne upon the right flank of the French, and the Dutch guards advancing still further fell upon their rear.
  • 65. These now emerged upon the table-land by the tomb of Ottomond, and the rest of the Allied horse dashed themselves once against the French front. The famous Maison du Roi after a hard fight was cut to pieces, and the whole of the French horse, despite Villeroy's efforts to stay them, were driven in headlong flight across the rear of their line of battle, leaving the battalions of infantry helpless and alone to be ridden over and trampled out of existence. Villeroy made frantic efforts to bring forward the cavalry of his left to cover their retreat, but the ground was encumbered by his baggage, which he had carelessly posted too close in his rear. The French troops in Ramillies now gave way, and Marlborough ordered the whole of the infantry that was massed before the village to advance across the morass upon Offus, with the Third and Sixth Dragoon Guards in support. The French broke and fled at their approach; and meanwhile the Buffs and Twenty-first, which had so far remained inactive on the right, forced their way through the swamps before them, and taking Autréglise in rear swept away the last vestige of the French line on the left. Five British squadrons followed them up and captured the entire King's Regiment (Regiment du Roi). The Third and Sixth Dragoon Guards also pressed on, and coming upon the Spanish and Bavarian horse- guards, who were striving to cover the retreat of the French artillery, charged them and swept them away, only narrowly missing the capture of the Elector himself, who was at their head.[337] On this the whole French army, which so far had struggled to effect an orderly retreat, broke up in panic and fled in all directions. The mass of the fugitives made for Judoigne, but the ways were blocked by broken-down baggage-waggons and abandoned guns, and the crush and confusion was appalling. The British cavalry, being quite fresh, quickly took up the pursuit over the table-land. The guns and baggage fell an easy prey, but these were left to others, while the red-coated troopers, not without memories of Landen, pressed on, like hounds running for blood, after the beaten enemy. The chase lay northwards to Judoigne and beyond it towards the refuge
  • 66. of Louvain. Not until two o'clock in the morning did the cavalry pause, having by that time reached Meldert, fifteen miles from the battlefield; nay, even then Lord Orkney with some few squadrons spurred on to Louvain itself, rekindled the panic and set the unhappy French once more in flight across the Dyle. May 13 24 . May 14 25 . May 15 26 . May 16 27 . Nor was the main army far behind the horse. Marching far into the night, the men slept under arms for two or three hours, started again at three o'clock, and before the next noon had also reached Meldert and were preparing to force the passage of the Dyle. Marlborough, who had been in the saddle with little intermission for nearly twenty-eight hours, here wrote to the Queen that he intended to march again that same night, but, through the desertion of the lines of the Dyle by the French, the army gained some respite. The next day he crossed the Dyle at Louvain and encamped at Betlehem, the next he advanced to Dieghem, a few miles north of Brussels, the next he passed the Senne at Vilvorde and encamped at Grimberghen, and here at last, after six days of incessant marching, the Duke granted his weary troops a halt, while the French, hopelessly beaten and demoralised, retired with all haste to Ghent.
  • 67. To face page 472 RAMILLIES May 12th " 23rd 1706. So ended the fight and pursuit of Ramillies, which effectually disposed of the taunt levelled at Marlborough after Blenheim, that he did not know how to improve a victory. The loss of the French in killed, wounded, and prisoners was thirteen thousand men, swelled by desertion during the pursuit to full two thousand more. The trophies of the victors were eighty standards and colours, fifty guns, and a vast quantity of baggage. The loss of the Allies was from four to five thousand killed and wounded, which fell almost entirely on the Dutch and Danes, the British, owing to their position on the extreme right, being but little engaged until the close of the day. The chief service of the British, therefore, was rendered in the pursuit, which they carried forward with relentless thoroughness and vigour. The Dutch were delighted that their troops should have done the heaviest of the work in such an action, and the British could console
  • 68. themselves with the performance of their cavalry, and above all, with the reflection that the whole of the success was due to their incomparable chief. May-June. The effect of the victory and of the rapid advance that followed it was instantaneous. Louvain and the whole line of Dyle fell into Marlborough's hands on the day after the battle; Brussels, Malines, and Lierre surrendered before the first halt, and gave him the line of the Senne and the key of the French entrenchments about Antwerp; and one day later, the surrender of Alost delivered to him one of the strongholds on the Dender. Never pausing for a moment, he sent forward a party to lay bridges on the Scheldt below Oudenarde in order to cut off the French retreat into France, a movement which obliged Villeroy forthwith to abandon the lines about Ghent and to retire up the Lys to Courtrai. Ghent, Bruges, and Damme thereupon surrendered on the spot; Oudenarde followed them, and after a few days Antwerp itself. Thus within a fortnight after the victory the whole of Flanders and Brabant, with the exception of Dendermond and one or two places of minor importance, had succumbed to the Allies, and the French had fallen back to their own frontier. June. Nor was even this all. A contribution of two million livres levied in French Flanders brought home to the Grand Monarch that the war was now knocking at his own gates. Villars, with the greater part of his army, was recalled from the Rhine to the Lys, and a number of French troops were withdrawn to the same quarter from Italy. Baden had thus the game in his own hand on the Rhine, and though he was too sulky and incapable to turn the advantage to account, yet his inaction was no fault of Marlborough's. We are hardly surprised to find that in the middle of this fortnight the Duke made urgent request for fresh stores of champagne; he may well have needed the stimulant amid such pressure of work and fatigue.[338]
  • 69. June 6 17 . He now detached Overkirk to besiege Ostend and another party to blockade Dendermond, at the same time sending off five British battalions, which we shall presently meet again, for a descent on the Charente which was then contemplated in England. This done he took post with the rest of the Army at Rouslers, to westward of the Lys, whence he could at once cover the siege of Ostend and menace Menin and Ypres. The operations at Ostend were delayed for some time through want of artillery and the necessity of waiting for the co-operation of the Fleet; but the trenches were finally opened on the 17th of June, and a few weeks later the town surrendered. June 27 July 8. Aug. 11 22 . Three days after this the army was reassembled for the siege of Menin. This fortress was of peculiar strength, being esteemed one of Vauban's masterpieces, and was garrisoned by five thousand men. Moreover, the French, being in command of the upper sluices of the Lys, were able greatly to impede the operations by cutting off the water from the lower stream, and thus rendering it less useful for purposes of transport. But all this availed it little; for three weeks after the opening of the trenches Menin surrendered. The British battalions[339] which had been kept inactive at Ramillies took a leading share in the work, and some of them suffered very heavily, but had the satisfaction of recapturing four of the British guns that had been taken at Landen. Aug. 25 Sept. 5. Sept. 12 23 . Sept. 21 Oct. 2.
  • 70. A few days later Dendermond was attacked in earnest and was likewise taken, after which Marlborough fell back across the Scheldt to secure the whole line of the Dender by the capture of Ath. Ten days sufficed for the work, after which Ath also fell into the hands of the Allies. The apathy of the French throughout these operations sufficiently show their discouragement. Owing to the supineness of Prince Lewis of Baden Villars had been able to bring up thirty-five thousand men to the assistance of Marshal Vendôme, who had now superseded Villeroy, but even with this reinforcement the two commanders only looked on helplessly while Marlborough reduced fortress after fortress before their eyes. They were, indeed, more anxious to strengthen the defences of Mons and Charleroi, lest the Duke should break into France by that line, than to approach him in the field. Nor were they not wholly unreasonable in their anxiety, for Marlborough's next move was upon the Sambre; but incessant rain and tempestuous weather forbade any further operations, so that Ath proved to be the last conquest of the year. Thus ended the campaign of Ramillies, one of the most brilliant in the annals of war, wherein Marlborough in a single month carried his arms triumphant from the Meuse to the sea.
  • 72. C H A P T E R V I 1706. From Flanders it is necessary to return to the Peninsula, where we left Peterborough bewailing his enforced inaction. Nothing is more remarkable in the story of these Peninsular campaigns than the utter want of unity in design between the forces of the Allies in Catalonia and in Portugal. Even in England the British troops in these two quarters were treated, for purposes of administration, as two distinct establishments, which might have been divided by the whole breadth of the Atlantic instead of by twice the breadth of England. Yet the fault could hardly be attributed to any English functionary, civil or military. Galway was as anxious as Peterborough to advance to Madrid; but the Portuguese were terrified at the prospect of moving far from their frontier, while the eyes of King Charles ever rested anxiously on the passes by which French reinforcements might advance into Catalonia. In such circumstances it was not easy to accomplish an effective campaign. Dec. 26, 1705. Jan. 6, 1706. The Spaniards of the Austrian party, as has been told, had by the winter of 1705 gained a precarious hold on the whole province of Valencia. Just before the close of the year came intelligence that the Spanish General de las Torres had crossed the northern frontier from Arragon into Valencia and had laid siege to San Mateo. The town was important, inasmuch as it commanded the communications between Catalonia and Valencia, but it was held by no stronger garrison than thirty of the Royal Dragoons and a thousand Spanish irregular infantry under Colonel Jones. This officer defended himself as well as he could, but at once begged urgently
  • 73. for reinforcements. King Charles thereupon appealed for help to Peterborough, who forthwith ordered General Killigrew to march with his garrison from Tortosa and cross the Ebro, while he himself, riding night and day from Barcelona, caught up the column at the close of the first day's march. King Charles had represented the force of Las Torres as but two thousand strong, and had added that thousands of peasants were up in arms against it. Peterborough now discovered that the Spaniards numbered four thousand foot and three thousand horse, while the thousands of armed peasantry were wholly imaginary. His own force consisted of three weak British battalions, the Thirteenth, Thirty-fifth, and Mountjoy's Foot, together with one hundred and seventy of the Royal Dragoons, in all thirteen hundred men. With such a handful his only hope of success must lie in stratagem. Dec. 28, 1705. Jan. 8, 1706. Advancing southward with all speed he split up his minute army into a number of small detachments, and pushing them forward by different routes arrived early in the morning, unseen and unsuspected, at Traguera, within six miles of the enemy's camp. That same day a spy was captured by the enemy and brought before Las Torres. On him was found a letter from Peterborough to Colonel Jones, written in the frankest and easiest style. "I am at Traguera," so it ran in effect, "with six thousand men and artillery. You may wonder how I collected them; but for transport and secrecy nothing equals the sea. Now, be ready to pursue Las Torres over the plain. It is his only line of retreat, for I have occupied all the passes over the hills. You will see us on the hill-tops between nine and ten. Prove yourself a true dragoon, and have your miquelets (irregulars) ready for their favourite plunder and chase." The spy, being threatened with death, offered to betray another messenger of Peterborough's who was lying concealed in the hills. This second spy was captured, and a duplicate of the same letter was found on him.