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 tej sekcji kursu skupimy się na tym, aby udoskonalić nasz istniejący projekt.
Tak naprawdę we wszystkich poprzednich
sekcjach tworzyliśmy fundamenty tego, na czym teraz będziemy pracować.
Czyli tak naprawdę lwia część tej pracy jest już za nami.
Tłumaczenie było zdecydowanie wyzwaniem.
Ja tutaj też posprzątałem troszkę nasz kod.
Po tej ostatniej sekcji, to znaczy uzupełnię brakujące zmienne.
W grze jest np.
tutaj default local.
Przypadkowo usunąłem i zostałem
przywitany w zamian błędami, że nie może znaleźć domyślnego języka.
W związku z czym takie małe drobne poprawki już tutaj wprowadziłem.
I w tej lekcji skupimy się na tym, aby
stworzyć odnośnik do oryginalnej strony na Wikipedii.
To znaczy wiemy, że tutaj zależy nam na tym, aby podglądać różne artykuły
z oryginalnego źródła danych, jakim jest Wikipedia.
Natomiast wypadałoby, tak jak tutaj napisaliśmy,
że jest to treść należąca i serwowana bezpośrednio z Wikipedii.
Po prostu zrobić prosty odnośnik
i mamy do tego na szczęście opcję w API wiki Page'a.
To znaczy tutaj jest taka sekcja URL.
Więc tak jak tworzyliśmy poprzednie endpoint i.
Zaktualizowaliśmy nasz widok.
No to w takim samym sposobie będziemy w stanie rozwiązać ten konkretny przykład.
Więc aby przypomnieć sobie jaki jest
proces na to musimy znaleźć po pierwsze plik, który chcemy edytować.
W naszym przypadku jest to index view
i chcemy, aby to był bezpośredni plik, czyli może mieć miejsce na link a.
I tutaj będziemy musieli wstawić jakąś wartość, w związku z czym
zmieńmy to tutaj na link i zróbmy tutaj odnośnik w postaci kotwic.
Za chwilę wypełnimy ten odnośnik prawdziwymi danymi.
Co musimy zrobić dalej to oczywiście rozszerzyć nasze wiki.
To jest naszym routerem.
Tak jak kopaliśmy poprzednie płyty, tak teraz możemy to skopiować.
Oczywiście nie jest to najlepszy sposób na
zarządzanie naszymi danymi, ale na nasze potrzeby działa.
W związku z czym zrobiłem po prostu tutaj URL.
Nawet Paint.
Który będzie pobierał ją.
Tak naprawdę moglibyśmy to ujednolicić do
jednego endpoint, albo zrobić to jako parametr i później dynamicznie odwoływać
się do tego pola, co w sumie byłoby całkiem fajnym clean.
Natomiast musielibyśmy dalej mieć różne
typy zwrotek, chyba że każdy z nich jest raczej sam.
Wiem, że w przeszłości nie był,
więc podczas takiego klienta możemy się tym zająć.
Na czym mamy zduplikowane te funkcje?
I tutaj ustawmy URL jako i nazwę.
Następnie w naszym wiki routingu nazwa funkcji też oczywiście mogłaby być inna.
Ustawimy set.
Oryginał.
Na które.
Zanim to zapiszemy, przejdźmy jeszcze do Store i dodajmy tutaj, na które jako.
I analogicznie Set Ojcze nasz i wiara.
State URL.
Tym razem już poprawny states powierzono URL na siłę.
I to mam już zapisane, więc teraz możemy zaktualizować nasz wiki Routing.
Zapisujemy.
I w tym momencie na naszym IG powinniśmy mieć dostęp do tej zmiennej.
Czyli możemy zmienić.
Zamiast statycznie odwoływać się do tego atrybutu.
Jako do stringów możemy zmienić na zmienną
i tutaj po prostu podpisać store state v6 url zapiszemy.
Mam nadzieję, że zadziała i faktycznie
widzimy, że jest to odnośnik w tym momencie.
Po odświeżeniu zobaczymy czy coś się stało.
Jeszcze nam to wszystko myli.
Długo nam to minęło i faktycznie widzimy, że
po kliknięciu tego odnośnika mamy oryginalny odnośnik do francuskiej
Wikipedii, która swoją drogą wygląda dosyć inaczej.
Nie spodziewałem się, że tak ona może
wyglądać, ale jak widać odnośniki do oryginalnej treści działają.
Możemy przejść do wersji angielskiej artykułu o Gravity Falls i przenieść się
bezpośrednio na oryginalny angielski odnośnik.
Więc to by było tak naprawdę tyle w tej lekcji.
Chciałem tylko jeszcze raz w krótki i szybki, wygodny sposób pokazać,
jak można rozszerzyć przykład w naprawdę kilka chwil.
Jeżeli mamy dobre Foundation i w sumie możemy tak naprawdę w
międzyczasie posprzątać sobie tutaj tego stora powiedzmy.
Czyli na zasadzie, że
tutaj po prostu zamienimy to na full info tutaj na content.
Żeby nie było, że robimy kopiuj.
Wkleję, chociaż tak czy siak jest to dosyć monotonne.
Images.
Najnowsze oraz Rank links Zapisujemy.
Mamy nadzieję, że działa.
Oczywiście do takich rzeczy różne rodzaje testów, czy to jednostkowe, czy by się
przydały, żebyśmy nie musieli wierzyć temu, co robimy na słowo.
No i analogicznie możemy też zaktualizować wiki.
Routing to znaczy konkretnie end pointy, które znajdują się w wiki teraz
i jak widzimy jest tutaj naprawdę dużo podobnego kodu.
Jedyna różnica jest to nazwa tutaj funkcji używanej oraz nazwa
endpoint to w związku z czym zrobimy to także stworzymy sobie nowy router.
Powiedzmy, że damy go na samą górę i tutaj podmieniamy to na FN jak Faction.
Jest to troszkę ryzykowne posunięcie.
Moglibyśmy jakoś tutaj to zabezpieczyć,
żeby nie dało się wywołać funkcji, na których nam nie zależy.
Natomiast.
Teraz odnosząc się do tej FM możemy po prostu zrobić Page FN i wywołać tą funkcję
i wtedy powinien być tak naprawdę każdy z tych naszych przypadków obsłużonych.
Spróbujmy to w sumie skomentować i
zobaczmy czy zadziała to na tych endpoint u.
Tam się już otworzyło.
Zapisujemy.
Nie ma żadnych błędów w konsoli.
Co sobotę odświeżamy i faktycznie nasza strona dalej działa, a
mamy tylko i wyłącznie jeden endpoint, więc da się naprawdę uprościć kod,
niezależnie jak dobrymi programistami jesteśmy.
Zawsze można.
Celować wyżej.
Gdy poznamy dany framework następnymi krokami, tak czy siak zawsze są
jakieś nowe architektoniczne wyzwania czy design patterns.
W związku z czym przy okazji tej prostej prezentacji Fletchera, zwanego
odnośnikiem do oryginalnej strony pod sprzątaliśmy troszkę nasz kod.
Zmiany wprowadzone w lekcji · 7 min
diff --git a/30/minipedia/api/routes/wiki.js b/30/minipedia/api/routes/wiki.js
index 5e8b930..a520cd7 100644
--- a/30/minipedia/api/routes/wiki.js
+++ b/30/minipedia/api/routes/wiki.js
@@ -3,28 +3,10 @@ import WikiJs from 'wikijs';
const router = Router();
-router.get('/content/page/:id/lang/:lang', async (req, res) => {
+router.get('/:fn/page/:id/lang/:lang', async (req, res) => {
const lang = req.params.lang || 'en';
- const Wiki = WikiJs({
- apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
- headers: { 'User-Agent': process.env.BOT_USER_AGENT}
- });
+ const fn = req.params.fn;
- try {
- const id = req.params.id;
-
- const page = await Wiki.page(id);
- const content = await page.content();
- return res.status(200).json(content);
-
- } catch (e) {
- console.error(e);
- return res.status(500).json(e);
- }
-});
-
-router.get('/rawImages/page/:id/lang/:lang', async (req, res) => {
- const lang = req.params.lang || 'en';
const Wiki = WikiJs({
apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
headers: { 'User-Agent': process.env.BOT_USER_AGENT}
@@ -34,102 +16,7 @@ router.get('/rawImages/page/:id/lang/:lang', async (req, res) => {
const id = req.params.id;
const page = await Wiki.page(id);
- const content = await page.rawImages();
- return res.status(200).json(content);
-
- } catch (e) {
- console.error(e);
- return res.status(500).json(e);
- }
-});
-
-router.get('/summary/page/:id/lang/:lang', async (req, res) => {
- const lang = req.params.lang || 'en';
- const Wiki = WikiJs({
- apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
- headers: { 'User-Agent': process.env.BOT_USER_AGENT}
- });
- try {
- const id = req.params.id;
-
- const page = await Wiki.page(id);
- const content = await page.summary();
- return res.status(200).json(content);
-
- } catch (e) {
- console.error(e);
- return res.status(500).json(e);
- }
-});
-
-router.get('/langlinks/page/:id/lang/:lang', async (req, res) => {
- const lang = req.params.lang || 'en';
- const Wiki = WikiJs({
- apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
- headers: { 'User-Agent': process.env.BOT_USER_AGENT}
- });
- try {
- const id = req.params.id;
-
- const page = await Wiki.page(id);
- const content = await page.langlinks();
- return res.status(200).json(content);
-
- } catch (e) {
- console.error(e);
- return res.status(500).json(e);
- }
-});
-
-router.get('/summary/page/:id/lang/:lang', async (req, res) => {
- const lang = req.params.lang || 'en';
- const Wiki = WikiJs({
- apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
- headers: { 'User-Agent': process.env.BOT_USER_AGENT}
- });
- try {
- const id = req.params.id;
-
- const page = await Wiki.page(id);
- const content = await page.summary();
- return res.status(200).json(content);
-
- } catch (e) {
- console.error(e);
- return res.status(500).json(e);
- }
-});
-
-router.get('/mainImage/page/:id/lang/:lang', async (req, res) => {
- const lang = req.params.lang || 'en';
- const Wiki = WikiJs({
- apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
- headers: { 'User-Agent': process.env.BOT_USER_AGENT}
- });
- 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/lang/:lang', async (req, res) => {
- const lang = req.params.lang || 'en';
- const Wiki = WikiJs({
- apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
- headers: { 'User-Agent': process.env.BOT_USER_AGENT}
- });
- try {
- const id = req.params.id;
-
- const page = await Wiki.page(id);
- const content = await page.fullInfo();
+ const content = await page[fn]();
return res.status(200).json(content);
} catch (e) {
@@ -138,6 +25,4 @@ router.get('/fullInfo/page/:id/lang/:lang', async (req, res) => {
}
});
-
-
export default router;
\ No newline at end of file
diff --git a/30/minipedia/middleware/wiki-routing.js b/30/minipedia/middleware/wiki-routing.js
index e1b3904..9a39a6c 100644
--- a/30/minipedia/middleware/wiki-routing.js
+++ b/30/minipedia/middleware/wiki-routing.js
@@ -8,6 +8,7 @@ export default async function ({ store, route, $axios, app: { i18n }}) {
store.commit('setSummary', await $axios.$get(`/api/wiki/summary/page/${path}/lang/${lang}`))
store.commit('setRawImages', await $axios.$get(`/api/wiki/rawImages/page/${path}/lang/${lang}`))
store.commit('setMainImage', await $axios.$get(`/api/wiki/mainImage/page/${path}/lang/${lang}`))
+ store.commit('setOriginalUrl', await $axios.$get(`/api/wiki/url/page/${path}/lang/${lang}`))
} catch (e) {
console.error(e);
}
diff --git a/30/minipedia/pages/wiki/_id.vue b/30/minipedia/pages/wiki/_id.vue
index 635eb58..330e735 100644
--- a/30/minipedia/pages/wiki/_id.vue
+++ b/30/minipedia/pages/wiki/_id.vue
@@ -4,7 +4,7 @@
{{ $route.params.id }}
</h1>
- <span class="notice"> {{ $t('Disclaimer') }} </span>
+ <a :href="$store.state.originalUrl" class="notice"> {{ $t('Disclaimer') }} </a>
<FullInfoBox :content="$store.state.fullInfo.general" />
diff --git a/30/minipedia/store/index.js b/30/minipedia/store/index.js
index 4d6bdeb..1ae0682 100644
--- a/30/minipedia/store/index.js
+++ b/30/minipedia/store/index.js
@@ -4,26 +4,30 @@ export const state = () => ({
summary: null,
rawImages: null,
mainImage: null,
+ originalUrl: null,
langlinks: [],
})
export const mutations = {
- setFullInfo (state, text) {
- state.fullInfo = text
+ setFullInfo (state, fullInfo) {
+ state.fullInfo = fullInfo
},
- setContent (state, text) {
- state.content = text
+ setContent (state, content) {
+ state.content = content
},
- setSummary (state, text) {
- state.summary = text
+ setSummary (state, summary) {
+ state.summary = summary
},
- setRawImages (state, text) {
- state.rawImages = text
+ setRawImages (state, rawImages) {
+ state.rawImages = rawImages
},
- setMainImage (state, text) {
- state.mainImage = text
+ setMainImage (state, mainImage) {
+ state.mainImage = mainImage
},
- setLangLinks (state, text) {
- state.langlinks = text
+ setLangLinks (state, langLinks) {
+ state.langlinks = langLinks
+ },
+ setOriginalUrl(state, url) {
+ state.originalUrl = url;
}
}
\ No newline at end of file