Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a conditional capability based loader capability #48

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

adamsilverstein
Copy link

Hi @chase-moskal I was working on testing capability based conditional loading for webp-hero and found you were already considering adding something directly (#42 (comment)). So I decided to try and contribute that capability to your project (thanks for the amazing work by the way!)

I worked up this PR as a proof of concept and have some questions:

  • you said "i'm not sure how to find the script src url of the bundle locally" - do you mean the URL's of the bundle/polyfill? currently I am assuming these load from the CDN, the idea being you would enqueue just the conditionally script (from the CDN) and it would enqueue the others
  • what about instead of immediately executing, we export a function like conditionallyLoadWebpHero that accepts the URLs for the bundle/polyfill and loads them if needed (using the cdn urls by default)?

Related question: why are two scripts used, could this be built as a single script? Asking in part because dynamically adding two scripts is messy!

Copy link
Owner

@chase-moskal chase-moskal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hello, i greatly appreciate your contribution and interest.

before we merge this, i'm going to ramble a little bit, so that hopefully we can share in some considerations. if you land on a solution that you are happy with, and that addresses the specific concerns in the other comments i've left, i'll be willing to merge your pull request.

oh, and one thing:
➡️ we should add a bit to the readme, explaining to users how to use this conditional installation pathway.

as you mentioned:

what about instead of immediately executing, we export a function like conditionallyLoadWebpHero

that might be a good strategy.

maybe, users of webp-hero could install a conditional-loading setup, based on the following example:

import {detectWebpSupport, loadScript} from "webp-hero/dist-cjs/conditionally.js"

const webpBundleUrl = "/node_modules/webp-hero/dist-cjs/webp-hero.bundle.js"

void async function main() {
  const webpSupported = await detectWebpSupport()
  if (webpSupported) {
    await loadScript(webpBundleUrl)
    const webpMachine = new webpHero.WebpMachine()
    await webpMachine.polyfillDocument()
  }
}()

in the above case, conditionally.ts would merely need to re-export detectWebpSupport and a new loadScript.

the downsides of the above example:

  • the url has to be hardcoded. hard to find a workaround for that.
  • this doesn't include a plan for a simple html-only installation (only esm/commonjs).
  • (like the rest of webp-hero's recommended installation pathways) it's a little clunky needing to include a block of javascript rather than just a simple script tag.

perhaps another way to think of this, would be to think of the ideal user experience, installing this via html-only

<script
  defer
  data-webp-hero
  src="https://unpkg.com/[email protected]/dist-cjs/conditionally.bundle.js"
></script>

i suppose the script could query for itself in the dom, find the src, do some regex-magic to find the appropriate url to the webp-hero.bundle.js.

i don't know. these are just some ideas.

lately, i'm not entirely satisfied with webp-hero, and have been thinking of a serious refactor to improve it's simplicity and ease-of-use (hopefully without any breaking changes) -- but i don't have the time to do so now, and probably not for awhile.

don't mean to be nit-picking -- if we can land on a solution that works for you, and that others like, we can certainly include it.

source/conditionally.ts Outdated Show resolved Hide resolved
document.body.appendChild(js)
js.addEventListener('load', function() {
var js2 = document.createElement('script');
js2.src = 'https://unpkg.com/[email protected]/dist-cjs/webp-hero.bundle.js';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think we want to hardcode this, neither to the unpkg cdn, nor to 0.0.2 — we need a different strategy.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder could the default url just be relative the the current document? eg src='./webp-hero-bundle.js'? Could be overridable by setting a variable before loading.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, that probably won't work actually because it would be relative to the HTML document. Maybe back to your regex idea, or even a simple split off of the last "/". I'll try that.

source/index.ts Outdated Show resolved Hide resolved
isWebpSupported(function(support) {
if (! support) {
var js = document.createElement('script');
js.src = 'https://unpkg.com/[email protected]/dist-cjs/polyfills.js';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should leave polyfills outside the specific scope of the conditionally script -- because an application author will want to avoid double-loading polyfills, and they may want to take responsibility to load their own polyfills for the rest of their application (and not use webp-hero's provided polyfills at all)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i still don't understand what the polyfills do exactly vs the bundle :(, is that documented somewhere? So are you saying we can leave off the polyfill loading here entirely?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamsilverstein sorry about the late reply,

yes, we should probably not engage in loading any polyfills via the conditionally script.

  • the polyfills include one for Promise, and another for Array
  • the inclusion of polyfills should be deferred to the author of the html page, who may decide to include their own polyfills for the other parts of their application, so we want to leave it in their hands (to avoid double-loading any polyfills)

document.body.appendChild(js2);
js2.addEventListener('load', function() {
var webpMachine = new webpHero.WebpMachine();
webpMachine.polyfillDocument();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the rest of the webp-hero installation techniques insist on the user having the flexibility to control the webpMachine as they see fit -- whereas this conditionally makes the hardcoded assumption that the user wants to call polyfillDocument -- surely most do, but some may want to use conditionally while also using the webpMachine differently 🤷‍♂️

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my goal here was to create a simple way for site to load a single script (ideally from a CDN) that would test for the capability, then load webp-hero and polyfill the document if needed. essentially all sites would need to do is include this single script to get performant webp support.

I will rework this with the async "loadScript" helper you suggested (in a separate file) - that way developers could build their own controlled load like your code sample, or they could include this single conditionally file from a cdn to get automatic compatibility.

@adamsilverstein
Copy link
Author

❤️ Thanks for the feedback and thoughts @chase-moskal - I'll work through these soon.

@adamsilverstein
Copy link
Author

➡️ we should add a bit to the readme, explaining to users how to use this conditional installation pathway.

Sure, happy to take a pass at the readme update.

the url has to be hardcoded. hard to find a workaround for that.

In the context of a CMS like WordPress the URL could actually be dynamic, eg. the script could easily be served from the origin domain.

i suppose the script could query for itself in the dom, find the src, do some regex-magic to find the appropriate url to the webp-hero.bundle.js.

I feel like having a way to set or pass the urls(s) is more flexible for developers who may want to serve the scripts from specific locations (for example building the detection into the site bundle, but loading the scripts from the CDN when needed).

this doesn't include a plan for a simple html-only installation (only esm/commonjs).

Right, for the simplest use case, maybe it makes sense to have a single script to enqueue that automatically runs the check and loads and runs webp-hero automatically. This would be a single drop in script with built in capability checking. We can still export the functions so developers could build their own implementations.

I'll review the code feedback next and work on iterating my patch.

@adamsilverstein
Copy link
Author

Thanks again for the code feedback and tips @chase-moskal - very helpful; I'll post an updated PR soon.

Appreciate any help understanding this (probably basic) question - #48 (comment)

@chase-moskal
Copy link
Owner

thanks @adamsilverstein

this will become the new official and recommended way to load webp-hero!

please give me some time this week to play with it, and i'll get it merged soon 👍

i'll take it from here, thanks for your great contribution ❤️

@chase-moskal
Copy link
Owner

hello @adamsilverstein

if you have the time, can you please review my changes that i'm thining about making on your branch?

please review this PR adamsilverstein#1

i guess it's weird to launch a PR onto another PR branch -- but, i also thought it's weird to push on somebody else's branch -- in retrospect i think i managed to pick the weirdest most-complicated option, and i think i regret it 🤷‍♂️

let me know what you think of the code!

🍻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants