vite-plugin-elm-watch

raw JSON →
1.4.4 verified Mon Apr 27 auth: no javascript

A Vite plugin for seamlessly integrating Elm into your Vite project with reliable Hot Module Replacement (HMR) powered by elm-watch, full-color error overlays, and JS minification for production builds. Current stable version is 1.4.4. The plugin supports multiple Elm compiler modes (debug, optimize, minify) and can export Elm apps as standard objects or React components. It automatically patches DOM for Browser.application usage and provides clickable error links to launch your editor. Experimental but actively maintained.

error Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/node_modules/vite-plugin-elm-watch/dist/index.js from /path/to/vite.config.js not supported.
cause The package is ESM-only (exports ES modules) but you are using require() or have CommonJS project settings.
fix
Change your vite.config.js to use import syntax: import elm from 'vite-plugin-elm-watch'. Also ensure your package.json has "type": "module" or rename file to .mjs.
error TypeError: Cannot read properties of undefined (reading 'app') / Uncaught TypeError: app.unmount is not a function
cause Attempting to unmount an Elm app that was not properly initialized or React component unmount ordering issue.
fix
If using React output, ensure the component is never swapped with a non-Elm component without proper cleanup. For standard mode, call init() before unmount.
error Error: Mismatched anonymous define() module: function...
cause Multiple copies of Elm runtime or incorrect module resolution when using UMD builds.
fix
Use a single version of Elm and ensure your bundler (Vite) handles Elm modules correctly. Avoid mixing CDN and bundled Elm.
error Uncaught (in promise) TypeError: elm.init is not a function
cause The imported Elm module does not have an init method; likely the .elm file does not expose 'main' correctly or the plugin version is incompatible.
fix
Ensure your Elm file defines a 'main' value using Browser.element, Browser.document, or Browser.application. Also verify that the plugin output mode matches your usage.
gotcha When using 'react' output mode, swapping an Elm component with a .tsx component can cause unmount errors because React removes the DOM node before Elm's app.unmount() runs.
fix Wrap Elm components in a container that handles unmounting lifecycle carefully, or avoid swapping Elm/React components at runtime.
gotcha Enabling isBodyPatchEnabled will clear the id attribute from the root element after Elm loads, as Elm removes attributes from its root node.
fix Do not rely on id attributes on the root node after Elm initialization; use class names or data attributes instead.
breaking In version 1.4.2, the plugin changed from using process.cwd() to viteConfig.root for running elm make, which may affect projects where Vite's root is different from the working directory.
fix Ensure Vite's root configuration points to the correct project root. Previously relied on process.cwd() which could be inconsistent.
gotcha Version 1.4.0 fixed a bug with patching DOM nodes internally; projects using Browser.application may have encountered issues with body patching before this fix.
fix Upgrade to v1.4.0 or later for proper Browser.application support.
gotcha Windows HMR detection could fail in v1.3.5 and earlier due to differences in path separators (/ vs \).
fix Update to v1.3.5 or later to fix Windows HMR path detection.
gotcha The plugin is still experimental and may have undiscovered bugs; not recommended for production without thorough testing.
fix Test your specific use case thoroughly, especially HMR and React interop.
npm install vite-plugin-elm-watch
yarn add vite-plugin-elm-watch
pnpm add vite-plugin-elm-watch

Basic setup for a Vite project with Elm: install plugin, configure in vite.config.js, and import .elm files. Shows both default and React output modes.

// vite.config.js
import { defineConfig } from 'vite'
import elm from 'vite-plugin-elm-watch'

export default defineConfig({
  plugins: [elm({ mode: 'auto', output: 'default' })]
})

// src/main.js
// Elm file (Main.elm) exposing 'main' using Browser.element
import Main from './src/Main.elm'

let app = Main.init({
  node: document.getElementById('root'),
  flags: { user: 'Alice' }
})

// For React output mode:
// src/App.tsx
// import ElmComponent from './src/Hello.elm'
// function App() { return <ElmComponent name="World" /> }