Beyond the Prior

Getting CMD+F Working in CodeMirror 6

I use a lightweight CodeMirror setup for an editor that has some custom inline badges to represent variable interpolation. Over time though, I noticed that the browser search (Cmd+F) wouldn’t find text in the editor. Finally, I looked into it some more, and realized that it’s due to CodeMirror’s use of virtual DOM for rendering the editor content. This makes a lot of sense for performance reasons, but for my case it wasn’t really needed (I was editing at most ~300 lines).

This was easy to disable in CodeMirror 5 by setting viewportMargin: Infinity. However, CodeMirror v6 made this intentionally difficult (apparently because a lot of CodeMirror 5 users disabled it and then complained about performance).

Finally, with a little help from AI, I found the viewportMargin hack still works in CodeMirror 6, just through a different config (VP.Margin). Unfortunately, this wasn’t something I could monkey-patch at runtime since it was hard-coded into the bundled JavaScript. I didn’t want to maintain a fork, so decided to use a Vite plugin to hackily rewrite the relevant parts of the code. This was the first time I’d used Vite like this, so I was pleasantly surprised by how simple it was:

// HACK: Disable CodeMirror virtual DOM by replacing VP.Margin with a huge value
// This forces CodeMirror to render all content instead of virtualizing
function disableCodeMirrorVirtualDom(): Plugin {
  return {
    name: 'disable-codemirror-virtual-dom',
    transform(code, id) {
      if (id.includes('@codemirror/view')) {
        return code.replaceAll('1000 /* VP.Margin */', '1e9 /* VP.Margin (HACKED) */')
      }
    },
  }

export default defineConfig({
  plugins: [
    ...
    disableCodeMirrorVirtualDom(),
    ...
  ],
  ...
})

This worked perfectly! Now I can Cmd-F to my heart’s content. And don’t worry @marijn, I promise I won’t complain about performance.