["Solved"] How to get rid of plone.patternslib?

At some point in the evolution of a Plone instance, I installed collective.venue which depends on plone.formwidget.geolocation and plone.patternslib. Then I stopped using this feature and uninstalled the addons, but for some reason the Plone instance seems addicted to plone.patternslib;
when I try to compile my resources using ./bin/plone-compile-resources,
it failed miserably...

How to manage the registry of resources in order to fix this issue?
I already spent days trying everything I could... Help!

Edit/Update:

Part of the solution was to run "Plone Patternslibs uninstall" in /portal_setup/manage_fullImport

But I must keep plone.patternslib in my buildout (even if I don't need it...)
Is there a better solution?

I reopened this topic; details at the end...

What error do you get if you remove it from buildout ?

44 errors related to the absence of plone.patternslib, like:

ERROR:plone.subrequest:Error handling subrequest to http://nohost/Plone/++plone++patternslib/bundle-leaflet.js
ERROR:plone.subrequest:Error handling subrequest to http://nohost/Plone/++plone++patternslib/components/desandro-matches-selector/matches-selector.js
ERROR:plone.subrequest:Error handling subrequest to http://nohost/Plone/++plone++patternslib/components/ev-emitter/ev-emitter.js

In /config.js there's more traces of patternslib (in the requirejs.config array), even when patternslib is not in the buildout:

"bundle-leaflet": "++plone++patternslib/bundle-leaflet",
"desandro-matches-selector": "++plone++patternslib/components/desandro-matches-selector/matches-selector",
"ev-emitter": "++plone++patternslib/components/ev-emitter/ev-emitter",

etc...

Also, something similar can be seen in the registry of resources (using some code in the debug console):

from zope.component import getUtility
from plone.registry.interfaces import IRegistry
from Products.CMFPlone.interfaces import IResourceRegistry

registry = getUtility(IRegistry)

resources = registry.collectionOfInterface(
    IResourceRegistry, prefix="plone.resources")
    
resources.keys()

Things like:

'bundle-leaflet',
'desandro-matches-selector',
'patterns',
'leaflet',
'pat-ajax',

etc.

Removing entries in the registry of resources could be a solution, but what I tried so far broke the Plone instance.

The problem is, that plone.patternslib defines an uninstall profile, but there is no "uninstall" directory in profiles folder, which should remove all resource/bundle keys defined in plone.patternslib/registry.xml at master · plone/plone.patternslib · GitHub ... either you add this in a PR of plone.patternslib or you remove them manually in /portal_registry ... first solution very welcome :wink:

I have not look at patterns lib in particular, but often you can fix this by making a new uninstall profile

Make a new folder 'uninstall', copy the 'install profile registry file there. Add 'remove=True' on all lines

It worked!

I'll let someone else contribute a PR with my files:

for "plone/patternslib/profiles/uninstall/registry/resources.xml" :

<?xml version="1.0" ?>
<registry>

    <records remove="True" prefix="plone.resources/text"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-base"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
              
    <records remove="True" prefix="plone.resources/pat-compat"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
              
    <records remove="True" prefix="plone.resources/pat-registry"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
              
    <records remove="True" prefix="plone.resources/pat-jquery-ext"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
              
    <records remove="True" prefix="plone.resources/pat-logger"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
              
    <records remove="True" prefix="plone.resources/pat-utils"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
              
    <records remove="True" prefix="plone.resources/pat-mockup-parser"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
              
    <records remove="True" prefix="plone.resources/logging"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/jquery.anythingslider"
              interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/ev-emitter"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/get-size"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/imagesloaded"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/jquery.browser"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/jcrop"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/jquery.placeholder"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/jquery.textchange"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/masonry"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/desandro-matches-selector"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/modernizr"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/modernizr-csspositionsticky"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/moment-timezone"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/moment-timezone-data"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/outlayer"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
    <records remove="True" prefix="plone.resources/pikaday"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/photoswipe"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/photoswipe-ui"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/prefixfree"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/showdown"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/showdown-github"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/showdown-table"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/slides"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/spectrum"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/stickyfill"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/validate"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-fullscreen"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-providers"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/leaflet-geosearch"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-geosearch-esri"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-geosearch-bing"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-geosearch-google"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-geosearch-openstreetmap"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-markercluster"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-awesomemarkers"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-locatecontrol"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-minimap"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-sleep"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/leaflet-simplemarkers"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/font-awesome"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-leaflet"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-depends_parse"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-dependshandler"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-input-change-events"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-htmlparser"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-parser"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-remove"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-store"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-ajax"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-auto-scale"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-auto-submit"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/pat-auto-suggest"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-breadcrumbs"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/pat-bumper"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-checked-flag"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-checklist"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-clone"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-collapsible"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-colour-picker"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-date-picker"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-datetime-picker"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-depends"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-equaliser"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-expandable"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-focus"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-form-state"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-forward"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-gallery"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-grid"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-image-crop"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-inject"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-legend"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-markdown"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-masonry"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-menu"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-modal"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-navigation"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-placeholder"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-scroll"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/pat-selectbox"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-slides"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-slideshow-builder"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-stacks"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/pat-sticky"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-subform"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-switch"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/pat-validation"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/pat-zoom"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>

    <records remove="True" prefix="plone.resources/bundle-leaflet"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
    <records remove="True" prefix="plone.resources/patterns"
            interface='Products.CMFPlone.interfaces.IResourceRegistry'/>
            
</registry>

for "plone/patternslib/profiles/uninstall/registry/bundles.xml" :

<?xml version="1.0" ?>
<registry>
        
    <records remove="True" prefix="plone.bundles/bundle-leaflet"
             interface='Products.CMFPlone.interfaces.IBundleRegistry'/>
            
    <records remove="True" prefix="plone.bundles/patterns"
             interface='Products.CMFPlone.interfaces.IBundleRegistry'/>

</registry>

It still does not solve the problem, my Plone instance is still addicted to plone.patternslib...
It seems that plone.mosaic needs it installed or else plone-compile-resources stops because of a dependency for pat-base:

Running command: /home/vagrant/Plone/zinstance/node_modules/grunt-cli/bin/grunt --gruntfile=/home/vagrant/Plone/zinstance/Gruntfile.js compile-all
Running "requirejs:filemanager" (requirejs) task
>> Error: ENOENT: no such file or directory, open '/pat-base.js'
>> In module tree:
>>    
>> /home/vagrant/Plone/buildout-cache/eggs/cp37m/plone.staticresources-1.4.3-py3
>> .7.egg/plone/staticresources/static/filemanager.js
>>       mockup-patterns-filemanager
Warning: RequireJS failed. Use --force to continue.

Even if I provide it, there's a new error:

Running command: /home/vagrant/Plone/zinstance/node_modules/grunt-cli/bin/grunt --gruntfile=/home/vagrant/Plone/zinstance/Gruntfile.js compile-all
Running "requirejs:bundle-leaflet" (requirejs) task

Running "requirejs:filemanager" (requirejs) task
>> Error: ENOENT: no such file or directory, open '/text.js'
>> In module tree:
>>    
>> /home/vagrant/Plone/buildout-cache/eggs/cp37m/plone.staticresources-1.4.3-py3
>> .7.egg/plone/staticresources/static/filemanager.js
>>       mockup-patterns-filemanager
Warning: RequireJS failed. Use --force to continue.

This plone-compile-resources business is very unfriendly... :frowning:

No, the main cause has less relevance to the resource registry: if an add'on has an install profile that applies settings to the configuration/contentdb, it is good custom to also provide an uninstall profile that does the reverse of applying all those settings.

Normally there is a obvious warning next to an add'on that you cannot uninstall it. (this is when there is an install, but no uninstall profile registered). Then you are warned as a non technical user, here be dragons. The nasty twist here is that there apparently is an incomplete or even empty uninstall profile. So in this case it is a developer mistake: the empty uninstall profile shouldn't have been registered so as an end user you'd have been warned that this add'on is a one way street.

What is an issue with the resource registry is a design choice that was made or 'what is worse' for how resources are handled in Plone 5.X. If you register a resource, but the resource later on cannot be retrieved through the given url/location for whatever reason, and this is just one, what should the bundler do: silently ignore the css and js, skip the resource, still create the productin css/js bundle and let all kinds of strange side effects happen in your website of which your users/visitors onlly notify you 2 weeks later? And then let the great search for root cause begin? Or sound the alarm and/or break of bundling immediately so that you know something is going on?

With a developer mindset you want to fail early, as an end user/webmaster mindset you just want everything to always work perfectly because somebody else didn't forget or have the need or time to create an uninstall profile....

This issue touches another discussion here on the forum on the future of TTW development with Plone. This is a fine example of the dilemma's we face when we want to continue with 'foolproof TTW' capabilities. It's not just the tools, it's also the mindset how you want the tools to function

I am pretty sure 'the default setup' of Mosaic does not need it (because I have some theme fragments that requires patternslib, and they do not work if I dont install it

  1. make a PR as suggested by @petschki

You can try with bin/plone-compile-resources -b <bundle name> to compile only your specific bundle and its dependencies .... the other bundles might need more node_modules installed then you have. Generally the ZODB-resource-registry-gruntfile-generator-driven-js-compiling™ was always a "bit" overengineered and we are happy to get rid of it in Plone 6 with ES6 and webpack for developing Javascript.

Yes, but I still can't get rid of plone.patternslib... What I discovered is that I can disable plone.patternslib so it's not included in the automated default.js and default.css aggregated resources. It's good enough, so I will consider my issue "solved"... Thank's all for your help.

Plone Foundation Code of Conduct