Repository navigation
Issues with dependency logic in Util::addScript #30278
Description
The new dependency logic as implemented in #30015 is broken if dependencies themselves have dependencies. E.g. when text app depends on viewer and viewer depends on files, the script from text is loaded first while the script from viewer comes later:
The problem is that the files dependency of viewer moves viewer/js/viewer-main to the last element of files, while the viewer dependendy on text moves text/js/text-viewer to the last element of viewer. Viewer is before files but viewer no longer contains viewer/js/viewer-main, so loading text/js/text-viewer from last fails.
self::$scripts from
Line 243 in 791d570
| $appScripts = array_map($mapFunc, self::$scripts); |
{
"accessibility": {
"first": [
"accessibility/l10n/en",
"accessibility/js/accessibilityoca"
]
},
"files_sharing": {
"first": [
"files_sharing/l10n/en",
"files_sharing/js/dist/main"
]
},
"text": {
"first": [
"text/l10n/en"
]
},
"viewer": {
"first": [
"viewer/l10n/en"
],
"last": [
"text/js/text-viewer"
]
},
"files": {
"first": [],
"last": [
"viewer/js/viewer-main"
]
},
"theming": {
"first": [
"theming/l10n/en",
"theming/js/theming"
]
},
"user_status": {
"first": [
"user_status/l10n/en",
"user_status/js/user-status-menu"
]
},
"core": {
"first": [],
"last": [
"core/js/dist/unified-search"
]
}
}After removing files dependency from viewer (in https://github.com/nextcloud/viewer/pull/1081/files#diff-a14aae69340720190ddf327b54675eacd97116b45f5b57f583ddb52829a3f152R41):
{
"accessibility": {
"first": [
"accessibility/l10n/en",
"accessibility/js/accessibilityoca"
]
},
"files_sharing": {
"first": [
"files_sharing/l10n/en",
"files_sharing/js/dist/main"
]
},
"text": {
"first": [
"text/l10n/en"
]
},
"viewer": {
"first": [
"viewer/l10n/en",
"viewer/js/viewer-main"
],
"last": [
"text/js/text-viewer"
]
},
"theming": {
"first": [
"theming/l10n/en",
"theming/js/theming"
]
},
"user_status": {
"first": [
"user_status/l10n/en",
"user_status/js/user-status-menu"
]
},
"core": {
"first": [],
"last": [
"core/js/dist/unified-search"
]
}
}So I guess we need to improve the logic and sort scripts by dependencies.
Activity
mejo- commentedon Dec 15, 2021
@skjnldsv and @juliushaertl
WIP: Sort app scripts by dependencies (Fixes: #30278)
WIP: Sort app scripts by dependencies (Fixes: #30278)
mejo- commentedon Dec 15, 2021
I opened #30279 as a first attempt to fix this.
ChristophWurst commentedon Dec 16, 2021
https://en.wikipedia.org/wiki/Topological_sorting
WIP: Sort app scripts by dependencies (Fixes: #30278)
Sort app scripts by dependencies (Fixes: #30278)
Sort app scripts by dependencies (Fixes: #30278)
Sort app scripts by dependencies (Fixes: #30278)
8 remaining items
mejo- commentedon Dec 22, 2021
I agree with you both. And I just realized that the whole dependency order logic is still flawed.
Now the problem is, that
uksort()doesn't change the underlying array in place, so usingarray_search($array)inside the callable doesn't work as expected.I spent another few hours with thinking and trying and by now I accepted that I won't find a cheap and simple way to sort the associative array
self::$scriptsby its dependencies.Let's try a (probably incomplete) description of the problem we face:
So let's have a look at the problem "app and dependeny both already in sorted list, but wrong order":
Well, I guess I just described a theoretical problem of each dependency solving algorithm 😬
mejo- commentedon Dec 22, 2021
The best I could come up with so far, is an algorithm that works as described above. In case of the "app and dependency both already in sorted list, but wrong order", it chooses "move dependency before the app". That implementation passes the unit tests and all manual testing that broke earlier (different subsets of collectives and deck app enabled and browsing files, collectives and deck app respectively). So it's certainly better than what we had so far, but probably not perfect:
ChristophWurst commentedon Dec 22, 2021
Use a topological sort algorithm. It solves your Problem with the ordering.
mejo- commentedon Dec 22, 2021
I was a bit reluctant to add a PHP dependency for this, but seems like https://github.com/marcj/topsort.php is nice and clean. Shall we use it? I could give it a try. But I didn't contribute much to the server code yet (still kind of a newbie here 😉), and to be honest I don't feel confident enough to take such a decision.
Also, performance is really critical here, as
getScripts()is run at the beginning of every browser request, right? Maybe we should even think about caching dependency chains (.e.g using a hash of alphabetical order of all apps in the list as indices)?Sort app scripts topologically by its dependencies
mejo- commentedon Dec 23, 2021
I couldn't resist and implemented a stripped down version of https://github.com/marcj/topsort.php: #30385
Related unit tests and manuall tests pass 🎉
Sort app scripts topologically by its dependencies
Sort app scripts topologically by its dependencies
Sort app scripts topologically by its dependencies
Sort app scripts topologically by its dependencies
Sort app scripts topologically by its dependencies
Sort app scripts topologically by its dependencies
Sort app scripts topologically by its dependencies