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

Bring back fable-loader? #2195

Closed
alfonsogarciacaro opened this issue Oct 8, 2020 · 19 comments
Closed

Bring back fable-loader? #2195

alfonsogarciacaro opened this issue Oct 8, 2020 · 19 comments

Comments

@alfonsogarciacaro
Copy link
Member

Continuation of discussion here: #2166 (comment)

Nagareyama will become a standalone dotnet tool and it won't be as much Webpack-focused as Fable 2 was, but we could try to release a new fable-loader version that just calls the dotnet tool to make it easier to upgrade existing projects.

I'm preparing a presentation for F# eXchange about the changes in Fable and I can write a blog after so we can get feedback from users. I think most will like the move as it aligns with other F# tools but I might be wrong, let's see.

@inosik
Copy link
Contributor

inosik commented Oct 10, 2020

What does the workflow you have in mind look like, if we won't have a loader? Will Fable simply compile the F# code to an output directory and then Webpack or any other bundler takes over from there?

I haven't been watching the progress on Nagareyama lately, so forgive me if this has been clarified somewhere already.

Having Fable be simple to set up without having to use a template would certainly be really nice.

@alfonsogarciacaro
Copy link
Member Author

Hi @inosik! The goal of Nagareyama is to make Fable simpler by removing the .NET/JS mixture in the compiler itself. So Fable will become a "pure" dotnet tool distributed through Nuget and its only responsibility will be to spit out JS files (avoiding complex interaction with JS tooling). So to compile an F# project (given its Fable-compatible) the only thing you'll need to do is:

dotnet tool install fable
dotnet fable src/Client

You can set an output directory if you want but by default Fable will put the .js files next to the .fs ones.

Then users can do whatever they need with the JS files. In the common case of bundling them with webpack, they only have to set the last generated .js file as the entry in the webpack.config (no extra npm dependencies like fable-loader needed). For simplicity, Fable can run a command after the compilation as in dotnet fable src/Client --run webpack or dotnet fable watch src/Client --run webpack-dev-server

@alfonsogarciacaro alfonsogarciacaro added this to To Do in Nagareyama via automation Oct 11, 2020
@fc1943s
Copy link

fc1943s commented Oct 25, 2020

I like the new approach.
Would this change impair speed optimizations in the future, like HMR? There isn't some kind of concurrency loss?

@alfonsogarciacaro
Copy link
Member Author

I don't think it should affect HMR, but please report if you see something. It's true that by using --run Webpack won't start until the compilation is complete, for that there's the --runFast option that will run the subprocess before the F#/Fable compilation. So if the JS files already exist (usually from a previous compilation) Webpack can work in parallel and the time from 0 to have the server running is reduced basically to the bundling time. And once Fable has finished in parallel, watch compilations are very fast as usual.

@uxsoft
Copy link

uxsoft commented Oct 28, 2020

I'm currently trying to put together an app with a backend using Azure Functions (to be hosted on Azure Static Websites) and what I'm struggling with is setting up redirects for the local development environment when using parcel as shown in the minimal fable3 example.

Personally, I'd be quite excited to get rid of webpack and simplify the stack but this some guidance on how to setup something like a SAFE stack app would be super helpful. If that could be done without fable-loader, then it should be ok not to have it.

Any tips would be appreciated :-)

@inosik
Copy link
Contributor

inosik commented Oct 29, 2020

@uxsoft Did you already see the API Proxy page in Parcels docs? But it looks like it's an upcoming feature of Parcel v2, which apparently isn't released yet. It looks like Parcel doesn't have a built-in proxy in v1.

I found a blog post from one year ago, where the author describes how to set up a dev environment with Parcel and an Express server which acts as a proxy. Maybe this helps.

@alfonsogarciacaro
Copy link
Member Author

@uxsoft Also, just to upgrade your project without touching Webpack, you can follow this example: MangelMaxime/fulma-demo#43

@uxsoft
Copy link

uxsoft commented Oct 29, 2020

Well in that case there should be no need for fable-loader if we can pipe to webpack dev server anyway, no?

@alfonsogarciacaro
Copy link
Member Author

Yes, that's right. The only purpose of the "new" fable-loader would be to let users upgrade to Fable 3 without touching their webpack config or build script, but I'd personally prefer if people get used to the new way as it is aligned with other F# tools and to avoid having to maintain/document two ways of using Fable.

In any case, from the feedback received it seems users are happy with the change, so I will close this issue for now to avoid confusion. We can revisit later if needed.

Nagareyama automation moved this from To Do to Done Oct 30, 2020
@Krzysztof-Cieslak
Copy link
Member

New fable-loader could be useful in case some JS tooling takes webpack config as an input/entry point. For example - Cloudflare Workers: https://developers.cloudflare.com/workers/cli-wrangler/webpack

@Zaid-Ajaj
Copy link
Member

Zaid-Ajaj commented Nov 2, 2020

@Krzysztof-Cieslak Deprecating fable-loader doesn't mean you can't use Fable with webpack anymore, it just means it becomes easier to use in webpack because it just becomes this:

  • dotnet fable triggers Fable as a dotnet CLI tool
  • Fable compiles F# files to JS files (modules)
  • Webpack bundles them

Instead of:

  • fable-loader triggers Fable as entry module loader
  • Fable compiles F# files into JSONified Babel AST (relatively slow)
  • babel-loader takes JSON babel AST and outputs JS code
  • Webpack bundles them

I raised the issue with @alfonsogarciacaro because I thought it would make migration easier if we kept fable-loader and just updated fablec-compiler (the npm package) to latest Fable but maybe it would be a lot better if we simplified all our templates and removed these loaders altogether (also works nicely with other bundles like parcel)

@Krzysztof-Cieslak
Copy link
Member

Sure, it "just" means I need to put additional steps in my build process for something that used to be single step.

Your call if that's reasonable trade off /shrug

@Zaid-Ajaj
Copy link
Member

Zaid-Ajaj commented Nov 2, 2020

The build step is still just one command, except now it doesn't require extra webpack loaders and can easily be used with different bundlers.

# compile project using Fable
dotnet fable ./src 

# compile project then trigger bundler (production build)
dotnet fable ./src --run webpack

# build in watch mode
dotnet fable watch ./src

# build in watch mode and trigger a bundler after compilation
dotnet fable watch ./src --run webpack-dev-server

Webpack only needs to know the entry JS file that is generated from Fable ({lastFile}.fs.js) as the entry file for bundling and minification. fable-loader and babel-loader aren't needed.

@Zaid-Ajaj
Copy link
Member

@alfonsogarciacaro Is there a dotnet fable run that is equivalent to dotnet run which automatically triggers node {lastFile}.fs.js after compilation finishes successfully? Might be an interesting command to show off Fable 🤔

@Krzysztof-Cieslak
Copy link
Member

Krzysztof-Cieslak commented Nov 2, 2020

The build step is still just one command

Not really in a case of CF Workers tooling - it used to be a single call to wrangler dev (which under the hood used webpack somehow, which under the hood executed fable with loader). Now it will be first compiling fable, and then calling wrangler.

Again, it's not a big deal - I'm more just giving an example where old workflow was fitting better.

@Zaid-Ajaj
Copy link
Member

I really liked the previous model too but now that I have tried the new stuff, I really appreciate the perf increase of the compilation when all that overhead is removed

@alfonsogarciacaro
Copy link
Member Author

Does something like dotnet fable dev --run wrangler dev work? In theory, we could have a new fable-loader that just calls dotnet fable but there may be issues with starting/stopping the processes, the watcher, etc. So I'd prefer to avoid it.

@Krzysztof-Cieslak
Copy link
Member

dotnet fable watch src --outDir tmp --run wrangler dev seems to do what I want (i.e. both fable and wrangler in watch mode).

There's some issue with wrangler process not getting killed after I killed dotnet fable process, but it's not a huge problem.

@alfonsogarciacaro
Copy link
Member Author

Cool! Hmm, there were some reports about a similar issue but I thought they were fixed. Can you please have a look at #2212? Are you using Windows? I'm only hooking the termination events in Windows because I didn't see that issue in macOS but we may need to do that as well:

Fable/src/Fable.Cli/Util.fs

Lines 127 to 136 in 111a0b2

// In Windows, terminating the main process doesn't kill the spawned ones so we need
// to listen for the Console.CancelKeyPress and AssemblyLoadContext.Unloading events
if isWindows() then
Console.CancelKeyPress.AddHandler(ConsoleCancelEventHandler(fun _ _ ->
runningProcess |> Option.iter kill))
let assemblyLoadContext =
getCurrentAssembly()
|> Loader.AssemblyLoadContext.GetLoadContext
assemblyLoadContext.add_Unloading(fun _ ->
runningProcess |> Option.iter kill)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Nagareyama
  
Done
Development

No branches or pull requests

6 participants