fable-compiler / Fable

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

Better support for fable-compiler-js #3794

Closed ken-okabe closed 5 months ago

ken-okabe commented 7 months ago

Description

Fable and fable-compiler-js are astonishing projects/products.

According to the Changelog of fable-compiler-js, recently, the project status has achieved to stable.

1.0.0 - 2024-02-12 Release stable version

I'm happy to see the stable version release and really appreciate your continued development.

I’m writing articles on F# and planning to introduce Fable. Especially, I observe that fable-compiler-js is promising as an AltJS solution with an easy setup using just Node.js, without the need for a .NET installation.

Here, I would like to request better support for fable-compiler-js.

README.md

The information:

This version is somewhat experimental

looks outdated, and

npm install fable-compiler-js
npx fable <PROJECT_PATH> <OUT_DIR> [--options]

although the installation succeeded, the npx fable command fails: fable-compiler-js package.json dependencies are broken #3793

After manual modification by myself, npx fable seems still unusable.

$ npx fable --help

file:///home/ken/Documents/p/c/fable/counter/node_modules/@fable-org/fable-compiler-js/dist/app.min.js:1
import{getAssembliesDir as Js}from"@fable-org/fable-metadata";import*as te from"fs";import*as he from"path";import Zs from"child_process";import{createRequire as Us}from"node:module";import{init as
...
...
SyntaxError: The requested module '@fable-org/fable-standalone' does not provide an export named 'init'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:134:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:217:5)
    at async ModuleLoader.import (node:internal/modules/esm/loader:323:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:120:12)

Node.js v21.7.1

Repro code

https://github.com/fable-compiler/Fable/blob/main/src/fable-compiler-js/README.md https://www.npmjs.com/package/@fable-org/fable-compiler-js

npm install fable-compiler-js
npx fable --help

Expected and actual results

Better support for fable-compiler-js

Related information

@fable-org/fable-compiler-js 1.1.0

MangelMaxime commented 7 months ago

According to the Changelog of fable-compiler-js, recently, the project status has achieved to stable.

In reality, it has been released as stable since a long time. The beta / stable version you see here is because we recently moved all Fable NPM package under @fable-org because we didn't have access to some of the packages preventing us to make new releases.

I’m writing articles on F# and planning to introduce Fable. Especially, I observe that fable-compiler-js is promising as an AltJS solution with an easy setup using just Node.js, without the need for a .NET installation.

Using Fable without .NET installation is in theory possible in reality you it will mostly never be the case. You need to have .NET installed in order to have your editors/IDE running unless you like using bloc note to edit code.

fable-compiler-js was mostly used to test out performance of Fable compiled JavaScript and also from time to time to write build script and run them on JavaScript instead of using dotnet fsx.

If your goal is to write documentation about using Fable, I would encourage you to guide your users to use the .NET version of Fable which is the one that we currently actively develop. fable-compiler-js still benefit from the latest features/fixes that we add to Fable thanks to fable-standalone package but beside that we don't really actively support it or think about it.

I will still look into making the CLI tool works again, as it is actually used in the CI so I think it should not be too difficult to fix.

ken-okabe commented 7 months ago

@MangelMaxime Thanks for your explanation and suggestion.
I appreciate it, and please close my issues.

the .NET version of Fable which is the one that we currently actively develop.

I understand that, and the below is absolutely not a feature request but for a future reference and my personal interest.

Has anyone here compiled Fable to WASM?

MangelMaxime commented 7 months ago

Thanks for your explanation and suggestion. I appreciate it, and please close my issues.

No problems with the issues you opened, we should fix fable-compiler-js to make it work. I start the work or it in #3795, it seems to be packaged correctly. But now, I believe that there are a few bugs in the actual code of fable-compiler-js it fails to create a folder on my disk when testing out. Will continue to investigate in the coming days.

Has anyone here compiled Fable to WASM?

Not that I know of. But this is something that was discussed in the past, as it could perhaps improve the packaging of Fable via NPM and makes it possible to better structure the REPL etc.

But by lack of time, it has not been explored yet.

ken-okabe commented 7 months ago

I start the work or it in https://github.com/fable-compiler/Fable/pull/3795

Thank you for your prompt contributions.

it could perhaps improve the packaging of Fable via NPM and makes it possible to better structure the REPL etc.

Exactly. As I mentioned earlier, since Fable compiles to JS, I see F# has huge potential as an AltJS.

Currently, people use

Alternatively, we use

Recently, interesting things going on at StackBlitz using WASM.

Introducing WebContainers: Run Node.js natively in your browser

Announcing Native Language Support in WebContainers

ncave commented 7 months ago

@ken-okabe Thank you for opening this issue, and thank you @MangelMaxime for fixing the build.

I agree with @MangelMaxime that most users should be steered towards the .NET tool release of Fable, as it is the most supported and capable version for cross-platform transpiling of F#.

That said, fable-compiler-js can also work just fine in some cases, but it has certain limitations:

About compiling Fable to WASM, we have not tried yet, but since WASM is only ~30% faster than JS, in theory it will still make it 2x slower than the .NET Fable.

To clarify, currently we have several ways to compile to WASM:

To summarize, fable-compiler-js can definitely work for small/simple projects, but given it's limitations it's more of a technological demo. There could in theory be other useful purposes based on it, like building a JavaScript-only VSCode LSP extension, for example. It's not going to be very fast, obviously, but it can run in a browser.

And lastly, if using Fable without any additional dependencies is a goal, it's possible to go completely the other direction and just build a native binary (.NET AOT to native). Of course, it's not going to be cross-platform, you'll have to build binaries for each platform you target, but is very fast. Anecdotally it used to be as much as 2x faster than managed .NET Fable version, but recent improvements in F# compiler may have shrunk that difference somewhat. Here is the test project again if you want to tinker with it.

ken-okabe commented 7 months ago

@ncave I really appreciate your elaborate explanation, and the provided information truly helps me out. I'm always impressed by your contribution to fable-library-rust since I've read the article for Fable 4 Alpha Release.

Yes, I know fable-raytracer. Thank you. Such a versatile, great testing project providing results that we exactly need to know. I've followed the discussion there. Quite interesting!

Rust>WASM is the most successful manner and now the eco is huge. It has a superior performance and portability(small footprint), but here, the only problem for me is that I really don't want to code Rust. So I've found your work is extremely valuable.

In fact, years ago, I asked you how you manage .net GC into non-GC Rust code, somewhere.

In real-time systems like Drone, auto-pilot or space projects, where latency and predictability are critical, code with garbage collection (GC) like .NET can be problematic. Real-time systems require Rust code without GC.

Fable -> Rust -> WASM: The Fable to Rust support has progressed a lot

So, I'm happy to hear the progress.

About compiling Fable to WASM, we have not tried yet, but since WASM is only ~30% faster than JS, in theory it will still make it 2x slower than the .NET Fable.

.NET AOT -> WASM: This probably works

Thanks, that's what I thought.

ken-okabe commented 7 months ago

I want to clarify why I'm so interested in Fable working on JS/WASM, not on .NET.

Recently, I found and studied VanJS: Reactive UI Framework without React/JSX.

https://risingstars.js.org/2023/en#section-framework image

It is such a minimal clean implementation, and here is the live demo.

https://jsfiddle.net/gh/get/library/pure/vanjs-org/vanjs-org.github.io/tree/master/jsfiddle/home/counter

image

It's just vanillaJS(VanJS named after this), no JSX, no compile.

I was impressed by the simple design of VanJS. Then, thanks to Fable(such an astonishing hard work), I thought it easy to develop a thin F# wrapper/bridge for VanJS; that should be named VanFS.

After a few days of work, here is the Program.fs and output:

module CounterApp

open Browser
open Browser.Types
open Fable.Core.JsInterop

open Van.Basic // import tags, add
open Van.MaterialComponents // import materialTags
open Van.Timeline // import Timeline

// use the identical tag names for the standard HTML tags
let h1: Tag = tags?h1
let span: Tag = tags?span
// any tag names can be defined for each material components
let filledButton: Tag = materialTags?``md-filled-button``

let Counter =
    fun _ ->
        let counter = Timeline 0

        counter
        |> bindT logT
        |> ignore

        span [
            h1 [ "❤️ "; counter.el; ];
            filledButton [{|onclick =
                        fun _ ->
                            counter
                            |> nextT (counter.lastVal + 1)|};
                    "👍"];
            filledButton [{|onclick =
                        fun _ ->
                            counter
                            |> nextT (counter.lastVal - 1)|};
                    "👎"];
        ]

add [document.body; Counter()]
|> ignore

image

Upcoming release of VanFS.


Currently, people use

Alternatively, we use

The reason people feel more comfortable with JavaScript and TypeScript is its strong and seamless integration to the UI Ecosystem.

However, if the Web UI relies on a simple function-based composition like VanJS, and ready-made components are easily imported as custom tags like Material Web Components, the web-developers no longer have to depend on JS/TS because the code becomes just for function calls based on tags(HTML standard/Web Components).

The current situation can change. F# as an AltJS.

Having said that, TypeScript is seamlessly included in NPM Eco.

https://www.npmjs.com/package/typescript

npm install -D typescript

then, I thought Fable was also the same.

https://www.npmjs.com/package/@fable-org/fable-compiler-js

npm install fable-compiler-js

If a compiler is available as an NPM package, the setup process is simplified. package.json dependencies can bundle the compiler within an NPM project with a single command: npm install.

Thanks to your elaborated answers, I now understand fable-compiler-js isn't the best path forward. However, any compiler distributed as an NPM package offers a convenient setup for the web community, including a WASM version.

I hope @ncave finds this discussion interesting 😊

ncave commented 7 months ago

@ken-okabe I can't open https://github.com/vanjs-org/van right now for some reason, but nice to see another framework used with Fable, thanks for sharing!

I see there is also this: https://www.npmjs.com/package/vanjs-component

MangelMaxime commented 7 months ago

Thanks for all the information in this thread.

Like @ncave I can't access the van repo right now, Github gives me a 404. 🤷‍♂️

But reading, through Van description here made me think about F# Sutil which is a pure F# framework to create web application without React, etc. I think it is based on how Svelte works but without needing a compilation phase other that Fable.

Having said that, TypeScript is seamlessly included in NPM Eco.

npmjs.com/package/typescript

npm install -D typescript

then, I thought Fable was also the same.

npmjs.com/package/@fable-org/fable-compiler-js

npm install fable-compiler-js

If a compiler is available as an NPM package, the setup process is simplified. package.json dependencies can bundle the compiler within an NPM project with a single command: npm install.

True, the main difference ATM is that TypeScript have it's binding on NPM too. While Fable, needs them to be on NuGet ATM. In the past, we had Fable + libraries distributed through NPM but the problem, is that then people are exposed to unusual ways of using F#.

For example, instead of referencing a library using PackageReference, users had to go find the project in their node_modules:

Which looked something like that (I don't exactly remember how it was written)

<Compile Include="node_modules/my-fable-library/Fle1.fs">
<Compile Include="node_modules/my-fable-library/Fle2.fs">
...
<ProjectReference Include="node_modules/my-fable-library/Project.fsproj">

There are discussions in creating a custom target framework for Fable, which could perhaps changes things a bit. But now, we need to be backward compatible in anything we do IHMO otherwise it will break the ecosystem and I don't think it would be able to move it forward fast enough without loosing too many users etc.

ken-okabe commented 7 months ago

This is so weird. I've checked the official site/repo hours ago.

https://www.npmjs.com/package/vanjs-core is still active, but obviously, they intentionally deleted the official site and Github repository at the same time. https://github.com/vanjs-org itself disappears. JSfiddle page is deleted, too. I have no idea what's going on...

ken-okabe commented 7 months ago

@MangelMaxime Thanks for your thought. True, come to think of it, if one wants to use F#, the one will install .NET framework locally.

ken-okabe commented 7 months ago

@ncave @MangelMaxime

https://vanjs.org/ is up again.

On the top of page:

🚨 My GitHub account was flagged due to some suspicious login activities (I've no idea what happened). As a result, all VanJS repos hosted in GitHub and my GitHub accounts are currently unavailable. This website (which was hosted via GitHub Pages) was also down for 2 hours (recovered after migrated to Deno Deploy). I have reached out to GitHub support team and will do my best to restore the access of my GitHub repos. Sorry for all the inconvenience. 🙏🙏🙏

ncave commented 7 months ago

@ken-okabe Just out of curiosity, if VanJS is so small (just 140 lines of JS), do you even need to depend on it for VanFS, can't you directly generate vanilla JavaScript?

ken-okabe commented 6 months ago

I've released the first version of VanFS! https://github.com/ken-okabe/vanfs I'm happy to have mentioned Fable in the README. Thanks again for this great product!

@ncave I am truly sorry for the delayed response.

if VanJS is so small (just 140 lines of JS), do you even need to depend on it for VanFS, can't you directly generate vanilla JavaScript?

You're right. If it were a virtualDOM framework, I could probably build my own. However, VanJS isn't a virtualDOM framework, and I confess I don't fully understand the underlying tricks. In fact, despite being a small library, the project is consistently updated: https://github.com/vanjs-org/van/releases and the community trust the project.

After all, it's written in JavaScript, so instead of reinventing the wheel, I wanted to depend on the project.

PS. Thanks a lot for your constant contributions to the Fable Rust!

ncave commented 6 months ago

@ken-okabe Congratulations on the VanFS release! Yes, on second thought it makes sense to take an existing JS front-end framework as a dependency, to benefit from its ecosystem.

ken-okabe commented 6 months ago

@ken-okabe Congratulations on the VanFS release! Yes, on second thought it's makes sense to take an existing JS front-end framework as a dependency, to benefit from its ecosystem.

Correct, and another aspect would be an advertisement/marketing 😉

Being recognized as an extension of a popular and highly trusted project such as VanJS would bring immense benefits in terms of raising awareness among many people about how great F# and Fable are.

I personally believe that F# and Fable are truly amazing and would like to contribute in any way to spread.

Actually, I contacted the author: Tao Xin and thankfully, had my project listed on the VanJS top page. I hope that as VanJS grows in popularity, the Fable-powered project will gain recognition among a wider audience!

image

MangelMaxime commented 5 months ago

This should be fixed now