Wednesday, September 12, 2018

Look Ma! No Resource Registries

Over the past years I have spent a lot of time trying to make our add-ons compatible with Plone 4.3 and Plone 5. This has been difficult for many reasons including differences in the API of default content types frameworks and registration of static resources, just to mention some.

On the latest topic I've been very critic of the approach taken and even tried to propose a different one to avoid some well known problems on PLIP 1896. Unfortunately this was not understood at the time and I just gave up because we didn't had use cases to justify the migration to Plone 5.

This has started to change in latest months and we can't continue kicking the can down the road any longer: Python 2.7 will be EOL in 2020, Zope 4 has been released, and there has been a lot of work lately to make Plone compatible with Python 3.

IMO, Plone 5 resource registries are complex and must be avoided for many reasons as stated in the PLIP aforementioned:
  • the revolutionary approach chosen (rewrite everything) has proven buggy and difficult to maintain, as shown by the many issues reported over the last years (the latest opened just 2 days ago)
  • some of the JavaScript tools used at the time (Bower, Grunt, RequireJS…) are less attractive nowadays than more modern options like npm, Yarn and webpack
  • resource bundling was a workaround for a limitation of the HTTP/1.1 protocol and not a CMS feature; HTTP/2 made this unnecessary and even undesirable
  • LESS is now way less popular than SASS

I still think that every add-on author must be able to use the tools of their choice, and I still think Plone should not have to worry about resource bundling.

In early 2016 we selected webpack for our projects and in early 2017 we developed a Buildout recipe (called sc.recipe.staticresources) to make the inclusion of it into the Plone ecosystem easier. Over the past 2 years we have been developing, testing, and enhancing this approach in many add-ons and projects. But the resource registries were still there…

Not anymore.

I'm pleased to announce the release of collective.lazysizes 4.1.1.1, the first add-on that uses a new and very opinionated approach on how to handle static resources in Plone: we just deprecated resource registries in favor of a viewlet registered in plone.htmlhead. This simplifies maintenance among multiple Plone versions and avoids bundling of unrelated resources.

How does it work?

We use webpack to generate all static resources (in our case, a JavaScript file, a page template and an icon; check the webpack.config.js file). The page template is used for the viewlet and includes  the following code on it:

<script async="" src="https://www.example.com/++resource++collective.lazysizes/lazysizes-43c36fc.js"></script>

As you can see, the JavaScript id already includes a hash (lazysizes-43c36fc.js), so you don't have to worry about cooking resources, neither caching the wrong file. The hash will only change if the related code changes.

(To understand better the work done, check the following pull requests: Deprecate resource registries and Create JS resource with unique ID.)

What are the benefits of this for developers?
  • you can work on your project using latest state-of-the-art JavaScript technologies like ES2015 and Vue.js
  • you don't have to worry about resource registries anymore as this approach works out of the box in all Plone versions: no more duplicated registrations, cleaner and simpler ZCML and XML files
  • you don't have to worry about upgrade steps anymore (at least the ones related with resource registry cooking/bundling)
  • you end up with better static resources: all CSS and JS files minimized, all images optimized
  • your code will be faster, as rendering a viewlet is less expensive than rendering a resource in the registry (at least, in Plone 4.3)
 What are the benefits of this for system administrators?
  • less steps to upgrade your sites
  • less unneeded cache invalidations
  • faster sites as resources can be loaded in parallel
See how easy is to add a new feature to our resources: Add lazysizes print plugin; and how easy is to update the version of the JavaScript library we're using: Upgrade lazysizes to 4.1.1.

Now you can concentrate in the things that matter and stop worrying about the ugly parts; isn't that fun?

Share and enjoy!