Isomorf applikasjon med React og Nashorn

1. Oversikt

I denne opplæringen vil vi forstå hva som er en isomorf app. Vi diskuterer også Nashorn, JavaScript-motoren som følger med Java.

Videre vil vi utforske hvordan vi kan bruke Nashorn sammen med et frontend-bibliotek som React for å lage en isomorf app.

2. Litt historie

Tradisjonelt ble klient- og serverapplikasjoner skrevet på en måte som var ganske tung på serversiden. Tenk på PHP som en skriptmotor som genererer mest statisk HTML og nettlesere som gjengir dem.

Netscape fulgte med støtte for JavaScript i sin nettleser helt tilbake på midten av nittitallet. Det begynte å flytte noe av behandlingen fra serversiden til klientsiden. I lang tid slet utviklere med forskjellige problemer angående JavaScript-støtte i nettlesere.

Med den økende etterspørselen etter raskere og interaktiv brukeropplevelse ble grensen allerede presset hardere. En av de tidligste rammene som endret spillet var jQuery. Det brakte flere brukervennlige funksjoner og mye forbedret støtte for AJAX.

Snart begynte det å dukke opp mange rammer for front-end-utvikling, noe som forbedret utviklerens opplevelse sterkt. Fra og med AngularJS fra Google, React fra Facebook og senere Vue, begynte de å fange utviklerens oppmerksomhet.

Med moderne nettleserstøtte, bemerkelsesverdige rammer og nødvendige verktøy, tidevannet i stor grad skifter mot klientsiden.

En oppslukende opplevelse på stadig raskere håndholdte enheter krever mer behandling på klientsiden.

3. Hva er en isomorf app?

Så vi så hvordan frontend-rammeverk hjelper oss med å utvikle en webapplikasjon der brukergrensesnittet blir fullstendig gjengitt på klientsiden.

Derimot, det er også mulig å bruke det samme rammeverket på serversiden og generere det samme brukergrensesnittet.

Nå trenger vi ikke å holde oss til bare klientsiden eller bare server-side-løsningene. En bedre måte er å ha en løsning der klienten og serveren kan begge behandle samme front-end-kode og generere det samme brukergrensesnittet.

Det er fordeler med denne tilnærmingen, som vi vil diskutere senere.

Slike nettapplikasjoner kalles Isomorf eller Universal. Nå er klientsiden språk mest utelukkende JavaScript. Derfor, for at en isomorf app skal fungere, må vi også bruke JavaScript på serversiden.

Node.js er det klart vanligste valget å bygge en gjengitt applikasjon på serversiden.

4. Hva er Nashorn?

Så hvor passer Nashorn inn, og hvorfor skal vi bruke den? Nashorn er en JavaScript-motor pakket som standard med Java. Derfor, hvis vi allerede har en webapplikasjon i Java og ønsker å bygge en isomorf app, er Nashorn ganske praktisk!

Nashorn er utgitt som en del av Java 8. Dette er primært fokusert på å tillate innebygde JavaScript-applikasjoner i Java.

Nashorn kompilerer JavaScript i minnet til Java Bytecode og overfører den til JVM for utførelse. Dette gir bedre ytelse sammenlignet med den tidligere motoren, Rhino.

5. Opprette en isomorf app

Vi har gått gjennom nok sammenheng nå. Vår applikasjon her vil vise en Fibonacci-sekvens og gi en knapp for å generere og vise neste nummer i sekvensen. La oss lage en enkel isomorf app nå med en back-end og front-end:

  • Front-end: En enkel React.js-basert front-end
  • Back-end: En enkel Spring Boot-back-end med Nashorn for å behandle JavaScript

6. Søknad Front-End

Vi bruker React.js for å lage frontend. React er et populært JavaScript-bibliotek for å bygge apper på en side. Den hjelper oss å dekomponere et komplekst brukergrensesnitt i hierarkiske komponenter med valgfri tilstand og enveis databinding.

React analyserer dette hierarkiet og skaper en datastruktur i minnet som kalles virtuell DOM. Dette hjelper Reage med å finne endringer mellom forskjellige tilstander og gjøre minimale endringer i nettleserens DOM.

6.1. Reager komponent

La oss lage vår første React-komponent:

var App = React.createClass ({displayName: "App", handleSubmit: function () {var last = this.state.data [this.state.data.length-1]; var secondLast = this.state.data [this .state.data.length-2]; $ .ajax ({url: '/ next /' + last + '/' + secondLast, dataType: 'text', success: function (msg) {var series = this.state. data; series.push (msg); this.setState ({data: series});} .bind (this), error: function (xhr, status, err) {console.error ('/ next', status, err .toString ());} .bind (this)});}, componentDidMount: function () {this.setState ({data: this.props.data});}, getInitialState: function () {return {data: []};}, gjengi: funksjon () {return (React.createElement ("div", {className: "app"}, React.createElement ("h2", null, "Fibonacci Generator"), React.createElement ( "h2", null, this.state.data.toString ()), React.createElement ("input", {type: "submit", verdi: "Next", onClick: this.handleSubmit})));}} );

La oss nå forstå hva kodene ovenfor gjør:

  • Til å begynne med har vi definert en klassekomponent i React kalt "App"
  • Det meste viktig funksjon inne i denne komponenten er "gjengi", som er ansvarlig for å generere brukergrensesnittet
  • Vi har gitt en stil klassenavn som komponenten kan bruke
  • Vi bruker komponenttilstanden her for å lagre og vise serien
  • Mens staten initialiseres som en tom liste, henter den data som sendes til komponenten som en rekvisitt når komponenten monteres
  • Til slutt, ved å klikke på knappen "Legg til", foretas et jQuery-anrop til REST-tjenesten
  • Anropet henter neste nummer i sekvensen og legger det til komponentens tilstand
  • Endring i komponentens tilstand gjengir komponenten automatisk

6.2. Bruke React Component

React ser etter et navngitt “div” -element på HTML-siden for å forankre innholdet. Alt vi trenger å gjøre er å tilby en HTML-side med dette "div" -elementet og laste inn JS-filene:

   Hei Reager ReactDOM.render (React.createElement (App, {data: [0,1,1]}), document.getElementById ("root")); 

Så la oss se hva vi har gjort her:

  • Vi importerte de nødvendige JS-bibliotekene, react, react-dom og jQuery
  • Etter det definerte vi et “div” -element kalt “root”
  • Vi importerte også JS-filen med React-komponenten
  • Deretter kalte vi React-komponenten "App" med noen frødata, de tre første Fibonacci-tallene

7. Søknadsbakside

La oss nå se hvordan vi kan lage en passende back-end for applikasjonen vår. Det har vi allerede bestemt oss for bruk Spring Boot sammen med Spring Web for å bygge denne applikasjonen. Enda viktigere, vi har bestemt oss for bruk Nashorn til å behandle JavaScript-basert front-end vi utviklet i den siste delen.

7.1. Maven avhengigheter

For vår enkle applikasjon bruker vi JSP sammen med Spring MVC, så vi legger til et par avhengigheter i POM:

 org.springframework.boot spring-boot-starter-web org.apache.tomcat.embed tomcat-embed-jasper provided 

Den første er den standard avhengighetsavhengigheten for en webapplikasjon. Den andre er nødvendig for å kompilere JSPer.

7.2. Webkontroller

La oss nå lage vår webkontroller, som vil behandle JavaScript-filen vår og returnere en HTML ved hjelp av JSP:

@Controller offentlig klasse MyWebController {@RequestMapping ("/") offentlig strengindeks (kartmodell) kaster unntak {ScriptEngine nashorn = ny ScriptEngineManager (). GetEngineByName ("nashorn"); nashorn.eval (ny FileReader ("static / js / react.js")); nashorn.eval (ny FileReader ("static / js / react-dom-server.js")); nashorn.eval (ny FileReader ("statisk / app.js")); Objekt html = nashorn.eval ("ReactDOMServer.renderToString (" + "React.createElement (App, {data: [0,1,1]})" + ");"); model.put ("content", String.valueOf (html)); returner "indeks"; }}

Så hva skjer akkurat her:

  • Vi henter en forekomst av ScriptEngine av typen Nashorn fra ScriptEngineManager
  • Da vi laste relevante biblioteker til React, react.js og react-dom-server.js
  • Vi laster også inn vår JS-fil som har vår reaksjonskomponent "App"
  • Til slutt vurderer vi et JS-fragment som skaper reaksjonselement med komponenten "App" og noen frødata
  • Dette gir oss utdata fra React, et HTML-fragment som Gjenstand
  • Vi sender dette HTML-fragmentet som data til den aktuelle visningen - JSP

7.3. JSP

Nå, hvordan behandler vi dette HTML-fragmentet i vår JSP?

Husk at React automatisk legger til utdataene til et navngitt “div” -element - “root” i vårt tilfelle. Derimot, Vi legger til det server-genererte HTML-fragmentet til det samme elementet manuelt i vår JSP.

La oss se hvordan JSP ser ut nå:

   Hei Reager! $ {content} ReactDOM.render (React.createElement (App, {data: [0,1,1]}), document.getElementById ("root")); 

Dette er den samme siden vi opprettet tidligere, bortsett fra det faktum at vi har lagt til HTML-fragmentet vårt i "root" div, som var tom tidligere.

7.4. REST-kontroller

Til slutt trenger vi også et REST-endepunkt på serversiden som gir oss neste Fibonacci-nummer i sekvensen:

@RestController public class MyRestController {@RequestMapping ("/ next / {last} / {secondLast}") public int index (@PathVariable ("last") int last, @PathVariable ("secondLast") int secondLast) kaster Unntak {retur siste + sekundSiste; }}

Ikke noe fancy her, bare en enkel Spring REST-kontroller.

8. Kjøre applikasjonen

Nå som vi har fullført vår front-end så vel som back-end, er det på tide å kjøre applikasjonen.

Vi bør starte Spring Boot-applikasjonen normalt, ved å bruke bootstrapping-klassen:

@SpringBootApplication public class Application utvider SpringBootServletInitializer {@Override-beskyttet SpringApplicationBuilder-konfigurasjon (SpringApplicationBuilder-applikasjon) {return application.sources (Application.class); } offentlig statisk ugyldig hoved (String [] args) kaster Unntak {SpringApplication.run (Application.class, args); }}

Når vi kjører denne klassen, Spring Boot kompilerer JSP-ene våre og gjør dem tilgjengelige på innebygde Tomcat sammen med resten av webapplikasjonen.

Nå, hvis vi besøker nettstedet vårt, ser vi:

La oss forstå hendelsesforløpet:

  • Nettleseren ber om denne siden
  • Når forespørselen om denne siden kommer, behandler Spring webcontroller JS-filene
  • Nashorn-motoren genererer et HTML-fragment og overfører dette til JSP
  • JSP legger til dette HTML-fragmentet i "root" div-elementet, og til slutt returnerer HTML-siden ovenfor
  • Nettleseren gjengir HTML, og i mellomtiden begynner å laste ned JS-filer
  • Til slutt er siden klar for handlinger på klientsiden - vi kan legge til flere tall i serien

Det viktige å forstå her er hva som skjer hvis React finner et HTML-fragment i "div" -elementet. I slike tilfeller, React sammenligner dette fragmentet med det det har og erstatter det ikke hvis det finner et lesbart fragment. Dette er nøyaktig hva som driver server-gjengivelse og isomorfe apper.

9. Hva mer er mulig?

I vårt enkle eksempel har vi nettopp riper på overflaten av hva som er mulig. Frontend-applikasjoner med moderne JS-baserte rammer blir stadig kraftigere og mer komplekse. Med denne ekstra kompleksiteten er det mange ting vi trenger å ta vare på:

  • Vi har opprettet bare en React-komponent i applikasjonen vår når dette i virkeligheten kan være flere komponenter som danner et hierarki som sender data gjennom rekvisitter
  • Vi vil gjerne lage separate JS-filer for hver komponent for å holde dem håndterbare og administrere sine avhengigheter gjennom "eksport / krever" eller "eksport / import"
  • Videre er det kanskje ikke mulig å administrere tilstanden bare i komponenter; kan det være lurt å bruke et statsforvaltningsbibliotek som Redux
  • Videre kan det hende at vi må samhandle med eksterne tjenester som bivirkninger av handlinger; dette kan kreve at vi bruker et mønster som redux-thunk eller Redux-Saga
  • Viktigst, vi vil ønske det utnytte JSX, en syntaksutvidelse til JS for å beskrive brukergrensesnittet

Selv om Nashorn er fullt kompatibel med ren JS, støtter den kanskje ikke alle funksjonene som er nevnt ovenfor. Mange av disse krever transkompilering og polyfills på grunn av JS-kompatibilitet.

Vanlig praksis i slike tilfeller er å utnytte en modulbundler som Webpack eller Rollup. Det de hovedsakelig gjør er å behandle alle React-kildefiler og pakke dem sammen i en enkelt JS-fil sammen med alle avhengigheter. Dette krever alltid en moderne JavaScript-kompilator som Babel for å kompilere JavaScript for å være bakoverkompatibel.

Den siste pakken har bare gode gamle JS, som nettlesere kan forstå og Nashorn følger også.

10. Fordeler med en isomorf app

Så vi har snakket mye om isomorfe apper og har til og med laget en enkel applikasjon nå. Men hvorfor skulle vi til og med bry oss om dette? La oss forstå noen av de viktigste fordelene ved å bruke en isomorf app.

10.1. Gjengivelse av første side

En av de viktigste fordelene med en isomorf app er raskere gjengivelse av første side. I det typiske gjengitte applikasjonen på klientsiden begynner nettleseren med å laste ned alle JS- og CSS-gjenstandene.

Etter det laster de inn og begynner å gjengi den første siden. Hvis vi sender den første siden som er gjengitt fra serversiden, kan dette være mye raskere, noe som gir en forbedret brukeropplevelse.

10.2. SEO vennlig

En annen fordel ofte sitert med gjengivelse på serversiden er relatert til SEO. Det antas at søkeroboter ikke er i stand til å behandle JavaScript og dermed ikke ser en indeksside gjengitt på klientsiden gjennom biblioteker som React. En gjengitt side på serversiden er derfor SEO-vennligere. Det er imidlertid verdt å merke seg at moderne søkemotorbots hevder å behandle JavaScript.

11. Konklusjon

I denne opplæringen gikk vi gjennom de grunnleggende konseptene for isomorfe applikasjoner og Nashorn JavaScript-motoren. Vi utforsket videre hvordan du bygger en isomorf app med Spring Boot, React og Nashorn.

Deretter diskuterte vi de andre mulighetene for å utvide front-end-applikasjonen og fordelene ved å bruke en isomorf app.

Som alltid kan koden bli funnet på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found