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

Use live feature detection instead of being based on User-Agent #111

Open
simevidas opened this issue Sep 11, 2014 · 18 comments

Comments

Projects
None yet
10 participants
@simevidas
Copy link

commented Sep 11, 2014

I would like to have this process:

  1. I define which APIs (from your polyfills directory) I want to have polyfilled.
  2. In my web pages, live feature detection is performed in the browser for those APIs, a custom //cdn.polyfill.io/v1/polyfill.min.js?features= <auto generated> &ua=false&gated=1 URL is generated (tailored to the browser and with ua disabled) and the corresponding bundle is requested and inserted into the page.

Beside having feature detection, another advantage of this approach is that it enables defining a set of APIs which are all already available in modern browsers (e.g. Chrome, Firefox), in which case Step 2 from above generates an empty "features" list, so nothing has to be requested (= we save the HTTP request completely for those browsers).

How this could work:

  1. The feature detection code (Step 2) would be auto-generated from the list (Step 1) and inlined in the website's pages. This could be performed via a (Grunt & co.) task.
  2. This code would then request the polyfill bundle by document.write()-ing a <script> onto the page (needed to perform a sync request).

Do my thoughts make sense? :)

@triblondon

This comment has been minimized.

Copy link

commented Sep 11, 2014

Makes sense, and we're not opposed to this at all. The main sticking point is that there are often multiple polyfills for the same feature, and the correct one is selected based on your UA, so it's not just whether you have the feature or not. For example, Element.prototype.matches is available prefixed in a big range of Firefox, so in those browsers we serve a one-line polyfill that assigns the prefixed property to the non-prefixed one. In other browsers that have no implementation at all, we serve the full polyfill.

So, if you prevent UA based logic and you demand a particular polyfill, we end up serving all the variants. See Financial-Times/polyfill-service#59 (comment) for a more detailed discussion of this problem.

@jdalton

This comment has been minimized.

Copy link

commented Sep 12, 2014

@triblondon triblondon changed the title Could you explain how this service can be used in conjunction with live feature detection instead of being based on User-Agent? Use live feature detection instead of being based on User-Agent Sep 15, 2014

@jonathantneal

This comment has been minimized.

Copy link

commented Nov 22, 2014

@triblondon, this is now possible with the latest release of the service, correct?

@triblondon

This comment has been minimized.

Copy link

commented Nov 22, 2014

Not that I can see! No, we still have the variants problem to address, and I think that's the biggest hurdle to making client side feature detection an option. If that were solved then it's just a matter of creating a generator to produce the inlineable code that tests and determines which polyfills to request.

@triblondon

This comment has been minimized.

Copy link

commented Aug 11, 2015

While we have variants, live feature detection is basically still a non starter. This is therefore blocked on #366.

@JakeChampion

This comment has been minimized.

Copy link
Contributor

commented Jan 31, 2016

We no longer have variants, meaning this is unblocked :-)

@tracker1

This comment has been minimized.

Copy link

commented Feb 1, 2016

Is the extra round-trip cost and delay worth the reduced bytes sent? This would have to be done synchronously and via a document.write(script-tag) in order to force evaluation and execution before other modules that rely on the polyfills.

Now, the detection script could be inlined into the page, and then document.write a script tag for the polyfills actually needed from the service. This would reduce the round trip, but delivering that detection script over a separate channel via src= may not actually be a savings in time to execute the page as a whole.

@triblondon

This comment has been minimized.

Copy link

commented Feb 5, 2016

This is a popular enough request that I think it should be done. Efforts to implement this are very welcome.

@mbrevda

This comment has been minimized.

Copy link

commented Nov 17, 2016

Perhaps this can be addressed in two steps:

  1. Add a UA-detection bypass option. This would force the server to load all requested polyfills without sniffing. While this puts the onus of testing on the dev, it also allows for greater flexibility and would have prevented issues like #988 from ever happening.
  2. Add a helper lib that can test for the requested polyfills and build a request at run time

The otherwise extra roundtrip can now be avoided, and unlike the current behaviour, even a single round trip is only necessary when using a browser that needs polyfills. This can lead to huge perf gains to evergreen browsers as the polyfill call, by definition, blocks all other scripts on the page.

Here is a naive implementation of what the helper lib might look like:

// helper for dynamicly adding scripts
var d = document,
    head = d.getElementsByTagName('head')[0],
    loadScript = function(src, cb){
        var script = d.createElement('script')
        script.src = src
        script.type = 'text/javascript'
        head.appendChild(script)
        if (cb) script.onload = cb
    }
// main polyfill helper
var polyLoader = function(cb, fills){
    // build a string of all fills to poly
    var list = Object.keys(fills).filter(function(fill){return !fills[fill]}).join(',')


    return !list // if there is nothing to polyfill
        ? cb() // just call the callback
        : loadScript( // otherwise, fill, and then execute the callback
            'https://cdn.polyfill.io/v2/polyfill.min.js?features=' + list,
            function() {cb()}
        )
}

// invoke
polyLoader({
    'Object.assign': Object.assign,
    'Array.from': Array.from,
    'fetch': 'fetch' in window,
    'Promise': 'Promise' in window,
    //etc...
}, function(){return loadScript(myScript)})

For those that don't care about perf or simply prefer the simplicity, an additional endpoint can be added to allow for two stage detection w/ a callback as in #841.

@triblondon

This comment has been minimized.

Copy link

commented Nov 17, 2016

@mbrevda the technique you describe is basically how we would do it, yes. The ability to force the server to ignore the UA is already present - just set flags=always (for perf reasons you'd also benefit from setting a hard coded UA in that case, eg flags=always&ua=chrome/50).

@mbrevda

This comment has been minimized.

Copy link

commented Nov 17, 2016

Ah cool. Im glad that feature detection wont require multiple round trips!

you'd also benefit from setting a hard coded UA

Can you expand on that?

@triblondon

This comment has been minimized.

Copy link

commented Jan 11, 2017

I've added a section to the docs describing some best practice loading strategies including feature-detection

https://polyfill.io/v2/docs/examples#feature-detection

@mauron85

This comment has been minimized.

Copy link

commented Mar 16, 2017

(for perf reasons you'd also benefit from setting a hard coded UA in that case, eg flags=always&ua=chrome/50).

I don't understand why setting ua with always flag has perf benefits. It just don't make sense, module should detect always flag and skip agent detection completely. It should be matter of one more if branch.

@JakeChampion

This comment has been minimized.

Copy link
Contributor

commented Mar 16, 2017

We vary the response based on user-agent (UA). If we only see the same UA for a specific polyfill bundle, we will serve the cached copy from our CDN (Fastly). If no ua query parameter is sent in the request, we will use the UA given to us by the browser, which will usually vary a lot for your user-base. If you set the ua query parameter, we will use that instead of the UA given by the browser.

TLDR: Setting the ua query parameter means that the request will nearly always be served a cached copy from our CDN, which is a faster request than one which needs to hit our origin servers.

@mauron85

This comment has been minimized.

Copy link

commented Mar 16, 2017

@JakeChampion so if I understand it correctly, setting ua to some common string means, request has higher chance to be handled by the CDN, which is faster than processing in node_js polyfill service. How does your CDN vary ua if it's not send as part of url? Does it read User-Agent HTTP request header?

EDIT: checked chrome dev tools and found probably answer:

screenshot 2017-03-16 23 24 33

If so, there must be dozen number of same User Agent anyway. So still don't understand where does this perf benefit comes from. And actually what happens if Chrome/50 will be very old? Will I have to change my hardcoded ua to Chrome/100? Or all those who hardcoded ua in their htmls, will keep CDN fresh? ;-)

@triblondon

This comment has been minimized.

Copy link

commented Mar 17, 2017

@mauron85 this is a workaround because our CDN layer does not understand or do anything with the always flag. If you are concerned about it, just omit the ua param, and your request will go through an unnecessary but probably almost instantaneous UA normalisation step. It's really not a big problem, and perhaps we should not mention this advice at all. If you want to continue to discuss can you move into a new issue, as this issue is supposed to be tracking the potential development of a built-in feature detection service.

@azu

This comment has been minimized.

Copy link

commented Feb 19, 2018

@rokoroku

This comment has been minimized.

Copy link

commented Sep 10, 2018

@JakeChampion JakeChampion self-assigned this Jan 23, 2019

@JakeChampion JakeChampion transferred this issue from Financial-Times/polyfill-service Feb 6, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.