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

The challenges of web apps: what we’ve solved a...

The challenges of web apps: what we’ve solved and what’s next?

###

This talk is an overview of how web apps evolved over time: from traditional CGI to full-stack SSR frameworks and local-first apps. By using an analogy of a physical distance between a human and computer, I tried to show that the variety of tools we have now and their complexity makes total sense. As developers, we are trying to wipe the boundary between desktop and web UX, while iterating on the platform and dev tools. I tried to provide a simple explanation of concepts like partial hydration, resumability, islands architecture and signals.

The second part of this talk is an overview of the arising web development trends (all-in-one tooling, local-first, backend-first) and some speculations of what’s coming next: for example, can AI run entirely in the browser? The illustrations and visual style for this talks were produced in collaboration with Liza Zaft.

Alexey Taktarov

December 09, 2024
Tweet

More Decks by Alexey Taktarov

Other Decks in Programming

Transcript

  1. ╔═════════════════════╦════════════════════════════╗ ║ Yes&'( ║ But ║ ╠═════════════════════╬════════════════════════════╣ ║ Network Computer

    ║ Slow ║ ║ Browser-first ║ Poor support of HTML4 ║ ║ Java Applets ║ Outdated Java 1.0 running ║ ║ Rich Apps ║ Not enough apps available ║ ╚═════════════════════╩════════════════════════════╝ *IBEUPBQPMPHJ[FUPNZTUVEFOUTGPSUIFTMPXBOE JODPOWFOJFOUNBDIJOFT*SFNFNCFSNBLJOHTPNFKPLFT BCPVUUFDIOPMPHJDBMQSPHSFTT %S"MFY3ZCB 'PSNFS1SPGFTTPSBU.BSRVFUUF6OJWFSTJUZ 2VPUFE.BSDI
  2. $0.165&3 ίϯϐϡʔλʔ )6."/ ώϡʔϚϯ 4PNFPOF`TCFESPPNJO+BQBO 4&37&3 αʔόʔ 4BO'SBODJTDP $(*)5.- 8JUI$(*

    $0.165&3CFDPNFTNPSF SFTQPOTJWFBOENPSFQFSTPOBMJTFE +41 1FSM 1)1 %KBOHP 3BJMT
  3. $0.165&3 ίϯϐϡʔλʔ )6."/ ώϡʔϚϯ 4&37&3 αʔόʔ %0.-FWFM  "+"9 

    %PKP  1SPUPUZQF  K2VFSZ  9)3 $(*)5.- +4 4FSWFSHFOFSBUFE)5.- +4TDSJQUT
  4. 1MBUGPSNBEWBODFNFOUT +BWB4DSJQUJTOPXGBTU 7   #SPXTFS)JTUPSZ"1*   "+"9 %ZOBNJD%0.

    BOENPSF %9 69 *OUFSBDUJWJUZ +4 'JSTU8FCTJUFT $PNQPOFOUCBTFE 7JFX-JCSBSJFT
  5. isLightOn true lightStatus “ON” Light is <span>“ON”!/span> when changed:
 turn

    the lights off after 5s lPCTFSWFS lPCTFSWBCMFz lDPNQVUFEz lUFNQMBUFz &NCFSKT DJSDB
  6. const RoomLight = Ember.Object.extend({ isLightOn: false, lightStatus: Ember.computed('isLightOn', function ()

    { return this.get('isLightOn') ? 'On' : 'Off'; }), autoTurnOff: Ember.observer('isLightOn', function () { if (this.get('isLightOn')) { Ember.run.later(this, function () { this.set('isLightOn', false); #$ Turn off the light }, 5000); } }), }); Light is <span>“{{lightStatus}}”!/span> &NCFSKT DJSDB
  7. const RoomLight = Ember.Object.extend({ isLightOn: false, lightStatus: Ember.computed('isLightOn', function ()

    { return this.get('isLightOn') ? 'On' : 'Off'; }), autoTurnOff: Ember.observer('isLightOn', function () { if (this.get('isLightOn')) { Ember.run.later(this, function () { this.set('isLightOn', false); #$ Turn off the light }, 5000); } }), }); Light is <span>“{{lightStatus}}”!/span> PCTFSWBCMF &NCFSKT DJSDB DPNQVUFE PCTFSWFS UFNQMBUF
  8.  l *TPNPSQIJD+BWB4DSJQUz  3FBDU 7VF l3FBDUIBTIBETFSWFSTJEFSFOEFSJOHTJODFJUXBT SFMFBTFEJO TUPQQSFUFOEJOHJUTOFX 3FEEJU

    renderComponentToString() 2    "OHVMBS "OHVMBS6OJWFSTBM &NCFS'BTU#PPU #SPXTFSJGZ l4DBMJOH*TPNPSQIJD+BWBTDSJQU$PEF /PEFKJUTV#MPH 8FCQBDL  &4'JOBM%SBGU
  9. 1MBUGPSNBEWBODFNFOUT &$."UI&EJUJPO &4   %ZOBNJDJNQPSU GFUDI  7BSJFUZPGJTPNPSQIJDQBDLBHFTPO/1. %9

    69 *OUFSBDUJWJUZ +4 'JSTU8FCTJUFT $PNQPOFOUCBTFE 7JFX-JCSBSJFT 443"QQT 'VMM4UBDL'SBNFXPSLT
  10.  /FYUKT   4WFMUF,JU 'JMFCBTFESPVUJOH EJSFDUPSZDPOWFOUJPOT DBOTIJQNPSFDPNQMFYBQQTXJUINPSFEFWUFBNTJOWPMWFE 443TFUVQPVUPGUIFCPY TBWFSFTPVSDFTPODPOpHVSJOHCVOEMFS

    USBOTQJMFS TFSWFSQPMZpMMT 3FDPNNFOEFEUPPMJOHBOECPPUTUSBQUFNQMBUFT RVJDLTUBSUMPXFS55) UJNFUPIBDLJOH  3FNJY    /VYUKT 2XJL$JUZ 3FEXPPE+4 %9/&&%4
  11. %&7&-01&3 σϕϩούʔ +--------------------+ | Oh, NO! | +--------------------+ \ 3FSFOEFSJOH1FSGPSNBODF*/1

    )PXGBTUUIFBQQDBOSFBDUUPVQEBUFT */1*OUFSBDUJPOUP/FYU1BJOU 55*5JNFUP*OUFSBDUJWF
  12. %&7&-01&3 σϕϩούʔ +--------------------+ | Oh, NO! | +--------------------+ \ 3FSFOEFSJOH1FSGPSNBODF*/1

    )PXGBTUUIFBQQDBOSFBDUUPVQEBUFT )ZESBUJPO1FSGPSNBODF55* )PXTPPODBOUIFBQQCFDPNFTJOUFSBDUJWF */1*OUFSBDUJPOUP/FYU1BJOU 55*5JNFUP*OUFSBDUJWF
  13. <App> ├── <Header> │ └── <NavBar> ├── <Main> │ ├──

    <About> │ ├── <Sidebar> │ └── <Content> │ └── <ItemList> │ ├── <Item> #1 │ ├── <Item> #2 │ └── <Item> #3 └── <Footer> BOBQQSFSFOEFSTCFDBVTFUIFTUBUFPGPOFPGJUT DPNQPOFOUTIBTDIBOHFE
  14. <App> ├── <Header> │ └── <NavBar> ├── <Main> │ ├──

    <About> │ ├── <Sidebar> │ └── <Content> │ └── <ItemList> │ ├── <Item> #1 │ ├── <Item> #2 │ └── <Item> #3 └── <Footer> BOBQQSFSFOEFSTCFDBVTFUIFTUBUFPGPOFPGJUT DPNQPOFOUTIBTDIBOHFE
  15. <App> ├── <Header> │ └── <NavBar> ├── <Main> │ ├──

    <About> │ ├── <Sidebar> │ └── <Content> │ └── <ItemList> │ ├── <Item> #1 │ ├── <Item> #2 │ └── <Item> #3 └── <Footer> BOBQQSFSFOEFSTCFDBVTFUIFTUBUFPGPOFPGJUT DPNQPOFOUTIBTDIBOHFE
  16. <App> ├── <Header> │ └── <NavBar> ├── <Main> │ ├──

    <About> │ ├── <Sidebar> │ └── <Content> │ └── <ItemList> │ ├── <Item> #1 │ ├── <Item> #2 │ └── <Item> #3 └── <Footer> BOBQQSFSFOEFSTCFDBVTFUIFTUBUFPGPOFPGJUT DPNQPOFOUTIBTDIBOHFE
  17. <App> ├── <Header> │ └── <NavBar> ├── <Main> │ ├──

    <About> │ ├── <Sidebar> │ └── <Content> │ └── <ItemList> │ ├── <Item> #1 │ ├── <Item> #2 │ └── <Item> #3 └── <Footer> BOBQQSFSFOEFSTCFDBVTFUIFTUBUFPGPOFPGJUT DPNQPOFOUTIBTDIBOHFE
  18. import { signal, computed, effect } from "@preact/signals"; const isLightOn

    = signal(true) const lightStatus = computed(() /0 isLightOn ? "ON" : "OFF") effect(() /0 { if (isLightOn) isLightOn.value = false }) 4JHOBMTJO1SFBDU
  19. let isLightOn = $state(true) let doubled = $derived(isLightOn ? "ON"

    : "OFF") effect(() /0 { if (isLightOn) isLightOn = false }) 3VOFTJO4WFMUF
  20. isLightOn true lightStatus “ON” Light is <span>“ON”!/span> when changed:
 turn

    the lights off after 5s lFGGFDUz lTJHOBMz lDPNQVUFEz +49 #VU&NCFSKTJOWFOUFEJUJO
  21. <form method="post" action="/_actions/color-scheme"> <input type="hidden" name="returnTo" value="/app"/1 <button value="light" name="colorScheme">Light2/button>

    <button value="light" name="colorScheme">Dark2/button> 2/form> 1SPHSFTTJWF&OIBODFNFOUJO3FNJY ╔═════════════════════╦════════════════════════════╗ ║ Non-Interactive ║ Submit Form (Navigation) ║ ║ Hydrated ║ fetch + setState (React) ║ ╚═════════════════════╩════════════════════════════╝
  22. $0.165&3 ίϯϐϡʔλʔ )6."/ ώϡʔϚϯ 4&37&3 αʔόʔ %$JO4BO'SBODJTDP 4PNFPOF`TCFESPPN 5PLZP &%(&4&37&3

    Τοδαʔόʔ %$5PLZP NT 4FSWFSMFTT+4POUIF&EHF $MPVEqBSF8PSLFST -BNCEB!&EHF %FOP%FQMPZ  4VQBCBTF&EHF'VODUJPOT FUD
  23. 1MBUGPSNBEWBODFNFOUT   7*TPMBUFT 8"4.POUIFFEHF 8FC4UBOEBSETGFUDI 3FRVFTU3FTQPOTF  8FC$SZQUP"1* FUD

    %9 69 *OUFSBDUJWJUZ +4 'JSTU8FCTJUFT $PNQPOFOUCBTFE 7JFX-JCSBSJFT 443"QQT 'VMM4UBDL'SBNFXPSLT 1FSGPSNBOU 3FOEFSJOH)ZESBUJPO
  24. 1MBUGPSNBEWBODFNFOUT   7*TPMBUFT 8"4.POUIFFEHF 8FC4UBOEBSETGFUDI 3FRVFTU3FTQPOTF  8FC$SZQUP"1* FUD

    %9 69 *OUFSBDUJWJUZ +4 'JSTU8FCTJUFT $PNQPOFOUCBTFE 7JFX-JCSBSJFT 443"QQT 'VMM4UBDL'SBNFXPSLT &EHF$PNQVUJOH 1FSGPSNBOU 3FOEFSJOH)ZESBUJPO
  25. 3FNJY SFNJYSVO "EBQUFSTGPS%FOP /PEF 7FSDFM  $MPVEGMBSF8PSLFST 7FSDFMFUD “WRITE ONCE,

    DEPLOY ANYWHERE” )POP IPOPEFW .VMUJSVOUJNFXFCTFSWFS 445 TTUEFW 4JOHMFDPOGJHGPS QSPWJEFST
  26. ╔════════════════════╦══════╦══════╦═══════╦══════╗ ║ Feature/Tool ║ Deno ║ Bun ║ Biome ║

    Oxc ║ ╠════════════════════╬══════╬══════╬═══════╬══════╣ ║ Runtime ║ YES ║ YES ║ NO ║ NO ║ ║ Test Runner ║ YES ║ YES ║ NO ║ NO1 ║ ║ Package Manager ║ YES ║ YES ║ NO ║ NO ║ ║ Bundler ║ NO ║ YES ║ NO ║ WIP ║ ║ Formatter ║ YES ║ NO ║ YES ║ WIP ║ ║ Linter ║ YES ║ NO ║ YES ║ YES ║ ║ Resolver ║ NO ║ NO ║ NO ║ YES ║ ║ Minifier ║ NO ║ NO ║ NO ║ YES ║ ╚════════════════════╩══════╩══════╩═══════╩══════╝ $BO7JUFTUCFDPNF0YD`TSFDPNNFOEFEUFTUSVOOFS
  27. +---------------------------+ | Give us the ownership of | | the

    infrastructure back! | | | #leavethecloud | +---------------------------+ / \ +---------------------------+ | Say NO to transpilation | | and bundling! | | #NOBUILD | +---------------------------+ #VOEMJOH$PEF4QMJUUJOH +495VSCPQBDL 3PMMEPXO7JUF 8FCQBDL48$ FTCVJME3PNF 5VSCPQBDLNJDSPCVOEMF 5ZQF4DSJQU$44JO+4 1PTU$44$44.PEVMFT 4FSWFSMFTT%#T)FBEMFTT"VUI #BCFM4UBUJD1SPQT %ZOBNJD3PVUFT44344( ).3-B[Z-PBEJOH 5SFF4IBLJOH.PEVMF'FEFSBUJPO &EHF'VODUJPOT%FOP 1SFBDU4PMJE+4 ;VTUBOE+PUBJ 341BDL.FUSP 3PMMVQ.JOJGJDBUJPO $IVOLJOH"TTFU0QUJNJ[BUJPO 4PVSDF.BQT)PU3FMPBEJOH
  28. 'SBNFXPSLT-JCSBSJFT 5JOZ#BTF 3FBDUJWF%#XJUI$3%5  :KT %BUBUZQFTGPS$3%5  "VUPNFSHF Local-First *O#SPXTFS%#T

    5VSTP 42-JUFDPNQBUJCMF  %VDL%# .VMUJ3VOUJNF BOBMZUJDBM  1(-JUF XWFDUPSTFBSDI 1SPQSJFUBSZ *OTUBOU 3FBM5JNF 4ZOD  GPS3FBDU7BOJMMB  +B[[UPPMT DMPVEPSTFMGIPTUFE 3FTPVSDFT MPDBMGJSTUXFCEFW MPDBMGJSTUGN MPDBMGJSTUDPOGDPN
  29. 1MBUGPSN"EWBODFNFOUT 8"4. 8FC(16 8FC//8$$BOEJEBUF3FD the State of in-browser AI *O#SPXTFS7FDUPS4FBSDI

    5VSTP 42-JUFDPNQBUJCMF  1(-JUF QH@WFDUPS .PEFMT (FNJOJ/BOPAXJOEPXBJA 8FC4UBCMF%JGGVTJPO 5SBOTGPSNFSTKT 8FC--.