replace-tag: Dynamically load content based on device capabilities
Bryan Ollendyke
Posted on February 17, 2021
I had an idea the other day that quickly consumed me; The magic script (see series) is great for developer workflow and integration is simple, but it seems like it could be even more performant. I was reading a blog post about the idea of querying a phone for it's connection speed and went down the rabbit hole to this idea: combining the two.
Video version
What replace-tag looks like
<replace-tag with="meme-maker"
top-text="Web components"
bottom-text="Its the platform"
image-url="https://media2.giphy.com/media/3cB7aOM6347PW/giphy.gif"
></replace-tag>
replace-tag
works with the wc-registry.json
file produced in the unbundled-webcomponents build routine.
Decision tree
replace-tag has the following checks in place:
- Am I visible? NOW you can import my definition, then replace the replace-tag with whatever is listed in
with=""
- If I have the
import-only
attribute, thenimport()
and - Am I a low performance device? If
import-method="view"
then still activate based on visibility; otherwise, don't import and replace until the user specifically clicks me to do so.
What is a low performance device?
By our definition, it's any of the following being true:
- Less than 1 gig of memory
- Less than 4 core processor
- 2g or 3g connection speed
- user saying they want to save data
- user's device having less than 25% power
Here's the cool block of code where we're able to do these detections using a series of navigator
calls - PerformanceDetect.js with this specific block:
async updateDetails() {
let details = {
lowMemory: false,
lowProcessor: false,
lowBattery: false,
poorConnection: false,
dataSaver: false,
};
if (navigator) {
// if less than a gig we know its bad
if (navigator.deviceMemory && navigator.deviceMemory < 1) {
details.lowMemory = true;
}
// even phones have multi-core processors so another sign
if (navigator.hardwareConcurrency && navigator.hardwareConcurrency < 2) {
details.lowProcessor = true;
}
// some platforms support getting the battery status
if (navigator.getBattery) {
navigator.getBattery().then(function (battery) {
// if we are not charging AND we have under 25% be kind
if (!battery.charging && battery.level < 0.25) {
details.lowBattery = true;
}
});
}
// some things report the "type" of internet connection speed
// for terrible connections lets save frustration
if (
navigator.connection &&
navigator.connection.effectiveType &&
["slow-2g", "2g", "3g"].includes(navigator.connection.effectiveType)
) {
details.poorConnection = true;
}
// see if they said "hey, save me data"
if (navigator.connection && navigator.connection.saveData) {
details.dataSaver = true;
}
}
return details;
}
This function has to be async
because getBattery()
(which is not in all platforms) is a Promise()
.
Posted on February 17, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.