Directory

⚓ T374072 CodeMirror 6 + 2017 wikitext editor race conditions
Page MenuHomePhabricator

CodeMirror 6 + 2017 wikitext editor race conditions
Closed, ResolvedPublicBUG REPORT

Description

Steps to replicate the issue (include links if applicable):

What happens?:

The editor loads, but without syntax highlighting. The option is missing from the 'Page options' dropdown where it is normally placed.

What should have happened instead?:

It should have syntax highlighting, and the option should be listed in the 'Page options' dropdown.

Other information

There's some sort of race condition with the combination of CodeMirror 6 and the 2017 editor (RL module ext.CodeMirror.v6.visualEditor). if things are slow enough, the ve.ui.CodeMirrorTool constructor doesn't get called.

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

The v6 module loads the CodeMirror lib (ext.CodeMirror.v6.lib) at the same time as the visualeditor module. In v5, it is loaded after VE and the toolbar have loaded. I'm fairly sure that's the problem. It may have something to do with the fact that ext.CodeMirror.v6 needs the library upfront, while ext.CodeMirror does not. Simply adjusting extension.json (adding ext.CodeMirror.v6.lib as a dependency, etc.) and even adding some mw.loader.using() blocks doesn't seem to reliably fix the issue.

I also suspect that ext.CodeMirror.v6.visualEditor's use of scripts over packageFiles may be to blame. I tried changing to use packageFiles to no avail.

Thus far, I've only been able to reproduce this in Firefox. When using Chromium, I even tried using a custom network profile to mimic weak 2G (the lowest Chromium offers by default is 3G).

I was able to repro in Chromium. Also, at full speed (no throttling). This is a must-fix issue.

This is definitely not a desired solution, but could we try a temporary fix first?

mw.hook( 've.activationComplete' ).add( () => {
	const { target } = ve.init;
	if ( !( target instanceof ve.init.mw.DesktopArticleTarget ) ) { // CM is only available on desktop so far
		return;
	}
	const toolGroup = target.getToolbar().getToolGroupByName( 'pageMenu' );
	if ( toolGroup.getItems().some( ( tool ) => tool instanceof ve.ui.CodeMirrorTool ) ) { // already attached to the toolbar
		return;
	}
	const codeMirrorTool = new ve.ui.CodeMirrorTool( toolGroup );
	toolGroup.addItems( codeMirrorTool );
	codeMirrorTool.setDisabled( target.getSurface().getMode() !== 'source' );
} );

I think the event system of VE is not designed to add tools after initialisation, so even if the above issue is fixed, the tool would still miss the onSurfaceChange event for its setup, and there are no good alternatives for it.

Instead of playing whack-a-mole further, I decided to handle the ve.loadModules hook, so the actual plugin module can be loaded by VE before initialisation. (although it's still a bit hacky when we are not loading the init module on every page view.)

Change #1101130 had a related patch set uploaded (by Func; author: Func):

[mediawiki/extensions/CodeMirror@master] ve.ui.CodeMirror.v6: Use plugin callback to load the actual module

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

By the way, I can also reproduce the bug with v5 after clearing the local storage cache. As mentioned by MusikAnimal, the payload for loading the v5 plugin is smaller and more likely to finish before VE initialisation, so it's not very reproducible in the real world.

Change #1101130 merged by jenkins-bot:

[mediawiki/extensions/CodeMirror@master] ve.ui.CodeMirror.v6: Use plugin callback to load the actual module

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

Change #1102141 had a related patch set uploaded (by Func; author: Func):

[mediawiki/extensions/CodeMirror@wmf/1.44.0-wmf.6] ve.ui.CodeMirror.v6: Use plugin callback to load the actual module

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

I realised that there would not be a 1.44.0-wmf.7 this week, scheduling a backport...

Change #1102141 merged by jenkins-bot:

[mediawiki/extensions/CodeMirror@wmf/1.44.0-wmf.6] ve.ui.CodeMirror.v6: Use plugin callback to load the actual module

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

Mentioned in SAL (#wikimedia-operations) [2024-12-11T14:19:43Z] <samtar@deploy2002> Started scap sync-world: Backport for [[gerrit:1102141|ve.ui.CodeMirror.v6: Use plugin callback to load the actual module (T374072)]], [[gerrit:1102142|styles: Avoid misalignments when line numbering is disabled (T381714)]]

Mentioned in SAL (#wikimedia-operations) [2024-12-11T14:22:59Z] <samtar@deploy2002> samtar, func: Backport for [[gerrit:1102141|ve.ui.CodeMirror.v6: Use plugin callback to load the actual module (T374072)]], [[gerrit:1102142|styles: Avoid misalignments when line numbering is disabled (T381714)]] synced to the testservers (https://wikitech.wikimedia.org/wiki/Mwdebug)

Mentioned in SAL (#wikimedia-operations) [2024-12-11T14:30:26Z] <samtar@deploy2002> Finished scap sync-world: Backport for [[gerrit:1102141|ve.ui.CodeMirror.v6: Use plugin callback to load the actual module (T374072)]], [[gerrit:1102142|styles: Avoid misalignments when line numbering is disabled (T381714)]] (duration: 10m 42s)