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

Command to compile F# files to JS/TS #17

Open
granicz opened this issue Apr 5, 2023 · 5 comments
Open

Command to compile F# files to JS/TS #17

granicz opened this issue Apr 5, 2023 · 5 comments
Assignees
Labels
0.1.11 enhancement New feature or request

Comments

@granicz
Copy link
Member

granicz commented Apr 5, 2023

WebSharper Library projects (websharper-lib) transpile F# code to JavaScript or TypeScript, and store the output as embedded resources in the resulting .dll file. To save the transpiled output into the file system as well, as often desired, users need to set jsOutput in wsconfig.json. While this works, one would often like an easier way to produce JS/TS from a single F# file.

This ticket adds the ability to translate F# files into JS/TS without a containing project or extra configuration setting. This is accomplished by providing a convenient way to use the WebSharper CLI (dotnet ws compile) to talk to the matching WebSharper Booster, which in turn will manage one or more compilation instances for single-file translation, as described below.

Here are some examples:

dotnet ws compile MyApp.fs
dotnet ws compile MyApp.fsx
dotnet ws compile MyApp.fsx -v 7.0.0.288-beta1
dotnet ws compile MyApp.fsx -ts
dotnet ws compile MyApp.fsx -p "../"
dotnet ws compile MyApp.fsx -o "MyApp.js"
dotnet ws compile MyApp.fsx -o "MyApp.ts"
dotnet ws compile MyApp.fs[x] [-v|--version 7.0.0.288-beta1] [-ts|--typescript] [-p|--path "../"] [-o|--output "MyApp.js"]

Note the new command arguments, all optional:

  • -v or --version to specify the NuGet version of the core package dependencies. If omitted, use latest packages, as noted below.
  • -ts or --typescript to generate TypeScript output.
  • -p or --path to specify a relative or absolute path for the output.
  • -o or --output to specify a single bundle output file (by default, we produce one file per class). The output type (JavaScript/TypeScript) is inferred from the extension of the given output file, for simplicity (JavaScript for ".js", TypeScript for ".ts", and an error otherwise.) If the inferred extension collides with -ts|--typescript, issue a warning (`"TypeScript output is produced into non-TypeScript file(s).")

We assume a well-defined set of references (REFS: those of a standard websharper-lib template: currently, the contents of the WebSharper and WebSharper.FSharp NuGet packages) and that the input file is self-contained and needs no other source files, otherwise a compiler error will be reported, as we only pass a single source file to the compiler. In .fsx files, compiler directives to include additional source files and/or reference dlls, other than a specific form of #r (see below) are ignored.

By default, a WebSharper Booster is fired up by the WebSharper compiler (wsfsc.exe), which itself is triggered by msbuild. Since msbuild needs a project file to build, there are some complexities that need to be handled for this ticket:

  1. Downloading into the local NuGet cache the latest stable NuGet packages for REFS, or those with the optional version specified (via -v|--version, here we assume that the same version applies to all NuGet packages for REFS), if not present on the local system already.

  2. Computing the actual assembly reference set from REFS ourselves. We can deal with extending this for .fsx input files via #r on a separate ticket (reference it here when it's created).

  3. Booster compilation instances are currently identified by the path of a project file, so we have to invent an extension of that (say, "P1+...+Pn+R1+...+Rn", where P's are sorted package references and R's are sorted additional assembly references, ignoring P0=WebSharper, or a longer "R1+...+Rn", where R's are the resolved and sorted assembly references, with versions included) in such a way that dotnet compile uses the same compilation instance for all input files with the same computed references. (dotnet ws stop should work as before, as it stops a given version of a Booster, or all, with all of its/their compilation instances).

  4. If an .fsx input file is given, all .fsx-specific compiler directives in it (#r, #I, etc. - but not those that are valid in .fs files as well) will be commented out (prefixing the affected lines with //) before passing it to the compilation pipeline.

@granicz granicz added the enhancement New feature or request label Apr 5, 2023
@granicz
Copy link
Member Author

granicz commented Apr 11, 2023

On a second though, no need to reinvent the wheel, we can rely on msbuild+nuget to do their job for this. Let's drop 0)+1) above, and instead create a project+wsconfig.json file in 2) in a well-defined temp folder (say, ${TEMP}\ws-compile\*) for a WebSharper Library project with the given source file, the dependencies we inferred from it, and with the output redirected to the original source folder (suffixed with the arg value we get from -o|--output).

Two input files with the same dependencies should use the same project file to avoid multiple redundant compilation instances, but a different one to input files with different dependencies. No two project files should be in the same folder to make msbuild happy.

To avoid concurrency issues in CI scenarios, provide an additional CLI argument:

  • -s|--standalone to use a subfolder whose name is based on the source folder. This will make a fresh compilation instance in the Booster for that folder, so subsequent sessions originating there will be boosted, but will be independent of others.

@granicz
Copy link
Member Author

granicz commented Apr 11, 2023

And keep WebSharperBuildService the default, so we use the Booster for all sessions.

@granicz
Copy link
Member Author

granicz commented Apr 17, 2023

Another low-hanging fruit would be to add:

  • -d|--debug to turn on debug-level output, as opposed to the default release mode one.

Jooseppi12 added a commit that referenced this issue Apr 24, 2023
Jooseppi12 added a commit that referenced this issue Apr 27, 2023
granicz pushed a commit that referenced this issue Apr 27, 2023
Jooseppi12 added a commit that referenced this issue Apr 28, 2023
@granicz
Copy link
Member Author

granicz commented Jul 12, 2023

Latest version has the following issue:

  1. I stop all running Booster instances:
dotnet ws stop
  1. I then compile a given .fs file:
dotnet ws compile MyApp.fs

At this point, the prompt is stuck and nothing seems to be happening. After checking the generated folder, it's there - so things didn't get echoed on the screen, nor the completion status.

Jooseppi12 added a commit that referenced this issue Jul 20, 2023
@granicz
Copy link
Member Author

granicz commented Aug 3, 2023

Latest still can't process dotnet ws compile App.fs[x] correctly - output is generated in the temp folder. The -p argument should be defaulted to ./.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0.1.11 enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants