Page MenuHomePhabricator

Lexeme pages broken with debug=true enabled
Closed, ResolvedPublic13 Estimated Story Points

Description

As a WikibaseLexeme developer, I want to use debug=true so that I can set resource loader to debug mode in order to disable JS minification for setting breakpoints and to disable caching.

At the moment, any lexeme page with debug=true fails to load any of the JavaScript functionality. It fails with Error: View lexemeview does not exist. Example: https://wikidata.beta.wmflabs.org/wiki/Lexeme:L1?debug=true

I think the following happens:

We should fix this soon since it makes working with the lexeme JavaScript code rather painful.

Questions:
Why does the code still work without debug=true?
This definitely worked at some point. When/why did it break? Recent ResourceLoader optimizations?

Event Timeline

I wasn't able to replicate the problem. Seems @Jakob_WMDE managed to fix with clearing LocalStorage

Tarrow moved this task from incoming to in progress on the Wikidata board.

I can now replicate it and clearing local storage doesn't help me

@Jakob_WMDE pointed out and I could reproduce that if running with chrome debug tools set to stop on caught exceptions there is a a notable one thrown on

extensions/Wikibase/view/resources/wikibase/view/ViewFactory.js#650:
because lexemeview is not found after looking for it in $.wikibase [ 'lexemeview' ]

There are also some other random selector errors that are caught that seem unimportant.

Attempting to run without debug=true and looking at the first call of the function where the error is thrown (extensions/Wikibase/view/resources/wikibase/view/ViewFactory.js _getView()) it appears that $.wikibase [ 'lexemeview' ] does exist.

Furthermore, running with debug=true and waiting until after page load $.wikibase [ 'lexemeview' ] also exists.

This strongly suggests that there is an issue with our resourceloader dependencies meaning that lexemeview isn't loaded at the right time.

To try and figure out what needs doing @Lucas_Werkmeister_WMDE helpfully showed a way to dump the dependencies:

graph = 'digraph dependencies{\n';
for (module in mw.loader.moduleRegistry) { for (depended of mw.loader.moduleRegistry[module].dependencies) { graph += `"${module}" -> "${depended}"\n`; } }
graph += '}\n';

The output of that can be seen in this paste: https://phabricator.wikimedia.org/P7789

a "pretty" svg can be built using graphviz and the dot package with dot -Tsvg

Addshore triaged this task as Medium priority.Nov 12 2018, 10:59 AM

Most curiously nothing explicitly depends on wikibase.lexeme.lexemeview however at first glance what appears backwards is wikibase.lexeme.view.ViewFactoryFactory is depended upon by jquery.wikibase.lexemeview

Attempting to have lexeme's ControllerViewFactory depend on

"jquery.wikibase.senselistview",
"jquery.wikibase.lexemeformlistview",
"wikibase.lexeme.lexemeview

and removing the lexemeview dependency on ViewFactoryFactory

Gets past the missing lexemeview however we then fall on what appears to be a similar problem

jquery.js?6a07d:3818 jQuery.Deferred exception: this.options.buildFormListView is not a function TypeError: this.options.buildFormListView is not a function
    at $.(anonymous function).(anonymous function)._create (http://default.web.mw.localhost:8080/mediawiki/extensions/WikibaseLexeme/resources/jquery.wikibase.lexemeview.js?1b1eb:52:17)
    at $.(anonymous function).(anonymous function)._create (http://default.web.mw.localhost:8080/mediawiki/resources/lib/jquery.ui/jquery.ui.widget.js?7d91d:90:26)
    at $.(anonymous function).(anonymous function)._createWidget (http://default.web.mw.localhost:8080/mediawiki/resources/lib/jquery.ui/jquery.ui.widget.js?7d91d:255:8)
    at new $.(anonymous function).(anonymous function) (http://default.web.mw.localhost:8080/mediawiki/resources/lib/jquery.ui/jquery.ui.widget.js?7d91d:54:9)
    at HTMLDivElement.<anonymous> (http://default.web.mw.localhost:8080/mediawiki/resources/lib/jquery.ui/jquery.ui.widget.js?7d91d:199:30)
    at Function.each (http://default.web.mw.localhost:8080/mediawiki/resources/lib/jquery/jquery.js?6a07d:354:19)
    at jQuery.fn.init.each (http://default.web.mw.localhost:8080/mediawiki/resources/lib/jquery/jquery.js?6a07d:189:17)
    at jQuery.fn.init.$.fn.(anonymous function) [as lexemeview] (http://default.web.mw.localhost:8080/mediawiki/resources/lib/jquery.ui/jquery.ui.widget.js?7d91d:194:9)
    at Object.SELF._getView (http://default.web.mw.localhost:8080/mediawiki/extensions/Wikibase/view/resources/wikibase/view/ViewFactory.js?3cefe:653:19)
    at Object.SELF.getEntityView (http://default.web.mw.localhost:8080/mediawiki/extensions/Wikibase/view/resources/wikibase/view/ViewFactory.js?3cefe:177:15) undefined

Breaking here results in a stack trace like that below:

_create (jquery.wikibase.lexemeview.js?1b1eb:47)
(anonymous) (jquery.ui.widget.js?7d91d:90)
_createWidget (jquery.ui.widget.js?7d91d:255)
$.(anonymous function).(anonymous function) (jquery.ui.widget.js?7d91d:54)
(anonymous) (jquery.ui.widget.js?7d91d:199)
each (jquery.js?6a07d:354)
each (jquery.js?6a07d:189)
$.fn.(anonymous function) (jquery.ui.widget.js?7d91d:194)
SELF._getView (ViewFactory.js?3cefe:653)
SELF.getEntityView (ViewFactory.js?3cefe:177)
createEntityView (wikibase.ui.entityViewInit.js?8d6a3:141)
(anonymous) (wikibase.ui.entityViewInit.js?8d6a3:357)
fire (jquery.js?6a07d:3268)
fireWith (jquery.js?6a07d:3398)
mightThrow (jquery.js?6a07d:3593)
process (jquery.js?6a07d:3602)
(anonymous) (jquery.js?6a07d:3632)
mightThrow (jquery.js?6a07d:3534)
process (jquery.js?6a07d:3602)
setTimeout (async)
(anonymous) (jquery.js?6a07d:3640)
fire (jquery.js?6a07d:3268)
fireWith (jquery.js?6a07d:3398)
fire (jquery.js?6a07d:3406)
fire (jquery.js?6a07d:3268)
fireWith (jquery.js?6a07d:3398)
mightThrow (jquery.js?6a07d:3593)
process (jquery.js?6a07d:3602)
setTimeout (async)
(anonymous) (jquery.js?6a07d:3640)
fire (jquery.js?6a07d:3268)
add (jquery.js?6a07d:3327)
(anonymous) (jquery.js?6a07d:3660)
jQuery.Deferred (jquery.migrate.js?cacf7:616)
then (jquery.js?6a07d:3645)
(anonymous) (wikibase.EntityInitializer.js?fdc51:65)
mightThrow (jquery.js?6a07d:3534)
process (jquery.js?6a07d:3602)
setTimeout (async)
(anonymous) (jquery.js?6a07d:3640)
fire (jquery.js?6a07d:3268)
add (jquery.js?6a07d:3327)
(anonymous) (jquery.js?6a07d:3660)
jQuery.Deferred (jquery.migrate.js?cacf7:616)
then (jquery.js?6a07d:3645)
getEntity (wikibase.EntityInitializer.js?fdc51:64)
(anonymous) (wikibase.ui.entityViewInit.js?8d6a3:356)
fire (jquery.js?6a07d:3268)
add (jquery.js?6a07d:3327)
(anonymous) (wikibase.ui.entityViewInit.js?8d6a3:346)
(anonymous) (wikibase.ui.entityViewInit.js?8d6a3:398)

Noticeable is that the lexeme ControllerViewFactory doesn't appear to be being used. In fact it appears that it's not even loaded by ResourceLoader at this point.

Addshore set the point value for this task to 13.Nov 13 2018, 2:21 PM
Addshore subscribed.

During the story time @Tarrow said that it might be worth asking @Jakob_WMDE about this a bit

So, after a lot of investigation I can basely confirm what is stated in the original description by @Jakob_WMDE(?):

  1. [[https://github.com/wikimedia/mediawiki-extensions-Wikibase/blob/ae4483832975af98862b75515e1e6f8eefda55d9/repo/includes/ParserOutput/EntityParserOutputGenerator.php#L244|EntityParserOutputGenerator line 244]] loads wikibase.ui.entityViewInit
  2. [[https://github.com/wikimedia/mediawiki-extensions-WikibaseLexeme/blob/b6f9af30c90b1f08a559382b02358bb0e6d8092b/src/MediaWiki/Actions/ViewLexemeAction.php#L22|ViewLexemeAction]] concurrently loads wikibase.lexeme.lexemeview
    • This is also the reason why nothing depends on wikibase.lexeme.lexemeview -- it is an entrypoint
  3. entityViewInit has no dependency on Lexeme, so it may run before any Lexeme code is there
  4. it recognizes (how?) that it has to construct a Lexeme entity and tries to use a lexeme ViewFactoryFactory
    • however, that factory might not be there because that in turn would be initialized by the js executed in the wikibase.lexeme.lexemeview dependency chain
  5. thus we have a race condition between the javascript of the two entry points
    • some playing around with the dependencies might make the Lexeme ViewFactoryFactory available in time, but ultimately the code depends on $.wikibase.lexemeview being available which I wasn't able to achive
  6. subsequently there is the exception in Wikibase [[https://github.com/wikimedia/mediawiki-extensions-Wikibase/blob/ae4483832975af98862b75515e1e6f8eefda55d9/view/resources/wikibase/view/ViewFactory.js#L650|ViewFactory]] that @Tarrow found

I'm not sure if there is a simple fix for this. Possible solutions I see:

  • somehow make sure that some js code is executed with higher priority than other code without creating an explicit dependency in resource loader?
  • refactor the code to provide a promise for ViewFactoryFactory that resolves when lexemeview is done loading
  • have wikibase.ui.entityViewInit-js somewhere trigger an event to which wikibase.lexeme.lexemeview-js somehow subscribes and only returns after it is done loading
Michael subscribed.

Can we somehow introduce a dependency from wikibase.ui.entityViewInit on wikibase.lexeme.lexemeview, e. g. by introducing a hook in Wikibase to collect additional lexeme views, and use that during ResourceLoader registration? (I have no idea if that’s possible.)

Change 474676 had a related patch set uploaded (by Michael Große; owner: Michael Große):
[mediawiki/extensions/Wikibase@master] Add hook to wait for views being loaded

https://gerrit.wikimedia.org/r/474676

Change 474678 had a related patch set uploaded (by Michael Große; owner: Michael Große):
[mediawiki/extensions/WikibaseLexeme@master] Ensure lexemeview is loaded during debugging

https://gerrit.wikimedia.org/r/474678

Change 474676 merged by jenkins-bot:
[mediawiki/extensions/Wikibase@master] Add hook to wait for views being loaded

https://gerrit.wikimedia.org/r/474676

Change 474678 merged by jenkins-bot:
[mediawiki/extensions/WikibaseLexeme@master] Ensure lexemeview is loaded during debugging

https://gerrit.wikimedia.org/r/474678