Page MenuHomePhabricator

2017 wikitext editor integration in CodeMirror 6
Open, Stalled, Needs TriagePublic

Description

Background

With CodeMirror 5, the CodeMirror object is in the global scope, making it simple for extensions to integrate with it. The 2017 wikitext editor (part of VisualEditor) does this with ve.ui.CodeMirrorAction.js and ve.ui.CodeMirrorTool.js, which live in MediaWiki-extensions-CodeMirror and registered as a PluginModule for VisualEditor. My naive interpretation is that the module binds listeners to the core CodeMirror library, and adds a mirrored ve.ui.Surface on top of the original Surface.

This strategy won't work in CodeMirror 6, as CodeMirror is no longer in the global scope. Additionally, CM6 requires the use of ECMAScript modules, which are currently not supported by ResourceLoader (T281781).

This task is to explore options on how to address the VE integration.

Possible solutions

Rewrite to use ECMAScript modules

The ext.CodeMirror.visualEditor module could be rewritten as a ES6 class, extending the CodeMirror class to get the essential logic, and making whatever additional changes and overrides as necessary.

This could work similar to the following:

// src/codeMirror.visualEditor.js

import CodeMirror from './codemirror';
import { mediaWikiLang } from './codemirror.mode.mediawiki';

class CodeMirrorVisualEditor extends CodeMirror {
    // override methods as necessary, such as initialize()
}

const cm = new CodeMirror( veSurface );
cm.initialize( [ ...cm.defaultExtensions, mediaWikiLang() ] );

We then bundle the compiled JS as a separate file in the dist/ directory, making it accessible to ResourceLoader, and thus can be passed as a PluginModule to VisualEditor.

This to me seems like the most sensible approach, but will require considerable work.

Use JS hooks

A hook could be added to CM6, such that when there's any change to the EditorState, we fire off a hook with the Transaction. We can give a more consumable data format if needed, as otherwise you may need to import CodeMirror classes in order to make use of the transaction data. The VE plugin then just listens to that hook and does it's thing, hopefully with minimal changes to existing code (?).

Status-quo

We also can simply let the old CM5 library remain for the time being. We've decided to give it the deprecation treatment, so it will likely be a while before the CM5 modules are removed. This is the easiest route, but means the 2017 editor won't get any of the new features and updates that come with CM6.

Event Timeline

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

I'm happy to take a stab at the ES6 rewrite, but would love to hear any thoughts from the Editing team before diving in. I may need a fair amount of assistance, too, as my knowledge of VE internals is quite limited.

How about exposing a global CM6 constructor from one RL module? Then all other modules (2003 editor/2010 editor/2017 editor) can easily depend on this module just like ext.CodeMirror.lib.

How about exposing a global CM6 constructor from one RL module? Then all other modules (2003 editor/2010 editor/2017 editor) can easily depend on this module just like ext.CodeMirror.lib.

Something like that would be most ideal, yes. However I'm struggling to find a clean solution. The main problem is we can't mix ECMAScript Modules with CommonJS-style modules, so a true global CodeMirror object (or maybe bound to mw.CodeMirror or something) is seemingly the only way to do it. Ideally we'd be able to do something like this:

mw.loader.using( [ 'ext.CodeMirror.v6` ], ( require ) => {
    const CodeMirror = require( 'ext.CodeMirror.v6` );
    …
} );

but we can't use module.exports in the source. We could have an additional wrapper just for ResourceLoader, still packaged as ext.CodeMirror.v6. We'd need to something similar for the mediawiki mode, and similar for others. It gets messy!

Solving this problem is basically the last chunk of work left. I'm going to make it my focus this week. I'd still love to hear any thoughts from the Editing team, if they have any.

MusikAnimal changed the task status from Open to Stalled.Mar 14 2024, 9:36 PM

Following T214989, we can load CodeMirror in much the same way as before. This may make migrating the 2017 editor integration considerably easier. I'm going to stall this task until that work is complete.