w3c / preload

Preload
https://w3c.github.io/preload/
Other
81 stars 31 forks source link

how to feature detect? #7

Closed getify closed 8 years ago

getify commented 9 years ago

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

igrigorik commented 9 years ago

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

getify commented 9 years ago

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 commented 9 years ago

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

getify commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

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

igrigorik commented 9 years ago

@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 commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

@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 commented 9 years ago

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

getify commented 9 years ago

https://lists.w3.org/Archives/Public/public-whatwg-archive/2015Apr/0000.html

igrigorik commented 9 years ago

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

toddreifsteck commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

No, it would be a spec change.

igrigorik commented 9 years ago

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 commented 9 years ago

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

https://github.com/filamentgroup/loadCSS/issues/59

igrigorik commented 9 years ago

@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 commented 9 years ago

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

zcorpan commented 9 years ago

Another (possibly better) idea is to make some changes to the DOMTokenList API to enable feature-checking, see https://www.w3.org/Bugs/Public/show_bug.cgi?id=29061

igrigorik commented 9 years ago

That looks great. I assume we'd add the validation algorithm for <link> in HTML spec? There'd need to be a hook for other specs to extend the validation mechanism.

yoavweiss commented 8 years ago

First step: https://github.com/whatwg/dom/pull/103

igrigorik commented 8 years ago

@yoavweiss awesome. thanks for nudging it forward!

igrigorik commented 8 years ago

Blink intent to implement: https://groups.google.com/a/chromium.org/d/msg/blink-dev/xEoWkGEd_g4/Pkn_o92EAwAJ

Yoav, I'm thinking we can add a note in the spec documenting this mechanism?

yoavweiss commented 8 years ago

Definitely! :) On Nov 19, 2015 19:23, "Ilya Grigorik" notifications@github.com wrote:

Blink intent to implement: https://groups.google.com/a/chromium.org/d/msg/blink-dev/xEoWkGEd_g4/Pkn_o92EAwAJ

Yoav, I'm thinking we can add a note in the spec documenting this mechanism?

— Reply to this email directly or view it on GitHub https://github.com/w3c/preload/issues/7#issuecomment-158126550.

toddreifsteck commented 8 years ago

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

igrigorik commented 8 years ago

@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 commented 8 years ago

I'll PR something in a bit

getify commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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

yoavweiss commented 8 years ago

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 commented 8 years ago

@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 commented 8 years ago

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

zcorpan commented 8 years ago

It always throws for e.g. classList.

safareli commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

@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 commented 6 years ago

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 commented 6 years ago

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

safareli commented 6 years ago

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?