|
1 | 1 | --- |
2 | | -title: Author a Fable library |
| 2 | +title: Author a Fable package |
3 | 3 | layout: standard |
| 4 | +toc: |
| 5 | + to: 3 |
4 | 6 | --- |
5 | 7 |
|
6 | | -## Requirements |
| 8 | +## Use Glutinum.Template |
7 | 9 |
|
8 | | -To write a library that can be used in Fable you need to fulfill a few conditions: |
| 10 | +[Glutinum.Template](https://github.com/glutinum-org/Glutinum.Template) is a template that can help you create a Fable package. |
9 | 11 |
|
10 | | -- Don't use FSharp.Core/BCL APIs that are not [compatible with Fable](../dotnet/compatibility.html). |
11 | | -- Keep a simple `.fsproj` file: don't use MSBuild conditions or similar. |
12 | | -- Include the source files in the Nuget package in a folder named `fable`. |
| 12 | +To use this template, you can run the following command: |
13 | 13 |
|
14 | | - :::info |
15 | | - If your library is a pure binding, you can skip this step. |
| 14 | +```bash |
| 15 | +dotnet new -i "Glutinum.Template::*" |
| 16 | +``` |
16 | 17 |
|
17 | | - This will improve Fable compilation time as the compiler will not need to parse the source files of the binding. |
18 | | - ::: |
| 18 | +Then you can create a new project with: |
19 | 19 |
|
20 | | - Add the following to your `.fsproj` file: |
| 20 | +```bash |
| 21 | +dotnet new glutinum -n MyProject |
| 22 | +``` |
21 | 23 |
|
22 | | - ```xml |
23 | | - <!-- Add source files to "fable" folder in Nuget package --> |
24 | | - <ItemGroup> |
25 | | - <!-- Include all files that are compiled with this project --> |
26 | | - <Content Include="@(Compile)" Pack="true" PackagePath="fable/%(RelativeDir)%(Filename)%(Extension)" /> |
27 | | - <!-- Include the project file itself as well --> |
28 | | - <Content Include="$(MSBuildThisFileFullPath)" Pack="true" PackagePath="fable/" /> |
29 | | - </ItemGroup> |
30 | | - ``` |
| 24 | +Once installed, you can refer to the [`MANUAL.md`](https://github.com/glutinum-org/Glutinum.Template/blob/main/content/MANUAL.md) file in the generated project for more information. |
31 | 25 |
|
32 | | - If you needs native files like `.js` or `.py`, you need to include them in the `fable` folder as well. |
| 26 | +## Use Fable.Package.SDK directly |
33 | 27 |
|
34 | | - Example: |
| 28 | +If you prefer to not use a template, here are the steps to author a Fable package manually. |
35 | 29 |
|
36 | | - ```xml |
37 | | - <ItemGroup> |
38 | | - <!-- Your F# code is already included because of the previous rules, so you only need to ensure the .js files are included as well --> |
39 | | - <Content Include="**/*.js" Exclude="**\*.fs.js" PackagePath="fable/%(RelativeDir)%(Filename)%(Extension)" /> |
40 | | - </ItemGroup> |
41 | | - ``` |
| 30 | +Install Fable.Package.SDK |
42 | 31 |
|
43 | | - :::info |
44 | | - Note that you don't want to include Fable generated files and so we exclude them with `Exclude="**\*.fs.js"` |
45 | | - ::: |
| 32 | +[Fable.Package.SDK](https://github.com/fable-compiler/Fable.Package.SDK) is a set of MSBuild targets that can help you create a Fable package. |
46 | 33 |
|
47 | | -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). |
| 34 | +**.NET CLI** |
48 | 35 |
|
49 | | -## Make your package usable by others |
| 36 | +```bash |
| 37 | +dotnet add package Fable.Package.SDK |
| 38 | +``` |
50 | 39 |
|
51 | | -In addition to the source files, there are a few things you should do to make your package easier to consume by others. Adding these items will improve the development experience for your users inside their editors, |
52 | | -specifically enabling Go To Definition (F12 in most editors) to work on your library's code. |
| 40 | +This will add the package to your project file. |
53 | 41 |
|
54 | 42 | ```xml |
55 | | -<PropertyGroup> |
56 | | - <!-- Ensure debugging information is easily found, so that editors can locate the source code locations for your library. |
57 | | - This slightly increases the size of your package, but the usability benefits are worth it. --> |
58 | | - <DebugType>embedded</DebugType> |
59 | | - <!-- Ensure that files that are generated during the build by the .NET SDK are also included in your compiled library. --> |
60 | | - <EmbedUntrackedSources>true</EmbedUntrackedSources> |
61 | | -</PropertyGroup> |
| 43 | +<PackageReference Include="Fable.Package.SDK" Version="x.y.z" /> |
| 44 | + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
| 45 | + <PrivateAssets>all</PrivateAssets> |
| 46 | +</PackageReference> |
62 | 47 | ``` |
63 | 48 |
|
64 | | -## Make your package discoverable |
65 | | - |
66 | | -[Fable.Packages](https://fable.io/packages/) is a tool making it easy for users to search for Fable packages. |
67 | | - |
68 | | -To make your packages listed on Fable.Packages, you need to add some tags to your `.fsproj`. |
69 | | - |
70 | | -<ul class="textual-steps"> |
71 | | - |
72 | | -<li> |
73 | | - |
74 | | -**All Fable** packages must have the `fable` tag. |
75 | | - |
76 | | -</li> |
77 | | - |
78 | | -<li> |
79 | | - |
80 | | -Specify what kind of package you are publishing. |
81 | | - |
82 | | -A fable package can be one of the following: |
83 | | - |
84 | | -- `fable-library`: A library that can be used in Fable |
85 | | - |
86 | | - Examples of libraries could be [Fable.Promise](https://github.com/fable-compiler/fable-promise/), [Elmish](https://elmish.github.io/), [Thoth.Json](https://thoth-org.github.io//Thoth.Json/), [Feliz](https://zaid-ajaj.github.io/Feliz/) |
87 | | - |
88 | | - <div></div> <!-- Force a space to improve visual --> |
89 | | - |
90 | | -- `fable-binding`: The package consist of a set of API to make a native library available |
91 | | - |
92 | | - For example: |
93 | | - |
94 | | - - A package which makes an NPM package API available |
95 | | - - A package which makes the Browser API available |
96 | | - - A package which makes a cargo package API available |
| 49 | +These rules are necessary to ensure that the package is not included in the final package, you don't want you package to depend on `Fable.Package.SDK` at runtime. |
97 | 50 |
|
98 | | -</li> |
| 51 | +**Paket** |
99 | 52 |
|
100 | | -<li> |
| 53 | +```bash |
| 54 | +# In your paket.dependencies |
| 55 | +nuget Fable.Package.SDK copy_local: true |
101 | 56 |
|
102 | | -Specify which targets are supported by your package. |
| 57 | +# In your paket.references |
| 58 | +Fable.Package.SDK |
| 59 | +``` |
103 | 60 |
|
104 | | -Choose one or more of the following tags: |
| 61 | +You can then refer to the [Fable.Package.SDK documentation](https://github.com/fable-compiler/Fable.Package.SDK) for more information. |
105 | 62 |
|
106 | | -- `fable-dart`: Dart is supported by the package |
107 | | -- `fable-dotnet`: .NET is supported by the package |
108 | | -- `fable-javascript`: JavaScript is supported by the package |
109 | | -- `fable-python`: Python is supported by the package |
110 | | -- `fable-rust`: Rust is supported by the package |
111 | | -- `fable-all`: Package is compatible with all Fable targets. |
| 63 | +## Guidelines |
112 | 64 |
|
113 | | - :::warning |
114 | | - A package can be compatible with all targets if it depends only on packages that are also compatible with all targets. |
| 65 | +### Include native files |
115 | 66 |
|
116 | | - A package compatible with all targets cannot be a binding, as these are target-specific. |
117 | | - ::: |
| 67 | +If you needs native files like `.js` or `.py`, you need to include them in the `fable` folder as well. |
118 | 68 |
|
119 | 69 | Example: |
120 | 70 |
|
121 | | -If your package supports only JavaScript you need to use `fable-javascript` |
122 | | - |
123 | | -If your package supports both JavaScript and Python, you need to use `fable-javascript` and `fable-python` |
124 | | - |
125 | | -</li> |
126 | | - |
127 | | -</ul> |
128 | | - |
129 | | -Examples: |
130 | | - |
131 | | -If your package is a binding which target JavaScript you need to write: |
132 | | - |
133 | 71 | ```xml |
134 | | -<PropertyGroup> |
135 | | - <PackageTags>fable;fable-binding;fable-javascript</PackageTags> |
136 | | -</PropertyGroup> |
| 72 | +<ItemGroup> |
| 73 | + <!-- Your F# code is already included because of the previous rules, so you only need to ensure the .js files are included as well --> |
| 74 | + <Content Include="**/*.js" Exclude="**\*.fs.js" PackagePath="fable/%(RelativeDir)%(Filename)%(Extension)" /> |
| 75 | +</ItemGroup> |
137 | 76 | ``` |
138 | 77 |
|
139 | | -If your package is a library which targets JavaScript and Python you need to write: |
| 78 | +:::info |
| 79 | +Note that you don't want to include Fable generated files and so we exclude them with `Exclude="**\*.fs.js"` |
| 80 | +::: |
140 | 81 |
|
141 | | -```xml |
142 | | -<PropertyGroup> |
143 | | - <PackageTags>fable;fable-library;fable-javascript;fable-python</PackageTags> |
144 | | -</PropertyGroup> |
145 | | -``` |
| 82 | +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). |
146 | 83 |
|
147 | | -## Native dependencies |
| 84 | +### Native dependencies with Femto |
148 | 85 |
|
149 | 86 | When authoring a binding you often need your user to install a native dependency. |
150 | 87 |
|
@@ -177,6 +114,20 @@ For Python packages via poetry: |
177 | 114 |
|
178 | 115 | Please refer to [Femto documentation](https://github.com/Zaid-Ajaj/Femto) for more information. |
179 | 116 |
|
180 | | -## Testing |
| 117 | +### Testing |
| 118 | + |
| 119 | +It's a good idea to write unit tests for your library to make sure everything works as expected before publishing. |
| 120 | + |
| 121 | +Find below some libraries that can help you write tests for your Fable library: |
| 122 | + |
| 123 | +- [Fable.Pyxpecto](https://github.com/Freymaurer/Fable.Pyxpecto): Inspired by the popular Expecto library for F#, Fable.Pyxpecto can be used to run tests in Python, JavaScript, TypeScript and .NET! |
| 124 | +- [Fable.Mocha](https://github.com/Zaid-Ajaj/Fable.Mocha): Fable library for testing. Inspired by the popular Expecto library for F# and adopts the testList, testCase and testCaseAsync primitives for defining tests. |
| 125 | +- Native runner like [Mocha](https://mochajs.org/), [example](https://github.com/fable-compiler/fable2-samples/tree/master/mocha). |
| 126 | + |
| 127 | +### Listing |
| 128 | + |
| 129 | +Once published to [NuGet](https://www.nuget.org/), your package will also be available on [Fable.Packages](https://fable.io/packages/) for easy discovery by the Fable community. |
181 | 130 |
|
182 | | -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. |
| 131 | +:::info |
| 132 | +This can take a few minutes to a few hours to be available on the website, depending on Nuget's indexing. |
| 133 | +::: |
0 commit comments