elm-break-dom

Build Status Netlify Status

Elm's Virtual DOM does not work well with Chrome extensions (Issue). This repository aims to resolve it by following process.

  • Gather information about how extensions break DOM (insert, wrap, etc.)
  • Make a patch for elm/virtual-dom
  • Try online with problematic extensions enabled/disabled

Known Extensions

This table describes where and when an element is inserted, thanks to the discussion in the discourse thread. More informarion is still welcome.

Plugin (Users) Where in <body> When Workaround (keep enabled) Workaround (disable)
Google Translate (10,000,000+) middle translate the page <meta name="google" content="notranslate"> in <head>
Google Translate bottom select words rough patch, use Browser.element
Grammarly (10,000,000+) middle focus on <textarea> data-gramm_editor="false"
Dark Reader (1,763,020) middle (sometimes) laod make <style> the last child, avoid using <style> in <body>
ChromeVox (161,918) top load, focus on something rough patch, use Browser.element
Viber (133,220) top, bottom load rough patch, use Browser.element

Note:

  • For "Where in <body>" Column, top and bottom breaks Browser.application and middle breaks both Browser.application and Browser.element. middle contains modifications to all descendant elements in the <body>.
  • Some of the extensions insert elements in <head> or after <body>. They are excluded from this list because it has no harm.

Test patched VirtualDOM

You can test the patched version of elm/virtual-dom. About the patch, see more details here.

Install

npm install

Build

npm run build

This will build:

  • patched version of elm/virtual-dom
  • simple.js from src/ using the original version
  • simple-patched.js from src/ using the patched version

Auto test

npm test

This test uses puppeteer and breaks DOM in various patterns without real Chrome extensions.

For each test case,

  • An element is inserted/removed via ports when a button is clicked.
  • Elm will update Virtual DOM. See the source to find where in the DOM is updated in each case.

Manual test

npm run test:extensions

This test coveres problematic cases of well-known extensions.

Since this test uses the real extensions, it cannot be covered by puppeteer. You need to see the result on your Chrome. Turn on and off the your extensions to see how the results change.

Appendix: Hacky patch for Browser.application

Here is a simple patch (thanks to a discourse comment) for Browser.application.

root_id=root # Note: <div id="$root_id"> must exist before Elm.Main.init()
cat elm.js\
  | sed "s/var bodyNode = _VirtualDom_doc.body;/var bodyNode = _VirtualDom_doc.getElementById('$root_id');/"\
  | sed "s/var nextNode = _VirtualDom_node('body')(_List_Nil)(doc.body);/var nextNode = _VirtualDom_node('div')(_List_Nil)(doc.body);/"\
  > elm-patched.js

Note: This is just a workaround, NOT a fix. For Browser.application, the root should be always <body> element. This is by design. Note: This will be no use once this patch is merged.