IMA.js – setup aplikace a vytvoření modelů

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í.
Seriál: IMA.js: framework od Seznam.cz (5 dílů)
- Co je IMA.js? Podívejme se na framework od Seznam.cz 25. 2. 2020
- IMA.js – setup aplikace a vytvoření modelů 13. 3. 2020
- IMA.js – Načítání a vykreslování dat 29. 4. 2020
- IMA.js – Detailní pohled na komponenty, eventy a extensions 22. 9. 2020
- IMA.js – Testování aplikace 8. 12. 2020
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.
Ahoj Vojto.
Býval jsem docela fanda Imy a myslím, že jsme se potkali vašem taky na workshopu o ní.
Nicméně jsem měl za to, že projekt byl mrtvý stejně jako Este. Z jednoduchého důvodu, že vyšel Next.js.
Mohl bys prosím shrnout, v čem nyní spočívá gro a hlavní důvod zvolit imu a ne next.js?
jo, v Este jsem dělal, dělal jsem i v Next a musím uznat, že čistý React je lepší, přehlednější. Z mého pohledu ani Ima, ani Next nepřináší nic nového, resp. to co je v nich vyřešeno, není nic co bych nebyl schopen napsat. Nehledě na to, že osobně se mi architektura Nextu nelíbí. Next prošel docela bouřlivým vývojem, dost často se nám stávalo, že nová minor verze rozje**la projekt, přestal fungovat. Za sebe, Next povařuji za paskvil pro lidi, který jsou líní napsat pár řádek navíc. Jo Ima, kdyby vznikla, tak před 10 lety, ale teď je krapet zastarale, hlavně že se snaží do JS zavádět OOP a DI, které sem nepatří. Holt seznam…