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.
Cześć w tej lekcji.
Analogicznie na lekcji poprzedniej będziemy rozwijać mini o dodatkowe
funkcjonalności bazując na wiedzy, którą już obecnie posiadamy.
Czyli jest to taka forma ćwiczeń i powtarzania poprzez praktykę.
Ja też zachęcam do tego, abyś
robił robiła dokładnie to samo równolegle ze mną,
bądź jeżeli będziesz miał jakiś pomysł zaimplementować go samodzielnie.
W tej lekcji stworzymy odnośnik, który będzie generował nam losowe artykuły.
Już mamy tutaj takie miejsca przygotowane
w naszej aplikacji i trzeba je tylko wypełnić odpowiednimi danymi i uzupełnić
fragmenty naszego kodu, abyśmy mieli osobny page do tego bądź
osobny middleware i w związku z czym stworzymy sobie nowy page Random View.
Kopiujemy nasz login jako punkt odniesienia.
Tak naprawdę tego już bardzo nie potrzebujemy.
Bardzo stary jest to komponent naszym blogiem kawą.
Pozbądźmy się też niepotrzebnych styli
random page, pozbądźmy się logo i w sumie analogicznie możemy zostawić to do.
Loginu.
W związku z czym teraz odwiedzając stronę random.
Będziemy faktycznie mieli tutaj wyświetlana taką informację.
Nie wiem skąd się wziął ten znak równości
i tutaj się zaczaił na nas i jest też w loginie więc go usuniemy.
Zapisujemy i to co chcielibyśmy zrobić to
oczywiście pobrać losowy artykuł z wikipedii.
I tutaj ponownie ratuje nas Wikipedia.
Jest w dokumentacji, jest do tego odpowiednia metoda.
W związku z czym z powrotem do dokumentacji.
I tutaj mamy metodę random.
Dzięki temu, że w poprzedniej lekcji zmodyfikowaliśmy troszkę nasze wpisy, nie
musimy dodawać nowego endpoint get dla każdej jednej metody.
Ale co możemy zrobić to stworzyć nowy middleware.
Nazwać go random. Kropka.
Czy jest?
I tutaj sobie skopiować powiedzmy.
Viki Translation istnieje, który jest prostszy, ma mniej kodu.
Może samo tutaj.
Deklarację funkcji przechowujemy i teraz co możemy zrobić to wykonać
ponownie zapytanie, tak samo z prośbą o informację o losowym artykule.
Const random.
Równa się tutaj i wpiszemy go po prostu do konsoli.
Zapiszemy i w naszym page'u.
Tym razem za deklarujemy minus.
Random i ponownie nazwa middleware bierze się z nazwy pliku.
Tutaj w zakładce middleware.
Czyli w tym momencie ten numer nie będzie robił nic poza logowaniem do konsoli.
Możemy go sobie tutaj wypisać i po wejściu na stronę random możemy ją odświeżyć.
Dla pewności to pass defined.
Zobaczmy gdzie jest tutaj zadeklarowane.
Oczywiście nie zaktualizowaliśmy naszego endpoint, więc tutaj pobierzemy sobie
metodę random i zobaczmy czy w ogóle ma to sens, abyśmy przekazywali tutaj page'a.
W naszym wiki dzieje się co się stanie, jeżeli Page nie istnieje.
Czy on nam tutaj zrobi coś złego? Chyba nie.
Chyba możemy zostawić to jako taką wartość.
Nie jest to najlepsza taktyka, zdecydowanie.
Ale powiedzmy, że damy sobie tutaj.
Not available bez slasha.
I mam nadzieję, że w tym momencie zadziała.
Link nie jest zdefiniowany i to jest akurat prawda.
Language musimy wyjąć sobie z.
Naszego i 18 albo bezpośrednio 18 lokal.
Cieszmy.
Request wpływ.
Error kod FIFA changed i nie ma takiego artykułu jak Dash.
Dlatego też uważałem, że nie jest to najlepsze rozwiązanie.
Zobaczmy czy API w ogóle wymaga pobrania.
Tutaj Tajga nie wymaga super, tak bym się tego spodziewał.
Natomiast w takim razie nie ma sensu wykorzystywać do tego tej metody.
Tworzymy sobie po prostu nowy endpoint.
Jest to dosyć specyficzne, bo ten endpoint
nie jest zależny w żadnym stopniu od Page'a, więc.
Router.
Dla pewności po prostu napiszemy.
I tutaj.
Random możemy zawsze odkodować request response.
I po prostu skopiuj tę treść.
Wraz z językiem.
Język się nam może akurat przydać, więc język sobie tutaj przekażmy.
I w sumie te też część możemy sobie skopiować.
Więc teraz dobierzemy się jeszcze do języka.
Nie potrzebujemy funkcji.
Potrzebujemy nowej instancji w odpowiednim języku.
I tutaj zamiast wiki zrobimy sobie wiki random.
I jako parametr możemy podać liczbę randomowych artykułów.
Więc możemy też zrobić links albo count.
Count.
I tutaj będzie to ilość.
Celowo domyślnie.
3.
I przekażemy sobie to tutaj jako wartość i jako zwrotka.
To jest po prostu promise, który daje nam
tablicę wyników, w związku z czym nie potrzebujemy tutaj żadnego kontentu.
Możemy zmienić nazwę tej funkcji.
Na Random Articles, podmienić ją tutaj i pozbyć się tego identyfikatora.
W tym momencie gdy zaktualizuje to failed powinna być to funkcja asynchroniczne.
Oczywiście zapisujemy i powinno się to nam
ładnie przebudować, więc teraz możemy odnieść się do tego.
Ola.
Random Middleware.
Podmienić informacje o języku tutaj.
I moglibyśmy w jakiś sposób jeszcze
przekazywać tutaj parametry do tego middleware.
Może np. przez roota?
Ale w tym momencie powiedzmy, że domyślnie
weźmiemy sobie jeden artykuł na sobie, zapiszemy.
I teraz po wejściu na naszą stronę losową.
Dalej dostają 500k request wpływ error kod five changed.
W takim razie zobaczmy co tam może być problemem, ale nic się nie pisało na.
Konsoli, więc
po prostu serwer w międzyczasie i zobaczę czy nie ma tutaj żadnej literówki.
Random język. Język.
Count count.
Random język. Język.
Count Count.
Super.
Nie ma tutaj żadnego błędu.
Powinno być ok.
Być może po prostu przez to, że serwer się wywrócił.
Wcześniej, gdy nieodłącznej słowa kluczowego they sing.
I po prostu nie chciał się już później przeładować.
Zobaczymy. Mam nadzieję, że to jest to.
I faktycznie to był problem.
Więc mamy tutaj informacje o danej nazwie Flaga.
Jestem ciekawy, czy zmieniając.
Wersję językową powiedzmy na francuski.
I biorąc losowy artykuł to jest chyba ten odnośnik.
Widzę, że tu się chyba nie zaktualizował.
Bo daleko Ćwieczka.
No i zobaczmy.
Same nazwiska trafiają, a chciałbym jakąś jakieś słowo po.
Po francusku.
Wydaje mi się, że to mogło być po francusku.
Franka zaimki.
I tak jak najbardziej w tym momencie dostajemy tę informację po francusku, w
związku z czym następne kroki będą naprawdę proste.
Jako że to jest tablica stringów, tablica nazw, które chcemy wyszukać.
No to możemy zrobić prosty redirect na poziomie middleware.
Czyli tutaj możemy sobie zobaczyć jak się robi redirect w dokumentacji rutera ruter
serwer i tutaj jest to jeden z pierwszych przykładów.
Nie o to mi chodziło.
Routera router middleware.
Zdecydowanie nie o to mi chodziło.
A mi chodziło.
Tak i tutaj mamy sekcje, że możemy
tworzyć, tak jak już wspominaliśmy, anonimowe middleware.
Niekoniecznie, ale jest tutaj też metoda
redirect i z niej właśnie chcemy skorzystać.
Więc wykorzystamy tutaj.
Ten relikt.
I przekieruje Cię na losowy artykuł, który znaleźliśmy, czyli tutaj.
Pobierzemy sobie.
Pierwszy wpis
chcemy przekierować na odpowiedni język, więc ustawiamy sobie tutaj.
Lang równa się i 18 cal.
Możemy w sumie to przesunąć wyżej i tutaj wstawić link.
I przekierowanie na blank.
Tutaj stringi, żeby wstawić wygodnie zmienną Viki.
I tutaj nazwa naszego artykułu, czyli random.
Z tym, że tutaj prawdopodobnie powinniśmy występować białe znaki.
Zobaczmy czy to zadziała.
Zapiszemy.
I faktycznie nie zadziałało bez
skopiowania białych znaków, w związku z czym teraz faktycznie jak już wyjdziemy na
losowe artykułu, co jest też podobno zachowaniem tego jak Wikipedia działa,
czyli klikając tutaj mamy odnośnik do losowego artykułu.
Nie jestem pewien dlaczego w wersji francuskiej to się nam tutaj nie ustawia.
Wejdźmy na stronę główną.
Strona główna nie ma chyba odnośnika z
obecnym językiem ustawionym na random article.
Tutaj widzę, że się na mnie ustawia. Ciekawe.
Wydawało mi się, że zaktualizowałem już.
Stronę Playa Chciałem być może nie.
W związku z czym tutaj random article możemy zmienić na plik tekstowy.
Możemy go tutaj sekcji na hosting.
Widzę, że w niektórych części dokumentacji
komponenty były pisane z wielkich liter, niektórym małymi.
Podzielone myślnikiem, czyli tak zwanym kebab.
Ja osobiście preferuję kebab case,
ale wydaje mi się, że większość community wie.
Jednak preferuję notację płaska, czyli z wielkich liter bez myślników.
Ale wracając do clue.
Możemy tutaj wpisać random jako przekierowanie i base jako wartość.
Tutaj wklejamy.
Usuwamy stare odnośniki, zapisujemy.
I w tym momencie random article powinien nas przenosić na odpowiednie wpisy.
Jestem ciekawy czy.
Nie zadziałało odpowiednio.
Mamy domyślny język ustawiony na angielski.
Chyba tak jest, w związku z czym
niestety ten random art w języku angielskim będzie to problematyczne.
Ale z drugiej strony jak nie ustawiliśmy tego w nast config, że jest.
W tym miejscu na default local.
To wtedy nam niestety homepage troszkę nie działał.
Zobaczymy czy to coś zmieni.
Prawdopodobnie będziemy mieli dużo błędów związanych z językiem angielskim.
To się daje, przebudowuje.
Na stronie głównej dostajemy page not
found właśnie ze względu na to, że prawdopodobnie teraz musimy dawać wszędzie
wersję językową, ale z drugiej strony działa nam w tym momencie random article.
W języku angielskim również.
W każdym razie właśnie tam się załadował.
Niektóre artykuły będą krótsze, ale cóż na to poradzić, Jestem ciekawy.
Jest to ciekawy problem związany z tym.
Domyślnym full bak lokal.
Ja chyba zostawię to w tym momencie w
takiej formie, aby te losowe artykuły nam działały.
Jeszcze tylko ustawię w naszym layoucie.
Taką zasadę, aby nasze linki, które.
Są linkami martwymi, chociaż ciężko to
teraz będzie wykryć, bo do każdej z nich mamy kotwicę.
Było jakoś wyróżnione, więc może zostawię to tak jak jest.
W każdym razie mamy stworzony nowy.
Endpoint oraz middleware, który losuje nam wybrane
artykuły za pomocą endpoint oraz za każdym razem, gdy wejdziemy na stronę Random.
Poprzedzoną oczywiście odpowiednim country kodem.
Będziemy dostawali losowe artykuły w tym języku.
I też warto zauważyć, że tutaj nam się zmieni ścieżka do tego artykułu.
Dlatego tak kluczowe jest zrozumienie
wszystkich relacji między store, między middleware, między partiami i między
naszymi API, aby móc tworzyć rozwiązania tego typu w sposób szybki i wydajny.
Zmiany wprowadzone w lekcji · 14 min
diff --git a/31/minipedia/api/routes/wiki.js b/31/minipedia/api/routes/wiki.js
index a520cd7..f9a1c12 100644
--- a/31/minipedia/api/routes/wiki.js
+++ b/31/minipedia/api/routes/wiki.js
@@ -1,4 +1,4 @@
-import { Router } from 'express';
+import { request, Router } from 'express';
import WikiJs from 'wikijs';
const router = Router();
@@ -25,4 +25,24 @@ router.get('/:fn/page/:id/lang/:lang', async (req, res) => {
}
});
+router.get('/random/lang/:lang/count/:count', async (req, res) => {
+ const lang = req.params.lang || 'en';
+ const count = req.params.count || 3;
+
+ const Wiki = WikiJs({
+ apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
+ headers: { 'User-Agent': process.env.BOT_USER_AGENT}
+ });
+
+ try {
+ const randomArticles = await Wiki.random(count);
+
+ return res.status(200).json(randomArticles);
+
+ } catch (e) {
+ console.error(e);
+ return res.status(500).json(e);
+ }
+})
+
export default router;
\ No newline at end of file
diff --git a/31/minipedia/layouts/default.vue b/31/minipedia/layouts/default.vue
index 58ad64b..9d422ff 100644
--- a/31/minipedia/layouts/default.vue
+++ b/31/minipedia/layouts/default.vue
@@ -2,16 +2,18 @@
<div class="wrapper">
<nav class="side-navigation">
<div class="logo">
- <a href="/">
+ <nuxt-link :to="localePath('/')">
<img src="/logo2.png" alt="">
Minipedia
- </a>
+ </nuxt-link>
</div>
<ul>
<li><a href="#main-page"> {{ $t('MainPage') }} </a></li>
<li><a href="#contents"> {{ $t('Contents') }} </a></li>
<li><a href="#current-events"> {{ $t('CurrentEvents') }} </a></li>
- <li><a href="#random-article"> {{ $t('RandomArticle') }} </a></li>
+ <li>
+ <nuxt-link :to="localePath('/random')"> {{ $t('RandomArticle') }} </nuxt-link>
+ </li>
<li><a href="#about-wikipedia"> {{ $t('AboutWikipedia') }} </a></li>
<li><a href="#contact-us"> {{ $t('ContactUs') }} </a></li>
<li><a href="#donate"> {{ $t('Donate') }} </a></li>
diff --git a/31/minipedia/middleware/random.js b/31/minipedia/middleware/random.js
new file mode 100644
index 0000000..79526e7
--- /dev/null
+++ b/31/minipedia/middleware/random.js
@@ -0,0 +1,5 @@
+export default async function ({ store, route, $axios, app: { i18n }, redirect}) {
+ const lang = i18n.locale;
+ const random = (await $axios.$get(`/api/wiki/random/lang/${lang}/count/1`))[0];
+ return redirect(`/${lang}/wiki/${random}`);
+}
\ No newline at end of file
diff --git a/31/minipedia/nuxt.config.js b/31/minipedia/nuxt.config.js
index 1bca110..2f0d7e4 100644
--- a/31/minipedia/nuxt.config.js
+++ b/31/minipedia/nuxt.config.js
@@ -68,8 +68,7 @@ module.exports = {
}
],
lazy: true,
- langDir: 'lang/',
- defaultLocale: 'en',
+ langDir: 'lang/'
},
basic: {
name: process.env.USERNAME,
diff --git a/31/minipedia/pages/index.vue b/31/minipedia/pages/index.vue
index 94e8d64..16aebeb 100644
--- a/31/minipedia/pages/index.vue
+++ b/31/minipedia/pages/index.vue
@@ -1,6 +1,6 @@
<template>
<article class="content">
- <h1>Minipedia - {{ $t('welcome') }} </h1>
+ <h1>Minipedia - {{ $t('Welcome') }} </h1>
<nuxt-link :to="switchLocalePath('en')">English</nuxt-link>
<nuxt-link :to="switchLocalePath('fr')">Français</nuxt-link>
diff --git a/31/minipedia/pages/login.vue b/31/minipedia/pages/login.vue
index 77ded5c..d3f84ec 100644
--- a/31/minipedia/pages/login.vue
+++ b/31/minipedia/pages/login.vue
@@ -1,59 +1,12 @@
<template>
- <article class="content">=
- <Logo />
+ <article class="content">
<h2>
- Please log in
+ Login
</h2>
</article>
</template>
<script>
export default {
- computed: {
- username() {
- return process.env.NUXT_ENV_USERNAME;
- }
- }
}
-</script>
-
-<style>
-.container {
- margin: 0 auto;
- min-height: 100vh;
- display: flex;
- justify-content: center;
- align-items: center;
- text-align: center;
-}
-
-.title {
- font-family:
- 'Quicksand',
- 'Source Sans Pro',
- -apple-system,
- BlinkMacSystemFont,
- 'Segoe UI',
- Roboto,
- 'Helvetica Neue',
- Arial,
- sans-serif;
- display: block;
- font-weight: 300;
- font-size: 100px;
- color: #35495e;
- letter-spacing: 1px;
-}
-
-.subtitle {
- font-weight: 300;
- font-size: 42px;
- color: #526488;
- word-spacing: 5px;
- padding-bottom: 15px;
-}
-
-.links {
- padding-top: 15px;
-}
-</style>
+</script>
\ No newline at end of file
diff --git a/31/minipedia/pages/random.vue b/31/minipedia/pages/random.vue
new file mode 100644
index 0000000..6cc5c40
--- /dev/null
+++ b/31/minipedia/pages/random.vue
@@ -0,0 +1,13 @@
+<template>
+ <article class="content">
+ <h2>
+ Random page
+ </h2>
+ </article>
+</template>
+
+<script>
+export default {
+ middleware: 'random',
+}
+</script>
\ No newline at end of file