IMA.js – setup aplikace a vytvoření modelů
Publikováno: 13.3.2020
V tomto díle začneme psát naši ukázkovou aplikaci. Povedeme Vás od úplného začátku až po finální deployment do produkce. V průběhu si ukážeme využití všech hlavních vlastností IMA.js a jak vytvořit často používané prvky webových aplikací.
Minule jsme si framework IMA.js představili, dnes se pustíme do práce.
Ukázková aplikace bude zobrazovat počasí v místě, které:
- uživatel vyhledá pomocí našeho vyhledávání
- bude zadáno v URL parametru (SEO optimalizace)
- uživatel nastaví a uloží jej do cookies.
- je nastaveno v aplikaci jako výchozí, pokud se nepoužije žádná z výše uvedených možností.
Pro jednoduchost pojmenujeme aplikaci WeatherApp.
Devtooly
Než se pustíme do samotného vývoje ukázkové aplikace, rádi bychom zmínili naše vývojové nástroje v podobě rozšíření do prohlížeče Google Chrome, které si můžete stáhnout zde. Tyto nástroje poskytují jednoduchý způsob, jak sledovat a ladit jednotlivá volání a události, které ve Vaší aplikaci probíhají.
Vývojovým nástrojům se budeme blíže věnovat v následujících dílech, pokud však chcete, můžete je začít používat už teď. Případně si o jejich možnostech něco pročíst v dokumentaci.
Setup
Slíbili jsme, že to vezmeme od začátku, ale také to nebudeme prodlužovat. Na instalaci taky není nic zajímavého.
K vývoji budete potřebovat:
- Node.js ve verzi 10 a výše
- NPM ve verzi 6 a výše.
cd <-- Váš adresář kde máte projekty --> npx create-ima-app weather-app
Při dotazu na volbu typu projektu vyberte Empty
. IMA.js totiž nabízí 3 demo „aplikace“, ze kterých si můžete vybrat. Jejich ukázky najdete na imajs.io/examples.
Pro naši aplikaci postačí základní Empty (Hello world!). Můžete však použít i Todos (TODO list aplikace) nebo Feed (Twitter-like feed aplikace).
Tímto máme vytvořený skeleton aplikace a nainstalované závislosti.
Adresářová struktura
V adresáři naší aplikace vzniklo několik podadresářů: app
, build
, node_modules
a server
. My se budeme zabývat pouze adresářem app
(ostatní jsou vysvětleny svým názvem).
assets
– obsahuje soubory, které jsou zpracovány pre-processory a zkopírovány dobuild
adresáře.less
– LESS soubory definující obecná pravidla, makra, mixins a základní strukturu UI.static
– jakékoliv soubory, které nepotřebují preprocessing (JS soubory 3. stran, obrázky, …)
component
– naše React komponenty, které budeme používat ve views. Více o komponentách si řekneme v 3. díle tohoto seriálu.config
– konfigurační soubory aplikace. Nyní se konfigurací nebudeme zabývat a ukážeme si jednotlivé možnosti až je budeme potřebovat v průběhu vytváření aplikace.page
– controllery, views a LESS soubory k views.error
– stránka, která se zobrazí pokud se vyskytne chyba v průběhu aplikace.home
– hlavní stránka aplikacenotFound
– stránka, která se zobrazí pokud uživatel zadá URL na neexistující routu.
Adresáře assets
a config
jsou povinné a měly by se v aplikaci vždy nacházet. Ostatní jsou volitelné a můžete si je přejmenovat. Je však potřeba upravit některé konfigurace a přihlížet k tomu v následném vývoji aplikace.
Modely
Modely nám v IMA.js aplikacích umožňují pracovat s daty. Pomocí modelů se data načítají, odesílají a transformují. V našem případě budeme využívat základní sestavu modelů (Service
, Entity
, Resource
a Factory
).
Entity
představuje objekt držící data nějakého celku (uživatele, článku, …).Factory
vytváří ze surových dat instanceEntity
.Resource
stahuje data ze serveru pomocí HTTP požadavků.Service
se stará o načítání dat zResource
a následné vytvoření entit pomocíFactory
.
Může se vám zdát, že Factory
a Resource
jsou zbytečné. Data můžeme přece stahovat už v Service
a tam také vytváře instance Entity
. Ano to jistě můžeme, ale jen v jednodušších případech. Jak se bude aplikace rozrůstat a začnou se objevovat zanořené závislosti, věřte, že samostatné Factory
a Resource
přijdou vhod.
Pokud by aplikace využívala REST API, můžeme Factory
a Resource
úplně nahradit použitím @ima/plugin-rest-client. Více o tomto pluginu se dočtete v jeho README.
Na začátku jsme si stanovili, co naše aplikace bude umět. Podle toho si teď rozvrhneme datovou strukturu a vytvoříme modely.
1. Proxy
Data o počasí nám poskytne služba Počasí.cz přes svoje API rozhraní https://wapi.pocasi.seznam.cz
. My ale na toto API rozhraní budeme přistupovat přes naši proxy. Vyhneme se tak problémům s CORS.
Proxy vytvoříme na stejném serveru, který se stará o výdej webové aplikace. Ve výchozím stavu je server připravený pouze pro jednu proxy. My jich však budeme potřebovat více. V souboru weather-app/server/server.js
– funkce runNodeApp
– najdeme řádek:
.use(environment.$Proxy.path + '/', proxy(environment.$Proxy.server, environment.$Proxy.options)
Vidíme, že server používá Express framework a pro proxy jeden z jeho doplňků express-http-proxy. Nastavení proxy se nachází v souboru weather-app/app/environment.js
prod
, test
a dev
. Tyto klíče představují nastavení pro jednotlivé vývojové prostředí s tím, že všechny vycházejí z prod
prostředí.
Poznámka: Tento styl konfigurace (prod – test – dev) si zapamatujte, neobjevuje se naposledy.
Naši proxy potřebujeme nastavit pouze v produkčním nastavení.
// app/environment.js module.exports = (() => { return { prod: { // ... $Proxy: { path: '/api', // na této URL bude proxy poslouchat server: 'https://wapi.pocasi.seznam.cz', // zde bude proxy přeposílat požadavky options: { proxyReqPathResolver: function (req) { const queryString = req.url.split('?')[1]; return '/v2/forecast' + (queryString ? '?' + queryString : ''); } } } } // ... }
2. Načítání dat o předpovědi počasí
V předchozím bodě jsme si nastavili proxy, která poslouchá na URL /api
. Aby jsme URL neopakovali v aplikaci několikrát, přidáme ji do nastavení v souboru weather-app/app/config/
. Zde se používá stejný styl konfigurace jako v environment.js
.
// app/config/settings.js export default (ns, oc, config) => { // ... return { prod: { // ... App: { api: config.$Protocol + '//' + config.$Host + '/api' } } } }
V adresáři weather-app/app/model
vytvoříme podadresář pro předpověď počasí – forecast
. V tomto adresáři vytvoříme soubory ForecastService.js
, ForecastResource.js
, ForecastFactory.js
a ForecastEntity.js
.
Začneme vytvořením ForecastResource. V aplikaci IMA.js funguje DI (Dependency Injection) skrz OC (Object Container). Více o OC a DI se dočtete v dokumentaci.
// app/model/forecast/ForecastResource.js import { HttpAgent } from '@ima/core'; export default class ForecastResource { static get $dependencies() { return [HttpAgent, '$Settings.App.api']; // $Settings umožňuje vkládat nastavení pomocí DI } constructor(http, apiUrl) { this._http = http; this._api = apiUrl; } async getForecast(lat, lon) { const response = await this._http.get( this._api, { lat, lon, include: ['place', 'daily'] } // query parametry ); return response.body; } }
Následuje ForecastFactory. Prozatím bude obsahovat jen jednu metodu, která z předaných dat vytvoří instanci ForecastEntity.
// app/model/forecast/ForecastFactory.js import ForecastEntity from './ForecastEntity'; export default class ForecastFactory { static get $dependencies() { return []; } createEntity(data) { return new ForecastEntity(data); } }
ForecastEntity pouze vezme data z constructoru a vytvoří si z nich vlastní properties.
// app/model/forecast/ForecastEntity.js export default class ForecastEntity { constructor(data) { this.place = data.place; this.daily = data.daily; Object.freeze(this); } }
ForecastService bude obsahovat prozatím pouze jednu metodu getForecast
. Ta pomocí ForecastResource načte data ze serveru a poté vytvoří instance ForecastEntity pomocí ForecastFactory.
// app/model/forecast/ForecastService.js import ForecastResource from './ForecastResource'; import ForecastFactory from './ForecastFactory'; export default class ForecastService { static get $dependencies() { return [ForecastResource, ForecastFactory]; } constructor(resource, factory) { this._resource = resource; this._factory = factory; } async getForecast(lat, lon) { const result = await this._resource.getForecast(lat , lon); return this._factory.createEntity(res ult); }
Vytvořili jsme také model pro geocoder – vyhledávání místa podle názvu z URL. Nebudeme zde ale rozepisovat kompletní postup, protože se v mnohém shoduje s modelem pro předpověď počasí. Kompletní podobu geocoder modelu najdete v kódu ukázkové aplikace.
Závěr
Po tomto díle byste měli mít nainstalovanou a funkční IMA.js aplikaci. Zároveň jsme si připravili datovou vrstvu (modely) pro další díl, ve kterém si ukážeme, jak data načítat a zobrazovat.