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

Closed
simevidas opened this issue Sep 11, 2014 · 19 comments
Closed

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

simevidas opened this issue Sep 11, 2014 · 19 comments
Assignees
Projects

Comments

@simevidas
Copy link

@simevidas simevidas 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
Copy link

@triblondon triblondon 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.

Loading

@jdalton
Copy link

@jdalton jdalton commented Sep 12, 2014

Loading

@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
Copy link

@jonathantneal jonathantneal commented Nov 22, 2014

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

Loading

@triblondon
Copy link

@triblondon triblondon 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.

Loading

@triblondon
Copy link

@triblondon triblondon commented Aug 11, 2015

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

Loading

@JakeChampion
Copy link
Member

@JakeChampion JakeChampion commented Jan 31, 2016

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

Loading

@tracker1
Copy link

@tracker1 tracker1 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.

Loading

@triblondon
Copy link

@triblondon triblondon commented Feb 5, 2016

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

Loading

@mbrevda
Copy link

@mbrevda mbrevda 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.

Loading

@triblondon
Copy link

@triblondon triblondon 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).

Loading

@mbrevda
Copy link

@mbrevda mbrevda 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?

Loading

@triblondon
Copy link

@triblondon triblondon 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

Loading

@mauron85
Copy link

@mauron85 mauron85 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.

Loading

@JakeChampion
Copy link
Member

@JakeChampion JakeChampion 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.

Loading

@mauron85
Copy link

@mauron85 mauron85 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? ;-)

Loading

@triblondon
Copy link

@triblondon triblondon 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.

Loading

@azu
Copy link

@azu azu commented Feb 19, 2018

Loading

@rokoroku
Copy link

@rokoroku rokoroku commented Sep 10, 2018

Loading

@JakeChampion JakeChampion self-assigned this Jan 23, 2019
@JakeChampion JakeChampion transferred this issue from Financial-Times/polyfill-service Feb 6, 2019
@chee chee added this to incoming in Origami Feb 1, 2020
Origami automation moved this from incoming to complete Oct 14, 2020
@JakeChampion
Copy link
Member

@JakeChampion JakeChampion commented Oct 14, 2020

Closing this issue because it is a feature we are not going to implement

Loading

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Origami
  
Done
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants