Skip to content
This repository was archived by the owner on Oct 1, 2019. It is now read-only.

Managing polyfills and feature detection #86

Closed
kavanagh opened this issue Jan 10, 2014 · 15 comments
Closed

Managing polyfills and feature detection #86

kavanagh opened this issue Jan 10, 2014 · 15 comments

Comments

@kavanagh
Copy link
Member

I'm concerned that some products will have as many polyfills as exist on github and multiple versions of those. I'm not sure adding polyfills to the A-list is a useful exercise either. I believe the addition of polyfills should be done in a consistent way across all modules. And I'd encourage product developers to extend the same approach to the product too.

We are also encouraging feature detection via documentElement classes. <html class="svg cssvmunnit hidpi hoverable touch"> etc.

I propose we allow developers to use the .origamiconfig file to note which features they are using (that are known to have less than 100% coverage). They should also then have the option to say whether each feature needs to be polyfilled or not. If not it's assumed that their code is handling cases when the feature is not supported.

This is also wrapped up in the use of something like Modernizr to manage those feature classes on the documentElement and to provide a consistent/shorthand way to do feature detection from within javascript code.

If a single process could be responsible for bundling the required polyfils and assembling the required build of Modernizr that would be very heat.

In the interactive graphics team we use a json file, modernizr.json where developers note the feature detection they are using for each product. A grunt task then builds Modernizr with only the necessary code needed to fulfill those feature checks. This greatly cuts down the size of Modernizr. This is especially useful now it has now been opened up to "community checks"; there are well over 100 checks now available (very handy I might add). It's also very simple to add custom checks.

Here's a recent modernizr.json from a real project.

{
  "matchCommunityTests": false,
  "tests": [
    "touch",
    "svg",
    "backgroundsize",
    "video",
    "url_data_uri",
    "css-vhunit",
    "css-vmaxunit",
    "css-vminunit",
    "css-vwunit",
    "audio",
    "csstransitions",
    "csstransforms",
    "fontface"
  ],
  "extra": {
    "shiv": true,
    "printshiv": false,
    "load": true,
    "mq": true,
    "cssclasses": true
  },
  "extensibility" : {
    "addtest" : true,
    "prefixed" : false,
    "teststyles" : false,
    "testprops" : false,
    "testallprops" : false,
    "hasevents" : false,
    "prefixes" : false,
    "domprefixes" : false
  }
}

You'll notice that as well as defining the feature tests we are also adding in the polyfills that can come with Modernizr... "shiv": true (html5 shim), "mq:true" (polyfill for window.matchQuery), "cssclasses": true (a fill for element.classList). I wouldn't do this in quite the same way for Origami but you get the idea.

I would do something in the .origamiconfig like

{
   ...
  "features": [
      "touch",
    "svg",
    "backgroundsize",
    "video",
    "url_data_uri",
    "css-vhunit",
    "css-vmaxunit",
    "css-vminunit",
    "css-vwunit",
    "audio",
    "csstransitions",
    "csstransforms",
    "fontface"
   ],
  "polyfills": [
     "html5",
     "csslist",
     "videotrack"
  ]
}

And then have a list of both supported feature names and polyfill names in the registry website, bundle the required js via the build service and perhaps make a grunt task to aid developers.

Thoughts?

@triblondon
Copy link
Contributor

This feels like another form of package management. Couldn't we somehow use the mechanism we already have? So in my bower.json I list o-modernizr-test1, o-modernizr-test2, and those tests have the modernizr core as a dependency? That's the only way I can see of making Modernizr part of our module ecosystem.

As for polyfills, those that modify global scope possibly shouldn't be in Origami. Let's discuss this one in person.

@triblondon
Copy link
Contributor

OK, we have a list of features, modules declare their required and optional features. Script won't work without required features, will use optional features if they exist. Prod developer is left to decide how to provide required features. Could do this by polyfilling or by adding those features to CTM.

@triblondon
Copy link
Contributor

Modernizr in full is 14.2KB minified (I realise we'd want people to use a custom build). That's a LOT of code for a crappy device to parse before it realises it's not going to CTM. I appreciate that the product dev will probably need to put Modernizr in the head to decorate <body> with classes so that we don't get FOUCs, but maybe it too needs its own CTM?

Something like:

<head>
   <script>
      if (browser isn't total shit) {
         document.write a script tag to load modernizr
      }
   </script>
</head>
<body>
   ... content and whatnot ...
   <script>
      if (modernizr exists AND browser cuts the mustard (where CTM would exclude things that we intend to polyfill)) {
         use modernizr to conditionally load desired polyfills
         async add a script tag to dom to load script bundle
      }
   </script>
</body>

Anyway, I guess whether or not you conditionally load Modernizr is a product decision. As this relates to Origami, the changes are:

  • modify origami.json to have the required and optional modernizr feature lists as discussed
  • update JavaScript rules to dictate no use of Modernizr API from within JavaScript (I'm absolutely determined on that point)

triblondon added a commit that referenced this issue Jan 17, 2014
Not sure about using Modernizr tests
@triblondon
Copy link
Contributor

OK, in the continuing adventures of Andrew's scepticism about Modernizr...

There's no queryselector test. There's no addeventlisterner test. So it's actually not possible to test for the BBC's key CTM features using Modernizr. I realise we could write plugins, but I'm... nervous.

There's also http://nefariousdesigns.co.uk/sniff-my-browser-the-modernizr-inadequacy.html.

I've just pushed some changes to define the required and optional browser features, but I think we should rethink how we're defining those feature keys. Are they Modernizr test names, or something else?

@triblondon
Copy link
Contributor

Discussed with @matthew-andrews and we don't see a nice solution to this. The best we can probably do is express our requirements using, as far as possible, Modernizr test names, but with some additional tests added. We'd need to maintain those tests in a repo of our own, and somehow make a custom modernizr build that includes tests for all the things that modules are requiring.

@kavanagh
Copy link
Member Author

Sorry, just need to be sure I understand the assumptions.

That's a LOT of code for a crappy device to parse before it realises it's not going to CTM.
...
There's no queryselector test. There's no addeventlisterner test. So it's actually not possible to test for the BBC's key CTM features using Modernizr.

So this is a problem for browsers who only receive the noscript site but have JS enabled. i.e. It is safer for Modernizr to exit (do nothing) when the browser does not CTM. Otherwise feature classes will be added to the html element and CSS applied throughout the page. This would affect the display of the site in ways that we are not willing to test.

Is that correct?

If yes, does that lead us down the road of all CSS having to layer up features using progressive enhancement, rather than graceful degradation. For example the following will not be possible:

.widget {
 background-image: url('background-graphic.svg');
}

.no-svg .widget{
 background-image: url('background-graphic.png');
}

There's no queryselector test. There's no addeventlisterner test.

It must be noted that in discussion we agreed that there would be certain features component developers do not have to put in their mandatory/options features list. In light of the CTM test they'd be unnecessary. queryselector and addeventlistener would be two such unnecessary tests.


I think we should rethink how we're defining those feature keys. Are they Modernizr test names, or something else?

I don't want to rebuild Modernizr. But I see it's problems too. Something more aligned with caniuse might be more usable in all cases.

@wheresrhys
Copy link
Contributor

update JavaScript rules to dictate no use of Modernizr API from within JavaScript (I'm absolutely determined on that point)

If this is mainly because Modernizr is a global then browserify-shim + defining it as an external in the main browserify bundle can make it available using require(). So it can be done, but on the down side would add complexity to the build and make using modules that depend on Modernizr less straightforward.

@triblondon
Copy link
Contributor

@wheresrhys - that would give an Origami bundle a dependency on the product developer having defined Modernizr and would not be a properly guarded dependency. Not having it. Using classes set by modernizr is fine and the appropriate compromise here.

@kavanagh I agree that modules can express a requirement for addqueryselector, but that doesn't make the test unnecessary, it makes the test mandatory. If I express a requirement for web audio, it stands to reason that the product developer would perform that test using Modernizr. If a requirement doesn't match the name of a Modernizr test, how is the developer supposed to know what to test for? Is it just 'common sense' that if I set 'queryselector' as one of the values in my 'required' array, that the test would be querySelector in document? My conclusion was that we would need to maintain a set of additional Modernizr tests that provided support for the things we wanted to list in our required array which weren't already in Modernizr.

@kavanagh
Copy link
Member Author

Does this mean Modernizr is missing checks for querySelector, classList and addEventListener?

Modernizr community checks are designed to add commonly needed extra tests. The ones currently in existence are listed on the download page under "Non-core detects"

@triblondon
Copy link
Contributor

Does this mean Modernizr is missing checks for querySelector, classList and addEventListener?

Yes. See https://twitter.com/Modernizr/status/425367337168945152. And there's no contrib test for it, I checked. I might be able to convince Paul and Stu to add those though, since they're very simple, and that would save us forking Modernizr or doing something complicated to maintain our own tests.

@wheresrhys
Copy link
Contributor

Should html5shiv be listed in origami.json browserFeatures or will the origami specs mandate that product developers must polyfill semantic html5 elements in order to use origami?

@triblondon
Copy link
Contributor

It seems like something that should be a listed browser requirement to me.
Would it be possible to write a Modernizr test for it?

On 22 January 2014 13:52, Rhys Evans [email protected] wrote:

Should html5shiv be listed in origami.json browserFeatures or will the
origami specs mandate that product developers must polyfill semantic html5
elements in order to use origami?


Reply to this email directly or view it on GitHubhttps://github.com//issues/86#issuecomment-33023459
.

@triblondon
Copy link
Contributor

I've raised a PR to add querySelector test to Modernizr. Paul Irish tells me it should be accepted pretty quickly.

Modernizr/Modernizr#1195

@triblondon
Copy link
Contributor

OK. I feel we've got to the bottom of this.

  • Modules express their requirements and desires in the browserFeatures property of origami.json (in the spec)
  • These must be expressed as the names of Modernizr tests (and we've now added the ones that were missing)
  • Modules do not attempt to polyfill browser features themselves, because that would violate Origami's encapsulation rules
  • Product developers are advised to use Modernizr to perform the necessary tests and polyfill as required (added https://redmine.labs.ft.com/issues/21782 to add tooling support to registry)

@triblondon
Copy link
Contributor

Approved at meeting yesterday.

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

No branches or pull requests

3 participants