Skip to content
This repository has been archived by the owner on May 5, 2022. It is now read-only.

how to feature detect? #7

Closed
getify opened this issue Mar 10, 2015 · 52 comments · Fixed by #52
Closed

how to feature detect? #7

getify opened this issue Mar 10, 2015 · 52 comments · Fixed by #52

Comments

@getify
Copy link

getify commented Mar 10, 2015

How do I feature test if a new browser supports link rel=preload?

@getify getify changed the title how to feature detect this new feature? how to feature detect? Mar 10, 2015
@igrigorik
Copy link
Member

Good question, not sure. Are there mechanisms to test if browser implements particular relation type? E.g. prerender, etc?

@getify
Copy link
Author

getify commented Mar 10, 2015

I have never considered FT for link rel=prefetch (or others) before, since its absence wasn't a problem. This feature would absolutely require to know if it's there to decide if it's going to be used (by script loaders, that is).

So, if a technique doesn't exist, I'd say it's a must that we invent something.

@igrigorik
Copy link
Member

I'm open to ideas :) /cc @marcoscaceres @slightlyoff

@getify
Copy link
Author

getify commented Mar 10, 2015

Here's a thought:

var s = document.create("link");
s.rel = "preload";
var supports = ("preload" in s);

That is, it adds the preload property to the element (value true) as soon as you set the rel to "preload".

@getify
Copy link
Author

getify commented Mar 10, 2015

An alternate is that instead of an onload event name, the preload event would be used (only possible on the <link> element and only used for these preloading purposes). So you could check for:

var supports = ("onpreload" in document.create("link"));

Side note: I like this option better semantically anyway, as "load" on a preloading-only element feels awkward.

@igrigorik
Copy link
Member

The more I think about this, the more I'm wary of trying to invent something in a context of this particular spec... This feels like a larger missing feature in the platform? Specifically, while we have libraries like Modernizr doing all kinds of crazy tricks in the background to feature detect particular features.. perhaps there should be a dedicated API to answer such things.

@getify
Copy link
Author

getify commented Mar 11, 2015

Yeah, that's been needed for years. I've asked for (soft proposed) it several times in fact. There's a whole slew of things that are currently not feature detectable, that such an API could help with.

Problem is people always say that the scope is too large to tackle it paired with whatever the one feature case is at the moment, so another ad hoc FT is designed, or (worse) FT is skipped (thankfully more rare these days).

If you think you could push a FeatureTests API through in roughly the same time period as rel=preload, I'd be all for it. My guess is that won't happen, given history.


Side note: this is somewhat tangential to my other feeling, which is that "client hints" should be extended to be able to send all the same kinds of info that a theoretical FT API would.

@marcoscaceres
Copy link
Member

The problem with this kind of API is that it's extremely problematic - what "supported" means is nebulous. See, for instance, .hasFeature() which was a previous attempts to provide this kind of thing:

hasFeature() originally would report whether the user agent claimed to support a given DOM feature, but experience proved it was not nearly as reliable or granular as simply checking whether the desired objects, attributes, or methods existed. As such, it should no longer be used, but continues to exist (and simply returns true) so that old pages don't stop working.

I agree that there should be some means of detecting preload by explaining it in terms of JS (and related DOM APIs), but I've not given this a lot of thought. It depends on the browser machinery handling the preload.

@getify
Copy link
Author

getify commented Mar 31, 2015

I understand Blink has announced intent-to-implement for this link..rel=preload feature. I still feel strongly that it must have a feature-test of some sort to be acceptable as a new feature.

I was asked to add an explicit description to this issue of why I feel this way.

The primary reason is that I maintain the LABjs dynamic script loader. It has various feature tests (and, unfortunately, inferences) in it for exploiting different preloading techniques (of sorts) in browsers, both new and old. If link..rel=preload lands in browsers, of course I would want to update LABjs to detect and use that new technique.

However, there must be a feature detect for this. I will not be using any new features in LABjs that do not have direct and reliable feature tests (no inferences or UA parsing or any of that junk).

Hopefully that underscores the necessity of a feature-test. :)

+@yoavweiss

@marcoscaceres
Copy link
Member

@getify, the problem is that there is no guarantee that preload will actually do the preloading (even if you could feature detect it). It's to the browser's (or possibly user settable) discretion if preload actually preloads and when the preload actually happens (it's low priority). The only way to detect the preload is on the preloaded resource, which will be able to detect that it has been loaded in the background through, IIRC, the page visibility API.

In other words, I don't see what you would gain from feature testing, rather than assuming with certainty that, being a "web standard", you are increasingly likely (over time/on new browsers) to get the desired effect when the browser's environmental conditions are right to perform the a preload.

@getify
Copy link
Author

getify commented Mar 31, 2015

there is no guarantee that preload will actually do the preloading

That doesn't match up with the semantics from my reading of the spec. If that's true, how is "preload" any different from "prefetch"?

That is, how is there any less guarantee that link..rel=preload will preload the script than there is that <script src> will load a resource? If they're roughly the same "guarantee", that's more than sufficient. If they're substantially different, that's a major design flaw with this feature.

it's low priority

AFAICT, priority wouldn't affect the decision to use the feature or not. In fact, that might be a benefit to be able to opt into a system for script loading which is lower priority than document.createElement("script") implies, if in fact it's different.

The only way to detect the preload is on the preloaded resource

How?

I don't see what you would gain from feature testing

I would absolutely expect that a browser should not make the feature-detect (whatever it is) return true for this link..rel=preload feature if it's not actually implemented in some meaningful way. If browsers do that, they're acting counter to the spirit. No, there's nothing I can do about that except complain on twitter.

But the possibility of misbehavior on the part of browser vendors is in no way an argument against features designed and relied upon in good spirit.

@hexalys
Copy link

hexalys commented Mar 31, 2015

@marcoscaceres I am also confused about your "no guarantee" statement here.
My understanding is that Preload was split as separate specs for the mandatory semantics.
Doesn't that mean that a link preload with no pr= and no loadpolicy= is a must?

In terms of feature detection, one alternative could be exposing some CONSTANTS at the HTMLLinkElementConstructor level, similarly to how's we'd detect support for CSSRULES?

@marcoscaceres
Copy link
Member

@hexalys oh dear, maybe I'm getting my prefetch, preload, prerenders confused again :/ Ignore me.

@igrigorik
Copy link
Member

@marcoscaceres @hexalys @getify yep, rel=preload is a MUST fetch.

Re, feature detect: the onpreload even suggestion sounds feasible, but it does feel a bit odd to me. First, it deviates from regular "fire the load event" pattern, which will undoubtedly create confusion and head-scratching for developers. Second, it's a preload specific thing.

<crazy thought>
But speaking of "MAY" fetch semantics.. Would there be value in exposing an API that allows the site to query whether the UA is willing to invoke a certain type of fetch? For example, the UA may support prerendering, but due to current environment/etc constraints is not willing to perform it: instead of leaving the application guessing, perhaps we should provide a way to the UA before submitting the request?

If we had such an API, it wouldn't be too farfetched to also ask for "is preload supported?"

@hexalys
Copy link

hexalys commented Apr 1, 2015

It could be an API extended to check support for all/any Link Types or associated rel properties. Which would be new, but useful on the long term for recent and future link attributes or rel types.

i.e. A more limited hasFeature() good for things like: crossorigin, media type, sizes, icon, prefetch, prerender, ping or even stylesheet support etc.. All very hard detects requiring expensive tests or tricks.

@igrigorik
Copy link
Member

@hexalys hasFeature() is different what I was thinking above.. I was pointing out the case where feature was supported, but based on runtime factors is "not active" - e.g. prefetch won't be triggered because the user is roaming and/or on expensive data plan. And, of course, not supported == not active.

For hasFeature scoped to link, this kinda smells like a whatwg question...

@hexalys
Copy link

hexalys commented Apr 1, 2015

@igrigorik Understood. But this could be a linkSupport designed to assume runtime or environment conditions, along the basic capability. With detects like: 'prefetch' in linkSupport.rel to detect feature support; and linkSupport.rel.prefetch === true|false for active or inactive; A whatwg question indeed.

@igrigorik
Copy link
Member

@getify open to kicking off a discussion on whatwg on feature testing ? :)

@getify
Copy link
Author

getify commented Apr 1, 2015

@igrigorik
Copy link
Member

@getify perfect, thank you! Let's see what we can come up with there.

@toddreifsteck
Copy link
Member

I like where this is going.

Semantically, feature detection and testing is 2 things:

  1. The ability to ask if a feature will work
  2. The ability to observe what that feature did or know the feature was triggered at a minimum.

These are requirement of detection/testing seems valuable for hints.

@yoavweiss
Copy link
Contributor

@zcorpan's suggestion on the WHATWG thread makes a ton of sense for preload, and <link> based features in general.

@zcorpan - that's not something that's currently part of the link element spec, right?

@zcorpan
Copy link
Member

zcorpan commented Apr 2, 2015

No, it would be a spec change.

@igrigorik
Copy link
Member

For reference, from the whatwg thread:

(@zcorpan) For <link rel>, we could solve the feature-testing problem by normalizing the case for supported keywords but not unsupported keywords, so you can check with .rel or .relList:

 function preloadSupported() {
   var link = document.createElement('link');
   link.rel = 'PRELOAD';
   return link.rel == 'preload';
}

^ sgtm. @zcorpan should we open a bug for this on whatwg?

@scottjehl
Copy link

Thanks for this thread. I'm trying to research how this might come together in a real implementation. Mind having a look, @igrigorik ? (Moved to an issue over at loadCSS to keep this thread on topic.)

filamentgroup/loadCSS#59

@igrigorik
Copy link
Member

@scottjehl commented on the issue; lgtm.

In related news, opened a bug for the HTML spec:
https://www.w3.org/Bugs/Public/show_bug.cgi?id=28616 /cc @zcorpan

@igrigorik
Copy link
Member

We don't have a label for "blocked on other spec", hence marking as 'help wanted'.

@toddreifsteck
Copy link
Member

Had @travisleithead from TAG review this and there was no pushback. Nicely done, @yoavweiss !

@igrigorik
Copy link
Member

@yoavweiss kudos on getting https://code.google.com/p/chromium/issues/detail?id=553945 fixed.

Do you have a 'best practice' code snippet I should put in the spec?

@yoavweiss
Copy link
Contributor

I'll PR something in a bit

@getify
Copy link
Author

getify commented Apr 4, 2016

What did we actually end up with for the feature detection? The snippet indicated here: https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/#feature-detection

... that really sucks if that's the required pattern for feature detect, having to wrap in a slowish try..catch. Please tell me there's a better way than that?

@marcoscaceres
Copy link
Member

Maybe:

function supportsToken(token) {
  return function(relList){
    if (relList.supports && token) {
      return relList.supports(token);
    }
    return false;
  }
};

var supportsPreload = supportsToken("preload");
var rl = document.createElement("link").relList;
console.log(supportsPreload(rl));

One could make a more generic variant of the above if necessary. Is that what you mean?

@getify
Copy link
Author

getify commented Apr 4, 2016

No, I meant that in the linked-to code snippet, a try..catch was wrapped around the supports(..) call, indicating that it could throw errors. Is the try..catch required or not?

@marcoscaceres
Copy link
Member

Ah, I'm concerned about that too. I hope it can't throw. That would be sad.

@yoavweiss
Copy link
Contributor

The try...catch is required when you're calling supports() on a DOMTokenList which may not have supported tokens.

If you're calling supports() on e.g. the result of relList of an HTMLLinkElement, try is not needed.

@getify
Copy link
Author

getify commented Apr 4, 2016

@yoavweiss are you suggesting that link#relList always has a list of supported tokens, so supports(..) would never throw on it? What are some examples of relLists where it would throw?

@yoavweiss
Copy link
Contributor

@getify yeah, assuming supports() is implemented according to spec. See https://html.spec.whatwg.org/#the-link-element:concept-supported-tokens

@zcorpan
Copy link
Member

zcorpan commented Apr 4, 2016

It always throws for e.g. classList.

@safareli
Copy link

on IE relList is not supported https://caniuse.com/#search=relList so this check only works on modern browsers which already support preload https://caniuse.com/#search=preload therefore using relList to check feature support is not useful, is there some other way to check this feature on old browsers?

@yoavweiss
Copy link
Contributor

If relList is not supported, that's an indication that preload isn't as well (as it was implemented alongside it, as the feature detection mechanism)

@getify
Copy link
Author

getify commented Jun 26, 2018

@yoavweiss that's a feature inference, not a feature detection. maybe parsing semantics, but I think it's important to be clear on such things.

@yoavweiss
Copy link
Contributor

While I agree that there could be a case of an implementation implementing preload without making sure its feature detection mechanism is shipped as well, I'm not aware of such a case. Therefore, I think the distinction makes very little difference in practice.

@getify
Copy link
Author

getify commented Jun 26, 2018

In practice? Maybe not much. It makes a bigger semantic difference though. From a documentation and code-readability perspective.

@safareli
Copy link

If relList "was implemented alongside preload, as the feature detection mechanism", shouldn't the spec mention that relList must also be implemented if preload is implemented or something like that?

@safareli
Copy link

created separate issue "spec shuold mention that relList must also be implemented if preload is implemented" #126 or feel free to close that and reopen this one.

@dalimian
Copy link

dalimian commented Dec 17, 2019

here is a simpler version of @yoavweiss's snippet (https://gist.github.com/yoavweiss/8490dabb3e0aa112fc74) tailored just for this specific use case

  function preloadSupported() {
    var relList = document.createElement('link').relList;
    return !!(relList && relList.supports && relList.supports('preload'));
  }

given that there is no need for try/catch for this case (as he confirmed). Worked, and did not throw in any browser I tested with (IE 10+, safari 10.1+, chrome 50+, firefox 50+, edge 15+)

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

Successfully merging a pull request may close this issue.

10 participants