CategoryNodeJS

NodeJS: neodchycené výjimky

Premisa 1: JavaScript, potažmo TypeScript, je komplexní, mocný programovací jazyk. Krom všeho možného 🙂
Premisa 2: všichni děláme chyby…

Je dobré o chybách vědět.
A to je cílem tohoto kódu:

Tento krátký kód se postará o obsluhu všech neodchycených výjimek kdekoliv v aplikaci. A proto je dobré jej umístit někam do míst startu aplikace, aby vše, co je španě, někde nepropadlo. V samotné funkci obsluhy výjimky pak může být cokoliv co vám dává smysl: výstup do konsole, notifikace někam přes sít, či cokoliv jiného co vám dává smysl.

Více zde.

NodeJS: Threads, práce s vlákny

NodeJS je báječný, a to hlavně díky svému Async I/O. Dalším silným znakem je to, že NodeJS je Single Threaded Event Loop Architecture. Jednoduché, čitelné a výkoné paradigma pro webové aplikace stavějící na Request/Response modelu.

Na základě tětchto principů se NodeJS moc nehodi na takové věci, jako je Machine Learning, nebo Artificial Intelligence, jinými slovy, úlohy závislé na silné paralelizaci. Byť vzhledem k tom, že je samotný javascriptový engine napsaný v C++ a nabízí tak dost vysoký výkon.

Tedy až do teď! 🙂

Od verze 10.5.0 umí NodeJS pracovat s vlákny! Což z něj dělá prostředí vhodné i pro věci kolem strojového učení a umělé inteligence. Funkcionalitu vláken přináší modul worker_threads.

Modul je dostupný od verze 10.5.0 a jen v při spuštění s paramatrem
--experimental-worker, protože se zatím jedná o novinku.

Příklad spuštění javascriptového kódu v několika, v tomto případě ve 2 vláknech.

Z příkladu je jasné, že v procesu potomka můžete spouštět jakýkoliv javascriptový kód, sdílet s rodičovským procesem proměnné (paměť) a také posílat si navzájem zprávy. Vše, co byste po vícevláknových aplikací požadovali.

Dokumentace modulu worker_threads.

ES moduly v NodeJS

Modularita, co by nezbytná vlastnost jakéhokoliv programovacího jazyka pro psaní velkých aplikací, je v NodeJS zajištěna pomocí funkce require. Samotnou fyzcickou definici a implementaci pak zajišťuje CommonJS.

Takže takto v NodeJS

JavaScript a import

JavaScript, skrze svou specifikaci ECMAScript 2015 zavádí, mimo jiné, i nové klíčové slova import a export pro možnost modularizovat javasxriptový kód.
To dovoluje následující zápis kódu:

Tohle vám bude například fungovat, pokud píšete React, VueJS, nebo Typescript aplikaci, protože ta je teprve skrze nějaký transpiler kompilována do požadované verze JavaScriptu.

Nicméně v NodeJS import nefunguje… Zatím 🙂

node –experimental-modules

A tady přichází na scénu parametr příkazového řádku --experimental-modules, který vám umožní v NodeJS používat klíčové slovo import místo require. Přesně tak, jak byste jej použili v Reactí apce…
Opravdu píšu místo, protože obě možnosti zatím nejdou kombinovat.
Takže pokud spustíte NodeJS script s tímto parametrem, můžete použít novou syntaxi pro importování, ale samozřejmě i exportování na úrovni modulu:

Dalším rozdílem je samotná přípona souboru se zdrojákem. Původní require funguje v klasických .js souborech, nově import pak v souborech s příponou .mjs.
Samozřejmě můžete import přímo psát do.js souboru a spouštět pokaždé s potřebným parametren, ale je to proti zavedené konvenci a navíc, nejde na první pohlef vidět jaký způsob práce s moduly jste použili.

Moje doporučení?

Pište v TypeScriptu 🙂 budete moct v .ts souborech použít obě konstrukce pro import, ale vedle toho mnohem víc věcí, které JavaScript dělají skutečně silným programovacím jazykem.

NPM: link

Pedpokládám, že každý kdo něco píše v JavaScriptu, nebo TypeScriptu zná NPM.
Pro ty co jsou tu prvně: největší a nejrychleji rostoucí repozitář (knihovna) javascriptových modulů. Samozřejmě se vším co k tomu patří.

Vedle toho, že NPM je nějaký síťový, skrze internet dostupný, centrálně spravovaný, byste třeba někdy chtěli dosáhnout stejného chování balíčků pomocí require pro nějaké vlastní, lokálně vyvíjené moduly, které neopustily disk vašeho notebooku.

NPM lokálně

Příklad

Mám někde na disku adresář, ve kterém mám vlastní implementaci super výkoné matematické knihovny:

zdrojový kód mé knihovny:

package.json v adresáři s knihovnou:

Tak a tenhle modul bych chtěl pak používat v dalších svých projektech stejně jako jakýkoliv jiný modul, který pochází z NPM.

Jak na to?

1. zaregistrování modulu

V adresáři s balíčkem ./my-math-lib spustím následující:

Tím dojde k vytvoření sym linku do globálního prostoru NPM balíčků na vašem stroji. O tom, že balíček se zaregistroval se přesvědčíte následovně:

2. samotné využití požadovaného balíčku

Pak už jen stačí v adresáři s projektem, kde chcete váš balíček používat spustit následující:

V podstatě náhrada za

Protože příkaz install by hledal a stahoval balíček z centrálního, síťového repozitáře a to nechceme.

Pak už můžeme v projekt klasicky použit require jak jsme zvyklý:

Resume

Celý fígl je v tom, že příkaz npm link vytváří symlinky mezi globálnín NPM uložištem na vašem stroji a adresářem node_modules v daném projektu.
Super je, že zůstává plně zachována plná funkcionalita práce s baličky, takže funguje i toto:

Tím dojde k odebrání balíčku z daného projketu, nicméně sdílený balíček půjde dál využívat v ostatních projektech.
Pokud budete chtít úplně zrušit sdílení lokálního balíčku, pak následovně:

Elegantní a hezhé řešení…

NodeJS: MongoDB callback VS async/await

Odjakživa co píšu v NodeJS se držím callbackového zápisu asynchronních funkcí. Callback-hellu se snažím vyhnout rozumnou dekompozicí řešené úlohy a Promises zápis mě nikdy nedostal… Nicméně s jazykovou konstrukcí async/await, která se do JavaScriptu dostala ve verzi ES2017, se dá leckdy kód napsat čitelněji, pochopitelněji a tím pádem snad i bezpečněji.

Takhle by tedy mohl vypadat kód pro čtení dat z MongoDB:

Původní callback implementace

Nová async/await implementace

Resumé

Na první pohled jde vidět několik věcí: ošetření všech chyb se přesouvá jen do jednoho místa a tím odpadá mnoho opakujícího se kódu, výsledek, načtená data nejsou nikde hluboce zanořená a nemusíte řešit problém s kaskádou otevřených závorek if-else větví.
Nutno podotknout, že výhoda nového zápisu ještě více vzroste v momentě, kdy máte sérii callback dotazů a obslužný kód vám začne ještě více narůstat.

Vedle toho si samozřejmě dokáži představit kód, kde bych se dál držel callback zápisu, ale to je věc konkrétního použití.

TypeScript: unit testy s Jest

Jest je, jak píše Facebook co by jeho tvůrce, skvělý JavaScriptový testovací framework. Jedná se o přímou náhradu, či konkurenci jinému, v současné době asi rozšířenějšímu, testovacímu frameworku, kterým je Mocha.

Proč Jest?

  • méně nutné konfigurace pro okamžité použití
  • velice jednoduché vše rozjet a okamžitě začít pokrývat zdroják testmi
  • na rozdíl od Mocha obsahuje i assert knihovnu (Chai) a mock knihovnu (SinonJS)
  • performance

Nicméně žádný z těchto důvodů nebrání použítí Mocha frameworku pro váš kokrétní projekt, či tým.

Jak na to?

Instalace

Předpokádám, že už máte nějaký NodeJS projekt a v něm package.json. Pak stačí jen doinstalovat pár balíčků nasledujícím způsobem:

Hotovo 🙂

Konfigurace

Do pakcage.json vložit konfiguraci pro Jest a následně upravit sekci script:test pro spuštění testů:

Samotná konfigurace Jestu může být alternativně uložena mimo package.json přímo do jest.config.js:

Vytvořte adresář __tests__ v root adresáři vašeho projektu. Adresář s testy se může samozřejmě pojmenovat jakkoliv jinak, stačí korektně přenastavit v konfiguraci.

Hotovo 🙂

Kódování, develop, vývoj…

Založte si src adresář a v něm vytvořte svůj nějaký soubor, který bude obsahovat váš TypeScript kód. Řekněme sum.ts, pro nějaké matematické funkce…

Hotovo. Máme knihovnu, která v tuto chvíli exportuje jednu jedinou funkcionalitu pro sčítání 2 čísel.

Konečně testování

V dříve založeném adresáři __tests__ vytvořte stejně jmenující se typescriptový soubor který bude obsahovat samotné testy, tentokrát s příponou .test.ts:

Hotovo 🙂 Můžeme testovat:

Výstupem je krom informace s výsledky testů i informace o tom, jak máte svůj zdroják testy pokrytý:

TDD

V rámci TDD si pak dokážu představit, že pro každou nově vyvíjenou funkcionalitu si nejdřív napíšete její testovací sekci, ve které pokryjete všechny scénáře, kterou mahou nastat a pak teprve začnete vyvíjet a píšete tak dlouho, dokud všechny zadefinované testy nejsou zelené 🙂

Zdroje

Jest homepage, dokumentace, blog

NVM, NPM problém

Pro běh NodeJS runtime používám NVM, který mi dovoluje do produkce dostat novější verzi NodeJS, než je v oficiálních balíčcích použité linuxové distribuce. A je v podstatě jedno, jestli běžíte na Centosu, Fedoře nebo Debianu, protože situace je v tomto ohledu všude stejná…

Vedle toho jsem v současné době začal vytvářet a distribuovat privátní NPM balíčky s funkcionalitami, které chci opakované používat ve více projektech. NPM je super. Vyvíjím v TypeScriptu, builduji balíček do čistého JavaScriptu, přidávám definice types (respektive se při vhodné konfiguraci generují sami), aby ostatní konzumenti mého balíčku věděli jak je použít.

Konfigurace produkce

Ale v podstatě i jakéhokoliv develop stroje, kde chcete mít přístup k privátním NPM balíčkům. Aby vám vše fungovalo jak má, je potřeba jen jemně dokonfigurovat prostředí. Úprava spočívá v úpravě .bashrc a .npmrc. Nic složitého:

1. Konfiguracve NVM

Někde na konci vašeho .bashrc přidejte pro NVM následující

Tím máte NVM funkční a můžete skrze něj instalovat požadované NodeJS runtimy:

A NodeJS vám běží v poslední dostupné stabilní verzí:

2. Konfigurace NPM
Vytvořte ~/.mpmrc a do něj vložte

A do svého .bashrc přidejte následující řádek:

Hotovo 🙂

No a tady přišel problém.

Pokud zmodifikujete své, nebo produkční prostředí, tak jak jsem popsal, přestane vám NodeJS fungovat 🙂
Problém je v nevinně vypadajícím export env proměnné NPM_TOKEN na konci vašeho .basrc. Pokud jej odeberete, nebo zakomentujete, bude vám NVM opět fungovat a tím pádem j node poběží…

Řešení

Stačí přemístit v .bashrc příkaz exportující NPM_TOKEN před příkazy exportující proměnné pro NVM…
Výsledná konfigurace v .bashrc by měla vypadat takto:

Funguje 🙂

SocketIO v NodeJS (předpověď počasí)

Našel jsem moc hezký článek jednoduše popisující SocketIO. Takže jestli hledáte technologické řešení, jak komunikovat s návštevníkem vaší www stránky v reálném čase, pak věřte, že to už nejde jednodušeji…

NodeJS: NODE_ENV dev || production

Taková ta uplná klasika: vyvíjíte aplikaci na svém stroji, kde máte samozřejmě úplně jinou konfiguraci, než na produkčním serveru, respektive také odlišnou od konfigurace kolegy, který se snaží psát pod Windejsi.
Tou jinou konfigirací může být cokoliv. Od propojení na externí služby až po způsob logování toho co a jak chcete vidět. Jasně že na developu vás zajíma víc věcí, které chcete na produkci vidět až když řešíte nějaký problém…

A řeči o tom, že byste měli kontejnerovat, dokrovat a tak vás taky nebaví. Nevidím jediný důvod, proč bych měl na svém lokále sestavovat nějaký dokr a pak spouštět virtuální stroj… WTF! Jediné co chci je spustit apku na mém mekovi prostě jinak nakonfigurovanou, ale funkčně pokud možná co nejvíc identickou s produkčním prostředím…

Dřív jsem rozdílnou konfiguraci do aplikace zaváděl skrze parametr příkazové řadky. Vstupní JS modul aplikace rozparsoval parametry příkazové řádky. Pokud našel parametr udávající soubor s konfigurací, pak se jej pokusil naimportovat. Pokud nic takové, pak natáhnul nějakou defaultní konfiguraci… Super. Funguje skvěle a umožnuje opravdu dobře nakonfigurovat kde co a to pokaždé úplně jinak. Prostě jak je libo…

Jenže jsem línější a línější a i tohle mi připadalo jako opruz. Je to přece jen nějaký kód navíc.. Já vím, že ne moc, ale je… Stačilo mi prostě něco lehčího.

NODE_ENV

A tak jsem se vrátil k NODE_ENV. Ne že bych o ní nevěděl, ale protože jsem vytvářel přece jen složitější struktury, mírně jsem podcenil možnosti této enviroment proměnné, a proto jí nějak moc rychle přeskočil. Chyba. NODE_ENV mi umožňuje dál lenošit a odpadl problém s konfigurací.

Jediné co jsem musel ořešit je jak NODE_ENV propašovat v různých způsobech spouštění, či využívání přímo do aplikace. Apku spouštím různě a nechtěl jsem se připravit o konfort kastomizovaných konfiguráků specifikovaných z příkazové řádky.

Základní implementace v package.json skrze sekci script:

Pokdud spouštíte apku z shellu, pak takto:

No a pokud potřebujete NODE_ENV sdílet s dalšími nástroji, jako je gulp, nebo cokoliv jiného, pak:

Samotný JS kód se pak k proměnné prostředí dostane odkudkoliv skrze globální promenou process, která obsahuje celý ENV, včetně toho co sami nějak nadefinujete:

Takže můj konfig dnes může vypadat i takto:

Samozřejmě se i tohle dá napsát jinak, dle libosti… 🙂

Nicméně tohle je obecný přístup, kterým se dá do vaší apky propašovat jakákoliv proměnná z prostředí operačního systému…

__main__ v NodeJS

Kdysi jsem tady popisoval jak v NodeJS připodobnit chování runtime při spouštění daného modulu. Něco, co se běžně v Pythonu dělá takto, ale v NodeJS se to moc nevidí:

Původně jsem v NodeJS tohle řešil následovně:

Další, možná o něco lépe vypadající řešení

Tahle podmínka mi prostě připadá logičtější 🙂

A k čemu je to dobré?

No třeba k samotnému testování… Jsem líný a někdy mi dělá problém dokopat se udělat nějaké testování nad modulem, kyterý je přece úplně jasnej: tady nemůže být žádná chyba…. A právě proto přímo dodaného modulu napíšu tuhle podmínku, která má nějakou sekci, která se provádí jen v případě, že modul spouštím přímo pod NodeJS a nerequiruji ho do nějakého dalšího, nadřazeného modulu.

© 2018 pepa.holla.cz

Theme by Anders NorénUp ↑