F# и React.js через Fable 🐉 Фелиз
- Fable 🐲 — это библиотека F# и инструмент dotnet, который предотвращает компиляцию кода F# на множество разных языков и фреймворков, в первую очередь F# может компилироваться в Javascript, Fable изначально означает F#-(B)abel. Начиная с Fable 4, он также может компилироваться в Python, Rust и Swift.
- Feliz — это адаптер/API-библиотека React.js для Fable, которая позволяет писать код на React с упрощенным синтаксисом.
- F# — удивительный первый функциональный (а также объектно-ориентированный) язык программирования с потрясающим выводом типов и системой типов, унаследованной от своего дедушки OCaml, он работает на .NET, как и его двоюродный брат C#, и он хорошо совместим со смешанными решениями C#/F#, вот некоторая информация о F# для веб-разработки.
Поехали 🐲🔥
Прежде всего, установите dotnet-sdk, если у вас его нет, я на Mac, так что… F# — это язык dotnet, поэтому он работает в среде выполнения .NET, и вы понадобится sdk, чтобы сделать с ним что-нибудь полезное.
brew install dotnet
Затем мы хотим установить последние шаблоны feliz, которые также используют удивительный сборщик и сервер разработки Vite вместо старого веб-пакета.
dotnet new -i Feliz.Template
и создайте новое приложение Feliz, представляющее собой приложение dotnet, которое будет скомпилировано в Javascript с использованием компонентов React.js с использованием Fable.js 🐉
dotnet new feliz -n AwesomeApp
вот как выглядит наш package.json
{ "private": true, "scripts": { "start": "dotnet tool restore && dotnet fable watch src --runFast vite", "build": "dotnet tool restore && dotnet fable src --run vite build", "clean": "dotnet fable clean src --yes" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@vitejs/plugin-react": "^3.1.0", "vite": "^4.1.0" }, "engines": { "node": ">=18" } }
Все готово, теперь вы можете установить и запустить, это, в свою очередь, также скомпилирует наши файлы .fs в .js и запустит сервер vite dev.
npm i && npm start
Ваше приложение Main.fs должно выглядеть так, как показано ниже, если вы хотите использовать маршрутизатор. После каждой компиляции fable выходные данные javascript сохраняются рядом с исходными файлами в виде .js, но нам не нужно об этом особо заботиться.
Следует иметь в виду, что порядок файлов имеет значение в F# для исключения циклических зависимостей (это был выбор компилятора), так что вот он. Всегда включайте файлы в порядке их зависимости (основной или корень всегда внизу).
<ItemGroup> <None Include="index.html" /> <Compile Include="Extensions.fs" /> <Compile Include="Components.fs" /> <Compile Include="Main.fs" /> </ItemGroup>
Затем вы можете вызвать маршруты в своем браузере, используя маршруты на основе хэша (#) (маршруты только для FE) для перехода к другим маршрутам, например /#hello.
// router [<ReactComponent>] static member Router() = let (currentUrl, updateUrl) = React.useState(Router.currentUrl()) React.router [ router.onUrlChanged updateUrl router.children [ match currentUrl with | [ ] -> Html.div [ Html.h1 "Welcome!" ] | [ "hello" ] -> Components.HelloWorld(). // #hello | [ "counter" ] -> Components.Counter() // #counter | otherwise -> Html.h1 "Not found" ] ]
Если вам интересно, вы также можете использовать встроенный JSX через эту статью и некоторые изменения в вашем файле .fsproj (или добавив пакеты через cli)
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net7.0</TargetFramework> <!-- 6.0 is LTS atm --> </PropertyGroup> <ItemGroup> <None Include="index.html" /> <Compile Include="Extensions.fs" /> <Compile Include="Components.fs" /> <Compile Include="Main.fs" /> </ItemGroup> <ItemGroup> <PackageReference Include="Feliz" Version="2.6.0" /> <!-- add compiler plugins --> <PackageReference Include="Feliz.CompilerPlugins" Version="2.2.0" /> <PackageReference Include="Feliz.Router" Version="4.0.0" /> <!-- add latest fable.core theta (maybe also latest just works in your case) --> <PackageReference Include="Fable.Core" Version="4.0.0-theta-006" /> </ItemGroup> </Project>
Благодаря этим дополнениям мы можем создавать образцы встроенных компонентов .jsx как таковые, но также возможно загружать их с диска для интеграции с внешними react компоненты или библиотеки!
namespace App open Feliz open Feliz.Router open Fable.Core // this is needed to create some extensions open Fable.React [<AutoOpen>] module JsxHelpers = let inline toJsx (el: ReactElement) : JSX.Element = unbox el let inline toReact (el: JSX.Element) : ReactElement = unbox el type Components = [<ReactComponent>] static member HelloWorld() = JSX.jsx $""" <> <h1>HELLO WORLD!</h1> <div>this is a div from JSX</div> </> """ |> toReact
Подробнее о взаимодействии внешних компонентов здесь:
- https://fable.io/blog/2022/2022-10-12-react-jsx.html
- https://zaid-ajaj.github.io/Feliz/#/Feliz/UsingJsx
Получайте удовольствие от React и Feliz и отличной недели!