Prosty i Nowoczesny Framework dla Vue.js
7 godz. 2 min · Vue.js · Full-stack i Programowanie
Wojciech PołowniakSr. Fullstack EngineerW tym projekcie tworzyć będziemy praktyczny projekt - klona Wikipedii! Minipedia pobierze dane z prawdziwego źrodła danych, zewnętrznego API WikiMedia - będzie łudząco podobna do oryginału oraz współdzieliła najważniejsze funkcjonalności, takie jak dostarczanie treści w różnych wersjach językowych, możliwość wyszukiwania artykułów, czy pobieranie najpopularniejszych wpisów dla danego języka. Stworzymy także podstronę wyświetlającą za każdym razem losowy artykuł w danej wersji językowej.Zobaczysz też, jak dokonać migracji ze statycznej strony HTML na Nuxt - oraz jak tworzyć przykładowe komponenty podczas tego procesu.Dzięki temu wszystkiemu, dowiesz się jak wykorzystać nabytą wiedzę w praktyce.
Dzięki Nuxtowi dowiesz się jak optymalizować Twoje strony www z duchem idei progressive enhancement, dostarczając coraz to lepsze doświadczenia dla swoich użytkowników oraz tworząc aplikację napisaną w 100% w JavaScript, która będzie działała nawet wtedy, gdy użytkownik jawnie wyłączy go w przeglądarce! To wszystko za SSR (Server Side Rendering), dzięki któremu treści będą gotowe do konsumpcji już przy wstępnej, pierwszej odpowiedzi z serwera WWW.Oczywiście, ma to swoje implikacje na wydajność naszej aplikacji - sprawiając że Lighthouse czy optymalizacja pod SEO staje się coraz prostsza!
Czymże jest ekosystem danego frameworka bez wsparcia społeczności! Dlatego podczas tego kursu nauczysz się instalować i wykorzystywać różne pluginy i moduły, które zaoszczędzą Ci dużo czasu. Dowiesz się też, jak tworzyć własne moduły - które rozszerzą działanie Twojej aplikacji Nuxt w sposób czysty i zarządzalny.
Nuxt jest frameworkiem w którym pracujemy zarówno po stronie front-endu, jak i back-endu. W związku z czym, stworzymy swoje własne API (bazujące na express.js) które będzie pewnego rodzaju pośrednikiem pomiędzy API WikiMedia oraz Twoją aplikacją internetową.
W tym kursie, dowiesz się także jak tworzyć swoje własne Middleware'y - czyli fragmenty kodu wywoływane pomiędzy przechodzeniem między stronami, czy podczas innych zapytań HTTP.Dodatkowo, zobaczysz jakie narzędzia daje nam Nuxt aby tworzyć progresywne aplikacje internetowe, oferując wsparcie dla takich funkcjonalności jak np. animacje między przejściami pojedynczymi podstronami naszego serwisu.
Tajemnicze i18n - czyli numeronim odpowiadający angielskiemu słowu "internalisation" - odnosi się w kontekście web developmentu do tłumaczenia danych na różne języki. Podczas realizacji projektu Minipedii, nie tylko wykorzystamy standardowe podejście do tłumaczeń stałych elementów naszego interfejsu użytkownika, ale także przetłumaczymy same dane zwracane z API, wykorzystując inną wersję językową w zależności od preferencji użytkownika!
Poznasz też kilka ciekawych pluginów i rozwiązań dotyczących optymalizacji pod SEO - poza faktem, że podejście spełniające intencje użytkownika jest najlepszym, co możemy zrobić - pluginy generujące nam mapę stron automatycznie na podstawie zadeklarowanych przez nas podstron, czy generatory danych jsonld pomogą w pozycjonowaniu Twojej wydajnej aplikacji jeszcze wyżej w hierarchii wyszukiwarek.
Aby móc efektywnie korzystać z tego kursu, powinieneś posiadać średnio zaawansowaną wiedzę z kategorii Front End, z naciskiem na umiejętność posługiwania się JavaScriptem oraz solidne podstawy NodeJS. Konieczna jest znajomość Vue, jako że Nuxt jest frameworkiem korzystającym z niego u swoich podstaw. Jeśli czujesz się dość swobodnie w wyżej wymienionych aspektach web developmentu, ten kurs będzie idealny dla Ciebie.
W poprzedniej. Lekcji zajęliśmy się.
Zrozumieniem.
Jak działa mechanizm async data i w jaki sposób możemy.
Przekazywać. Dane na frontend z backendu.
Wewnątrz samych. Komponentów.
Natomiast nie jest to najbardziej skalowalne rozwiązanie.
Jest ono dobre, jeżeli mamy dosyć specyficzne przypadki,
który nie da się wyprowadzić do jakiegoś jednego wspólnego mianownika, czyli np.
do routing middleware.
I my właśnie ten routing stworzymy,
ponieważ każda z naszych podstron będzie dotyczyła.
Jakiegoś artykułu na Wikipedii.
W związku z czym będzie miała dosyć podobne struktury.
I dosyć podobne potrzeby. Więc to co.
Zrobimy najpierw, to pozbędziemy się tego Fromma, a nie będziemy tego potrzebowali.
Możemy pozbyć się tak naprawdę całego
passing data, ale ja sobie skopiuję tutaj ten request.
I to co. Możemy zrobić, to stworzyć nowe menu.
Tutaj jest. Katalog.
Podpisane właśnie jako middleware.
I tak jak w poprzednich przypadkach możemy
stworzyć tutaj nowy plik powiedzmy o nazwie.
Wiki kropka jest albo.
Routing wiki routing.
Czy jest.
Nie ma to tak naprawdę takiego znaczenia, jeśli zerkniemy tutaj na tę dokumentację.
Jak zostaniemy tutaj przekierowani.
To zobaczmy. Że.
Tutaj wpiszemy sobie.
Coaching for.
On dokładnie.
To zobaczymy.
Tutaj jest przykład, a ja chciałem zobaczyć faktycznie dokumentację.
No ale możemy wykorzystać też to.
I jak wejdziemy sobie do naszego serwera troszkę to się ładuje niestety.
Cały sandbox czasami potrafi się troszkę zaciąć.
I widzimy, że to co musimy zrobić to po prostu wyeksportować funkcję, która
również ma dostęp do kontekstu i dowolną rzecz, którą tam zrobimy.
Będzie ona się faktycznie aplikowałam. Więc kopiujemy.
Sobie ten fragment kodu. I to co trzeba.
Zrobić drugie.
I nie jestem pewien jak akurat jest to zrobione w tym przykładzie.
Możliwe, że jest to podane tutaj w layout
albo w pakietach router menedżer, albo jeszcze w next config.
Dzieje się tak.
Więc mamy różne możliwości rejestrowania.
Naszych middleware.
Jednym z nich jest taki globalny routing
middleware znajdujący się wewnątrz max config jest.
A inne opcje to np.
wewnątrz.
Naszych page layoutów.
Po prostu też możemy analogicznie stworzyć
sobie middleware i przekazać tutaj tablicę jego nazw.
A ta nazwa bierze się właśnie z tego, jaką nazwę pliku tutaj sobie ustawię.
Czyli tutaj daliśmy plik, czyli tutaj daliśmy nazwę pliku.
Class kropka. Jest, więc tutaj.
W menu też musimy dać nazwę klasy jako string.
Więc wróćmy do naszego przykładu. I tak jak tutaj.
Ustawiliśmy sobie w wiki routing.
To moglibyśmy to tutaj na poziomie next.
Config ustawić jako true i tutaj przekazać.
Przypominam router middleware to nie jest serwer for.
Natomiast my wykorzystamy do tego po prostu Page.
I tutaj wpisałem sobie middleware i przekazałem tablicę.
W tym momencie to już będzie tylko jeden element zapiszemy,
tylko najpierw wypełnimy ten plik jakimiś danymi, więc ja tutaj sobie to wkleję.
Nie mamy oczywiście takiej mutacji w naszym Starze, więc tutaj
zrobimy sobie renomę i wpiszemy sobie ród name.
Zobaczmy co tu się stanie.
Zapiszemy i po zapisaniu tutaj też możemy zapisać.
I wyświetlimy nasz store stats example stats.
Powinno się to nam zaktualizować.
Nie przypominam sobie abyśmy usuwali te.
Te widoki i tutaj faktycznie widzimy, że jest to na.
Początku indeks, ale później.
Modyfikujemy to jako modified state, bo
mamy taką logikę tutaj zaimplementowaną, więc możemy się tego tutaj.
Pozbyć i widzimy, że.
Obecny jest to indeks, co się zgadza, bo nie mamy tutaj żadnego pacha.
I do czego możemy to wykorzystać,
skoro mamy takie miejsce, które również posiada dostęp do kontekstu.
W takim razie również też posiada Accessa.
Więc możemy tutaj pobrać.
Następnie wywołać go.
Zrobić z tego funkcje asynchroniczne.
Nie powinno być z tym żadnego problemu. Co robić tutaj?
Czekać na. Ten.
W sumie nie jestem pewien co powinno się stać w sytuacji jak nasz middleware.
Nie mógł pobrać tych danych. I w tym momencie.
Możemy po prostu zapisać to do. Store.
Oczywiście w tym. Momencie zawieszamy to pod.
W tego naszego.
Example state, ale nie powinno być z tym problemu.
Jak tutaj to sobie napiszemy.
To widzimy, że po odświeżeniu faktycznie to tam się pokazało.
Tylko, że ten modified tak daje nam się nadpisuje.
Widocznie nie zapisałem naszego pliku index czy jest.
Więc mamy już możliwość modyfikacji naszego store.
Na poziomie middleware i nasze komponenty mogą być naprawdę czyste w tym momencie.
W związku z czym to co ja zrobiłem?
To pozbędę się tutaj tych map.
Zanim to zrobię jednak.
Komentuję też tą linijkę.
I w naszym indeksie pozbędę się tego fragmentu.
Bo nie chcę.
Żeby aplikacja się w międzyczasie wysypała.
Przejdziemy do naszego. Store, czyli indeks jest w store.
I wypełnimy to faktycznie informacjami, których będziemy potrzebowali.
Czyli full info może być domyślnie null.
Ustaw na wszystkie po prostu pola, które będziemy chcieli wypełnić jako NULL.
Początkowo.
Następnie content.
NULL.
Zobaczmy czy jeszcze Viki jest tutaj nam podpowie jakie to były właściwości.
Napewno chcieliśmy.
Full info content images.
Oraz sam.
Więc wracamy do.
Sam.
NULL.
Robimy null.
I prawdopodobnie tam nam zależało na main image.
Którego chyba nie stworzyliśmy.
Swoją drogą.
Ale możemy to szybciutko zrobić.
To już nie powinno nam zająć za długo.
Po prostu kopiuj wklej.
Nowa metoda.
Nie tutaj. To było mecz.
Oraz tutaj mail podpowiada widać, że aplikacja napisana w skrypcie.
Znaczy widzi, że jest nasza aplikacja nie jest napisana w skrypcie.
I w tym momencie jak mamy dostęp do Stora
to już jest tutaj ustawione na to musimy stworzyć.
Te nasze mutacje.
Więc co ja zrobię to tutaj.
Trenujemy na razie na Renatę.
Skopiuje to tyle razy.
Ile mamy właściwości, czyli jest to 5 razy 2.
3. 4.
Shift option albo Shift alt strzałka w
dole, strzałka w dół, zduplikowane obecne zaznaczenie.
No i teraz command D.
Czy control D będzie nam zaznaczała lub kochało kursor na tyle
na ile znalazło takich samych zaznaczenie w naszym pliku.
W związku z czym możemy tutaj.
Zamienić nazwę tych wszystkich plików na to, co się tutaj znajduje.
Ma, Zróbmy to może w ten sposób.
Czyli weźmiemy 5 z kopiujemy wszystko.
Tutaj zaznaczmy sobie te 5.
Dwukropka.
Kopiujemy do schowka.
Następnie do pliku Jana.
Kursor 5 razy.
I teraz możemy wkleić.
I faktycznie nam się to ładnie wkleiła.
Czyli możemy zrobić.
Set.
I tutaj po prostu jest kapitalizm.
Tę pierwszą literkę w każdym przypadku full content.
Content summary images.
Image.
I ponownie tutaj zaznaczamy po prostu i wklejamy to co tam mieliśmy zaznaczone.
Dzięki temu będziemy mieli. Mutacje, które pozwolą nam.
Zaktualizować.
Nasz stan.
I przechodząc do naszego wiki routingu.
Możemy tutaj wykonać te wszystkie zapisy.
Czyli zamiast komentować tutaj,
możemy to sobie też raz, dwa, trzy, cztery, pięć razy skomentować.
Za dużo zrobiło.
Ponownie dopisujemy.
Wklejamy.
Dodajemy tutaj set full info set content.
Set. Sam Marek starał images set main image.
I tutaj modyfikujemy ten kontent.
To.
Modyfikujemy ten kontent.
Tutaj zastanawiam się jak można to łatwo zrobić.
Chyba po prostu zaznaczę w ten sposób.
I teraz przejdę do.
Kontentu wklejam ponownie.
I co powinno zadziałać.
Jest taki tylko problem, że jeżeli którykolwiek z tych requestów.
Się tutaj. Nie powiedzie, no to w tym.
Momencie reszta się też nie zapisze, co nie jest idealnym scenariuszem.
Ale możemy to zapisać i zobaczymy co się stanie.
Mam nadzieję, że aplikacja się nie wywróci.
Odświeżamy.
Teraz request będą się tam.
Działy w tle, w związku z czym nasza
aplikacja będzie trwała troszkę dłużej, będzie się dłużej ładowała.
Wygląda na to, że wszystko działa, w związku z czym spróbujmy tylko.
Wyświetlić te wszystkie informacje tutaj.
I tak jak widzieliśmy, aby dostać się do stara.
Musimy odnieść się poprzez toner Store state i tutaj nazwa.
W związku z czym ponownie nazwać. Się 4.
5.
I publikujemy tutaj to, co wpisaliśmy wcześniej.
Nasze wartości i prawdopodobnie każda z tych wartości
powinna być w osobnych wąsach, w osobnym template.
W związku z czym tutaj zrobimy sobie dwa razy nawiasy.
Klamrowych ponownie i te klamry pozbędziemy się ich, aby to był poprawny.
Syntax.
I po odświeżeniu.
Chwila prawdy.
I faktycznie nasza strona się. Wygenerowała.
Jest naprawdę bardzo dużo danych.
Te dane będziemy w kolejnych lekcjach wykorzystywać właśnie w komponentach.
Zobaczmy tylko, czy nie ma żadnego błędu. Błędów żadnych nie ma.
Jest tutaj warning o różnicy między wygenerowanym przez serwer SID.
Kontakcie oraz tym, które jest ustalane przez WP.
Natomiast tym się nie musimy w tym momencie martwić, więc.
To, co nam się udało tutaj. Zrobić.
To po pierwsze stworzyliśmy nasz.
Własny routing Middleware i.
Uruchomiliśmy go. Dzięki temu.
Że w naszym index.
Wykorzystujemy.
Właściwość middleware? Dokładnie tak.
Moglibyśmy też to. Zdefiniować wewnątrz nas konflikt czy
wewnątrz layoutu, jeżeli mielibyśmy taką potrzebę.
No i oczywiście możemy tutaj podać kilka różnych wartości.
Ta nazwa jest powiązana z nazwą pliku.
Którą umieściliśmy wewnątrz katalogu.
Middleware właśnie tutaj.
No i ten routing middleware korzysta z
dwóch rzeczy korzysta z AX i OSA, aby skomunikować.
Się z. API oraz korzysta ze Store.
Aby.
Ustawić wartość naszego statku na takie informacje, jakich potrzebujemy.
W tym momencie powinniśmy zrobić jeszcze dwie rzeczy.
To znaczy najlepiej zmienić tutaj logikę, aby jeden request nie czekał na drugi, bo
w tym momencie tak się dzieje, że najpierw musimy podać wszystkie info.
Dopiero później robi się request po. Content i.
Dopiero później po summary.
Może nie jest to tak widoczne.
W Performance.
Natomiast zauważyliśmy, że. Aplikacja ładuje.
Się chociaż troszkę.
Wolniej, więc możemy to zmienić.
No i tutaj faktycznie powinniśmy.
Przekazywać prawdziwy parametr.
Natomiast w tym momencie nie mamy jeszcze dynamicznych.
Tagów, które będziemy robili już niedługo.
Ale to co możemy zrobić w tej sekundzie to właśnie.
Podzielić ten store commit na takiej zasadzie, aby questy działo się równolegle
i moglibyśmy do tego wykorzystać albo klasyczne Promise down, albo po prostu
Promise, ale z takim niejawnym ustawieniem.
Tutaj kopiujemy.
Czyli tutaj ustawiamy.
Promise jako. Tablicę i.
Wklejamy tutaj nasze wszystkie questy.
Więc przecinek po każdej.
Deklaracji.
Zapisujemy tutaj, wyrównujemy.
Wcięcia i teraz.
Możemy zrobić sobie łatę Promise, ale promise.
Tak naprawdę dalej. Jeżeli któryś z tych requestów się nie uda
to promise, ale nam się też nie rozwiąże, ale możemy to podmienić na nowsze Promise.
Kropka wraz z toString.
Jak to się nazywała ta metoda. Jest metoda.
Która generalnie nie będzie tak surowa jak Promise.
Czyli jeżeli dane request. Się nie powiedzie to tak czy.
Siak.
Promise wywoła.
To wyrażenie też możemy sobie przypisać do zmiennej.
Np. jako val i wtedy val jest foreign.
Vallejo.
Będziemy przepisywali do odpowiednich
miejsc, w związku z czym moglibyśmy tutaj też stworzyć.
Dodatkową tablicę, żeby.
Wiedzieć, do którego miejsca to przypisać.
Ale widzę, że tutaj faktycznie ten.
Kod będzie troszkę mniej czytelne w takim wypadku, w związku.
Z czym zostawmy tę. Mniej wydajną opcję.
W każdym razie warto tutaj pamiętać po
prostu, że każdy request będzie zależny od poprzedniego
i jeżeli którykolwiek z nich się nie uda, to niestety będziemy musieli
pogodzić się z tym, że nasza aplikacja się w danym momencie zepsuła.
W związku z czym gdy stworzymy dynamiczne
Page, zamienimy tutaj tę wartość za hardkorowe.
Janusz Korczak na coś, co faktycznie
pochodzi z naszego adresu przeglądarki, czyli stąd.
A w następnej lekcji skupimy się na tym, aby te wartości, które sobie tutaj
ustawiliśmy i do których mamy dostęp wewnątrz naszego komponentu index miał.
Prze propagować do naszych.
Komponentów, które stworzyliśmy wcześniej. I być może troszkę.
Posprzątać przy okazji, bo niektóre rzeczy mogą być ze sobą niekompatybilne.
Jeśli
dane z serwera będą się troszkę różnić strukturą niż to co tutaj przygotowaliśmy.
Zmiany wprowadzone w lekcji · 15 min
diff --git a/18/minipedia/api/routes/wiki.js b/18/minipedia/api/routes/wiki.js
index a657fc5..c3c4cc9 100644
--- a/18/minipedia/api/routes/wiki.js
+++ b/18/minipedia/api/routes/wiki.js
@@ -56,6 +56,19 @@ router.get('/summary/page/:id', async (req, res) => {
}
});
+router.get('/mainImage/page/:id', async (req, res) => {
+ try {
+ const id = req.params.id;
+ const page = await Wiki.page(id);
+ const content = await page.mainImage();
+ return res.status(200).json(content);
+ } catch (e) {
+ console.error(e);
+ return res.status(500).json(e);
+ }
+});
+
+
router.get('/fullInfo/page/:id', async (req, res) => {
try {
const id = req.params.id;
diff --git a/18/minipedia/middleware/wiki-routing.js b/18/minipedia/middleware/wiki-routing.js
new file mode 100644
index 0000000..92fbb19
--- /dev/null
+++ b/18/minipedia/middleware/wiki-routing.js
@@ -0,0 +1,12 @@
+export default async function ({ store, route, $axios }) {
+ try {
+ store.commit('setFullInfo', await $axios.$get('/api/wiki/fullInfo/page/Janusz%20Korczak'))
+ store.commit('setContent', await $axios.$get('/api/wiki/content/page/Janusz%20Korczak'))
+ store.commit('setSummary', await $axios.$get('/api/wiki/summary/page/Janusz%20Korczak'))
+ store.commit('setRawImages', await $axios.$get('/api/wiki/rawImages/page/Janusz%20Korczak'))
+ store.commit('setMainImage', await $axios.$get('/api/wiki/mainImage/page/Janusz%20Korczak'))
+ } catch (e) {
+ console.error(e);
+ }
+
+}
diff --git a/18/minipedia/pages/index.vue b/18/minipedia/pages/index.vue
index ec99025..309612d 100644
--- a/18/minipedia/pages/index.vue
+++ b/18/minipedia/pages/index.vue
@@ -1,6 +1,10 @@
<template>
<article class="content">
- {{ fromAsyncData }}
+ {{ $store.state.fullInfo }}
+ {{ $store.state.content }}
+ {{ $store.state.summary }}
+ {{ $store.state.rawImages }}
+ {{ $store.state.mainImage }}
<h1>
Janusz Korczak
</h1>
@@ -180,22 +184,7 @@
export default {
layout: 'default',
- methods: {
- ...mapMutations({
- rename: 'rename'
- }),
- },
- mounted() {
- this.rename('modified state');
- },
- async asyncData(config) {
- const value = config.store.state.exampleState;
- const $axios = config.$axios;
-
- return {
- fromAsyncData: await $axios.$get('/api/wiki/content/page/Janusz%20Korczak'),
- }
- },
+ middleware: ['wiki-routing'],
computed: {
fullInfo() {
return {
diff --git a/18/minipedia/store/index.js b/18/minipedia/store/index.js
index 7e0cf7c..2d8bd21 100644
--- a/18/minipedia/store/index.js
+++ b/18/minipedia/store/index.js
@@ -1,9 +1,25 @@
export const state = () => ({
- exampleState: 'initial state'
+ fullInfo: null,
+ content: null,
+ summary: null,
+ rawImages: null,
+ mainImage: null,
})
export const mutations = {
- rename (state, text) {
- state.exampleState = text
+ setFullInfo (state, text) {
+ state.fullInfo = text
+ },
+ setContent (state, text) {
+ state.content = text
+ },
+ setSummary (state, text) {
+ state.summary = text
+ },
+ setRawImages (state, text) {
+ state.rawImages = text
+ },
+ setMainImage (state, text) {
+ state.mainImage = text
},
}
\ No newline at end of file