Posty z tej serii:

Programowanie Webowe. Sposób wytwarzania oprogramowania, dzięki któremu produkt może zostać uruchomiony w przeglądarce internetowej. Zagadnienie jest bardzo obszerne. Możliwości realizacji można dzielić na różne kategorie, np. ze względu na miejsce generowania wyniku:

  • Server Side - generowanie zawartości po stronie serwera, a następnie przesłanie do klienta - przeglądarki internetowej
  • Client Side - generowanie zawartości po stronie klienta - przeglądarce internetowej

Inny podział to sposób generowania wyniku:

  • Statyczny - pobieranie gotowej, wcześniej przygotowanej zawartości
  • Dynamiczny - generowanie zawartości na żądanie, w momencie jej pobierania

Kategorie można łączyć ze sobą:

  • Server Side / Statyczny - pierwsze strony internetowe
  • Server Side / Dynamiczny - wyświetlanie strony internetowej w zależności od zapisanych danych
  • Client Side / Statyczny - cache przeglądarki internetowej
  • Client Side / Dynamiczny - początki języka JavaScript

Na bazie różnych kategorii powstało wiele podejść oraz technologii, które pozwalają realizować końcowe produkty.

Świat F# oferuje wiele z programowania webowego. Moją uwagę przykuło Bolero.

Picture1

Jakbym miał zobrazować, na czym to polega to, zrobiłbym to tak:

Picture2

Bolero umożliwia pisanie aplikacji webowych w języku F#. Kod konstruuje się w podejściu Elmish - implementacji architektury Model-View-Update, zapoczątkowanej wraz z pojawieniem się języka Elm. Wynikiem kompilacji jest program, który za pomocą Blazor oraz .NET uruchamiany jest w środowisku WebAssembly - alternatywy dla środowiska JavaScript.

Simple Program

Najszybszy sposób zapoznania się z możliwościami Bolero, to wygenerowanie przykładowego projektu, postępując wg wskazówek ze strony. Utworzony program zawiera implementację głównych feature’ów. Kod, generowany jest na podstawie Template’u, przygotowanego przez Loïc Denuzière - autora Bolero.

Template zawiera parametry, którymi można konfigurować końcowy efekt. Najprostszy program można wygenerować, postępując wg kroków:

  • zainstalować Template
dotnet new -i Bolero.Templates
  • utworzyć projekt
dotnet new bolero-app -o Simple --minimal=true --server=false
  • uruchomić program
cd Simple
dotnet run -p src/Simple.Client
  • otworzyć stronę wpisując w przeglądarkę adres wypisany na konsoli np.
http://localhost:5000

Najważniejsze elementy wygenerowanego programu to:

  • Main.fs - plik z głównym kodem
  • Startup.fs - plik z konfiguracją
  • wwwroot - katalog zawierający statyczne elementy

Główy kod programu wygląda tak:

module Simple.Client.Main

open Elmish
open Bolero
open Bolero.Html

type Model =
    {
        x: string
    }

let initModel =
    {
        x = ""
    }

type Message =
    | Ping

let update message model =
    match message with
    | Ping -> model

let view model dispatch =
    text "Hello, world!"

type MyApp() =
    inherit ProgramComponent<Model, Message>()

    override this.Program =
        Program.mkSimple (fun _ -> initModel) update view

Przejdźmy przez poszczególne elementy:

Klasa MyApp

Komponent ładowany przy starcie. Plik Startup.fs zawiera konfigurację uruchomienia:

builder.RootComponents.Add<Main.MyApp>("#main")

Klasa MyApp dziedziczy po klasie ProgramComponent, która w parametrach generycznych przyjmuje Model oraz Message. Uruchomienie następuje w momencie wywołania funkcji mkSimple, która w parametrach przyjmuje opisane poniżej wartości.

Funkcja view

Renderuje widok, czyli to wszystko, co użytkownik widzi na ekranie. Posiada dostęp do aktualnego stanu programu w postaci parametru model. Drugi parametr dispatch pozwala wysyłać Message’e do programu, które umożliwiają kodowanie zachowania.

Funkcja update

Uruchamiana w momencie obsługi Message’a. Parametr message określa jego rodzaj. Stan aktualizuje się, zmieniając wartości w parametrze model.

Discriminated Union Message

Definiuje rodzaje Message’y, jakie można zgłaszać np. sygnalizacja naciśnięcia odpowiedniego przycisku na stronie.

Value initModel

Początkowy stan programu, inicjalizowany przez mkSimple.

Record Model

Model reprezentujący aktualny stan programu.

Powyższy przykład zawiera najprostszą logikę działania - wypisanie tekstu na ekranie. Nie wykorzystuje on wszystkich wymienionych właściwości. Działanie kończy się na funkcji view. Zmieńmy to implementując prosty licznik.

Simple Counter

Definiujemy Model tak, aby przechowywał aktualną wartość licznika

type Model =
    {
        value: int
    }

Ustawiamy początkową wartość

let initModel =
    {
        value = 0
    }

Definiujemy Message’e

  • Increment - przesuwa licznik do przodu
  • Decrement - przesuwa licznik do tyłu
  • Reset - ustawia początkową wartość
type Message =
    | Increment
    | Decrement
    | Reset

Aktualizujemy funkcję update, ustawiając odpowiednią wartość licznika w zależności od Message’a

let update message model =
    match message with
    | Increment -> { model with value = model.value + 1 }
    | Decrement -> {model with value = model.value - 1 }
    | Reset -> { model with value = 0 }

Aktualizujemy funkcję view tak, aby wyświetliła interfejs użytkownika zawierający:

  • pokazanie aktualnej wartości licznika
  • przyciski przesunięcia licznika w dwie strony
  • zresetowanie licznika

Dodatkowo funkcja zgłasza odpowiedni Message w zależności od tego, który przycisk zostanie kliknięty.

Poniższy kod pokazuje jedną z właściwości Bolero - konstruowanie UI w kodzie F#:

let view model dispatch =
    concat [
        div [] [
            button [on.click (fun _ -> dispatch Decrement)] [text "-"]
            text (string model.value)
            button [on.click (fun _ -> dispatch Increment)] [text "+"]
        ]

        div [] [
            button [on.click (fun _ -> dispatch Reset)] [text "Reset"]
        ]
    ]

Uruchamiamy program

dotnet run -p src/Simple.Client

Sprawdzamy efekt w przeglądarce internetowej

Picture3

Zgodnie z implementacją przycisk + zwiększa wartość licznika, a przycisk - zmniejsza. Przycisk Reset ustawia początkową wartość.

Istnieje jeszcze jeden, bardziej znany, sposób konstruowania UI - za pomocą standardowych znaczników HTML. Strona napisana w HTML reprezentowana jest w kodzie Bolero w postaci tzw. Templates.

Początek Serii

Spędziłem wiele miesięcy w poszukiwaniu sposobu programowania webowego, który najbardziej by mi odpowiadał. Taki sposób znalazłem w świecie F#. Obecnie zapoznaję się z różnymi możliwościami Bolero. Wyniki będę umieszczał na GitHub’e, a poszczególne elementy opisywał w serii, której pierwszy artykuł właśnie czytasz. Zachęcam Cię do własnych eksperymentów. Może taki sposób pisania kodu będzie odpowiadał również Tobie.

W następnym artykule zobaczymy, w jaki sposób używać wyżej wymienionych Templates.

=