fable-compiler / Fable

F# to JavaScript, TypeScript, Python, Rust and Dart Compiler
http://fable.io/
MIT License
2.93k stars 301 forks source link

Using babel presets with fableconfig.json #431

Closed Pauan closed 8 years ago

Pauan commented 8 years ago

First off, I deeply appreciate all of the work that you've done on Fable. As a JavaScript developer, it was very easy to set things up, and everything Just Worked! In addition, the code output is impressively good. I especially like that top-level functions (i.e. directly inside of a module) don't use currying, for maximum speed!


Having said that, I want to use babili to minify my code before bundling with Webpack. But the recommended way to use babili is to use a preset. Fable has a babelPlugins option, but I don't see a babelPresets option. Would it be difficult to add?


On a related note, rather than having babelPlugins, babelPresets, module, and loose, it might be better to just have a single babel option which passes all options straight to babel:

// fableconfig.json
{
  "babel": {
    "presets": [
      ["es2015", { "loose": true, "modules": false }]
    ],
    "plugins": [ ... ]
  }
}

Or alternatively you could remove all of the babel-specific options and rely on .babelrc instead, which is already common practice.

That does make configuration a bit more tedious in the common case (since you need to create package.json, fableconfig.json, .babelrc, and webpack.config.js), but it is more consistent with existing practices, and it gives more control without cluttering up fableconfig.json

Pauan commented 8 years ago

Also, it appears that Fable is ignoring the .bablerc file completely when compiling. This makes it impossible to customize Babel in various ways, because fableconfig.json does not support all of the options that .babelrc does.

So I think either fableconfig.json should have a babel option which would work with all Babel options (as described above), or alternatively it should work with .babelrc

alfonsogarciacaro commented 8 years ago

Thank you very much for your kind words. I'm trying to make Fable easy to setup both for F# and JS developers which is not always easy. But I'm glad it worked for you :)

Actually it was possible to use .babelrc before (though I wasn't aware of the fact) but I had to disable it because there're some scenarios (mainly React Native application) where .babelrc is also used and it can interfere with Fable compilation.

I'm not completely agains the idea of making Babel configuration independent, but it would be a breaking change and, as commented above, I'm trying to make the setup easy also for people not so used to JS developments and that's why Babel configuration is sort of hidden.

I need to check about babili. Right now it should be possible to pass plugin options directly in fableconfig.json (using an array with the name of the plugin and the option object). Maybe the best way to cover your use case without breaking current configuration would be to add a babelPresets compiler argument. Would that work for you?

Pauan commented 8 years ago

I understand the concerns about making it easy for non-JS developers. It certainly is easier for Fable to manage everything.

I'm okay with adding a babelPresets option, but I've changed my mind: I would actually prefer if a babelrc option was added. It would default to false, but you could set it to true to enable the .babelrc file.

(If breaking backwards compatibility is okay, you could instead default it to true, and then the user would need to set it to false when using React Native. I don't care much whether the default is true or false, as long as there's some way to specify all the Babel options.)

This keeps the default case simple (module, loose, and babelPlugins), but still allows for using .babelrc when you need more control. Also, I think module/loose/babelPlugins should be optional, so that it's possible for a user to specify all of the Babel options in .babelrc, if they want.

I prefer a babelrc option because using .babelrc is a de-facto standard, so it might make it easier to port existing JS projects to Fable: you would just need to set babelrc to true and it would use the already-existing .babelrc

The only caveat is that if a user is half-way through porting an existing JS project to Fable they might want the JS part of their project to use .babelrc, and they might want Fable to use a different .babelrc. They can handle that by placing their JS code into the /js folder, then placing their F# code into the /fsharp folder, then having /js/.babelrc and /fsharp/.babelrc

Pauan commented 8 years ago

Also, something I just ran into:

I want to write a fairly big JavaScript application in Fable. Of course I'm going to need good integration with existing JS code, and I will also need to write some custom ES6 modules in order to handle the things that Fable/F# can't do.

When using the FFI to import an ES6 module into Fable (e.g. [<Import("*", "foo.js")>]), it simply inserts a require("foo.js"), but it doesn't actually transpile the foo.js file. So you still need to use webpack, babel-core, babel-loader, and babel-preset-es2015 in order to transpile foo.js to ES5.

So right now I have some code duplication: I have to specify things like module and babelPlugins in fabelconfig.json and then specify them a second time in .babelrc (so that the babel-loader can use it).

I think it would be nicer to just specify "babelrc": true in fableconfig.json rather than having duplication between Fable and Webpack.

Of course module, loose, and babelPlugins would still exist, in the situations where people don't want to use .babelrc

Pauan commented 8 years ago

After further experimentation, I tried using this fableconfig.json:

{
  "module": "es2015",
  "ecma": "es2015"
}

Then I transpiled everything through Rollup/Webpack, rather than letting Fable do the transpilation. Now it works correctly with .babelrc, including using babili in the presets

So I'm not sure what the right course of action is:

alfonsogarciacaro commented 8 years ago

Sorry for the late response. Glad to see you managed to adapt the current settings to your case. In any case, I think you had a compelling point for adding a babelrc argument, so I just did it. This will be released very shortly. Please have a look and tell me if that's what you were thinking of.

Pauan commented 8 years ago

Thanks a lot! Version 0.6.8 isn't released on npm yet, so I'm not able to test it, but I took a look at the commit and it seems correct.

Pauan commented 8 years ago

I just tested fable-compiler version 0.6.9 and babelrc seems to work great. Thanks again!