mESI (minimal Edge Side Includes) is a lightweight implementation of Edge Side Includes (ESI) in Golang, designed to add ESI support to multiple web servers. It provides basic but correct handling of the following ESI instructions:
<esi:include>
– dynamic content inclusion,<esi:remove>
– removal of specified sections,<esi:comment>
– comments invisible to the end user,<!--esi ... -->
– inline ESI processing.
- Parallel Fetching – Unlike many other ESI implementations, mESI supports parallel fetching of ESI fragments, improving response times for dynamic content.
- Lightweight & Minimal – Focuses on essential ESI features while remaining easy to integrate and extend.
- Multi-Server Support – Can be integrated with various web servers to enhance content delivery performance.
- A/B testing - Set
fetch-mode="ab"
to easily compare the effectiveness of two versions of content to see which one appeals more to people visiting web pages / viewing specific information. - Concurrent fetch - You need ultra performance - set
fetch-mode="concurrent"
to always fetch content from the fastest source. - esi:include timeout - Timeout can be set both globally and specifically for a selected
esi:include
tag. In combination with fallback content, you can easily manage the page generation time. - Fallback content - Set the content to be displayed if remote content download fails.
This document describes the configuration structure for the mESI parser.
The parser configuration is defined using the following structure:
type EsiParserConfig struct {
DefaultUrl string
MaxDepth uint
Timeout time.Duration
ParseOnHeader bool
}
DefaultUrl
Base URL that will be used as a prefix for relative URL paths. If the provided URL in ESI tags doesn't start with "http://" or "https://", this base URL will be prepended to paths starting with "/".
MaxDepth
Defines the maximum allowed recursion depth for esi:include tags. This parameter prevents infinite loops that could occur when ESI templates reference each other.
The recursion count value can be lowered for a selected esi:include
tag using the max-depth
attribute:
<esi:include max-depth="1" src="http://foo.bar/recursive"/>
Timeout
Specifies the maximum time to wait for a server response when processing esi:include tags. The request will be terminated if this timeout is exceeded.
Timeout can also be defined independently in the esi:include
tag. The timeout attribute value is given in seconds.
Decimal values can be given, the decimal separator is a dot, e.g. 1.2
<esi:include timeout="0.2" src="http://foo.bar/some-long request" />
NOTE:
- If the
alt
attribute is provided and first request fails the time budget will be split between both requests. - In case of recursion, the timeout value is reduced by the time it took to execute the previous step.
- When a timeout value is set in both
EsiParserConfig
andesi:include
, the smaller value will be chosen.
ParseOnHeader
If set to true, then server responses will process ESI tags only when the response contains the Edge-control: dca=esi
header
fetch-mode - esi:include
tag only
Allows you to choose between three content download modes:
- fallback - default way to download content. In case of an error downloading from the first location (
src
attribute), the content will be downloaded from an alternative address (alt
attribute). Thealt
attribute is not mandatory. This mode is selected if thefetch-mode
attribute is missing. - ab - Allows to download with different probability from two different locations src and alt. In case of no alt attribute, the src location will always be downloaded.
The proportions of A and B are specified using the
ab-ratio
attribute, and it has the form X:Y where X and Y are positive integers. In case of no attribute or an incorrect value, the default proportion is 50:50. - concurrent - both locations are fetched at the same time, but the result is returned from the fastest location. If the alt attribute is missing, the same location will be called twice.
ab-ratio - esi:include
tag only
Used only when fetching data when fetch-mode
is set to ab
. Specifies the proportion of fetches from src
to alt
.
Given in the form X:Y
, where X
and Y
are non-negative integers.
For example, a value of 90:10
specifies that 10%
of all queries will be fetched from alt
source.
In case of no attribute ab-ratio
or an incorrect value, the default proportion is 50:50
.
If missing alt
attribute, src
will be always used.
<esi:include fetch-mode="ab" ab-ratio="90:10" src="http://foo.bar/A" alt="http://foo.bar/B" />]
I this case B
will be fetched 10% of the time.
By default, the esi:include
tag does not contain a body. mESI allows you to set the so-called fallback content,
or the content that will be displayed in case the download of remote content fails. Example:
<esi:include src="https://foo.bar/bad-url">
Failed to load remote content
</esi:include>
A fallback will be displayed both when we get an error in the server response or when the response time is too long.
In combination with the timeout
attribute, we can easily manage the page generation time. For example, if 250ms
is exceeded,
we can download this code fragment using FetchAPI or htmlx
<esi:include timeout="0.25" src="https://foo.bar/can-be-slow">
<div hx-trigger="load" hx-swap="outerHTML" hx-get="https://foo.bar/can-be-slow"></div>
</esi:include>
✅ Initial Implementation – Basic support for ESI processing.
🔄 Upcoming Integrations:
- Plugin for Traefik - See Installation and configuration
- Plugin for RoadRunner - See Installation and configuration
- PHP extension - See Installation and configuration
- Plugin for Nginx - See Installation and configuration
- Plugin for Caddy - See Installation and configuration
- Plugin for FrankenPHP - See Installation and configuration
- CLI - for testing
- Plugin for Apache (if possible)
- Standalone proxy server - for testing
🔄 Performance & Scalability:
- Implement include path without host
- Add timeout parameter for ESI requests
- Option to parse esi only when
Edge-control: dca=esi
header - Add work modes:
- Fallback
- A/B testing with ratio
- Concurrent fetching
- Add max concurrent request limit
- Implement worker pool for optimized request handling
- Debug mode - add a lot of debug messages
🔄 Caching Enhancements:
- Add in memory cache
- Add cache key option
- Add Redis cache support
- Add Memcached cache support
To run E2E test just type make test-e2e
🚀 Looking for contributors! If you are interested in helping with development, feel free to submit PRs or open issues.