compiler icon indicating copy to clipboard operation
compiler copied to clipboard

elm make refuses to write to standard output

Open LiberalArtist opened this issue 5 years ago • 9 comments

Quick Summary: It would be nice for elm make to be able to write to standard output.

SSCCE

$elm make src/Main.elm --output=/dev/stdout
This flag was given a bad value:

    --output=/dev/stdout

I need a valid <output-file> value. For example:

    --output=elm.js
    --output=index.html
    --output=/dev/null
  • Elm: 0.19.0
  • Browser: n/a
  • Operating System: macOS 10.14.3

Additional Details

I found the error message confusing, in that it was not clear why --output=/dev/null was ok but --output=/dev/stdout was not. It looks like /dev/null is treated as a special case here: https://github.com/elm/compiler/blob/76e90792bc166eab2fe45ec475fe32d2cc320902/builder/src/Generate/Output.hs#L234-L238

Aside from potentially adding another case (e.g. Stdout), I think it would be helpful for the error message to be more explicit about the restrictions on <output-file> values. I, at least, didn't manage to infer them correctly from the examples alone.

LiberalArtist avatar Mar 28 '19 09:03 LiberalArtist

Why are you interested in having the output go to stdout? Do you want JS or HTML? More details on the root motivation would be really helpful in assessing an ideas like this!

evancz avatar Mar 30 '19 00:03 evancz

Thanks for looking at this!

This has come up for me a few times when I've been running elm make programmatically as part of larger projects that are mostly not in Elm. In these cases, I've wanted to generate JS. For example, as part of the process for building a complete application that consists of mostly back-end code, I would like to be able to run essentially elm make Main.elm --optimize --output /dev/stdout | uglifyjs --compress "pure_funcs='F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9',pure_getters,keep_fargs=false,unsafe_comps,unsafe" | uglifyjs --mangle | <… do more work …> (but not in Bash, and with my script supplying a few Elm files to compile, not just Main.elm). In one case where I'm actually doing something like this, <… do more work …> does another simple pass to turn the output of elm make into an ES6 module, then places the output in the directory where the back-end part of the project (which is most of the project) expects to find static files to serve. I also check for problems at each step in the pipeline and either fall back gracefully (e.g. if uglifyjs isn't available) or report the error in terms of what my collaborator ultimately running the build process (who may know nothing about Elm) needs to do. I'm happy to get into as much more detail as would be useful!

Does elm make decide whether to generate JS or HTML based on the extension of the --output file? I guess it seems like it might, though I hadn't totally put that together until now. If so, I could imagine that supporting stdout might be a bigger change than it had seemed at first. I certainly wouldn't object if it seems better not to address potentially supporting stdout until/unless more people emerge who would actually want that. For me personally, at least, working around this by making a temporary file is not a big deal: it definitely took less time than stubbornly trying to figure out why I couldn't write to stdout :)

(I also just wanted to say that I've really enjoyed working with Elm, and I especially appreciate the thoughtful and deliberate design approach you've taken both for the language itself and for the surrounding environment. Thank you for all of your work!)

LiberalArtist avatar Mar 31 '19 18:03 LiberalArtist

Yes, the file extension of --output will decide what get's generated.

So you basically want to keep the content of the file in memory and do some postprocessing? The only benefit I can think of (if I understood you) would be that you skip a write to disk? Anything else I'm missing?

razzeee avatar Mar 31 '19 21:03 razzeee

That's basically right. Keeping the output in memory can also make it easier to avoid overwriting old output until you know if the whole pipeline succeeds, but obviously that can be worked around.

I guess another way to say mostly the same thing is that some interfaces (e.g. for other command-line tools) are oriented more toward piping stdin and stdout around than working with intermediate files. While it's always possible to bridge that gap, having to do so adds an inconvenience factor to those workflows.

LiberalArtist avatar Apr 01 '19 02:04 LiberalArtist

I can think of cases where I'd want this to produce JS, but are there cases where it'd make sense to produce HTML? I think it's worth brainstorming on that.

From there, it'd need some special logic to avoid printing out progress when that kind of output is chosen. That probably should match what happens with --output=/dev/null though. Not sure if it makes sense to have that output no progress messages.

evancz avatar Apr 04 '19 19:04 evancz

Some ideas:

  • Print all non-output data to stderr
  • Accept --output=- as a shorthand to stdout
  • Accept a flag for specifying the format like --output-format=js|html
  • Emit an error message and halt if neither --output-format nor a filename with a .html or .js extension was specified

These ideas would be a step towards upholding the Unix principle "Expect the output of every program to become the input to another, as yet unknown, program."

ggPeti avatar Sep 06 '20 13:09 ggPeti

Another issue with the special handling of --output=/dev/null is that in conjunction with --optimize it doesn't emit the debug remnants warning, because it doesn't run code generation. Maybe this special case should be renamed to elm typecheck while lifting the restriction on output filenames. @evancz would you be okay with a pull request in that vein?

ggPeti avatar Feb 06 '22 13:02 ggPeti