Skip to content

Update docs #75

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

Merged
merged 3 commits into from
Sep 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ instance/

# Sphinx documentation
docs/_build/
docs/_sources/
docs-src/_build

# PyBuilder
Expand Down
7 changes: 7 additions & 0 deletions Build.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ Target.create "Build" (fun _ ->
run dotnet $"fable --exclude Fable.Core --lang Python --outDir {buildPath}" srcPath
)

Target.create "Docs" (fun _ ->
run poetry "run jb build docs-src --path-output docs" "."
)

Target.create "Run" (fun _ ->
run dotnet "build" srcPath
)
Expand Down Expand Up @@ -56,6 +60,9 @@ let dependencies = [
"Build"
==> "Test"

"Build"
==> "Docs"

"Build"
==> "Pack"
]
Expand Down
1 change: 1 addition & 0 deletions Helpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ let dotnet = createProcess "dotnet"

let pytest = createProcess "pytest"
let poetry = createProcess "poetry"
let jupyterBook = createProcess "jb"

let npm =
let npmPath =
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ It contains example code for using Fable Python with:
- [Femoto](https://github.com/Zaid-Ajaj/Femto)
- [AsyncRx](https://github.com/dbrattli/AsyncRx)
- [Fable.Aether](https://xyncro.tech/aether/)
- [Fable.Giraffe](https://github.com/dbrattli/Fable.Giraffe)
- [Fable.Logging](https://github.com/dbrattli/Fable.logging)
- [Fable.Giraffe](https://github.com/dbrattli/Fable.Giraffe), port of Giraffe to Fable.Python
- [Fable.Logging](https://github.com/dbrattli/Fable.logging), logging for Fable.Python
- [Fable.Requests](https://github.com/Zaid-Ajaj/Fable.Requests)
- [Fable.Jupyter](https://github.com/fable-compiler/Fable.Jupyter), Jupyter Notebook using Fable.Python
- [Fable.SimpleJson.Python](https://github.com/Zaid-Ajaj/Fable.SimpleJson.Python)
- [Fable.Sedlex](https://github.com/thautwarm/Fable.Sedlex)
- [Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine)
Expand Down
425 changes: 61 additions & 364 deletions docs-src/index.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions docs-src/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ F# is already used on the server for web and cloud apps, and it's also used quit

F# is a great choice to build beautiful apps that run in the browser. F# is:

* Succinct with lightweight syntax
* Robust with a great type system and pattern matching
* Safe with immutability baked into the language
* Supported by large companies (such as Microsoft and Jetbrains) and comes with commercial tooling support
- Succinct with lightweight syntax
- Robust with a great type system and pattern matching
- Safe with immutability baked into the language
- Supported by large companies (such as Microsoft and Jetbrains) and comes with commercial tooling support

When compared with Python, F# is safer, more robust, and more pleasant to read and write.

Expand Down
23 changes: 13 additions & 10 deletions docs-src/introduction/py-users-read-this.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@

Hi!

We're happy you decided to try Fable. Since F# is a language originally created for the .NET environment, Fable uses some tools that come from there.
We're happy you decided to try Fable. Since F# is a language originally created for the .NET environment, Fable uses
some tools that come from there.

Don't panic! There is enough documentation to explain how the .NET tools integrate in your environment. And there are basically only two things you need to know:
Don't panic! There is enough documentation to explain how the .NET tools integrate in your environment. And there are
basically only two things you need to know:

1. Fable uses F# project files (`.fsproj`) to list your F# code files and libraries.
2. Fable uses NuGet to load F# libraries, which is the equivalent of NPM for the .NET environment
2. Fable uses NuGet to load F# libraries, which is the equivalent of PyPI for the .NET environment

Voilà. Nothing else. We'll come to explanations later in the docs. But we promise, there's nothing you won't understand right away. Apart from these facts, it's all JavaScript!
Voilà. Nothing else. We'll come to explanations later in the docs. But we promise, there's nothing you won't understand
right away. Apart from these facts, it's all JavaScript!

**Welcome home!**

- Fable transpiles F# to ES2015 JavaScript, Fable uses the great [Babel](https://babeljs.io/) tool for that.
- Fable integrates with the popular [Webpack](https://webpack.js.org/). And it's not hard to use another bundler.
- JS Dependencies are listed in your common `package.json` file.
- Unit testing is available through [Fable.Mocha](https://github.com/Zaid-Ajaj/Fable.Mocha) (but you can use another test runner if you wish).
- In most cases, building and running a Fable project only requires to call `npm install` and `npm start`.
- Fable transpiles F# to Python 3.9.
% - Fable integrates with the popular [Webpack](https://webpack.js.org/). And it's not hard to use another bundler.
- Python Dependencies are listed in your common `pyproject.toml` file.
- Unit testing is available through [pytest](https://docs.pytest.org) (but you can use another test runner if you wish).
- In most cases, building and running a Fable project only requires to call `dotnet fable --lang py` and `poetry run python`.

So since we're mainly using JavaScript tools, you won't be lost with Fable!
So since we're using many of the well known Python tools, you won't be lost with Fable!
6 changes: 5 additions & 1 deletion docs-src/new-to-fsharp/learning-the-language.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Learning the language

There are many resources available to learn F#. This section is only intended as a general guide targeted to JS developers, but is mainly contribution-driven and is still a work in progress. If you already know the basics of the language you can skip to [the next section](../2-steps/setup.html) or you can also check other sites and books about F# like:
There are many resources available to learn F#. This section is only intended as a
general guide targeted to Python developers, but is mainly contribution-driven and is still
a work in progress. If you already know the basics of the language you can skip to [the
next section](../2-steps/setup.html) or you can also check other sites and books about
F# like:

- [Tour of F#](https://docs.microsoft.com/en-us/dotnet/fsharp/tour)
- [F# for Fun and Profit](https://fsharpforfunandprofit.com/)
Expand Down
31 changes: 22 additions & 9 deletions docs-src/new-to-fsharp/let-keyword.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# The let keyword

`let` is the F# keyword used to bind any value to a name, it's used to bind the so called primitive types such as a `string` or an `integer`, to bind to a function or more complex structures such as arrays or records.
`let` is the F# keyword used to bind any value to a name, it's used to bind the so called primitive types such as a
`string` or an `integer`, to bind to a function or more complex structures such as arrays or records.

Here's how you can bind a string to an identifier named `x`:

```fsharp
let x = "some text"
```

The above snippet would be considered a constant in some other languages such as JavaScript. In F# there's no `var` or `const` there's only `let` and since in F# every value is immutable by default, that snippet is the equivalent of a constant.
The above snippet would be considered a variable in some other languages such as Python. In F# there's no `var` or
`const` there's only `let` and since in F# every value is immutable by default, that snippet is the equivalent of a
constant.

Note that `let` in F# is different than `let` in JavaScript and this will be mentioned later on this page.
Note that `let` in F# is different than assignment in Python and this will be mentioned later on this page.

We're going to see more on functions later but here's how you can bind a function to an identifier named `add`:

Expand All @@ -19,11 +22,13 @@ let add x y =
x + y
```

In the above snippet a function that adds two integers is being bound to an identifier named `add` and then two values are being bound to the identifiers `x` and `y`.
In the above snippet a function that adds two integers is being bound to an identifier named `add` and then two values
are being bound to the identifiers `x` and `y`.

## Shadowing

In F#, bindings are immutable by default which means that normally one _can't_ reassign a value to a named binding, rather, if you try to do so using `let` what will happen is that you'll shadow an existing binding.
In F#, bindings are immutable by default which means that normally one _can't_ reassign a value to a named binding,
rather, if you try to do so using `let` what will happen is that you'll shadow an existing binding.

For instance, in the following example:

Expand All @@ -32,7 +37,9 @@ let x = "the answer"
let x = 42
```

In this case `x` is not being redefined nor its type is being changed from a `string` to an `int`, instead there are two different bindings with the same name `x` to different values. Of course, this example is not very useful because one binding is happening right after the other, but consider the following:
In this case `x` is not being redefined nor its type is being changed from a `string` to an `int`, instead there are two
different bindings with the same name `x` to different values. Of course, this example is not very useful because one
binding is happening right after the other, but consider the following:

```fsharp
let printName name =
Expand All @@ -47,14 +54,20 @@ let printName name =
printName "John Doe"
```

Don't worry too much if you don't fully grasp the above code, the main goal of that snippet is to demonstrate that the function `printName` expects an argument named `name` and in its body it defines another function `stripLastName` that also expects an argument `name`. Inside the scope of `stripLastName` the `name` argument is creating a new binding and thus shadowing the `name` argument received on the `printName` function. And that can be asserted by the two prints at the end of the `printName` function.
Don't worry too much if you don't fully grasp the above code, the main goal of that snippet is to demonstrate that the
function `printName` expects an argument named `name` and in its body it defines another function `stripLastName` that
also expects an argument `name`. Inside the scope of `stripLastName` the `name` argument is creating a new binding and
thus shadowing the `name` argument received on the `printName` function. And that can be asserted by the two prints at
the end of the `printName` function.

## Comparing with Python

The main differences that the `let` keyword in F# has from assignments in Python are:

- In Python one would use an assignment to define a named variable, and its value can be reassigned which is not the case in F#.
- In Python assignments are scope bound, so one can declare a new variable with an already used name as long as it is in a different scope, in F# that can be done within the same scope.
- In Python one would use an assignment to define a named variable, and its value can be reassigned which is not the
case in F#.
- In Python assignments are scope bound, so one can declare a new variable with an already used name as long as it is in
a different scope, in F# that can be done within the same scope.

### References

Expand Down
9 changes: 7 additions & 2 deletions docs-src/your-fable-project/author-a-fable-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ The last point may sound complicated but it's only a matter of adding a couple o
</ItemGroup>
```

That's all it takes to make your library compatible with Fable! In order to publish the package to Nuget check [the Microsoft documentation](https://docs.microsoft.com/en-us/nuget/quickstart/create-and-publish-a-package-using-the-dotnet-cli) or alternatively you can also [use Fake](https://fake.build/dotnet-nuget.html#Creating-NuGet-packages).
That's all it takes to make your library compatible with Fable! In order to publish the package to Nuget check [the
Microsoft
documentation](https://docs.microsoft.com/en-us/nuget/quickstart/create-and-publish-a-package-using-the-dotnet-cli) or
alternatively you can also [use Fake](https://fake.build/dotnet-nuget.html#Creating-NuGet-packages).

## Testing

It's a good idea to write unit tests for your library to make sure everything works as expected before publishing. The simplest way for that is to use a JS test runner like [Mocha](https://mochajs.org/), as in [this sample](https://github.com/fable-compiler/fable2-samples/tree/master/mocha). Or you can also use a library like [Fable.Mocha](https://github.com/Zaid-Ajaj/Fable.Mocha) containing more tools for Fable projects.
It's a good idea to write unit tests for your library to make sure everything works as expected before publishing. The
simplest way for that is to use a Python test runner like [pytest](https://pytest.org/), as in [this
project](https://github.com/dbrattli/Fable.Giraffe).
43 changes: 6 additions & 37 deletions docs-src/your-fable-project/build-and-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,14 @@

Your project is ready? Then it's time to build and run it.

This process, however, is different depending on whether we are still in development or we are already preparing the project to deploy it to production. In development we don't care so much about optimizations and we want fast builds so we can see the results of our changes on-screen almost immediately. While for production we can endure a slower build in order to get JS code that is more optimized.
## Build

Webpack can be a bit difficult to configure. Most of the [samples](https://github.com/fable-compiler/fable3-samples) have a `webpack.config.js` file that you can use for reference. And there's also a [webpack config template for Fable](https://github.com/fable-compiler/webpack-config-template/blob/master/webpack.config.js) that is prepared to work in most projects.

## Development

Even if we already have our own server, when developing our frontend we want a server that is capable of detecting changes in the code and load them without restarting the app! This is what [webpack-dev-server](https://github.com/webpack/webpack-dev-server) does, so normally we'll be running it together with Fable in watch mode, as in `dotnet fable watch src --run webpack serve src/App.fs.js --mode development`

> In most Fable projects, we use a `webpack.config.js` file to pass arguments to Webpack so you will only see the `webpack serve` command.

If you use [npm-scripts](https://docs.npmjs.com/misc/scripts) as shortcuts for common actions, it's customary to use `npm start` to run in development mode. Example of `package.json`:

```json
"scripts": {
"start": "dotnet fable watch src --run webpack serve"
},
```console
> dotnet fable --lang py project.fsx
```

> If you also have your own server, you probably want to redirect API calls to it. You can use the [devServer.proxy](https://webpack.js.org/configuration/dev-server#devserverproxy) Webpack configuration option for that.

The webpack-dev-server will keep running until you kill the process, picking up the changes in your code after you save a file. If you use [Hot Module Replacement](https://elmish.github.io/hmr/) it will try to inject the changes without restarting the app. Otherwise it will just refresh the web page.

Note that webpack-dev-server serves the generated files from memory and doesn't actually write to disk. We will do that in the next step: building for production!
## Run

## Production

When preparing the files for deployment, we don't need a special server. We can call Webpack CLI directly in production mode to enable optimizations like [JS minification](https://webpack.js.org/configuration/optimization#optimizationminimize): `dotnet fable src --run webpack --mode production`.

> As before, in most configurations you don't need to set the `--mode` argument explicitly. And it's also customary to have a "build" (or sometimes "deploy") npm-script for this operation:

```json
"scripts": {
"start": "dotnet fable watch src --run webpack serve",
"build": "dotnet fable src --run webpack"
},
```console
> python project.py
```

Webpack will run only once and will write the generated files in the [output.path](https://webpack.js.org/configuration/output#outputpath). This is the directory you have to deploy to your host!

## I don't want to use Webpack

Then, depending on the sample you've chosen, build options may differ. Please refer to the README file for the chosen sample to get more information.
9 changes: 6 additions & 3 deletions docs-src/your-fable-project/project-file.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# The project file

Unlike JS, F# projects require all sources to be listed **in compilation order** in an `.fsproj` file. This may look quite restrictive at first, but it does have [some advantages](https://fsharpforfunandprofit.com/posts/cyclic-dependencies/).
Since an F# project takes its roots from the .NET ecosystem, we need to follow a few obligatory steps in order to add a file to an F# project.
Unlike Python, F# projects require all sources to be listed **in compilation order** in an `.fsproj` file. This may look
quite restrictive at first, but it does have [some
advantages](https://fsharpforfunandprofit.com/posts/cyclic-dependencies/). Since an F# project takes its roots from the
.NET ecosystem, we need to follow a few obligatory steps in order to add a file to an F# project.

:::{note}
Many F# IDEs already provide commands to perform operations like creating a project or adding/removing a file. The steps below are only necessary if you want to do this manually.
Many F# IDEs already provide commands to perform operations like creating a project or adding/removing a file. The steps
below are only necessary if you want to do this manually.
:::

<ul class="textual-steps">
Expand Down
Loading