Jadikan Web Anda Front-end Andal dengan Elm

Diterbitkan: 2022-03-11

Berapa kali Anda mencoba men-debug front-end web Anda dan mendapati diri Anda terjerat dalam kode yang berurusan dengan rangkaian peristiwa yang kompleks?

Apakah Anda pernah mencoba memfaktorkan ulang kode untuk UI yang menangani banyak komponen yang dibuat dengan jQuery, Backbone.js, atau kerangka kerja JavaScript populer lainnya?

Salah satu hal yang paling menyakitkan tentang skenario ini adalah mencoba mengikuti beberapa urutan kejadian yang tidak pasti dan mengantisipasi dan memperbaiki semua perilaku ini. Hanya mimpi buruk!

Saya selalu mencari cara untuk keluar dari aspek mengerikan dari pengembangan front-end web ini. Backbone.js bekerja dengan baik untuk saya dalam hal ini dengan memberikan struktur front-end web yang telah lama mereka lewatkan. Tetapi mengingat verbositas yang diperlukan untuk melakukan beberapa hal yang paling sepele, ternyata tidak jauh lebih baik.

Jadikan Web Anda Front-end Andal dengan Elm

Lalu aku bertemu Elm.

Elm adalah bahasa fungsional yang diketik secara statis berdasarkan bahasa pemrograman Haskell, tetapi dengan spesifikasi yang lebih sederhana. Kompiler (juga dibuat menggunakan Haskell) mem-parsing kode Elm dan mengompilasinya ke dalam JavaScript.

Elm awalnya dibangun untuk pengembangan front-end, tetapi insinyur perangkat lunak telah menemukan cara untuk menggunakannya untuk pemrograman sisi server juga.

Artikel ini memberikan ikhtisar tentang bagaimana Elm dapat mengubah cara kita berpikir tentang pengembangan front-end web dan pengenalan dasar-dasar bahasa pemrograman fungsional ini. Dalam tutorial ini, kami akan mengembangkan aplikasi sederhana seperti keranjang belanja menggunakan Elm.

Mengapa Elm?

Elm menjanjikan banyak keuntungan, yang sebagian besar sangat berguna dalam mencapai arsitektur front-end web yang bersih. Elm menawarkan keunggulan kinerja rendering HTML yang lebih baik dibandingkan kerangka kerja populer lainnya (bahkan React.js). Selain itu, Elm memungkinkan pengembang untuk menulis kode, yang dalam praktiknya, tidak menghasilkan sebagian besar pengecualian runtime yang mengganggu bahasa yang diketik secara dinamis seperti JavaScript.

Kompilator menyimpulkan jenis secara otomatis dan memancarkan kesalahan ramah, membuat pengembang mengetahui potensi masalah apa pun sebelum runtime.

NoRedInk memiliki 36.000 baris Elm dan, setelah lebih dari satu tahun berproduksi, masih belum menghasilkan satu pun pengecualian runtime. [Sumber]

Anda tidak perlu mengonversi seluruh aplikasi JavaScript yang ada hanya agar Anda dapat mencoba Elm. Melalui interoperabilitas yang luar biasa dengan JavaScript, Anda bahkan dapat mengambil hanya sebagian kecil dari aplikasi yang ada, dan menulis ulang di Elm.

Elm juga memiliki dokumentasi luar biasa yang tidak hanya memberi Anda deskripsi menyeluruh tentang apa yang ditawarkannya, tetapi juga memberi Anda panduan yang tepat untuk membangun front-end web mengikuti The Elm Architecture - sesuatu yang bagus untuk modularitas, penggunaan kembali kode, dan pengujian .

Mari Membuat Gerobak Sederhana

Mari kita mulai dengan potongan kode Elm yang sangat singkat:

 import List exposing (..) cart = [] item product quantity = { product = product, qty = quantity } product name price = { name = name, price = price } add cart product = if isEmpty (filter (\item -> item.product == product) cart) then append cart [item product 1] else cart subtotal cart = -- we want to calculate cart subtotal sum (map (\item -> item.product.price * toFloat item.qty) cart)

Teks apa pun yang didahului oleh -- adalah komentar di Elm.

Di sini kita mendefinisikan troli sebagai daftar item, di mana setiap item adalah catatan dengan dua nilai (produk yang sesuai dengannya dan kuantitasnya). Setiap produk adalah catatan dengan nama dan harga.

Menambahkan produk ke troli melibatkan pemeriksaan apakah item tersebut sudah ada di troli.

Jika ya, kita tidak melakukan apa-apa; jika tidak, kami menambahkan produk ke troli sebagai item baru. Kami memeriksa apakah produk sudah ada di keranjang dengan memfilter daftar, mencocokkan setiap item dengan produk, dan memeriksa apakah daftar terfilter yang dihasilkan kosong.

Untuk menghitung subtotal, kami mengulangi item di keranjang, menemukan kuantitas dan harga produk yang sesuai, dan menjumlahkan semuanya.

Ini seminimalis gerobak dan fungsi terkaitnya bisa didapat. Kami akan mulai dengan kode ini, dan memperbaikinya langkah demi langkah menjadikannya komponen web yang lengkap, atau program dalam istilah Elm.

Mari kita mulai dengan menambahkan tipe ke berbagai pengidentifikasi dalam program kita. Elm mampu menyimpulkan tipe dengan sendirinya tetapi untuk memaksimalkan Elm dan kompilernya, disarankan agar tipe ditunjukkan secara eksplisit.

 module Cart1 exposing ( Cart, Item, Product , add, subtotal , itemSubtotal ) -- This is module and its API definition {-| We build an easy shopping cart. @docs Cart, Item, Product, add, subtotal, itemSubtotal -} import List exposing (..) -- we need list manipulation functions {-| Cart is a list of items. -} type alias Cart = List Item {-| Item is a record of product and quantity. -} type alias Item = { product : Product, qty : Int } {-| Product is a record with name and price -} type alias Product = { name : String, price : Float } {-| We want to add stuff to a cart. This is a function definition, it takes a cart, a product to add and returns new cart -} add : Cart -> Product -> Cart {-| This is an implementation of the 'add' function. Just append product item to the cart if there is no such product in the cart listed. Do nothing if the product exists. -} add cart product = if isEmpty (filter (\item -> item.product == product) cart) then append cart [Item product 1] else cart {-| I need to calculate cart subtotal. The function takes a cart and returns float. -} subtotal : Cart -> Float {-| It's easy -- just sum subtotal of all items. -} subtotal cart = sum (map itemSubtotal cart) {-| Item subtotal takes item and return the subtotal float. -} itemSubtotal : Item -> Float {-| Subtotal is based on product's price and quantity. -} itemSubtotal item = item.product.price * toFloat item.qty

Dengan anotasi tipe, kompiler sekarang dapat menangkap masalah yang seharusnya menghasilkan pengecualian runtime.

Namun, Elm tidak berhenti di situ. Arsitektur Elm memandu pengembang melalui pola sederhana untuk menyusun front-end web mereka, dan melakukannya melalui konsep yang sebagian besar pengembang sudah kenal:

  • Model: Model memegang status program.
  • View: View adalah representasi visual dari keadaan.
  • Pembaruan: Pembaruan adalah cara untuk mengubah status.

Jika Anda menganggap bagian dari kode Anda yang berhubungan dengan pembaruan sebagai pengontrol, maka Anda memiliki sesuatu yang sangat mirip dengan paradigma Model-View-Controller (MVC) lama yang baik.

Karena Elm adalah bahasa pemrograman fungsional murni, semua data tidak dapat diubah, yang berarti model tidak dapat diubah. Sebagai gantinya, kita dapat membuat model baru berdasarkan model sebelumnya, yang kita lakukan melalui fungsi pembaruan.

Mengapa begitu hebat?

Dengan data yang tidak dapat diubah, fungsi tidak lagi memiliki efek samping. Ini membuka dunia kemungkinan, termasuk debugger perjalanan waktu Elm, yang akan kita bahas segera.

Tampilan dirender setiap kali perubahan model memerlukan perubahan tampilan, dan kami akan selalu memiliki hasil yang sama untuk data yang sama dalam model - dengan cara yang sama seperti fungsi murni selalu mengembalikan hasil yang sama untuk argumen masukan yang sama.

Mulailah dengan Fungsi Utama

Mari kita lanjutkan dan terapkan tampilan HTML untuk aplikasi keranjang kita.

Jika Anda sudah familiar dengan React, ini adalah sesuatu yang saya yakin Anda akan menghargai: Elm memiliki paket hanya untuk mendefinisikan elemen HTML. Ini memungkinkan Anda untuk mengimplementasikan tampilan Anda menggunakan Elm, tanpa harus bergantung pada bahasa templat eksternal.

Pembungkus untuk elemen HTML tersedia di bawah paket Html :

 import Html exposing (Html, button, table, caption, thead, tbody, tfoot, tr, td, th, text, section, p, h1)

Semua program Elm dimulai dengan menjalankan fungsi utama:

 type alias Stock = List Product type alias Model = { cart : Cart, stock : Stock } main = Html.beginnerProgram { model = Model [] [ Product "Bicycle" 100.50 , Product "Rocket" 15.36 , Product "Biscuit" 21.15 ] , view = view , update = update }

Di sini, fungsi utama menginisialisasi program Elm dengan beberapa model, tampilan, dan fungsi pembaruan. Kami telah menetapkan beberapa jenis produk dan harganya. Untuk kesederhanaan, kami mengasumsikan bahwa kami memiliki jumlah produk yang tidak terbatas.

Fungsi Pembaruan Sederhana

Fungsi pembaruan adalah tempat aplikasi kita menjadi hidup.

Dibutuhkan pesan dan memperbarui status berdasarkan konten pesan. Kami mendefinisikannya sebagai fungsi yang mengambil dua parameter (pesan dan model saat ini) dan mengembalikan model baru:

 type Msg = Add Product update : Msg -> Model -> Model update msg model = case msg of Add product -> { model | cart = add model.cart product }

Untuk saat ini, kami menangani satu kasus ketika pesannya Add product , di mana kami memanggil metode add on cart dengan product .

Fungsi pembaruan akan berkembang seiring dengan bertambahnya kompleksitas program Elm.

Menerapkan Fungsi Tampilan

Selanjutnya, kita mendefinisikan tampilan untuk keranjang kita.

View adalah fungsi yang menerjemahkan model ke dalam representasi HTML-nya. Namun, ini bukan hanya HTML statis. Generator HTML mampu memancarkan pesan kembali ke aplikasi berdasarkan berbagai interaksi dan peristiwa pengguna.

 view : Model -> Html Msg view model = section [style [("margin", "10px")]] [ stockView model.stock , cartView model.cart ] stockView : Stock -> Html Msg stockView stock = table [] [ caption [] [ h1 [] [ text "Stock" ] ] , thead [] [ tr [] [ th [align "left", width 100] [ text "Name" ] , th [align "right", width 100] [ text "Price" ] , th [width 100] [] ] ] , tbody [] (map stockProductView stock) ] stockProductView : Product -> Html Msg stockProductView product = tr [] [ td [] [ text product.name ] , td [align "right"] [ text ("\t$" ++ toString product.price) ] , td [] [ button [ onClick (Add product) ] [ text "Add to Cart" ] ] ]

Paket Html menyediakan pembungkus untuk semua elemen yang umum digunakan sebagai fungsi dengan nama yang sudah dikenal (misalnya section fungsi menghasilkan elemen <section> ).

Fungsi style , bagian dari paket Html.Attributes , menghasilkan objek yang dapat diteruskan ke fungsi section untuk mengatur atribut gaya pada elemen yang dihasilkan.

Lebih baik untuk membagi tampilan menjadi fungsi-fungsi terpisah untuk dapat digunakan kembali dengan lebih baik.

Untuk mempermudah, kami telah menyematkan CSS dan beberapa atribut tata letak langsung ke kode tampilan kami. Namun, ada perpustakaan yang menyederhanakan proses penataan elemen HTML Anda dari kode Elm.

Perhatikan button di dekat akhir cuplikan dan bagaimana kami mengaitkan pesan Add product ke acara klik tombol.

Elm menangani pembuatan semua kode yang diperlukan untuk mengikat fungsi panggilan balik dengan peristiwa aktual dan menghasilkan dan memanggil fungsi pembaruan dengan parameter yang relevan.

Akhirnya, kita perlu menerapkan bit terakhir dari pandangan kita:

 cartView : Cart -> Html Msg cartView cart = if isEmpty cart then p [] [ text "Cart is empty" ] else table [] [ caption [] [ h1 [] [ text "Cart" ]] , thead [] [ tr [] [ th [ align "left", width 100 ] [ text "Name" ] , th [ align "right", width 100 ] [ text "Price" ] , th [ align "center", width 50 ] [ text "Qty" ] , th [ align "right", width 100 ] [ text "Subtotal" ] ] ] , tbody [] (map cartProductView cart) , tfoot [] [ tr [style [("font-weight", "bold")]] [ td [ align "right", colspan 4 ] [ text ("$" ++ toString (subtotal cart)) ] ] ] ] cartProductView : Item -> Html Msg cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align "right" ] [ text ("$" ++ toString item.product.price) ] , td [ align "center" ] [ text (toString item.qty) ] , td [ align "right" ] [ text ("$" ++ toString (itemSubtotal item)) ] ]

Di sini kita telah mendefinisikan bagian lain dari pandangan kita di mana kita merender isi keranjang kita. Meskipun fungsi tampilan tidak memancarkan pesan apa pun, tetap harus memiliki jenis Html Msg yang dikembalikan agar memenuhi syarat sebagai tampilan.

Tampilan tidak hanya mencantumkan isi keranjang tetapi juga menghitung dan merender subtotal berdasarkan isi keranjang.

Anda dapat menemukan kode lengkap untuk program Elm ini di sini.

Jika Anda menjalankan program Elm sekarang, Anda akan melihat sesuatu seperti ini:

Bagaimana cara kerjanya?

Program kami dimulai dengan status yang cukup kosong dari fungsi main - keranjang kosong dengan beberapa produk kode keras.

Setiap kali tombol “Tambahkan ke Keranjang” diklik, sebuah pesan dikirim ke fungsi pembaruan, yang kemudian memperbarui keranjang sesuai dan membuat model baru. Setiap kali model diperbarui, fungsi tampilan dipanggil oleh Elm untuk membuat ulang pohon HTML.

Karena Elm menggunakan pendekatan Virtual DOM, mirip dengan React, perubahan pada UI dilakukan hanya jika diperlukan, memastikan kinerja yang cepat.

Bukan Hanya Pemeriksa Tipe

Elm diketik secara statis, tetapi kompiler dapat memeriksa lebih dari sekadar mengetik.

Mari kita buat perubahan pada jenis Msg kita dan lihat bagaimana kompiler bereaksi terhadapnya:

 type Msg = Add Product | ChangeQty Product String

Kami telah mendefinisikan jenis pesan lain - sesuatu yang akan mengubah jumlah produk di keranjang. Namun, mencoba menjalankan program lagi tanpa menangani pesan ini dalam fungsi pembaruan akan menampilkan galat berikut:

Menuju Keranjang yang Lebih Fungsional

Perhatikan bahwa di bagian sebelumnya kami menggunakan string sebagai tipe untuk nilai kuantitas. Ini karena nilainya akan berasal dari elemen <input> yang akan bertipe string.

Mari tambahkan fungsi baru changeQty ke modul Cart . Itu selalu lebih baik untuk menjaga implementasi di dalam modul untuk dapat mengubahnya nanti jika diperlukan tanpa mengubah API modul.

 {-| Change quantity of the product in the cart. Look at the result of the function. It uses Result type. The Result type has two parameters: for bad and for good result. So the result will be Error "msg" or a Cart with updated product quantity. -} changeQty : Cart -> Product -> Int -> Result String Cart {-| If the quantity parameter is zero the product will be removed completely from the cart. If the quantity parameter is greater then zero the quantity of the product will be updated. Otherwise (qty < 0) the error will be returned. -} changeQty cart product qty = if qty == 0 then Ok (filter (\item -> item.product /= product) cart) else if qty > 0 then Result.Ok (map (\item -> if item.product == product then { item | qty = qty } else item) cart) else Result.Err ("Wrong negative quantity used: " ++ (toString qty))

Kita tidak boleh membuat asumsi tentang bagaimana fungsi akan digunakan. Kita dapat yakin bahwa parameter qty akan berisi Int tetapi nilainya bisa apa saja. Oleh karena itu, kami memeriksa nilainya dan melaporkan kesalahan jika nilainya tidak valid.

Kami juga memperbarui fungsi update kami sesuai:

 update msg model = case msg of Add product -> { model | cart = add model.cart product } ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> { model | cart = cart } Err msg -> model -- do nothing, the wrong input Err msg -> model -- do nothing, the wrong quantity

Kami mengonversi parameter quantity string dari pesan ke angka sebelum menggunakannya. Jika string berisi nomor yang tidak valid, kami melaporkannya sebagai kesalahan.

Di sini, kami menjaga model tidak berubah ketika terjadi kesalahan. Atau, kita bisa memperbarui model dengan cara melaporkan kesalahan sebagai pesan dalam tampilan untuk dilihat pengguna:

 type alias Model = { cart : Cart, stock : Stock, error : Maybe String } main = Html.beginnerProgram { model = Model [] -- empty cart [ Product "Bicycle" 100.50 -- stock , Product "Rocket" 15.36 , Product "Bisquit" 21.15 ] Nothing -- error (no error at beginning) , view = view , update = update } update msg model = case msg of Add product -> { model | cart = add model.cart product } ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> { model | cart = cart, error = Nothing } Err msg -> { model | error = Just msg } Err msg -> { model | error = Just msg }

Kami menggunakan tipe Maybe String untuk atribut kesalahan dalam model kami. Mungkin adalah tipe lain yang dapat menampung Nothing atau nilai dari tipe tertentu.

Setelah memperbarui fungsi tampilan sebagai berikut:

 view model = section [style [("margin", "10px")]] [ stockView model.stock , cartView model.cart , errorView model.error ] errorView : Maybe String -> Html Msg errorView error = case error of Just msg -> p [style [("color", "red")]] [ text msg ] Nothing -> p [] []

Anda harus melihat ini:

Mencoba memasukkan nilai non-numerik (misalnya "1a") akan menghasilkan pesan kesalahan seperti yang ditunjukkan pada gambar di atas.

Dunia Paket

Elm memiliki repositori paket open source sendiri. Dengan manajer paket untuk Elm, menjadi mudah untuk memanfaatkan kumpulan paket ini. Meskipun ukuran repositori tidak sebanding dengan beberapa bahasa pemrograman dewasa lainnya seperti Python atau PHP, komunitas Elm bekerja keras untuk mengimplementasikan lebih banyak paket setiap hari.

Perhatikan bagaimana tempat desimal dalam harga yang diberikan dalam pandangan kami tidak konsisten?

Mari kita ganti penggunaan toString yang naif dengan sesuatu yang lebih baik dari repositori: numeral-elm.

 cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align "right" ] [ text (formatPrice item.product.price) ] , td [ align "center" ] [ input [ value (toString item.qty) , onInput (ChangeQty item.product) , size 3 --, type' "number" ] [] ] , td [ align "right" ] [ text (formatPrice (itemSubtotal item)) ] ] formatPrice : Float -> String formatPrice price = format "$0,0.00" price

Kami menggunakan fungsi format dari paket Numeral di sini. Ini akan memformat angka dengan cara yang biasanya kami format mata uang:

 100.5 -> $100.50 15.36 -> $15.36 21.15 -> $21.15

Pembuatan Dokumentasi Otomatis

Saat memublikasikan paket ke repositori Elm, dokumentasi dibuat secara otomatis berdasarkan komentar dalam kode. Anda dapat melihatnya beraksi dengan melihat dokumentasi untuk modul Keranjang kami di sini. Semua ini dihasilkan dari komentar yang terlihat di file ini: Cart.elm.

Debugger Sejati untuk Front-end

Masalah yang paling jelas terdeteksi dan dilaporkan oleh kompiler itu sendiri. Namun, tidak ada aplikasi yang aman dari kesalahan logika.

Karena semua data di Elm tidak dapat diubah dan semuanya terjadi melalui pesan yang diteruskan ke fungsi pembaruan, seluruh aliran program Elm dapat direpresentasikan sebagai serangkaian perubahan model. Bagi para debugger, Elm seperti game strategi berbasis giliran. Hal ini memungkinkan debugger untuk melakukan beberapa prestasi yang sangat menakjubkan, seperti bepergian melalui waktu. Itu dapat bergerak maju mundur melalui aliran program dengan melompat di antara berbagai perubahan model yang terjadi selama masa program.

Anda dapat mempelajari lebih lanjut tentang debugger di sini.

Berinteraksi dengan Back-end

Jadi, katamu, kami telah membuat mainan yang bagus, tetapi bisakah Elm digunakan untuk sesuatu yang serius? Sangat.

Mari hubungkan front-end keranjang kita dengan beberapa back-end asinkron. Untuk membuatnya menarik, kami akan menerapkan sesuatu yang istimewa. Katakanlah kita ingin memeriksa semua gerobak dan isinya secara real-time. Dalam kehidupan nyata, kami dapat menggunakan pendekatan ini untuk menghadirkan beberapa kemampuan pemasaran/penjualan tambahan ke toko online atau pasar kami, atau memberikan beberapa saran kepada pengguna, atau memperkirakan sumber daya stok yang dibutuhkan, dan banyak lagi.

Jadi, kami menyimpan kereta di sisi klien dan juga memberi tahu server tentang setiap kereta secara real time.

Untuk mempermudah, kami akan mengimplementasikan back-end kami menggunakan Python. Anda dapat menemukan kode lengkap untuk back-end di sini.

Ini adalah server web sederhana yang menggunakan WebSocket dan melacak isi keranjang di memori. Untuk mempermudah, kami akan membuat keranjang orang lain di halaman yang sama. Ini dapat dengan mudah diimplementasikan di halaman terpisah atau bahkan sebagai program Elm terpisah. Untuk saat ini, setiap pengguna akan dapat melihat ringkasan keranjang pengguna lain.

Dengan back-end di tempat, kami sekarang perlu memperbarui aplikasi Elm kami untuk mengirim dan menerima pembaruan keranjang ke server. Kami akan menggunakan JSON untuk mengkodekan muatan kami, yang didukung oleh Elm dengan sangat baik.

CartEncoder.elm

Kami akan menerapkan encoder untuk mengubah model data Elm kami menjadi representasi string JSON. Untuk itu, kita perlu menggunakan library Json.Encode.

 module CartEncoder exposing (cart) import Cart2 exposing (Cart, Item, Product) import List exposing (map) import Json.Encode exposing (..) product : Product -> Value product product = object [ ("name", string product.name) , ("price", float product.price) ] item : Item -> Value item item = object [ ("product", product item.product) , ("qty", int item.qty) ] cart : Cart -> Value cart cart = list (map item cart)

Pustaka menyediakan beberapa fungsi (seperti string , int , float , object , dll.) yang mengambil objek Elm dan mengubahnya menjadi string yang dikodekan JSON.

CartDecoder.elm

Menerapkan dekoder sedikit lebih rumit karena semua data Elm memiliki tipe dan kita perlu menentukan nilai JSON apa yang perlu dikonversi ke tipe mana:

 module CartDecoder exposing (cart) import Cart2 exposing (Cart, Item, Product) -- decoding for Cart import Json.Decode exposing (..) -- will decode cart from string cart : Decoder (Cart) cart = list item -- decoder for cart is a list of items item : Decoder (Item) item = object2 Item -- decoder for item is an object with two properties: ("product" := product) -- 1) "product" of product ("qty" := int) -- 2) "qty" of int product : Decoder (Product) product = object2 Product -- decoder for product also an object with two properties: ("name" := string) -- 1) "name" ("price" := float) -- 2) "price"

Aplikasi Elm yang Diperbarui

Karena kode Elm terakhir sedikit lebih panjang, Anda dapat menemukannya di sini. Berikut ringkasan perubahan yang telah dilakukan pada aplikasi front-end:

Kami telah membungkus fungsi update asli kami dengan fungsi yang mengirimkan perubahan isi keranjang ke back-end setiap kali keranjang diperbarui:

 updateOnServer msg model = let (newModel, have_to_send) = update msg model in case have_to_send of True -> -- send updated cart to server (!) newModel [ WebSocket.send server (encode 0 (CartEncoder.cart newModel.cart)) ] False -> -- do nothing (newModel, Cmd.none)

Kami juga telah menambahkan jenis pesan tambahan dari ConsumerCarts String untuk menerima pembaruan dari server dan memperbarui model lokal yang sesuai.

Tampilan telah diperbarui untuk membuat ringkasan gerobak orang lain menggunakan fungsi consumersCartsView .

Koneksi WebSocket telah dibuat untuk berlangganan ke back-end untuk mendengarkan perubahan pada gerobak orang lain.

 subscriptions : Model -> Sub Msg subscriptions model = WebSocket.listen server ConsumerCarts server = "ws://127.0.0.1:8765"

Kami juga telah memperbarui fungsi utama kami. Kami sekarang menggunakan Html.program dengan parameter init dan subscriptions tambahan. init menentukan model awal program dan subscription menentukan daftar langganan.

Berlangganan adalah cara bagi kami untuk memberi tahu Elm agar mendengarkan perubahan pada saluran tertentu dan meneruskan pesan tersebut ke fungsi update .

 main = Html.program { init = init , view = view , update = updateOnServer , subscriptions = subscriptions } init = ( Model [] -- empty cart [ Product "Bicycle" 100.50 -- stock , Product "Rocket" 15.36 , Product "Bisquit" 21.15 ] Nothing -- error (no error at beginning) [] -- consumer carts list is empty , Cmd.none)

Akhirnya kami telah menangani cara kami memecahkan kode pesan ConsumerCarts yang kami terima dari server. Ini memastikan bahwa data yang kami terima dari sumber eksternal tidak akan merusak aplikasi.

 ConsumerCarts message -> case decodeString (Json.Decode.list CartDecoder.cart) message of Ok carts -> ({ model | consumer_carts = carts }, False) Err msg -> ({ model | error = Just msg, consumer_carts = [] }, False)

Jaga agar Front-end Anda tetap waras

Elm berbeda. Ini mengharuskan pengembang untuk berpikir secara berbeda.

Siapa pun yang berasal dari ranah JavaScript dan bahasa serupa akan menemukan diri mereka mencoba mempelajari cara Elm melakukan sesuatu.

Namun pada akhirnya, Elm menawarkan sesuatu yang seringkali sulit dilakukan oleh kerangka kerja lain - bahkan yang paling populer sekalipun. Yaitu, menyediakan sarana untuk membangun aplikasi front-end yang kuat tanpa terjerat dalam kode verbose yang besar.

Elm juga mengabstraksikan banyak kesulitan yang ditimbulkan JavaScript dengan menggabungkan kompiler cerdas dengan debugger yang kuat.

Elm adalah apa yang telah lama dirindukan oleh para pengembang front-end. Sekarang setelah Anda melihatnya beraksi, lakukan sendiri, dan raih keuntungannya dengan membangun proyek web Anda berikutnya di Elm.