DOM-modifying JS libraries possible without Native code?

I looked around for a long time for a way to embed a code editor (such as Ace or CodeMirror) in an Elm application. Most things didn’t work, or had unexpected behavior, probably due to the fact that those JC libraries modify the DOM, which Elm doesn’t play well with.

I tried every option on this list, and the only thing that I was able to get working is this: https://github.com/DenisKolodin/elm-ace

It uses native code, in some way that I don’t fully understand, to be able to embed the Ace code editor in an Elm application (as opposed to what I think Ellie does, which is to have a JS application with Elm components, keeping the editor itself away from Elm). My question in the subject line may be misplaced, in the sense that I’m not sure whether DOM-modifying is the crucial idea here.

Perhaps it will never be the case that a DOM-modifying library such as Ace could ever be used within an Elm application, so perhaps the answer is “this will never happen, so there will be no embeddable code editor for Elm until someone writes one from scratch in Elm”. If I’m wrong about there, is there an “officially suggested” way to handle this, now that native code will be out?

2 Likes

I dont think a native module is necessary to implement an ace code editor in an Elm application. I think you could do it just with custom elements (https://github.com/webcomponents/custom-elements) @luke mentioned them in another thread and said he uses them at work in their Elm code base. We actually do the same thing where I work.

They work like this.
0 You can make custom html elements like <ace-editor/> in your DOM.
1 You can write a bit of code that automatically runs when an <ace-editor/> is rendered.
2 That code can initialize an ace editor and render it inside your <ace-editor/> tag.

Put those parts together, and that means that you can make your project work in such a way that whenever Elm renders an <ace-editor/> a bit of JavaScript fires up and does the rest of the work rendering an ace editor in that element.

1 Like

Ellie is full Elm application that manages CodeMirror instances with ports:

https://github.com/lukewestby/ellie/blob/master/client/src/Pages/Editor/Layout/View.elm#L101-L105
https://github.com/lukewestby/ellie/blob/master/client/src/Ellie/CodeMirror.elm#L19-L22
https://github.com/lukewestby/ellie/blob/master/client/src/Ellie/CodeMirror/Runner.js#L11

It works because Elm doesn’t think there are any children in that div, so it doesn’t bother to try and mess with any of the children and the CodeMirror content is left alone to do what it wants.

In the next iteration of Ellie this will all be accomplished inside of a custom element:

https://github.com/lukewestby/ellie/blob/server-purs/client/src/Ellie/Ui/CodeEditor.elm#L70
https://github.com/lukewestby/ellie/blob/server-purs/client/src/Ellie/Ui/CodeEditor.js#L43

It works for the same reasons as above, but is nicer from a state management perspective. As far as I’m concerned, using a custom element is the recommended way to embed JavaScript-based DOM widgets when your browsers support them, and ports will work just fine for this use-case otherwise.

12 Likes

This is a very interesting solution.

I’ve tried looking into the browser support, here:

And it seems there is a v0 and v1.

v1 seems to be supported as far as custom html elements goes in Chrome, Firefox and Safari, but there is zero support for IE/Edge.

I think it is important to outline the browser support when suggesting these solutions.

A couple of questions:

  • Does anyone know the difference between v0 and v1?
  • Is there a custom elements polyfill for IE/Edge?

The difference is noticable so you’ll need a polyfill for the v0 browsers. WebComponents.org has you covered for IE11+/Edge

1 Like

@luke I have a question about using customElements. You must be polyfilling this in Ellie, yes? As it works on MS Edge. I looked at the source code but could not easily find where it is polyfilled.

The example you posted above is on the ‘server-purs’ branch. So I wonder if this is not production code? I am guessing this is currently something you are experimenting with in a branch?

It’s in progress and will be published in conjunction with the 0.19 public release. I haven’t installed the polyfill for Ellie yet, but I wouldn’t call it an experiment either. We’re using a custom element in production at NoRedInk for this exact purpose as well. Our error reporting shows occasional runtime errors for very old versions of browsers that we do not support, but all of the browsers in our support range work with the polyfill, including Edge and IE11.

1 Like

Yepp, CustomElements are here to stay. So happy :star_struck: