Crearea aplicațiilor Vue.js redate pe server folosind Nuxt.js
Publicat: 2022-03-11Cadrele/bibliotecile JavaScript, cum ar fi Vue, pot oferi o experiență de utilizator fantastică atunci când vă navigați pe site. Majoritatea oferă o modalitate de a schimba dinamic conținutul paginii fără a fi nevoie să trimiteți o solicitare la server de fiecare dată.
Cu toate acestea, există o problemă cu această abordare. Când încărcați inițial site-ul dvs. web, browserul dvs. nu primește o pagină completă de afișat. În schimb, este trimisă o grămadă de piese pentru a construi pagina (HTML, CSS, alte fișiere) și instrucțiuni despre cum să le asociezi pe toate (un cadru/o bibliotecă JavaScript). Este nevoie de o perioadă măsurabilă de timp pentru a pune împreună toate aceste informații. înainte ca browserul tău să aibă de fapt ceva de afișat. Este ca și cum ai fi trimis o grămadă de cărți împreună cu o bibliotecă cu pachet plat. Mai întâi ar trebui să construiești bibliotecă și apoi să o umpli cu cărțile.
Soluția este inteligentă: aveți o versiune a cadrului/bibliotecii pe server care poate construi o pagină gata de afișat. Apoi trimiteți această pagină completă la browser împreună cu posibilitatea de a face modificări ulterioare și de a avea în continuare conținut dinamic al paginii (cadru/biblioteca), la fel ca și cum vi se trimite o bibliotecă gata făcută împreună cu unele cărți. Sigur, mai trebuie să pui cărțile în bibliotecă, dar ai ceva utilizabil imediat.
Dincolo de analogia stupidă, există și o grămadă de alte avantaje. De exemplu, o pagină care se modifică rar, cum ar fi pagina Despre noi, nu trebuie să fie recreată de fiecare dată când un utilizator o solicită. Deci, un server îl poate crea o dată și apoi îl poate stoca în cache sau îl poate stoca undeva pentru utilizare ulterioară. Aceste tipuri de îmbunătățiri ale vitezei pot părea mici, dar într-un mediu în care timpul până la receptivitatea este măsurat în milisecunde (sau mai puțin), fiecare mic contează.
Dacă doriți mai multe informații despre avantajele SSR într-un mediu Vue, ar trebui să consultați articolul lui Vue despre SSR. Există o varietate de opțiuni pentru a obține aceste rezultate, dar cea mai populară, care este recomandată și de echipa Vue, este Nuxt.
De ce Nuxt.js
Nuxt.js se bazează pe o implementare a SSR pentru populara bibliotecă React numită Next. După ce am văzut avantajele acestui design, a fost proiectată o implementare similară pentru Vue numită Nuxt. Cei familiarizați cu combinația React+Next vor observa o mulțime de asemănări în designul și aspectul aplicației. Cu toate acestea, Nuxt oferă caracteristici specifice Vue pentru a crea o soluție SSR puternică, dar flexibilă pentru Vue.
Nuxt a fost actualizat la o versiune 1.0 pregătită pentru producție în ianuarie 2018 și face parte dintr-o comunitate activă și bine susținută. Unul dintre lucrurile grozave este că construirea unui proiect folosind Nuxt nu este atât de diferită de construirea oricărui alt proiect Vue. De fapt, oferă o mulțime de caracteristici care vă permit să creați baze de cod bine structurate într-un timp redus.
Un alt lucru important de remarcat este că Nuxt nu trebuie să fie utilizat pentru SSR . Este promovat ca un cadru pentru crearea aplicațiilor Vue.js universale și include o comandă ( nuxt generate
) pentru crearea aplicațiilor Vue generate statice folosind aceeași bază de cod. Deci, dacă vă temeți să vă scufundați adânc în SSR, nu vă panicați. Puteți crea oricând un site static, profitând în continuare de funcțiile Nuxt.
Pentru a înțelege potențialul Nuxt, să creăm un proiect simplu. Codul sursă final pentru acest proiect este găzduit pe GitHub dacă doriți să-l vedeți sau puteți vizualiza o versiune live creată folosind nuxt generate
și găzduită pe Netlify.
Crearea unui proiect Nuxt
Pentru a începe, să folosim un generator de proiecte Vue numit vue-cli
pentru a crea rapid un exemplu de proiect:
# install vue-cli globally npm install -g vue-cli # create a project using a nuxt template vue init nuxt-community/starter-template my-nuxt-project
După ce parcurgeți câteva opțiuni, aceasta va crea un proiect în folderul my-nuxt-project
sau orice ați specificat. Apoi trebuie doar să instalăm dependențe și să rulăm serverul:
cd my-nuxt-project npm install # Or yarn npm run dev
Iată-ne. Deschideți browserul la localhost:3000
și proiectul dvs. ar trebui să ruleze. Nu este foarte diferit de crearea unui proiect Vue Webpack. Cu toate acestea, când ne uităm la structura reală a aplicației, nu există prea multe, mai ales în comparație cu ceva de genul șablonului Vue Webpack.
Privind în pachetul.json, de asemenea, arată că avem o singură dependență, package.json
însuși. Acest lucru se datorează faptului că fiecare versiune de Nuxt este adaptată pentru a funcționa cu versiuni specifice de Vue, Vue-router și Vuex și le grupează pe toate pentru tine.
Există, de asemenea, un fișier nuxt.config.js
la rădăcina proiectului. Acest lucru vă permite să personalizați o mulțime de funcții pe care le oferă Nuxt. În mod implicit, setează etichetele antetului, culoarea barei de încărcare și regulile ESLint pentru dvs. Dacă ești nerăbdător să vezi ce poți configura, iată documentația; vom acoperi câteva opțiuni în acest articol.
Deci, ce este atât de special la acele directoare?
Aspectul proiectului
Dacă răsfoiți directoarele create, toate au însoțitor un Readme care indică un scurt rezumat al acelui director și adesea un link către documente.
Acesta este unul dintre beneficiile utilizării Nuxt: o structură implicită pentru aplicația dvs. Orice dezvoltator front-end bun va structura o aplicație asemănătoare cu aceasta, dar există multe idei diferite despre structuri, iar atunci când lucrați în echipă, inevitabil va trece ceva timp pentru a discuta sau alege această structură. Nuxt vă oferă unul.
Nuxt va căuta anumite directoare și va construi aplicația dvs. în funcție de ceea ce găsește. Să examinăm aceste directoare unul câte unul.
Pagini
Acesta este singurul director necesar . Orice componente Vue din acest director sunt adăugate automat la vue-router
pe baza numelor lor de fișiere și a structurii directoarelor. Acest lucru este extrem de convenabil. În mod normal, aș avea oricum un director Pagini separat și trebuie să înregistrez manual fiecare dintre aceste componente într-un alt fișier de router. Acest fișier de router poate deveni complex pentru proiecte mai mari și poate necesita împărțire pentru a menține lizibilitatea. În schimb, Nuxt se va ocupa de toată această logică pentru tine.
Pentru a demonstra, putem crea o componentă Vue numită about.vue
în directorul Pages. Să adăugăm doar un șablon simplu, cum ar fi:
<template> <h1>About Page</h1> </template>
Când salvați, Nuxt va genera din nou rutele pentru dvs. Având în vedere cum am numit componenta noastră about.vue
, dacă navigați la /about
, ar trebui să vedeți acea componentă. Simplu.
Există un nume de fișier care este special. Numirea unui fișier index.vue
va crea o rută rădăcină pentru acel director. Când proiectul este generat, există deja o componentă index.vue
în directorul de pagini care se corelează cu pagina de pornire sau pagina de destinație a site-ului dvs. (În exemplul de dezvoltare, acesta ar fi pur și simplu localhost:3000
.)
Dar rutele mai adânci? Subdirectoarele din directorul Pagini vă ajută să vă structurați rutele. Deci, dacă am dori o pagină Vizualizare produs, am putea structura directorul nostru Pagini cam așa:
/pages --| /products ----| index.vue ----| view.vue
Acum, dacă navigăm la /products/view
, vom vedea componenta view.vue
în directorul de produse. Dacă navigăm în schimb la /products
, vom vedea componenta index.vue
în directorul de produse.
S-ar putea să vă întrebați de ce nu am creat doar o componentă products.vue
în directorul de pagini, așa cum am făcut pentru pagina /about
. Puteți crede că rezultatul ar fi același, dar există o diferență între cele două structuri. Să demonstrăm acest lucru adăugând o altă pagină nouă.
Să presupunem că am vrut o pagină Despre separată pentru fiecare angajat. De exemplu, să creăm o pagină Despre pentru mine. Ar trebui să fie localizat la /about/ben-jones
. Inițial, putem încerca să structurem directorul Pagini astfel:
/pages --| about.vue --| /about ----| ben-jones.vue
Când încercăm să accesăm /about/ben-jones
, obținem în schimb componenta about.vue
, la fel ca /about
. Ce se petrece aici?
Interesant, ceea ce face Nuxt aici este să genereze o rută imbricată . Această structură sugerează că doriți o rută permanentă /about
și orice în interiorul acelui traseu ar trebui să fie imbricat în propria zonă de vizualizare. În vue-router, acest lucru ar fi indicat prin specificarea unei componente <router-view />
în interiorul componentei about.vue
. În Nuxt, acesta este același concept, cu excepția faptului că, în loc de <router-view />
, pur și simplu folosim <nuxt />
. Deci, să actualizăm componenta noastră about.vue
pentru a permite rute imbricate:
<template> <div> <h1>About Page</h1> <nuxt /> </div> </template>
Acum, când navigăm la /about
, obținem componenta about.vue
pe care o aveam înainte, doar cu un titlu. Cu toate acestea, când navigăm la /about/ben-jones
, avem în schimb titlul și componenta ben-jones.vue
redate acolo unde era substituentul <nuxt/>
.
Nu asta ne doream inițial, dar ideea de a avea o pagină Despre cu o listă de oameni care, atunci când se dă clic, umple o secțiune din pagină cu informațiile lor este un concept interesant, așa că haideți să o lăsăm așa cum este deocamdată . Dacă ați dorit cealaltă opțiune, atunci tot ce am face este să ne restructuram directoarele. Ar trebui doar să mutăm componenta about.vue
în directorul /about
și să o redenumim index.vue
, astfel încât structura rezultată ar fi:
/pages --| /about ----| index.vue ----| ben-jones.vue
În cele din urmă, să presupunem că am vrut să folosim parametrii de rută pentru a prelua un anumit produs. De exemplu, dorim să putem edita un produs navigând la /products/edit/64
unde 64 este product_id
. Putem face acest lucru în felul următor:
/pages --| /products ----| /edit ------| _product_id.vue
Rețineți liniuța de subliniere de la începutul componentei _product_id.vue
— aceasta înseamnă un parametru de rută care este apoi accesibil pe obiectul $route.params
sau pe obiectul params
din Contextul lui Nuxt (mai multe despre asta mai târziu). Rețineți că cheia parametrului va fi numele componentei fără caracterul de subliniere inițial - în acest caz, product_id
- așa că încercați să le păstrați unice în cadrul proiectului. Drept urmare, în _product_id.vue
, este posibil să avem ceva de genul:
<template> <h1>Editing Product {{ $route.params.product_id }}</h1> </template>
Puteți începe să vă imaginați machete mai complexe, care ar fi dificil de configurat folosind vue-router. De exemplu, putem combina toate cele de mai sus într-un traseu cum ar fi:
/pages --| /categories ----| /_category_id ------| products.vue ------| /products --------| _product_id.vue
Nu este prea greu să raționezi ce ar afișa /categories/2/products/3
. Am avea componenta products.vue
cu o componentă imbricată _product_id.vue
, cu doi parametri de rută: category_id
și product_id
. Este mult mai simplu de motivat decât o configurare echivalentă a routerului.
În timp ce suntem la subiect, un lucru pe care tind să-l fac în configurația routerului este configurarea pazilor routerului. Deoarece Nuxt construiește routerul pentru noi, acest lucru se poate face în schimb pe componenta însăși cu beforeRouteEnter
. Dacă doriți să validați parametrii rutei, Nuxt oferă o metodă de componentă numită validate
. Deci, dacă doriți să verificați dacă product_id
a fost un număr înainte de a încerca să randați componenta, ați adăuga următoarele la eticheta de script a _product_id.vue
:
export default { validate ({ params }) { // Must be a number return /^\d+$/.test(params.product_id) } }
Acum, navigarea la /categories/2/products/someproduct
are ca rezultat un 404, deoarece someproduct
nu este un număr valid.
Asta este pentru directorul Pagini. Este esențial să înveți cum să-ți structurezi rutele corect în acest director, așa că la început este important să petreci puțin timp pentru a profita la maximum de Nuxt. Dacă căutați o scurtă prezentare generală, este întotdeauna util să consultați documentele pentru rutare.
Dacă vă faceți griji că nu aveți controlul asupra routerului, nu fiți. Această configurare implicită funcționează excelent pentru o mare varietate de proiecte, cu condiția ca acestea să fie bine structurate. Cu toate acestea, există unele cazuri în care poate fi necesar să adăugați mai multe rute la router decât le generează automat Nuxt sau să le restructurați. Nuxt oferă o modalitate de a personaliza instanța routerului în configurație, permițându-vă să adăugați rute noi și să personalizați rutele generate. De asemenea, puteți edita funcționalitatea de bază a instanței routerului, inclusiv opțiunile suplimentare adăugate de Nuxt. Deci, dacă întâmpinați un caz marginal, aveți în continuare flexibilitatea de a găsi soluția potrivită.
Magazin
Nuxt vă poate construi magazinul Vuex pe baza structurii directorului magazinului, similar cu directorul Pages. Dacă nu aveți nevoie de un magazin, eliminați directorul. Există două moduri pentru magazin, Clasic și Module.
Classic necesită să aveți un fișier index.js
în directorul magazinului. Acolo trebuie să exportați o funcție care returnează o instanță Vuex:
import Vuex from 'vuex' const createStore = () => { return new Vuex.Store({ state: ..., mutations: ..., actions: ... }) } export default createStore
Acest lucru vă permite să creați magazinul așa cum doriți, la fel ca folosind Vuex într-un proiect Vue normal.
Modul module necesită , de asemenea, să creați un fișier index.js
în directorul magazinului. Cu toate acestea, acest fișier trebuie doar să exporte starea rădăcină/mutațiile/acțiunile pentru magazinul dumneavoastră Vuex. Exemplul de mai jos specifică o stare rădăcină goală:
export const state = () => ({})
Apoi, fiecare fișier din directorul magazinului va fi adăugat magazinului în propriul spațiu de nume sau modul. De exemplu, să creăm un loc unde să stocăm produsul curent. Dacă creăm un fișier numit product.js
în directorul magazinului, atunci o secțiune cu spațiu de nume a magazinului va fi disponibilă la $store.product
. Iată un exemplu simplu despre cum poate arăta acel fișier:
export const state = () => ({ _id: 0, title: 'Unknown', price: 0 }) export const actions = { load ({ commit }) { setTimeout( commit, 1000, 'update', { _id: 1, title: 'Product', price: 99.99 } ) } } export const mutations = { update (state, product) { Object.assign(state, product) } }
setTimeout
din acțiunea de încărcare simulează un fel de apel API, care va actualiza magazinul cu răspunsul; în acest caz, durează o secundă. Acum, să-l folosim în pagina de products/view
:
<template> <div> <h1>View Product {{ product._id }}</h1> <p>{{ product.title }}</p> <p>Price: {{ product.price }}</p> </div> </template> <script> import { mapState } from 'vuex' export default { created () { this.$store.dispatch('product/load') }, computed: { ...mapState(['product']) } } </script>
Câteva lucruri de reținut: aici, numim API-ul nostru fals atunci când componenta este creată. Puteți vedea că acțiunea de product/load
pe care o trimitem este spațiată de nume sub Produs. Acest lucru face clar exact cu ce secțiune a magazinului avem de-a face. Apoi, prin maparea statului la o proprietate calculată locală, o putem folosi cu ușurință în șablonul nostru.
Există o problemă: vedem starea originală pentru o secundă în timp ce API-ul rulează. Mai târziu, vom folosi o soluție oferită de Nuxt pentru a remedia acest lucru (cunoscută sub numele de fetch
).
Doar pentru a sublinia acest lucru din nou, nu a trebuit niciodată să npm install vuex
, deoarece este deja inclus în pachetul Nuxt. Când adăugați un fișier index.js
în directorul magazinului, toate aceste metode sunt apoi deschise automat .
Acestea sunt principalele două directoare explicate; restul sunt mult mai simple.
Componente
Directorul Componente este acolo pentru a conține componentele dvs. reutilizabile, cum ar fi o bară de navigare, galerie de imagini, paginare, tabele de date etc. Având în vedere că componentele din directorul Pagini sunt convertite în rute, aveți nevoie în altă parte pentru a stoca aceste tipuri de componente. Aceste componente sunt accesibile în pagini sau alte componente prin importul lor:
import ComponentName from ~/components/ComponentName.vue
Active
Acesta conține active necompilate și are mai mult de-a face cu modul în care Webpack încarcă și procesează fișierele, mai degrabă decât cu modul în care funcționează Nuxt. Dacă sunteți interesat, vă sugerez să citiți ghidul din Readme.
Static
Acesta conține fișiere statice care sunt mapate în directorul rădăcină al site-ului dvs. De exemplu, plasarea unei imagini numite logo.png în acest director ar face-o disponibilă la /logo.png
. Acest lucru este bun pentru meta fișiere precum robots.txt, favicon.ico și alte fișiere de care aveți nevoie disponibile.
Aspecte
În mod normal, într-un proiect Vue, aveți un fel de componentă rădăcină, numită în mod normal App.vue
. Aici vă puteți configura aspectul aplicației (în mod normal static), care poate include o bară de navigare, un subsol și apoi o zonă de conținut pentru route-routerul dvs. Aspectul default
face exact acest lucru și vă este furnizat în folderul layout-uri. Inițial, tot ce are este un div cu o componentă <nuxt />
(care este echivalentă cu <router-view />
), dar poate fi stilat după cum doriți. De exemplu, am adăugat o bară de navigare simplă la proiectul exemplu pentru navigarea în diferitele pagini demonstrative.

Poate doriți să aveți un aspect diferit pentru o anumită secțiune a aplicației dvs. Poate aveți un fel de CMS sau panou de administrare care arată diferit. Pentru a rezolva acest lucru, creați un nou aspect în directorul Layouts. De exemplu, să creăm un aspect admin-layout.vue
care are doar o etichetă de antet suplimentară și fără bară de navigare:
<template> <div> <h1>Admin Layout</h1> <nuxt /> </div> </template>
Apoi, putem crea o pagină admin.vue
în directorul Pagini și folosim o proprietate oferită de Nuxt numită layout
pentru a specifica numele (sub formă de șir) aspectului pe care vrem să-l folosim pentru acea componentă:
<template> <h1>Admin Page</h1> </template> <script> export default { layout: 'admin-layout' } </script>
Cam despre asta e. Componentele paginii vor folosi aspectul default
dacă nu este specificat, dar când navigați la /admin
, acum folosește aspectul admin-layout.vue
. Desigur, acest aspect poate fi partajat pe mai multe ecrane de administrare, dacă doriți. Singurul lucru important de reținut este că layout-urile trebuie să conțină un element <nuxt />
.
Există un ultim lucru de remarcat despre machete. Este posibil să fi observat în timp ce experimentați că, dacă introduceți o adresă URL nevalidă, vi se afișează o pagină de eroare. Această pagină de eroare este, de fapt, un alt aspect. Nuxt are propriul aspect de eroare (codul sursă aici), dar dacă doriți să îl editați, creați un aspect error.vue
și acesta va fi folosit în schimb. Avertismentul aici este că aspectul de eroare nu trebuie să aibă un element <nuxt />
. De asemenea, veți avea acces la un obiect de error
de pe componentă cu câteva informații de bază de afișat. (Acesta este tipărit în terminalul care rulează Nuxt dacă doriți să îl examinați.)
Middleware
Middleware-urile sunt funcții care pot fi executate înainte de randarea unei pagini sau a unui aspect. Există o varietate de motive pentru care ați putea dori să faceți acest lucru. Protejarea rutei este o utilizare populară în care puteți verifica magazinul Vuex pentru o autentificare validă sau să validați niște parametri (în loc să utilizați metoda de validate
pe componenta în sine). Un proiect la care am lucrat middleware folosit recent pentru a genera breadcrumb dinamice bazate pe traseu și parametri.
Aceste funcții pot fi asincrone; Fiți atenți, deoarece nimic nu va fi afișat utilizatorului până când middleware-ul este rezolvat. Au acces și la Contextul lui Nuxt, pe care îl voi explica mai târziu.
Pluginuri
Acest director vă permite să înregistrați pluginurile Vue înainte ca aplicația să fie creată. Acest lucru permite ca pluginul să fie partajat în întreaga aplicație pe instanța Vue și să fie accesibil în orice componentă.
Majoritatea pluginurilor majore au o versiune Nuxt care poate fi înregistrată cu ușurință în instanța Vue, urmărind documentele lor. Cu toate acestea, vor exista circumstanțe în care veți dezvolta un plugin sau trebuie să adaptați un plugin existent în acest scop. Un exemplu pe care îl împrumut din documente arată cum se face acest lucru pentru vue-notifications
. Mai întâi, trebuie să instalăm pachetul:
npm install vue-notifications --save
Apoi creați un fișier în directorul de pluginuri numit vue-notifications.js
și includeți următoarele:
import Vue from 'vue' import VueNotifications from 'vue-notifications' Vue.use(VueNotifications)
Foarte similar cu modul în care ați înregistra un plugin într-un mediu Vue normal. Apoi editați fișierul nuxt.config.js
la rădăcina proiectului și adăugați următoarea intrare la obiectul module.exports:
plugins: ['~/plugins/vue-notifications']
Asta e. Acum puteți utiliza vue-notifications
în aplicația dvs. Un exemplu în acest sens este la /plugin
în proiectul exemplu.
Deci, aceasta completează o descriere a structurii directoarelor. Poate părea mult de învățat, dar dacă dezvoltați o aplicație Vue, configurați deja același tip de logică. Nuxt ajută la abstracția configurației și vă ajută să vă concentrați pe construcție.
Nuxt face mai mult decât să ajute la dezvoltare. Îți supraalimentează componentele oferind funcționalitate suplimentară.
Componentele supraalimentate ale Nuxt
Când am început să cercetez Nuxt, am continuat să citesc despre modul în care componentele Page sunt supraalimentate . Suna grozav, dar nu a fost imediat evident ce înseamnă exact asta și ce beneficii aduce.
Ceea ce înseamnă este că toate componentele Page au metode suplimentare atașate pe care Nuxt le poate folosi pentru a oferi funcționalități suplimentare. De fapt, am văzut deja una dintre acestea mai devreme când am folosit metoda de validate
pentru a verifica parametrii și a redirecționa un utilizator dacă nu sunt validi.
Cele două principale utilizate într-un proiect Nuxt vor fi metodele asyncData
și fetch
. Ambele sunt foarte asemănătoare ca concept, sunt rulate asincron înainte ca componenta să fie generată și pot fi folosite pentru a popula datele unei componente și ale magazinului. Ele permit, de asemenea, redarea completă a paginii pe server înainte de a o trimite către client, chiar și atunci când trebuie să așteptăm o bază de date sau un apel API.
Care este diferența dintre asyncData
și fetch
?
-
asyncData
este folosit pentru a popula datele componentei Page. Când returnați un obiect, acesta este apoi îmbinat cudata
de ieșire înainte de randare. -
fetch
este folosit pentru a popula Magazinul Vuex. Dacă returnați o promisiune, Nuxt va aștepta până când aceasta va fi rezolvată înainte de redare.
Așa că haideți să le folosim bine. Vă amintiți, mai devreme, pe pagina /products/view
, am avut o problemă în care starea inițială a magazinului era afișată pentru scurt timp în timp ce a fost efectuat apelul nostru API fals? O modalitate de a remedia acest lucru este să aveți un boolean stocat pe componentă sau în Magazin, cum ar fi loading = true
și apoi afișarea unei componente de încărcare în timp ce apelul API se termină. După aceea, am seta loading = false
și am afișa datele.
În schimb, să folosim fetch
pentru a popula Magazinul înainte de randare. Într-o pagină nouă numită /products/view-async
, să schimbăm metoda created
pentru a fetch
; asta ar trebui sa mearga, nu?
export default { fetch () { // Unfortunately the below line throws an error // because 'this.$store' is undefined... this.$store.dispatch('product/load') }, computed: {...} }
Iată problema: aceste metode „supraalimentate” rulează înainte ca componenta să fie creată, astfel încât this
nu indică componenta și nimic din ea nu poate fi accesat. Deci, cum accesăm Magazinul aici?
API-ul Context
Desigur, există o soluție. Pe toate metodele lui Nuxt, vi se oferă un argument (în mod normal primul) care conține un obiect extrem de util numit Context. În aceasta este tot ce veți avea nevoie de referință în aplicație, ceea ce înseamnă că nu trebuie să așteptăm ca Vue să creeze mai întâi acele referințe pe componentă.
Aș recomanda cu căldură să consultați documentele Context pentru a vedea ce este disponibil. Unele la îndemână sunt app
, unde puteți accesa toate pluginurile, redirect
, care poate fi folosită pentru a schimba rutele, error
pentru a afișa pagina de eroare și unele care se explică de la sine, cum ar fi route
, query
și store
.
Deci, pentru a accesa Magazinul, putem destructura Contextul și extrage Magazinul din acesta. De asemenea, trebuie să ne asigurăm că returnăm o promisiune, astfel încât Nuxt să poată aștepta ca aceasta să se rezolve înainte de a reda componenta, așa că trebuie să facem și o mică ajustare acțiunii noastre din Magazin.
// Component export default { fetch ({ store }) { return store.dispatch('product/load') }, computed: {...} } // Store Action load ({ commit }) { return new Promise(resolve => { setTimeout(() => { commit('update', { _id: 1, title: 'Product', price: 99.99 }) resolve() }, 1000) }) }
Puteți utiliza metode asincrone/așteptare sau alte metode în funcție de stilul dvs. de codare, dar conceptul este același - îi spunem lui Nuxt să se asigure că apelul API se termină și că Magazinul este actualizat cu rezultatul înainte de a încerca randarea componentei. Dacă încercați să navigați la /products/view-async
, nu veți vedea fulgerul conținutului în care produsul se află în starea sa inițială.
Vă puteți imagina cât de util poate fi acest lucru în orice aplicație Vue, chiar și fără SSR. Contextul este, de asemenea, disponibil pentru toate middleware- urile, precum și pentru alte metode Nuxt, cum ar fi NuxtServerInit
, care este o acțiune specială a magazinului care rulează înainte ca Magazinul să fie inițializat (un exemplu în acest sens este în secțiunea următoare)
Considerații la utilizarea SSR
Sunt sigur că mulți (inclusiv eu) care încep să folosească o tehnologie precum Nuxt în timp ce o tratează ca orice alt proiect Vue, în cele din urmă, se lovesc de un perete unde ceva ce știm că ar funcționa în mod normal pare imposibil în Nuxt. Pe măsură ce mai multe dintre aceste avertismente sunt documentate, va fi mai ușor de depășit, dar principalul lucru de luat în considerare atunci când începeți depanarea este că clientul și serverul sunt două entități separate.
Când accesați o pagină inițial, o solicitare este trimisă către Nuxt, serverul construiește cât mai mult posibil din pagina respectivă și din restul aplicației, apoi serverul vi le trimite. Apoi, responsabilitatea revine clientului de a continua navigarea și de a încărca bucăți după cum are nevoie de ele.
Vrem ca serverul să facă cât mai mult posibil mai întâi, dar uneori nu are acces la informațiile de care are nevoie, ceea ce are ca rezultat ca munca să fie efectuată în schimb la nivelul clientului. Sau mai rău, atunci când conținutul final prezentat de client este diferit de ceea ce se aștepta serverul, clientului i se spune să-l reconstruiască de la zero. Acesta este un mare indiciu că ceva nu este în regulă cu logica aplicației. Din fericire, o eroare va fi generată în consola browserului dvs. (în modul de dezvoltare) dacă acest lucru începe să se întâmple.
Să luăm un exemplu despre cum să rezolvăm o problemă comună, gestionarea sesiunii. Imaginați-vă că aveți o aplicație Vue în care vă puteți conecta la un cont și sesiunea dvs. este stocată folosind un simbol (JWT, de exemplu) pe care decideți să îl păstrați în localStorage
. Când accesați inițial site-ul, doriți să autentificați acel token cu un API, care returnează câteva informații de bază despre utilizator dacă sunt valide și pune acele informații în Magazin.
După ce ați citit documentele Nuxt, vedeți că există o metodă la îndemână numită NuxtServerInit
, care vă permite să populați asincron Magazinul o dată la încărcarea inițială. Suna perfect! Așa că vă creați modulul de utilizator în Magazin și adăugați acțiunea corespunzătoare în fișierul index.js
din directorul Magazin:
export const actions = { nuxtServerInit ({ dispatch }) { // localStorage should work, right? const token = localStorage.getItem('token') if (token) return dispatch('user/load', token) } }
Când reîmprospătați pagina, primiți o eroare, localStorage is not defined
. Gândindu-mă unde se întâmplă asta, are sens. Această metodă este rulată pe server, nu are idee ce este stocat în localStorage
pe client; de fapt, nici nu știe ce este „localStorage”! Deci nu este o opțiune.
Deci care este soluția? Sunt câteva, de fapt. Puteți determina clientul să inițializeze Magazinul, dar ajunge să piardă beneficiile SSR, deoarece clientul ajunge să facă toată munca. Puteți configura sesiuni pe server și apoi le puteți utiliza pentru a autentifica utilizatorul, dar acesta este un alt strat de configurat. Ceea ce seamănă cel mai mult cu metoda localStorage
este utilizarea cookie-urilor.
Nuxt are acces la cookie-uri deoarece acestea sunt trimise cu cererea de la client către server. Ca și în cazul altor metode Nuxt, nuxtServerInit
are acces la Context, de data aceasta ca al doilea argument deoarece primul este rezervat magazinului. Pe Context, putem accesa obiectul req
, care stochează toate anteturile și alte informații din cererea clientului. (Acest lucru va fi mai ales familiar dacă ați folosit Node.js.)
Deci, după ce ați stocat tokenul într-un cookie (numit „token”, în acest caz), să-l accesăm pe server.
import Cookie from 'cookie' export const actions = { nuxtServerInit ({ dispatch }, { req }) { const cookies = Cookie.parse(req.headers.cookie || '') const token = cookies['token'] || '' if (token) return dispatch('user/load', token) } }
O soluție simplă, dar care s-ar putea să nu fie imediat evidentă. Învățarea să se gândească unde au loc anumite acțiuni (client, server sau ambele) și la ce au acces durează ceva timp, dar beneficiile merită.
Implementare
Implementarea cu Nuxt este extrem de simplă. Folosind aceeași bază de cod, puteți crea o aplicație SSR, o aplicație cu o singură pagină sau o pagină statică.
Aplicație redată pe server (aplicația SSR)
Acesta este probabil ceea ce ați urmărit când utilizați Nuxt. Conceptul de bază pentru implementare aici este să rulați procesul de build
pe orice platformă pe care o alegeți și să setați câteva configurații. Voi folosi exemplul Heroku din documente:
Mai întâi, configurați scripturi pentru Heroku în package.json
:
"scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", "heroku-postbuild": "npm run build" }
Apoi configurați mediul Heroku folosind heroku-cli
(instrucțiuni de configurare aici:
# set Heroku variables heroku config:set NPM_CONFIG_PRODUCTION=false heroku config:set HOST=0.0.0.0 heroku config:set NODE_ENV=production # deploy git push heroku master
Asta e. Acum, aplicația dvs. SSR Vue este gata live pentru întreaga lume. Alte platforme au configurații diferite, dar procesul este similar. Metodele oficiale de implementare enumerate în prezent sunt:
- Acum
- Dokku (Oceanul digital)
- Nginx
Aplicație pentru o singură pagină (SPA)
Dacă doriți să profitați de unele dintre funcțiile suplimentare oferite de Nuxt, dar să evitați ca serverul să încerce să redea pagini, atunci puteți implementa în schimb ca SPA.
În primul rând, cel mai bine este să vă testați aplicația fără SSR, deoarece în mod implicit npm run dev
rulează cu SSR activat. Pentru a schimba asta, editați fișierul nuxt.config.js
și adăugați următoarea opțiune:
mode: 'spa',
Acum, când rulați npm run dev
, SSR va fi dezactivat și aplicația va rula ca un SPA pentru a fi testat. Această setare asigură, de asemenea, că nicio versiune viitoare nu va include SSR.
Dacă totul arată bine, atunci implementarea este exact aceeași ca pentru o aplicație SSR. Nu uitați că trebuie să setați mai întâi mode: 'spa'
pentru a informa procesul de construire că doriți un SPA.
Pagini statice
Dacă nu doriți deloc să aveți de-a face cu un server și, în schimb, doriți să generați pagini pentru a fi utilizate cu servicii de găzduire statică, cum ar fi Surge sau Netlify, atunci aceasta este opțiunea pe care o alegeți. Țineți cont de faptul că, fără un server, nu veți putea accesa req
and res
în Context, așa că dacă codul dvs. se bazează pe asta, asigurați-vă că îl includeți. De exemplu, atunci când se generează exemplul de proiect, funcția nuxtServerInit
aruncă o eroare deoarece încearcă să preia un simbol din cookie-urile din anteturile solicitării. În acest proiect, nu contează, deoarece acele date nu sunt folosite nicăieri, dar într-o aplicație reală, ar trebui să existe o modalitate alternativă de a accesa acele date.
Odată ce este sortat, implementarea este ușoară. Un lucru pe care probabil că va trebui să îl schimbați mai întâi este adăugarea unei opțiuni, astfel încât comanda nuxt generate
să creeze și un fișier alternativ. Acest fișier va solicita serviciului de găzduire să lase Nuxt să se ocupe de rutare, mai degrabă decât de serviciul de găzduire, arătând o eroare 404. Pentru a face acest lucru, adăugați următoarea linie la nuxt.config.js
:
generate: { fallback: true },
Iată un exemplu de utilizare a Netlify, care nu se află în prezent în documentele Nuxt. Rețineți că, dacă este prima dată când utilizați netlify-cli
, vi se va solicita să vă autentificați:
# install netlify-cli globally npm install netlify-cli -g # generate the application (outputs to dist/ folder) npm run generate # deploy netlify deploy dist
Este la fel de simplu! După cum sa menționat la începutul articolului, există o versiune a acestui proiect aici. Există, de asemenea, documentație oficială de implementare pentru următoarele servicii de mai jos:
- Surge
- Pagini GitHub
Aflați mai multe
Nuxt se actualizează rapid, iar aceasta este doar o mică selecție a funcțiilor pe care le oferă. Sper că acest articol vă încurajează să îl încercați și să vedeți dacă ar putea ajuta la îmbunătățirea capacităților aplicațiilor dvs. Vue, permițându-vă să vă dezvoltați mai rapid și să profitați de funcțiile sale puternice.
Dacă căutați mai multe informații, atunci nu căutați mai departe decât linkurile oficiale ale Nuxt:
- Documentație
- Playground
- GitHub
- FAQ
Looking to up your JavaScript game? Try reading The Comprehensive Guide to JavaScript Design Patterns by fellow Toptaler Marko Mišura.