Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Think About Front-end Web Development with Rust

0fa1c2ed2eb4a18ddec3dd70cb1f72db?s=47 Yosuke Onoue
November 01, 2020

Think About Front-end Web Development with Rust

This slide is the presentation material for rustfest global 2020.
https://rustfest.global/session/16-think-about-front-end-web-development-with-rust/

Abstract:
With the recent advances in WebAssembly and front-end application frameworks implemented in Rust, such as Yew and Percy, we are ready to develop web applications with Rust alone. However, there are still many issues such as performance and accessibility when compared to traditional front-end Web development with JavaScript. In this talk, I will report on the current state of front-end web development with Rust, including WebAssembly, toolchains, libraries and frameworks, and discuss future directions for more realistic front-end web development.

0fa1c2ed2eb4a18ddec3dd70cb1f72db?s=128

Yosuke Onoue

November 01, 2020
Tweet

Transcript

  1. :PTVLF0OPVF 5IJOL"CPVU 'SPOUFOE8FC%FWFMPQNFOU XJUI3VTU 3VTU'FTU(MPCBM 

  2. w :PTVLF0OPVFʢඌ্༸հʣ w "TTPDJBUF1SPGFTTPS %FQBSUNFOUPG*OGPSNBUJPO4DJFODF  $PMMFHFPG)VNBOJUJFTBOE4DJFODFT  /JIPO6OJWFSTJUZ w

    3FTFBSDI*OUFSFTUT w *OGPSNBUJPO7JTVBMJ[BUJPO w .BUIFNBUJDBM0QUJNJ[BUJPO w %FDJTJPO4VQQPSU w -PWFT w 3VTU w 8FCUFDIOPMPHJFT "CPVU.F IUUQTUXJUUFSDPN@MJLS IUUQTWETMBCKQ IUUQTKVEHJUOFU
  3.  3FDFOU'SPOUFOE8FC%FWFMPQNFOU  'SPOUFOE'SBNFXPSLTJO3VTU  'VUVSF$IBMMFOHFT  4VNNBSZ

  4.  3FDFOU'SPOUFOE8FC%FWFMPQNFOU  'SPOUFOE'SBNFXPSLTJO3VTU  'VUVSF$IBMMFOHFT  4VNNBSZ

  5. 3FDFOU8FC%FWFMPQNFOU w $IBOHFTJOBSDIJUFDUVSFPGXFCBQQTBOEXFCTJUFT    w *ODSFBTJOHXFJHIUPGGSPOUFOEXFCEFWFMPQNFOU w #FUUFS69BOECFUUFSQFSGPSNBODF

    w $PNQMJDBUJPOPGEFWFMPQNFOUQSPDFTT w 5SBOTQJMJOH CVOEMJOH UFTUJOH BTTFUNBOBHFNFOU FUD %#4FSWFS 8FC"QQ4FSWFS 8FC#SPXTFS )5.-HFOFSBUJPOXJUIUFNQMBUFFOHJOFT 1)1 1ZUIPO 3VCZ FUD )5.- $44 +BWB4DSJQU $MBTTJDBM8FC"QQ
  6. 3FDFOU8FC%FWFMPQNFOU w $IBOHFTJOBSDIJUFDUVSFPGXFCBQQTBOEXFCTJUFT    w *ODSFBTJOHXFJHIUPGGSPOUFOEXFCEFWFMPQNFOU w #FUUFS69BOECFUUFSQFSGPSNBODF

    w $PNQMJDBUJPOPGEFWFMPQNFOUQSPDFTT w 5SBOTQJMJOH CVOEMJOH UFTUJOH BTTFUNBOBHFNFOU FUD %#4FSWFS 8FC"QQ4FSWFS 8FC#SPXTFS )5.-HFOFSBUJPOXJUIUFNQMBUFFOHJOFT 1)1 1ZUIPO 3VCZ FUD )5.- $44 +BWB4DSJQU $MBTTJDBM8FC"QQ "QQ4FSWFS 8FC4FSWFS %#4FSWFS 8FC#SPXTFS +40/ )5.- $44 +BWB4DSJQU 6*DPOTUSVDUJPO JO8FC#SPXTFS +BWB4DSJQU 4JOHMF1BHF"QQ 41"  3&45"1*
  7. 3FDFOU8FC%FWFMPQNFOU w $IBOHFTJOBSDIJUFDUVSFPGXFCBQQTBOEXFCTJUFT    w *ODSFBTJOHXFJHIUPGGSPOUFOEXFCEFWFMPQNFOU w #FUUFS69BOECFUUFSQFSGPSNBODF

    w $PNQMJDBUJPOPGEFWFMPQNFOUQSPDFTT w 5SBOTQJMJOH CVOEMJOH UFTUJOH BTTFUNBOBHFNFOU FUD %#4FSWFS 8FC"QQ4FSWFS 8FC#SPXTFS )5.-HFOFSBUJPOXJUIUFNQMBUFFOHJOFT 1)1 1ZUIPO 3VCZ FUD )5.- $44 +BWB4DSJQU $MBTTJDBM8FC"QQ "QQ4FSWFS 8FC4FSWFS %#4FSWFS 8FC#SPXTFS +40/ )5.- $44 +BWB4DSJQU 6*DPOTUSVDUJPO JO8FC#SPXTFS +BWB4DSJQU 4JOHMF1BHF"QQ 41"  3&45"1*
  8. $BO3VTUDPOUSJCVUFUPUIFDPNQMFY GSPOUFOEXFCEFWFMPQNFOU

  9. 4USFOHUITPG3VTU w 1FSGPSNBODF w ;FSPDPTUBCTUSBDUJPO OPHBSCBHFDPMMFDUJPO w 3FMJBCJMJUZ w 3JDIUZQFTZTUFN

    w 1SPEVDUJWJUZ w .PEFSOUPPMDIBJO IUUQTXXXSVTUMBOHPSH
  10. #SJOHJOHUIF1PXFSPG3VTUUPUIF8FC w 8FC"TTFNCMZ 8"4.  IUUQTXFCBTTFNCMZPSH w #JOBSZGPSNBUMBOHVBHFSVOOJOHPOXFCCSPXTFST w 8FCTUBOEBSE

    w 'JSTUDMBTTTVQQPSUGPS8FC"TTFNCMZJO3VTU w /FBSOBUJWFQFSGPSNBODF w 4NBMMCJOBSZTJ[F
  11. 3VTUBOE'SPOUFOE8FC%FWFMPQNFOU w 8PSLJOHXJUI+BWB4DSJQUBOECSPXTFS"1*T w XBTNCJOEHFO KTTZTBOEXFCTZT IUUQTHJUIVCDPNSVTUXBTNXBTNCJOEHFO w 8SJUJOH+BWB4DSJQUQBDLBHFTXJUI3VTU w

    XBTNQBDL IUUQTHJUIVCDPNSVTUXBTNXBTNQBDL w 8SJUJOHFOUJSFGSPOUFOEXFCBQQTXJUI3VTU w 'SPOUFOEGSBNFXPSLTXSJUUFOJO3VTU
  12. 3VTUBOE'SPOUFOE8FC%FWFMPQNFOU w 8PSLJOHXJUI+BWB4DSJQUBOECSPXTFS"1*T w XBTNCJOEHFO KTTZTBOEXFCTZT IUUQTHJUIVCDPNSVTUXBTNXBTNCJOEHFO w 8SJUJOH+BWB4DSJQUQBDLBHFTXJUI3VTU w

    XBTNQBDL IUUQTHJUIVCDPNSVTUXBTNXBTNQBDL w 8SJUJOHFOUJSFGSPOUFOEXFCBQQTXJUI3VTU w 'SPOUFOEGSBNFXPSLTXSJUUFOJO3VTU
  13. w 7JSUVBM%0. w %FDMBSBUJWF6*DPOTUSVDUJPO w &⒏DJFOUEJ⒎BMHPSJUIN w 4UBUFNBOBHFNFOU w 5IF&MN"SDIJUFDUVSF

    IUUQTHVJEFFMNMBOHPSHBSDIJUFDUVSF w *OTQJSFECZUIFDPODFQUTPG GVODUJPOBMQSPHSBNNJOH 1PQVMBS'SPOUFOE'SBNFXPSL"SDIJUFDUVSF IUUQTRJJUBDPN"@LJSJTBLJJUFNTGBBDDED
  14. 3VTUJTTVJUBCMFGPSNPEFSO XFCGSPOUFOEBSDIJUFDUVSFT

  15.  3FDFOU'SPOUFOE8FC%FWFMPQNFOU  'SPOUFOE'SBNFXPSLTJO3VTU  'VUVSF$IBMMFOHFT  4VNNBSZ

  16. "WBJMBCMF'SPOUFOE'SBNFXPSLT w :FX w 1FSDZ w 4FFE w %PESJP w

    4BVSPO w %SBDP w 4NJUIZ w %PNJOBUPS w .PHXBJ w TRVBSL w NJLB Rust Web Framework Comparison https://github.com/flosse/rust-web-framework-comparison (JU)VC4UBST  :FX 1FSDZ 4FFE %PESJP TBVSPO %SBDP 4NJUIZ %PNJOBUPS NPHXBJ TRVBSL     
  17. "WBJMBCMF'SPOUFOE'SBNFXPSLT w :FX w 1FSDZ w 4FFE w %PESJP w

    4BVSPO w %SBDP w 4NJUIZ w %PNJOBUPS w .PHXBJ w TRVBSL w NJLB Rust Web Framework Comparison https://github.com/flosse/rust-web-framework-comparison (JU)VC4UBST  :FX 1FSDZ 4FFE %PESJP TBVSPO %SBDP 4NJUIZ %PNJOBUPS NPHXBJ TRVBSL     
  18. :FX w IUUQTZFXST w $PNQPOFOUCBTFEXFCBQQGSBNFXPSLMJLF3FBDUBOE&MN w 'FBUVSFT w )5.-NBDSP w

    4UBUFNBOBHFNFOU w 3PVUFS w FUD w "DUJWFEFWFMPQNFOU
  19. :FX&YBNQMF w 4JNQMFDPVOUFSFYBNQMF IUUQTHJUIVCDPNZFXTUBDLZFXUSFF NBTUFSFYBNQMFTDPVOUFS w 6*DPOTUSVDUJPO w WJFXGVODUJPOBOEIUNMNBDSP w

    $PNQPOFOUTUBUFNBOBHFNFOU w VQEBUFGVODUJPODIBOHFTFMGTUBUF w DIBOHFGVODUJPODIBOHFGSPNQBSFOU 17 impl Component for Model { 18 type Message = Msg; 19 type Properties = (); 20 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 21 Model { link, value: 0 } 22 } 23 fn update(&mut self, msg: Self::Message) -> ShouldRender { 24 match msg { 25 Msg::Increment => { 26 self.value += 1; 27 } 28 Msg::Decrement => { 29 self.value -= 1; 30 } 31 } 32 true 33 } 34 fn change(&mut self, _: Self::Properties) -> ShouldRender { 35 false 36 } 37 fn view(&self) -> Html { 38 html! { 39 <div> 40 <nav class="menu"> 41 <button onclick=self.link.callback(|_| Msg::Increment)> 42 { "Increment" } 43 </button> 44 <button onclick=self.link.callback(|_| Msg::Decrement)> 45 { "Decrement" } 46 </button> 47 </nav> 48 <p>{ self.value }</p> 49 </div> 50 } 51 } 52 }
  20. :FX&YBNQMF w 4JNQMFDPVOUFSFYBNQMF IUUQTHJUIVCDPNZFXTUBDLZFXUSFF NBTUFSFYBNQMFTDPVOUFS w 6*DPOTUSVDUJPO w WJFXGVODUJPOBOEIUNMNBDSP w

    $PNQPOFOUTUBUFNBOBHFNFOU w VQEBUFGVODUJPODIBOHFTFMGTUBUF w DIBOHFGVODUJPODIBOHFGSPNQBSFOU 17 impl Component for Model { 18 type Message = Msg; 19 type Properties = (); 20 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 21 Model { link, value: 0 } 22 } 23 fn update(&mut self, msg: Self::Message) -> ShouldRender { 24 match msg { 25 Msg::Increment => { 26 self.value += 1; 27 } 28 Msg::Decrement => { 29 self.value -= 1; 30 } 31 } 32 true 33 } 34 fn change(&mut self, _: Self::Properties) -> ShouldRender { 35 false 36 } 37 fn view(&self) -> Html { 38 html! { 39 <div> 40 <nav class="menu"> 41 <button onclick=self.link.callback(|_| Msg::Increment)> 42 { "Increment" } 43 </button> 44 <button onclick=self.link.callback(|_| Msg::Decrement)> 45 { "Decrement" } 46 </button> 47 </nav> 48 <p>{ self.value }</p> 49 </div> 50 } 51 } 52 }
  21. :FX&YBNQMF w 4JNQMFDPVOUFSFYBNQMF IUUQTHJUIVCDPNZFXTUBDLZFXUSFF NBTUFSFYBNQMFTDPVOUFS w 6*DPOTUSVDUJPO w WJFXGVODUJPOBOEIUNMNBDSP w

    $PNQPOFOUTUBUFNBOBHFNFOU w VQEBUFGVODUJPODIBOHFTFMGTUBUF w DIBOHFGVODUJPODIBOHFGSPNQBSFOU 17 impl Component for Model { 18 type Message = Msg; 19 type Properties = (); 20 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 21 Model { link, value: 0 } 22 } 23 fn update(&mut self, msg: Self::Message) -> ShouldRender { 24 match msg { 25 Msg::Increment => { 26 self.value += 1; 27 } 28 Msg::Decrement => { 29 self.value -= 1; 30 } 31 } 32 true 33 } 34 fn change(&mut self, _: Self::Properties) -> ShouldRender { 35 false 36 } 37 fn view(&self) -> Html { 38 html! { 39 <div> 40 <nav class="menu"> 41 <button onclick=self.link.callback(|_| Msg::Increment)> 42 { "Increment" } 43 </button> 44 <button onclick=self.link.callback(|_| Msg::Decrement)> 45 { "Decrement" } 46 </button> 47 </nav> 48 <p>{ self.value }</p> 49 </div> 50 } 51 } 52 } 3FOEFSJOHDPNQPOFOUTUBUF
  22. :FX&YBNQMF w 4JNQMFDPVOUFSFYBNQMF IUUQTHJUIVCDPNZFXTUBDLZFXUSFF NBTUFSFYBNQMFTDPVOUFS w 6*DPOTUSVDUJPO w WJFXGVODUJPOBOEIUNMNBDSP w

    $PNQPOFOUTUBUFNBOBHFNFOU w VQEBUFGVODUJPODIBOHFTFMGTUBUF w DIBOHFGVODUJPODIBOHFGSPNQBSFOU 17 impl Component for Model { 18 type Message = Msg; 19 type Properties = (); 20 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 21 Model { link, value: 0 } 22 } 23 fn update(&mut self, msg: Self::Message) -> ShouldRender { 24 match msg { 25 Msg::Increment => { 26 self.value += 1; 27 } 28 Msg::Decrement => { 29 self.value -= 1; 30 } 31 } 32 true 33 } 34 fn change(&mut self, _: Self::Properties) -> ShouldRender { 35 false 36 } 37 fn view(&self) -> Html { 38 html! { 39 <div> 40 <nav class="menu"> 41 <button onclick=self.link.callback(|_| Msg::Increment)> 42 { "Increment" } 43 </button> 44 <button onclick=self.link.callback(|_| Msg::Decrement)> 45 { "Decrement" } 46 </button> 47 </nav> 48 <p>{ self.value }</p> 49 </div> 50 } 51 } 52 }
  23. :FX&YBNQMF w 4JNQMFDPVOUFSFYBNQMF IUUQTHJUIVCDPNZFXTUBDLZFXUSFF NBTUFSFYBNQMFTDPVOUFS w 6*DPOTUSVDUJPO w WJFXGVODUJPOBOEIUNMNBDSP w

    $PNQPOFOUTUBUFNBOBHFNFOU w VQEBUFGVODUJPODIBOHFTFMGTUBUF w DIBOHFGVODUJPODIBOHFGSPNQBSFOU 17 impl Component for Model { 18 type Message = Msg; 19 type Properties = (); 20 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 21 Model { link, value: 0 } 22 } 23 fn update(&mut self, msg: Self::Message) -> ShouldRender { 24 match msg { 25 Msg::Increment => { 26 self.value += 1; 27 } 28 Msg::Decrement => { 29 self.value -= 1; 30 } 31 } 32 true 33 } 34 fn change(&mut self, _: Self::Properties) -> ShouldRender { 35 false 36 } 37 fn view(&self) -> Html { 38 html! { 39 <div> 40 <nav class="menu"> 41 <button onclick=self.link.callback(|_| Msg::Increment)> 42 { "Increment" } 43 </button> 44 <button onclick=self.link.callback(|_| Msg::Decrement)> 45 { "Decrement" } 46 </button> 47 </nav> 48 <p>{ self.value }</p> 49 </div> 50 } 51 } 52 } %JTQBUDINFTTBHF
  24. :FX&YBNQMF w 4JNQMFDPVOUFSFYBNQMF IUUQTHJUIVCDPNZFXTUBDLZFXUSFF NBTUFSFYBNQMFTDPVOUFS w 6*DPOTUSVDUJPO w WJFXGVODUJPOBOEIUNMNBDSP w

    $PNQPOFOUTUBUFNBOBHFNFOU w VQEBUFGVODUJPODIBOHFTFMGTUBUF w DIBOHFGVODUJPODIBOHFGSPNQBSFOU 17 impl Component for Model { 18 type Message = Msg; 19 type Properties = (); 20 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 21 Model { link, value: 0 } 22 } 23 fn update(&mut self, msg: Self::Message) -> ShouldRender { 24 match msg { 25 Msg::Increment => { 26 self.value += 1; 27 } 28 Msg::Decrement => { 29 self.value -= 1; 30 } 31 } 32 true 33 } 34 fn change(&mut self, _: Self::Properties) -> ShouldRender { 35 false 36 } 37 fn view(&self) -> Html { 38 html! { 39 <div> 40 <nav class="menu"> 41 <button onclick=self.link.callback(|_| Msg::Increment)> 42 { "Increment" } 43 </button> 44 <button onclick=self.link.callback(|_| Msg::Decrement)> 45 { "Decrement" } 46 </button> 47 </nav> 48 <p>{ self.value }</p> 49 </div> 50 } 51 } 52 } 4UBUFVQEBUF
  25. :FX&YBNQMF w 4JNQMFDPVOUFSFYBNQMF IUUQTHJUIVCDPNZFXTUBDLZFXUSFF NBTUFSFYBNQMFTDPVOUFS w 6*DPOTUSVDUJPO w WJFXGVODUJPOBOEIUNMNBDSP w

    $PNQPOFOUTUBUFNBOBHFNFOU w VQEBUFGVODUJPODIBOHFTFMGTUBUF w DIBOHFGVODUJPODIBOHFGSPNQBSFOU 17 impl Component for Model { 18 type Message = Msg; 19 type Properties = (); 20 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 21 Model { link, value: 0 } 22 } 23 fn update(&mut self, msg: Self::Message) -> ShouldRender { 24 match msg { 25 Msg::Increment => { 26 self.value += 1; 27 } 28 Msg::Decrement => { 29 self.value -= 1; 30 } 31 } 32 true 33 } 34 fn change(&mut self, _: Self::Properties) -> ShouldRender { 35 false 36 } 37 fn view(&self) -> Html { 38 html! { 39 <div> 40 <nav class="menu"> 41 <button onclick=self.link.callback(|_| Msg::Increment)> 42 { "Increment" } 43 </button> 44 <button onclick=self.link.callback(|_| Msg::Decrement)> 45 { "Decrement" } 46 </button> 47 </nav> 48 <p>{ self.value }</p> 49 </div> 50 } 51 } 52 } 3FSFOEFSJOH
  26.  3FDFOU'SPOUFOE8FC%FWFMPQNFOU  'SPOUFOE'SBNFXPSLTJO3VTU  'VUVSF$IBMMFOHFT  4VNNBSZ

  27. 'VUVSF$IBMMFOHFT w 8PSLJOHXJUI8PSLFST w 8PSLJOHXJUI$44 w 4FSWFSTJEFSFOEFSJOH w 8FC$PNQPOFOUTBOE.JDSPGSPOUFOET

  28. 'VUVSF$IBMMFOHFT w 8PSLJOHXJUI8PSLFST w 8PSLJOHXJUI$44 w 4FSWFSTJEFSFOEFSJOH w 8FC$PNQPOFOUTBOE.JDSPGSPOUFOET

  29. w %FMBZFESFTQPOTFUPVTFST w 'SBNFSBUFESPQ .BJO5ISFBEJO8FC#SPXTFST w 5BTLTPGUIFNBJOUISFBE w %0.PQFSBUJPOT )5.-MBZPVU

     FWFOUIBOEMJOH TDSJQUJOH  FUD 5BTL 'SBNF 5BTL 5BTL 5BTL 'SBNF 'SBNF 'SBNF 'SBNF 'SBNF ❌ ❌ .BJO5ISFBE 5BTL &WFOU )BOEMJOH 8BJUJOH5JNF &WFOU .BJO5ISFBE
  30. 0⒎UIFNBJOUISFBE w -PBECBMBODJOHIFBWZUBTLT VTJOH8FC8PSLFST w *ODSFBTJOHNBJOUISFBEJEMFUJNF w *NQSPWJOH69 w "OPUIFSQPTTJCMFTPMVUJPO

    8FC"TTFNCMZ5ISFBET 5BTL 'SBNF 'SBNF 'SBNF 'SBNF 'SBNF 'SBNF .BJO5ISFBE 5BTL 'SBNF 5BTL 5BTL 5BTL 'SBNF 'SBNF 'SBNF 'SBNF 'SBNF ❌ ❌ .BJO5ISFBE 5BTL 8PSLFS 5BTL 5BTL 5BTL 5BTL 5BTL 5BTL 5BTL
  31. "HFOUTJO:FX 27 impl Agent for Worker { 43 fn update(&mut

    self, msg: Self::Message) { 44 match msg { 45 Msg::Updating => { 46 info!("Tick..."); 47 } 48 } 49 } 50 51 fn handle_input(&mut self, msg: Self::Input, who: HandlerId) { 52 info!("Request: {:?}", msg); 53 match msg { 54 Request::GetDataFromServer => { 55 // TODO fetch actual data 56 self.link.respond(who, Response::DataFetched); 57 } 58 } 59 } 64 } 19 impl Component for Model { 23 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 24 let callback = link.callback(|_| Msg::DataReceived); 25 let worker = Worker::bridge(callback); 26 27 Model { link, worker } 28 } 29 30 fn update(&mut self, msg: Self::Message) -> ShouldRender { 31 match msg { 32 Msg::SendToWorker => { 33 self.worker.send(Request::GetDataFromServer); 34 } 35 Msg::DataReceived => { 36 info!("DataReceived"); 37 } 38 } 39 true 40 } 41 42 fn view(&self) -> Html { 43 html! { 44 <div> 45 <nav class="menu"> 46 <button onclick=self.link.callback(|_| Msg::SendToWorker)>{"Send"}</button> 47 </nav> 48 </div> 49 } 50 } 55 } w IUUQTZFXSTEPDTFODPODFQUTBHFOUT w $BODBMMXPSLFSTUISPVHI BCTUSBDUFEJOUFSGBDF w "DUPSNPEFM .BJO5ISFBE 8PSLFS
  32. "HFOUTJO:FX 27 impl Agent for Worker { 43 fn update(&mut

    self, msg: Self::Message) { 44 match msg { 45 Msg::Updating => { 46 info!("Tick..."); 47 } 48 } 49 } 50 51 fn handle_input(&mut self, msg: Self::Input, who: HandlerId) { 52 info!("Request: {:?}", msg); 53 match msg { 54 Request::GetDataFromServer => { 55 // TODO fetch actual data 56 self.link.respond(who, Response::DataFetched); 57 } 58 } 59 } 64 } 19 impl Component for Model { 23 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 24 let callback = link.callback(|_| Msg::DataReceived); 25 let worker = Worker::bridge(callback); 26 27 Model { link, worker } 28 } 29 30 fn update(&mut self, msg: Self::Message) -> ShouldRender { 31 match msg { 32 Msg::SendToWorker => { 33 self.worker.send(Request::GetDataFromServer); 34 } 35 Msg::DataReceived => { 36 info!("DataReceived"); 37 } 38 } 39 true 40 } 41 42 fn view(&self) -> Html { 43 html! { 44 <div> 45 <nav class="menu"> 46 <button onclick=self.link.callback(|_| Msg::SendToWorker)>{"Send"}</button> 47 </nav> 48 </div> 49 } 50 } 55 } w IUUQTZFXSTEPDTFODPODFQUTBHFOUT w $BODBMMXPSLFSTUISPVHI BCTUSBDUFEJOUFSGBDF w "DUPSNPEFM .BJO5ISFBE 8PSLFS
  33. "HFOUTJO:FX 27 impl Agent for Worker { 43 fn update(&mut

    self, msg: Self::Message) { 44 match msg { 45 Msg::Updating => { 46 info!("Tick..."); 47 } 48 } 49 } 50 51 fn handle_input(&mut self, msg: Self::Input, who: HandlerId) { 52 info!("Request: {:?}", msg); 53 match msg { 54 Request::GetDataFromServer => { 55 // TODO fetch actual data 56 self.link.respond(who, Response::DataFetched); 57 } 58 } 59 } 64 } 19 impl Component for Model { 23 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 24 let callback = link.callback(|_| Msg::DataReceived); 25 let worker = Worker::bridge(callback); 26 27 Model { link, worker } 28 } 29 30 fn update(&mut self, msg: Self::Message) -> ShouldRender { 31 match msg { 32 Msg::SendToWorker => { 33 self.worker.send(Request::GetDataFromServer); 34 } 35 Msg::DataReceived => { 36 info!("DataReceived"); 37 } 38 } 39 true 40 } 41 42 fn view(&self) -> Html { 43 html! { 44 <div> 45 <nav class="menu"> 46 <button onclick=self.link.callback(|_| Msg::SendToWorker)>{"Send"}</button> 47 </nav> 48 </div> 49 } 50 } 55 } w IUUQTZFXSTEPDTFODPODFQUTBHFOUT w $BODBMMXPSLFSTUISPVHI BCTUSBDUFEJOUFSGBDF w "DUPSNPEFM .BJO5ISFBE 8PSLFS
  34. "HFOUTJO:FX 27 impl Agent for Worker { 43 fn update(&mut

    self, msg: Self::Message) { 44 match msg { 45 Msg::Updating => { 46 info!("Tick..."); 47 } 48 } 49 } 50 51 fn handle_input(&mut self, msg: Self::Input, who: HandlerId) { 52 info!("Request: {:?}", msg); 53 match msg { 54 Request::GetDataFromServer => { 55 // TODO fetch actual data 56 self.link.respond(who, Response::DataFetched); 57 } 58 } 59 } 64 } 19 impl Component for Model { 23 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 24 let callback = link.callback(|_| Msg::DataReceived); 25 let worker = Worker::bridge(callback); 26 27 Model { link, worker } 28 } 29 30 fn update(&mut self, msg: Self::Message) -> ShouldRender { 31 match msg { 32 Msg::SendToWorker => { 33 self.worker.send(Request::GetDataFromServer); 34 } 35 Msg::DataReceived => { 36 info!("DataReceived"); 37 } 38 } 39 true 40 } 41 42 fn view(&self) -> Html { 43 html! { 44 <div> 45 <nav class="menu"> 46 <button onclick=self.link.callback(|_| Msg::SendToWorker)>{"Send"}</button> 47 </nav> 48 </div> 49 } 50 } 55 } w IUUQTZFXSTEPDTFODPODFQUTBHFOUT w $BODBMMXPSLFSTUISPVHI BCTUSBDUFEJOUFSGBDF w "DUPSNPEFM .BJO5ISFBE 8PSLFS
  35. "HFOUTJO:FX 27 impl Agent for Worker { 43 fn update(&mut

    self, msg: Self::Message) { 44 match msg { 45 Msg::Updating => { 46 info!("Tick..."); 47 } 48 } 49 } 50 51 fn handle_input(&mut self, msg: Self::Input, who: HandlerId) { 52 info!("Request: {:?}", msg); 53 match msg { 54 Request::GetDataFromServer => { 55 // TODO fetch actual data 56 self.link.respond(who, Response::DataFetched); 57 } 58 } 59 } 64 } 19 impl Component for Model { 23 fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { 24 let callback = link.callback(|_| Msg::DataReceived); 25 let worker = Worker::bridge(callback); 26 27 Model { link, worker } 28 } 29 30 fn update(&mut self, msg: Self::Message) -> ShouldRender { 31 match msg { 32 Msg::SendToWorker => { 33 self.worker.send(Request::GetDataFromServer); 34 } 35 Msg::DataReceived => { 36 info!("DataReceived"); 37 } 38 } 39 true 40 } 41 42 fn view(&self) -> Html { 43 html! { 44 <div> 45 <nav class="menu"> 46 <button onclick=self.link.callback(|_| Msg::SendToWorker)>{"Send"}</button> 47 </nav> 48 </div> 49 } 50 } 55 } w IUUQTZFXSTEPDTFODPODFQUTBHFOUT w $BODBMMXPSLFSTUISPVHI BCTUSBDUFEJOUFSGBDF w "DUPSNPEFM .BJO5ISFBE 8PSLFS
  36. 'VUVSF$IBMMFOHFT w 8PSLJOHXJUI8PSLFST w 8PSLJOHXJUI$44 w 4FSWFSTJEFSFOEFSJOH w 8FC$PNQPOFOUTBOE.JDSPGSPOUFOET

  37. .PEFSO$448PSLqPX w .PUJWBUJPO w "WPJEJOH$44USPVCMFT w "TTFUPQUJNJ[BUJPO w 4PMVUJPOT w

    $MBTTOBNJOHDPOWFOUJPOTMJLF#&. w $44.PEVMFT w $44JO+4MJLF4UZMFE$PNQPOFOUT
  38. 3VTU"QQSPBDIFT w $MBTTJEFOUJpFSHFOFSBUJPO w DTTNBDSPJO1FSDZ IUUQTHJUIVCDPNDIJOFEVGOQFSDZUSFF NBTUFSFYBNQMFTDTTJOSVTU w $44JO3VTU IUUQTHJUIVCDPNMVLJEPFTDPEFDTTJOSVTU

    w 5ZQFTBGF$44HFOFSBUJPO w 3644 IUUQTHJUIVCDPNTJLVSVTT 12 impl Component for App { 16 fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self { 17 let style = match Style::create("App", include_str!("app.scss")) { 18 Ok(style) => style, 19 Err(error) => { 20 panic!("An error occured while creating the style: {}", error); 21 } 22 }; 23 App { style } 24 } 34 fn view(&self) -> Html { 35 html! {<div class=self.style.clone()> 38 </div>} 39 } 40 } 17 assert_eq!( 18 render(Calc::bin_div(Calc::bin_div(Length::px(100), 2), 2)), 19 "calc((100px / 2) / 2)" 20 ); 21 assert_eq!( 22 render(Color::rgba(Calc::bin_sub(255, 5), 0, 153, 1)), 23 "rgb(calc(255 - 5),0,153,1)" 24 );
  39. 'VUVSF$IBMMFOHFT w 8PSLJOHXJUI8PSLFST w 8PSLJOHXJUI$44 w 4FSWFSTJEFSFOEFSJOH w 8FC$PNQPOFOUTBOE.JDSPGSPOUFOET

  40. 4FSWFS4JEF3FOEFSJOH 443 w .PUJWBUJPO w *NQSPWJOHJOJUJBMQBJOUJOHQFSGPSNBODF w 3FOEFSJOHDPOUFOUTXJUIPVU+BWB4DSJQU 1SPHSFTTJWF&OIBODFNFOU 41"

    41" 443 w4DSJQU-PBEJOH w4DSJQU&YFDVUJPO w3FOEFSJOHDPOUFOUT 'JSTU1BJOU 'JSTU1BJOU 3FBEZUP*OUFSBDUJWF 3FBEZUP*OUFSBDUJWF %JTQMBZ%FMBZ
  41. 4FSWFS4JEF3FOEFSJOHJO1FSDZ w IUUQTHJUIVCDPNDIJOFEVGOQFSDZ w 8FC"TTFNCMZCBTFEBQQGSBNFXPSLTVQQPSUTTFSWFSTJEFSFOEFSJOH w *TPNPSQIJDFYBNQMF IUUQTHJUIVCDPNDIJOFEVGOQFSDZUSFFNBTUFSFYBNQMFTJTPNPSQIJD w *TPNPSQIJDXPSLTUIFTBNFPOUIFTFSWFSBOEDMJFOU

    "QQ4FSWFS 8FC#SPXTFS )BOEMJOHVTFSJOUFSBDUJPOT 1FSDZ "DUJYXFC 3PDLFU FUD 3VTU (FOFSBUJOHJOJUJBMWJFXBOEJOJUJBMTUBUF 1FSDZ 8FC"TTFNCMZ IUUQTFYBNQMFDPNTPNFQBUI QBSBNWBMVF %0$5:1&IUNM IUNM IFBEIFBE CPEZ EJWJEFOUSZQPJOU JOJUJBMWJFX EJW TDSJQU JOJUJBM4UBUF\ JOJUJBMTUBUF ^ TDJSQU CPEZ IUNM
  42. +BNTUBDLJO3VTU 1SPCBCMZ3BNTUBDL w +BNTUBDL w +BWB4DSJQU "1*T .BSLVQ w #FUUFSMPBEJOHQFSGPSNBODF

    VTJOH$%/ w /FYUKT w 3FBDUCBTFEGSBNFXPSLTVQQPSUT443BOE44( w &BTJMZQVCMJTIJOHXFCBQQTPWFS$%/T w )JHIMFWFMGSBNFXPSLMJLF/FYUKTXJMMIFMQ UPEFWFMPQTDBMBCMFXFCBQQTXJUI3VTU .JDSPTFSWJDFT $%/ 8FC#SPXTFS )5.- $44 +BWB4DSJQU &⒏DJFOUMZTFSWJOHTUBUJDDPOUFOUTPWFS$%/ +BNTUBDL
  43. 'VUVSF$IBMMFOHFT w 8PSLJOHXJUI8PSLFST w 8PSLJOHXJUI$44 w 4FSWFSTJEFSFOEFSJOH w 8FC$PNQPOFOUTBOE.JDSP'SPOUFOET

  44. 8FC$PNQPOFOUT w IUUQTXXXXFCDPNQPOFOUTPSH w 8FCOBUJWFDPNQPOFOUTZTUFN w 4QFDJpDBUJPOT w $VTUPN&MFNFOUT 4IBEPX%0.

     &4.PEVMFT )5.-5FNQMBUF w *OIFSJUBODFPG+BWB4DSJQUDMBTTCZXBTNCJOEHFO JTVOEFSEJTDVTTJPO IUUQTHJUIVCDPNSVTUXBTNSGDTQVMM
  45. 8IZ8FC$PNQPOFOUTXJUI3VTU IUUQTNJDSPGSPOUFOETPSH w &NCFEEJOH6*QBSUTXSJUUFOJO3VTUJOUP XFCBQQT w .JDSP'SPOUFOET w 4QMJUUJOHFOMBSHFEXFCTZTUFNT w

    *OUFHSBUJPOPGTVCTZTUFNT JNQMFNFOUFEJOWBSJPVTGSBNFXPSLT
  46. 8IZ8FC$PNQPOFOUTXJUI3VTU IUUQTNJDSPGSPOUFOETPSH w &NCFEEJOH6*QBSUTXSJUUFOJO3VTUJOUP XFCBQQT w .JDSP'SPOUFOET w 4QMJUUJOHFOMBSHFEXFCTZTUFNT w

    *OUFHSBUJPOPGTVCTZTUFNT JNQMFNFOUFEJOWBSJPVTGSBNFXPSLT 8SJUUFOCZ"OHVMBS 8SJUUFOCZ3FBDU 8SJUUFOCZ3VTU 8FC"TTFNCMZ FH
  47.  3FDFOU'SPOUFOE8FC%FWFMPQNFOU  'SPOUFOE'SBNFXPSLTJO3VTU  'VUVSF$IBMMFOHFT  4VNNBSZ

  48. 4VNNBSZ w 3FDFOUDPNQMFYGSPOUFOEXFCEFWFMPQNFOUSFRVJSFT BQPXFSGVMMBOHVBHFMJLF3VTU w 8JUIUIFEFWFMPQNFOUPGUPPMDIBJOTBOEGSBNFXPSLT GSPOUFOE XFCEFWFMPQNFOUXJUI3VTUJTBQQSPBDIJOHQSBDUJDBMVTF w 'SPOUFOEXFCEFWFMPQNFOUXJUI3VTUBMTPOFFETUP

    JODPSQPSBUFXFCCFTUQSBDUJDFTEFWFMPQFEXJUI+4 w -FUTDSFBUFUIFGVUVSFPG3VTUBOEUIFXFC
  49. 4VNNBSZ w 3FDFOUDPNQMFYGSPOUFOEXFCEFWFMPQNFOUSFRVJSFT BQPXFSGVMMBOHVBHFMJLF3VTU w 8JUIUIFEFWFMPQNFOUPGUPPMDIBJOTBOEGSBNFXPSLT GSPOUFOE XFCEFWFMPQNFOUXJUI3VTUJTBQQSPBDIJOHQSBDUJDBMVTF w 'SPOUFOEXFCEFWFMPQNFOUXJUI3VTUBMTPOFFETUP

    JODPSQPSBUFXFCCFTUQSBDUJDFTEFWFMPQFEXJUI+4 w -FUTDSFBUFUIFGVUVSFPG3VTUBOEUIFXFC 5IBOLZPV