Closed joepavitt closed 1 year ago
Currently knee deep in learning about Netlify's Edge Functions as Eleventy Edge (https://www.11ty.dev/docs/plugins/edge/) seems an option, although still trying to understand constraints.
Our biggest challenge is that we're generating static content via Eleventy, but need a dynamic variable for each user depending on the response from the PostHog Feature Flag API call https://posthog.com/manual/feature-flags
turns out we want "Experiments" in PostHog (https://posthog.com/manual/experimentation) not Feature Flags
Having played with this more, these are my findings:
{% edge %} content {% endedge %}
where you can then access cookies & query params directly inside the template.{% abtesting "flag", "control"%}
<h1 class="text-gray-50 max-w-lg m-auto">
DevOps for Node-RED
</h1>
{% endabtesting %}
{% abtesting "flag", "test"%}
<h1 class="text-gray-50 max-w-lg m-auto">
Run Node-RED in Production
</h1>
{% endabtesting %}
and then uses the PostHog Experiments call in the shortcode handler:
eleventyConfig.addPairedShortcode("abtesting", async function (content, flag, value) {
const fFlag = await posthog.getFeatureFlag('test-flag', 'joepavitt@flowforge.com')
console.log(fFlag)
if (fFlag === value) {
return `${content}`
} else {
return ''
}
})
From my understanding, we are now left with 3 options:
Just discovered that, whilst the Eleventy Edge Function documentation is terrible, the Netlify Edge Function documentation is much better and details all of the available Web APIs - including fetch
, so we could call an API directly, additionally, it details here about how we can actually use remotely served js libraries too
new investigation beginning.
Eleventy is so fiddly and tricky to work with. Following examples and best-guessing this to the best of my ability, but I just don't think this is possible for what we want to do.
Edge functions are very broken in Eleventy unfortunately. Work okay first time round, as long as you're just rendering raw content, then on refresh, they break. Really am swaying more and more towards option 3 here.
Seems as though I'm not the first to be having these issues with Eleventy: https://github.com/11ty/eleventy/issues/2585
okay, breakthrough... I have a working solution that just uses cookies and hardcoded option, but it toggles between content using an Edge Function to parse cookies.
To avoid the bug above, all of our Edge Functions must be written in liquid
instead of njk
.
I also have to list all of the cookies we plan on using with the Eleventy config, so we can't just add a new cookie for each feature, as such, I nest the feature flags inside a JSON object, and then encodeURIComponent()
and JSON.stringify()
that in order to store it. We reverse this process in the edge function with a toObj
filter.
End Result in the template .njk
files is something like this:
{% edge "liquid" %}
{% assign feats = eleventy.edge.cookies.feats | toObj %}
{% if feats.flagA == 'optionA' %}
Hello Option A
{% endif %}
{% if feats.flagA == 'optionB' %}
Hello Option B
{% endif %}
{% endedge %}
Now added
eleventyConfig.addGlobalData("feats", () => {
const encoded = context.cookies.get('feats')
const decoded = decodeURIComponent(encoded)
const feats = JSON.parse(decoded)
return feats
});
into our Eleventy Edge function which makes feat
a global property (sensible given we' can use it store all feature flags), and now reads as this in templates:
{% edge "liquid" %}
{% if feats.flagA == 'optionA' %}
Hello Option A
{% endif %}
{% if feats.flagA == 'optionB' %}
Hello Option B
{% endif %}
{% endedge %}
Our main constraint is the cookie size limit of 4kB. A very rough, back of paper calculation, I've estimated we can handle about 150-200 feature flags, which is never going to be an issue.
Thought I would try reverting back to using Eleventy Shortcodes within Edge Functions now that I wasn't using njk
edge functions, and it works:
{% edge "liquid" %}
{% abtesting "flagA", "optionA" %}
Hello Option A
{% endabtesting %}
{% abtesting "flagA", "optionB" %}
Hello Option B
{% endabtesting %}
{% endedge %}
I prefer this formatting as it makes it explicitly clear that it's A/B Testing taking place, and not easily confused with other if
conditionals we have within the website.
Latest updates - fully working end-to-end PoC is in place. Still to-do:
control
option shows if no flag or PostHog is found.https://answers.netlify.com/t/edge-functions-negate-endpoints-in-netlify-toml/88455
above link for me investigating the challenges around getting edge function to just run on html endpoints, and not for all images, css files, etc.
Story
No response
Description
A/B Testing in PostHog is known as "Feature Flags" - https://posthog.com/manual/feature-flags
Given we generate static content through Eleventy, we need to investigate what we can get away with and our our site would render the Feature Flags accordingly.
This task will be scoped to exploring the options, and testing out results in PostHog, to understand what the workflow looks like.