Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option for UMD-friendly module creation #1920

Closed
MikeTschudi opened this issue Apr 2, 2019 · 4 comments
Closed

Add option for UMD-friendly module creation #1920

MikeTschudi opened this issue Apr 2, 2019 · 4 comments

Comments

@MikeTschudi
Copy link

MikeTschudi commented Apr 2, 2019

Quick Summary:

Please consider a compiler option to add the boilerplate around a compiled >=0.19 Elm module so that the module can be imported in a type-safe way into a TypeScript program.

cf. Support for importing generated code through ES6 imports #193, Compiled Elm code is not friendly to JS modules #1029, Add CommonJS/Node/AMD snippet to end of compiled output #50

SSCCE

From a TypeScript program,

import { Elm } from "./src/Main";
          :          :
const elmComponent = Elm.Main.init({

where src/Main/index.d.ts has been generated by elm-typescript-interop. Interface is typed.

The transpiled TypeScript is

var Main_1 = require("./src/Main");
          :          :
var elmComponent = Main_1.Elm.Main.init({

Without the boilerplate, Main_1 is "3" rather than an object, and thus fails at runtime.

  • Elm: 0.19
  • Browser: Chrome, Firefox, Safari,...
  • Operating System: Windows, Mac OS X

Additional Details

My project is a subset of a much bigger project that uses the Dojo loader, which appears to be less flexible than RequireJS.

As a workaround for my project, I am using a Node script that replaces (function(scope){ at the beginning of the compiled Elm with

(function(factory) {
  if (typeof module === "object" && typeof module.exports === "object") {
    var v = factory(require, exports);
    if (v !== undefined) module.exports = v;
  } else if (typeof define === "function" && define.amd) {
    define(["require", "exports"], factory);
  }
})(function(require, scope) {

and deletes (this) at the end of the compiled Elm.

Discussion in the elmlang.slack.com upgrading channel starts here.

@evancz
Copy link
Member

evancz commented May 6, 2019

The existing output should allow you to put code around the output and integrate with whatever style JS you need. Something like this:

var Elm = function()
{
    // output from compiler
    return this.Elm;
}();

Doing this means you do not need to change the output of the compiler at all, just add a couple lines on either side.

Note: We used to have some code to support different JS module exports style, but after some amount of maintenance woes, we decided that there are too many different ways to load imports in JS (and they changed too often for us) to have the compiler keep up with whatever is going on over there. Doing so would also add extra bytes to the resulting JS files that are only needed by some users in some circumstances.

@evancz evancz closed this as completed May 6, 2019
@Mouvedia
Copy link

Mouvedia commented Jun 5, 2019

@MikeTschudi
Copy link
Author

Nice tool--thanks, @Mouvedia!

@ccapndave
Copy link

ccapndave commented Oct 27, 2022

In case anyone else stumbles upon this, here is a Linux one-liner to turn the output from elm make into something you can import:

echo '1s/^/export const Elm = (function () {/\n$s/$/; return this.Elm; }).apply({}, []);/\nw\nq\n' | ed -s dist/app.js > /dev/null 2>&1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants