Coder Social home page Coder Social logo

hmsk / vite-plugin-elm Goto Github PK

View Code? Open in Web Editor NEW
194.0 4.0 31.0 2.83 MB

A plugin for Vite enables you to compile an Elm application/document/element

Home Page: https://www.npmjs.com/package/vite-plugin-elm

License: Other

TypeScript 80.69% HTML 2.57% Elm 13.94% JavaScript 2.79%
vite elm vite-plugin

vite-plugin-elm's Introduction

vite-plugin-elm

npm npm next channel GitHub Workflow Status

A plugin that enables us to compile an Elm application, document, or element within your Vite project. In development, hot module replacement works to some extent.

import { Elm } from './MyApplication.elm'

Elm.MyApplication.init()

Setup

npm i -D vite-plugin-elm

In vite.config.(js|ts):

import { defineConfig } from 'vite'
import elmPlugin from 'vite-plugin-elm'

export default defineConfig({
  plugins: [elmPlugin()]
})

Then you can import a .elm file and run it like:

import { Elm } from './Hello.elm'

// Mount "Hello" Browser.{element,document} on #root
Elm.Hello.init({
  node: document.getElementById('root'),
  flags: "Initial Message"
})

You can explore the /example directory to experiment with an actual Vite project. Additionally, this functional website can serve as a helpful resource to learn how to use it effectively.

Options

debug (Default: process.env.NODE_ENV !== 'production')

You can control the debug mode of Elm, which toggles the Elm Debugger, by providing a boolean value.

image

elmPlugin({ debug: false })

When set to false, it disables debug mode in both development and production. Conversely, setting it to true enables debug mode even in production. It's important to note that when the production build has debug mode enabled, Elm's compiler optimizations do not take place.

optimize (Default: !debug && process.env.NODE_ENV === 'production')

You can control build optimization by providing a boolean value, which can be useful for using Debug functions in your Elm code.

elmPlugin({ debug: false, optimize: false })

When set to true, it optimizes the build and prohibits the usage of Debug Elm functions. If you specify the optimize attribute, you must indicate whether debugging is needed. This is because you might want to have debug traces for the purpose of observing all actions, not necessarily for debugging specific issues.

Static Assets Handling

This plugin supports importing assets by using a specific tag [VITE_PLUGIN_ELM_ASSET:<path to asset>] to leverage Vite's asset handling. When your Elm code contains a tag, this plugin replaces that string with the imported asset. It's important to note that the string should be a standalone string without any concatenation.

Html.img [ Html.Attributes.src "[VITE_PLUGIN_ELM_ASSET:/assets/logo.jpg]" ] []

Helper package

We can simplify the tagging process by using the Elm package elm-vite-plugin-helper:

elm install hmsk/elm-vite-plugin-helper
import VitePluginHelper

Html.img [ Html.Attributes.src <| VitePluginHelper.asset "/assets/logo.png?inline" ] []

Combine multiple main files (Experimental)

By passing importing paths via the with URL-ish parameter(s), the plugin compiles multiple main files in a single compilation process. This results in a single Elm export that contains multiple properties, each corresponding to a given main file. This feature helps reduce the bundle size when compared to importing each file separately because common modules and Elm core code are not repeated.

// `Elm.App` and `Elm.Another`, both can work as like importing individually.
import { Elm } from './App.elm?with=./Another.elm'

Elm.App.init({
  node: document.getElementById('rootForApp'),
})
Elm.Another.init({
  node: document.getElementById('rootForAnother'),
})

For 3+ main files:

import { Elm } from './App.elm?with=./Another.elm&with=./YetAnother.elm'

Acknowledgement

License

MIT

vite-plugin-elm's People

Contributors

andrewgryan avatar anmolitor avatar ccapndave avatar dependabot[bot] avatar hmsk avatar icidasset avatar jamesbirtles avatar janwirth avatar klaftertief avatar mapmarkus avatar marc136 avatar mattpolzin avatar nnnnathann avatar notgne2 avatar shanekenney avatar wadouk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

vite-plugin-elm's Issues

Undefined initialStateTuple.a.state.a

When testing version 2.4.0 ( first found it in 2.4.1 , 2.3.1 appears to not have this issue ) I got a

Uncaught TypeError: Cannot read property 'a' of undefined

that I've traced to this line :

9c910a2#diff-a2a171449d862fe29692ce031981047d7ab755ae7f84c707aef80701b3ea0c80R313

initializingInstance.initialState = JSON.stringify(initialStateTuple.a.state.a)
initialStateTuple.a

exists, but doesn't contain any .state

recreated both vith [email protected] and [email protected]

graphql gen, other preprocessors

I'm curious if you would implement adding calling elm/graphql's code gen as part of this plugin or recommend defining a second vite plugin which performed that task and defined a proper ordering between the two plugins?

Not working after Elm error

Hey πŸ‘‹ Thank you for this plugin!

I'm wondering if I'm doing something wrong or not. Whenever I make a change that results in an Elm compilation error, it seems like the vite server stops working and I have to restart it. Hot module reloading stops working, and a manual page refresh shows a blank page with the error message:

Uncaught SyntaxError: The requested module '/Application/Main.elm?t=1619816081719&import' does not provide an export named 'Elm'

Any thoughts on how to resolve this?

Additional notes:
v2.1.2 of this plugin with vite v2.2.3

Toggle Elm debugger

@hmsk I notice that debug mode is triggered by checking production mode, e.g. with !isBuild. Would it make sense to add an option to the plugin constructor function?

For example, elmPlugin({ debug: false }), the debug option could default to !(process.env.NODE_ENV == 'production') if not explicitly set by the user.

I ask because there are occasions in development when it would be nice to disable the debugger, e.g. when developing for mobile or when the app state is large.

I'm happy to submit a PR if you find this functionality useful, I haven't attempted a solution yet and apologies if opening an issue is not the best way to get in touch.

vanilla install has dependency error

Describe the bug
I installed vite@latest
then tried npm i -D vite-plugin-elm

and got

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/vite
npm ERR!   dev vite@"^4.2.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer vite@"^3.0.0 || ^2.0.0" from [email protected]
npm ERR! node_modules/vite-plugin-elm
npm ERR!   dev vite-plugin-elm@"*" from the root project

Possible race condition that leads to a corrupt elm-stuff folder

Hello @hmsk,

I'm not sure if I should really create this as an issue because I did not reproduce this problem with vite: But the elm compiler does not like it when he runs twice at the same time on the same main elm file. It can lead to a corrupted elm-stuff folder.
So far I only reproduced this with larger code bases.

Anyway, I wanted to make you aware of this potential issue and also link you to how I solved the problem in my snowpack plugin in case you need it.

Cheers,
marc

Documentation out of date

Describe the bug
The instructions here are out of date: https://www.npmjs.com/package/vite-plugin-elm?activeTab=readme

The code below no longer works:

import { defineConfig } from 'vite'
import elmPlugin from 'vite-plugin-elm'

export default defineConfig({
  plugins: [elmPlugin()]
})

I get the following:

~/code/dc/dentalcloud__frontend main ?11 ❯ tree
.
β”œβ”€β”€ public
β”‚   └── vite.svg
β”œβ”€β”€ src
β”‚   └── Main.elm
β”œβ”€β”€ counter.js
β”œβ”€β”€ index.html
β”œβ”€β”€ javascript.svg
β”œβ”€β”€ main.js
β”œβ”€β”€ package.json
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ style.css
└── vite.config.js

3 directories, 10 files
~/code/dc/dentalcloud__frontend main ?11 ❯ npm run dev

> [email protected] dev
> vite

failed to load config from /home/j/code/dc/dentalcloud__frontend/vite.config.js
error when starting dev server:
TypeError: elmPlugin is not a function
    at file:///home/j/code/dc/dentalcloud__frontend/vite.config.js.timestamp-1706023752392-5120f0bc7e145.mjs:5:13
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async loadConfigFromBundledFile (file:///home/j/code/dc/dentalcloud__frontend/node_modules/vite/dist/node/chunks/dep-9A4-l-43.js:68383:21)
    at async loadConfigFromFile (file:///home/j/code/dc/dentalcloud__frontend/node_modules/vite/dist/node/chunks/dep-9A4-l-43.js:68240:28)
    at async resolveConfig (file:///home/j/code/dc/dentalcloud__frontend/node_modules/vite/dist/node/chunks/dep-9A4-l-43.js:67841:28)
    at async _createServer (file:///home/j/code/dc/dentalcloud__frontend/node_modules/vite/dist/node/chunks/dep-9A4-l-43.js:60327:20)
    at async CAC.<anonymous> (file:///home/j/code/dc/dentalcloud__frontend/node_modules/vite/dist/node/cli.js:764:24)
~/code/dc/dentalcloud__frontend main ?11 ❯

Example in README for multiple inputs is not correct

Describe the bug

Basically, is not & but &with=

import { Elm } from './App.elm?with=./Another.elm&./YetAnother.elm'

Expected behavior

import { Elm } from './App.elm?with=./Another.elm&with=./YetAnother.elm'

Vite 2.5 Cannot read property '_addedImports' of undefined

This plug-in works fine in vite 2.4 But with 2.5 I'm getting this (redacted):

Internal server error: Cannot read property '_addedImports' of undefined
Plugin: vite-plugin-elm
vite    |   File: [..]/spa/.elm-spa/defaults/Main.elm
vite    |       at addWatchFile ([..]/spa/node_modules/vite/dist/node/chunks/dep-98dbe93b.js:51077:19)
vite    |       at Array.forEach (<anonymous>)
vite    |       at TransformContext.transform ([..]/spa/node_modules/vite-plugin-elm/dist/index.js:427:34)
vite    |       at async Object.transform ([..]/spa/node_modules/vite/dist/node/chunks/dep-98dbe93b.js:51311:30)
vite    |       at async transformRequest ([..]/spa/node_modules/vite/dist/node/chunks/dep-98dbe93b.js:67150:29)

Thanks

Debug flag defaulting to true even if NODE_ENV=production

I've noticed there's cases where the debug flag defaults to true even if NODE_ENV is eventually set to production by Vite. This is because defaulting the debug flag happens too early (when the plugin is loaded), before Vite has finished determining what the NODE_ENV is.

You can reproduce the issue by using a dotenv file to set the NODE_ENV, similiar to what's described in the modes section of the documentation.

https://vitejs.dev/guide/env-and-mode.html#modes

Reference assets from elm

Hi, and thanks for maintaining this nice library :)
As web developers we often have the need for importing static assets from our code without actuallly knowing what the asset is going to be called after a build e.g. because of hashed naming).
Vitejs' approach to this is (similar to to webpack etc.) is to let users import assets as EJS modules which then resolve to a url string. Another benefit this has is that Vitejs can only package assets which are referenced by your code at the time.

I've struggled with missing this feature in Elm for a while. For webpack there is a custom loader that does this by patching the resulting js, but this is hacky and also not available in Vitejs which I like more conceptually.

I was wondering whether some form of this feature could be implemented in the elm plugin. I'm not sure yet how it would work internally, maybe using some code generation that creates a module containing functions for all the assets (this would have the benefit of allowing for code completion)

Can't install the vite-plugin-elm package

Describe the bug
When I run npm i -D vite-plugin-elm as per the instructions, I get the following error:

image

Reproducible repo
Provide a link for a minimum repo to reproduce your problem in other developers local instantly. It'll be great providing screenshots/screencasts to help explain your problem.

Or clone and edit /example project under this plugin's repo with tests under /cypress/integration which fails for your expected behavior.

Expected behavior
Expect the package to be installed successfully.

Can't take default import in ES module

Docs say

import elmPlugin from 'vite-plugin-elm'

export default defineConfig({
  plugins: [elmPlugin()]
})

that does not work, but the example gives a clue to using plugins: [elmPlugin.plugin()]

Vite 5 support

Describe the bug
Upgrading Vite from 4.X -> 5.X causes plugin error. I believe this is because Vite 5 deprecated CJS support in the major version change.

Reproducible repo
Link for a minimum repo here

Screenshot 2023-11-23 at 11 46 24β€―AM Screenshot 2023-11-28 at 11 53 24β€―AM

Expected behavior
Plugin works wonderfully w/ Vite 5 as it did with Vite 4.

Additional context

Elm - v0.19.1
Node - v20.5.1
Vite - v5.0.3
TypeScript - v5.3.2
vite-plugin-elm - v2.8.0

example app fails to build

Describe the bug
The example app does not build. Running npm run dev results in

failed to load config from /Users/fcy/vendor/vite-plugin-elm/example/vite.config.ts
error when starting dev server:
Error: Cannot find module '/Users/fcy/vendor/vite-plugin-elm/example/node_modules/vite-plugin-elm/dist/index.js'. Please verify that the package.json has a valid "main" entry
    at tryPackage (node:internal/modules/cjs/loader:354:19)
    at Module._findPath (node:internal/modules/cjs/loader:567:18)
    at Module._resolveFilename (node:internal/modules/cjs/loader:925:27)
    at Module._load (node:internal/modules/cjs/loader:780:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (/Users/fcy/vendor/vite-plugin-elm/example/vite.config.ts:27:30)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at require.extensions.<computed> [as .ts] (/Users/fcy/vendor/vite-plugin-elm/example/node_modules/vite/dist/node/chunks/dep-88bd5805.js:61911:20)
    at Module.load (node:internal/modules/cjs/loader:981:32)

Reproducible repo
Clone this repo. Then do:

cd example
npm install
npm run dev

Expected behavior
I expect vite to build the example app and start up a dev server.

Additional context

  • version v2.7.0-beta.2-14-g05de8ab of this repo, per git describe
  • macOS 12.3.1
  • npm 8.8.0
  • Elm 0.19.1

Cannot find module or its corresponding type declarations

Describe the bug
You get an error when you import vite-plugin-elm inside of a typescript file:
Cannot find module 'vite-plugin-elm' or its corresponding type declarations.ts(2307)

Reproducible repo
npm i vite-plugin-elm and import elmPlugin from 'vite-plugin-elm' in any .ts file should suffice.

Expected behavior
No error

Additional context
I have already opened a PR which fixed the issue by adding the "types" field to package.json.
#684

'Could not find Browser.Navigation.Key'

Hey there,

the following error occurs right after the first hot reload

[vite-plugin-elm] Hot-swapping Main not possible: could not find Browser.Navigation.Key in the new app model

This seems be related to a change in Elm. The issue was already resolved in elm-hot klazuka/elm-hot@1454183

Thank you for this plugin!

HMR on Windows

Describe the bug
On windows, when you have a Main.elm file and any other file (lets call it Test.elm) that Main.elm imports,
changes to Test.elm do not trigger a HMR. The browser does not receive any updates. Right now,
the only workaround is changing Main.elm occasionally to sync the rest of the changed modules as well.

Reproducible repo
This repositories /example project should work perfectly fine, if not please let me know.

Expected behavior
I expect changes to depending modules to trigger HMR updates so I see the most recent version of my files in the browser.

Proposed fix
#287

Additional context
Elm 0.19.1
Vite 2.9.14
Plugin 2.6.1
OS Windows 10

Handle optimize flag without debug or build

Hi,

My use case is to generate multiple sub elm programs that are loaded togehter and maybe debugging all together because of integration or communication problems between JS and Elm sub programs. To make the way I have configured the build of sub modules are built the vite build in this way I produce a file that could be loaded as "JS umd". Sometimes to debug one module, or all together, I need to run vite build but for dev purpose with having Debug.log.
I don't find any way in vite to have multiple entries and handle all my programs by the same vite so I have one vite for the top application, and vite build that generate "JS umd" for submodules so I need to have optimize: false in those submodules in dev but with vite build.

Any advice ? workaround ?
I will fork and propose the fix.

Vite server 500 crash when using `VitePluginHelper.asset` with concatenated string

When I go to add VitePluginHelper.asset to my svg path strings in Elm, the server no longer works, and vite crashes with:

TypeError: Invalid value used in weak set
    at WeakSet.add (<anonymous>)
    at output (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:12529:30)
    at Object.error (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:12571:13)
    at logError (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:42888:26)
    at viteErrorMiddleware (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:42902:9)
    at call (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:48900:7)
    at next (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:48848:5)
    at call (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:48913:3)
    at next (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:48848:5)
    at call (file:///home/adroit/Projects/Minder/node_modules/.pnpm/[email protected]_@[email protected]/node_modules/vite/dist/node/chunks/dep-79892de8.js:48913:3)

But as soon as I take it out and leave it as a plain string, it works fine again.

Dependencies outside of src directory do not get watched.

My directory structure is as follows

/frontend
  /Main.elm
  /elm.json
/framework
  /frontend
    /Router.elm

In my elm.json I have "source-directories": [".", "../framework/frontend"].

There are two subsequent problems that I solved in my local copy of the plugin but I am not sure if I broke something else.

  1. When I save Router.elm there is no compilation triggered at all. That is, handleHotUpdate never gets called. This is how I tested it:
handleHotUpdate({ file, server, modules }) {
            console.log('hot', file)
            // ...

How I fix it:

Below line 401 (https://github.com/hmsk/vite-plugin-elm/blob/main/src/index.ts#L402) I insert:

            dependencies.forEach(dep => {
                this.addWatchFile(dep)
            })
  1. If Router.elm breaks once, it gets removed from the compileableFiles set: https://github.com/hmsk/vite-plugin-elm/blob/main/src/index.ts#L411. Then it is not found in the compilableFiles anymore: https://github.com/hmsk/vite-plugin-elm/blob/main/src/index.ts#L379

If I comment this out the compileableFiles.delete it works without problems.

What is the purpose of compileableFiles? What am I breaking with this modification?

Allow multiple input files

It would be great if the plugin could support multiple elm files.

I'm thinking that one could use import { Elm } from './src/Hello|Ola.elm' in the typescript part and the plugin would compile ./src/Hello.elm and ./src/Ola.elm into the same output. They would then be available as Elm.Hello and Elm.Ola.

the node-elm-compiler already supports multiple input files so, it looks like only a matter of turning id into a file list and reduce that list to the full list of dependencies.

Preserve colours in Elm error messages

Currently all the colours from the Elm compiler are stripped out and Vite shows everything in the same colour. It would be lovely if the colours could be preserved as it makes errors much easier to read.

Update readme

The readme is kinda confusing as it mentions markdown

Official support for elm-optimize-level-2

We currently use elm-optimize-level-2 with this vite plugin using the trick described in #2

We quite rely on elm-optimize-level-2 for our application to run efficiently, but we'd also like to enable eol2's --optimize-speed flag, which isn't possible the way things are now.

Would you consider adding official support for elm-optimize-level-2 to this plugin, with the option to pass additional flags?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.