Deno 2, TypeScript bez konfiguracji i uprawnienia
Deno to środowisko uruchomieniowe dla JavaScriptu i TypeScriptu, stworzone przez autora Node.js jako poprawka do rzeczy, które w tamtym projekcie uznał za błędy. Bieżące wydanie z lipca 2026 nosi numer 2.9.4.
Jeśli Twoja opinia o tym narzędziu pochodzi z pierwszej wersji, warto ją odświeżyć, bo druga odwróciła najważniejszą decyzję projektową i zmieniła powód, dla którego w ogóle warto po nie sięgać.
Co odwróciła druga wersja
Pierwsza odsłona miała wyraźną tezę: npm i katalog z zależnościami to pomyłka, więc importujemy prosto z adresów URL, a menedżera pakietów nie ma.
Teza była spójna i rozbiła się o rzeczywistość. Ekosystem npm liczy miliony pakietów i żaden projekt komercyjny nie zaczyna od porzucenia ich wszystkich. Ambitne środowisko bez dostępu do bibliotek, których zespół używa na co dzień, pozostawało ciekawostką.
Druga wersja tę decyzję odwróciła. Pakiety z npm działają natywnie, obsługiwana jest zdecydowana większość z nich, a wsteczna zgodność z Node została potraktowana jako cel, nie jako ustępstwo.
Praktyczny skutek jest taki, że powód sięgnięcia po to narzędzie przestał brzmieć „ucieczka od npm", a zaczął brzmieć „lepsze ustawienia domyślne". To jest znacznie słabszy argument marketingowo i znacznie mocniejszy w codziennej pracy.
Cztery rzeczy, które działają od razu
Warto je wymienić konkretnie, bo to one stanowią realną wartość.
TypeScript uruchamia się bez kroku budowania i bez pliku konfiguracyjnego. Piszesz plik z rozszerzeniem typowanym i uruchamiasz go poleceniem. Znika cała warstwa narzędzi, którą w projekcie na Node trzeba złożyć i utrzymywać.
Uprawnienia są odbierane domyślnie. Program bez jawnej zgody nie odczyta pliku, nie otworzy połączenia sieciowego i nie sięgnie po zmienne środowiskowe. Zgodę nadajesz przy uruchomieniu, wskazując konkretne katalogi i domeny.
Narzędzia są wbudowane. Formatowanie, analiza statyczna, uruchamianie testów, budowanie pojedynczego pliku wykonywalnego i generowanie dokumentacji przychodzą razem ze środowiskiem. Projekt startuje bez wybierania pięciu bibliotek i sklejania ich konfiguracji.
Interfejsy przeglądarkowe działają tak samo jak w przeglądarce. Pobieranie zasobów, obsługa strumieni, kryptografia i przechowywanie danych używają tych samych nazw, więc kod przenosi się między środowiskami bez tłumaczenia.
Uprawnienia, czyli najciekawszy pomysł
Ta jedna rzecz zasługuje na osobne omówienie, bo rozwiązuje realny problem, którego reszta ekosystemu nie rozwiązuje.
Pakiet zainstalowany w projekcie na Node ma pełny dostęp do wszystkiego: dysku, sieci, zmiennych środowiskowych, uruchamiania procesów. Nie ma tam poziomu, na którym dałoby się powiedzieć, że biblioteka do formatowania dat nie potrzebuje połączenia z internetem.
deno run --allow-net=api.mojafirma.pl --allow-read=./dane skrypt.tsTutaj taki poziom istnieje. Skrypt uruchomiony z powyższymi uprawnieniami nie połączy się z niczym poza wskazaną domeną i nie odczyta niczego poza wskazanym katalogiem, niezależnie od tego, co robią jego zależności.
Ma to dwa realne zastosowania. Przy skryptach pobieranych z internetu i uruchamianych jednorazowo daje pewność, że narzędzie do konwersji plików nie wyśle ich gdzie indziej. Przy projekcie z wieloma zależnościami ogranicza szkody z podmienionej wersji pakietu, czyli scenariusza, który zdarza się regularnie.
Uprawnienia można też sprawdzić i wywołać z poziomu kodu, co przydaje się w narzędziach proszących o dostęp dopiero wtedy, gdy jest potrzebny.
const stan = await Deno.permissions.query({ name: 'net', host: 'api.mojafirma.pl' })
if (stan.state !== 'granted') {
const wynik = await Deno.permissions.request({ name: 'net', host: 'api.mojafirma.pl' })
if (wynik.state !== 'granted') throw new Error('Brak zgody na polaczenie')
}Warto natomiast wiedzieć, gdzie ta ochrona się kończy. Uprawnienie do uruchamiania procesów obchodzi resztę, bo proces potomny dostaje własny zestaw. Podobnie szeroko udzielone uprawnienie sieciowe bez ograniczenia do domen. Wygodne skróty w postaci zgody na wszystko sprowadzają cały mechanizm do zera i są niestety tym, co ludzie wpisują najczęściej.
Zamiast wpisywać listę uprawnień przy każdym uruchomieniu, warto zapisać ją jako zadanie w pliku konfiguracyjnym projektu. Wtedy zestaw jest jeden, widoczny w repozytorium i podlega przeglądowi jak każda inna zmiana.
{
"tasks": {
"dev": "deno run --allow-net=api.mojafirma.pl --allow-read=./dane --watch main.ts",
"test": "deno test --allow-read=./dane --coverage=cov"
},
"imports": {
"@std/assert": "jsr:@std/assert@^1"
}
}Pakiety i skąd je brać
Dostępne są trzy drogi i warto rozumieć, kiedy która.
Pakiety z npm działają przez przedrostek w nazwie importu albo przez zwykły plik z listą zależności, w zależności od tego, jak wolisz. Wsteczna zgodność jest tu na tyle dobra, że większość projektów po prostu działa.
Rejestr własny tego środowiska stawia na TypeScript: pakiety publikuje się bez kroku budowania, dokumentacja generuje się z typów, a moduły działają zarówno tutaj, jak i w Node. To jest droga rozsądna przy publikowaniu własnych bibliotek i mniej istotna przy konsumowaniu cudzych, bo tam rozstrzyga to, co już istnieje.
Import prosto z adresu URL nadal działa i nadal ma sens przy skryptach jednoplikowych. Przy projekcie zespołowym warto go unikać, bo bez pliku z listą zależności i pliku blokującego wersje odtworzenie tego samego zestawu po pół roku jest kwestią szczęścia.
Do uruchamiania narzędzi bez instalowania służy osobne polecenie, będące odpowiednikiem tego, co w Node robi się wywołaniem uruchamiającym pakiet z rejestru. Przydaje się przy narzędziach używanych raz na jakiś czas.
Narzędzia wbudowane w praktyce
Warto rozwinąć ten punkt, bo brzmi jak wygoda, a przy dłuższym utrzymaniu jest czymś więcej.
Formatowanie i analiza statyczna działają bez konfiguracji i bez zależności w projekcie. Znika przy tym cała klasa dyskusji, które w zespołach potrafią ciągnąć się tygodniami: który zestaw reguł, która wtyczka, dlaczego u kolegi formatuje inaczej. Reguły są jedne i przychodzą ze środowiskiem.
Uruchamianie testów jest wbudowane i obsługuje pokrycie kodu bez dokładania czegokolwiek. To jest różnica wobec sytuacji, w której narzędzie do testów, narzędzie do pokrycia i wtyczka spinająca je z typami mają trzy niezależne cykle wydawnicze i regularnie się rozjeżdżają.
import { assertEquals } from '@std/assert'
import { policzRabat } from './rabaty.ts'
Deno.test('rabat progowy nalicza sie od tysiaca', () => {
assertEquals(policzRabat(999), 0)
assertEquals(policzRabat(1000), 50)
})deno fmt
deno lint
deno test --coverage=cov && deno coverage cov
deno compile --allow-net=api.mojafirma.pl -o narzedzie main.tsOstatnie polecenie jest tym, które najczęściej robi wrażenie. Powstaje jeden plik uruchamiany na maszynie bez zainstalowanego środowiska, a uprawnienia podane przy budowaniu zostają w nim zapieczętowane, więc odbiorca nie może ich po cichu rozszerzyć.
Budowanie pojedynczego pliku wykonywalnego zasługuje na osobne zdanie. Skrypt zamieniony w plik, który uruchamia się bez instalowania środowiska, rozwiązuje problem dystrybucji narzędzi wewnętrznych taniej niż kontener. Osoba, która ma go użyć, nie musi mieć niczego zainstalowanego.
Wbudowany magazyn klucz i wartość jest ostatnią z tych rzeczy i najrzadziej wymienianą. Przy prostych narzędziach, gdzie trzeba coś zapamiętać między uruchomieniami, oszczędza stawiania bazy dla trzech wartości.
Cena tego wszystkiego jest jedna i warto ją znać: dostajesz zestaw wybrany przez autorów, a nie przez siebie. Przy zespole mającym własne, dopracowane przez lata ustawienia to bywa krokiem wstecz, a nie naprzód.
Kiedy to się naprawdę opłaca
Trzy scenariusze, w których przewaga jest wyraźna i mierzalna.
Pierwszy to skrypty. Zadanie automatyzujące coś w firmie, uruchamiane raz w tygodniu, w typowym ekosystemie wymaga pliku z zależnościami, konfiguracji kompilatora i kroku budowania. Tutaj jest jednym plikiem, który się uruchamia, i to jest różnica między godziną a pięcioma minutami.
Drugi to narzędzia wewnętrzne rozdawane zespołowi. Pojedynczy plik wykonywalny, uprawnienia ograniczone do tego, czego narzędzie faktycznie potrzebuje, i brak wymagań instalacyjnych po stronie odbiorcy.
Trzeci to kod, który ma działać zarówno w przeglądarce, jak i poza nią. Interfejsy są te same, więc biblioteka napisana raz działa w obu miejscach bez warstwy tłumaczącej, co przy narzędziach współdzielonych między frontendem a zapleczem oszczędza sporo kodu.
Poza tymi trzema scenariuszami decyzja robi się mniej oczywista i warto ją oprzeć na czynnikach spoza samego środowiska: co zna zespół, jakie narzędzia zakłada Wasz proces wdrożeniowy i czy ktokolwiek poza autorem będzie to utrzymywał.
Deno kontra alternatywy
| Środowisko | Mocna strona | Słabość | Kiedy wybrać |
|---|---|---|---|
| Deno | Ustawienia domyślne, uprawnienia, narzędzia w komplecie | Mniejszy ekosystem wokół samego środowiska | Nowy projekt, skrypty, narzędzia wewnętrzne |
| Node.js | Największy ekosystem i rynek pracy | Konfiguracja narzędzi po Twojej stronie | Projekt komercyjny z długim utrzymaniem |
| Bun | Szybkość uruchamiania i instalacji | Krótsza historia w produkcji | Zależy Ci głównie na czasie budowania |
| Środowiska brzegowe | Bliskość użytkownika, skalowanie | Ograniczony zestaw interfejsów | Proste funkcje odpowiadające na żądania |
Wybór między pierwszym a drugim wierszem nie jest już kwestią możliwości, bo te się zbliżyły. Jest kwestią tego, ile konfiguracji chcesz utrzymywać i czy uprawnienia są dla Ciebie wartością.
Przy narzędziach wewnętrznych, skryptach automatyzujących i małych usługach pierwszy wiersz wygrywa wyraźnie, bo projekt startuje w minutę zamiast w godzinę. Przy dużej aplikacji komercyjnej drugi nadal ma przewagę, którą trudno podważyć: więcej osób go zna, więcej narzędzi go zakłada i więcej problemów jest już opisanych.
Warto też pamiętać, że TypeScript uruchamiany bez konfiguracji to wygoda, a nie sprawdzanie typów w potoku budowania. Środowisko usuwa typy przy uruchomieniu, więc osobny krok sprawdzający nadal jest potrzebny, jeśli chcesz, żeby błędy zatrzymywały wdrożenie.
Gdzie to nadal zawodzi
Uczciwa lista jest krótsza niż kiedyś i wciąż istnieje.
Pakiety sięgające po natywne rozszerzenia bywają kłopotliwe. Zgodność obejmuje zdecydowaną większość, natomiast biblioteki kompilowane do kodu maszynowego są tą częścią, która potrafi nie zadziałać, i sprawdza się to wyłącznie na własnym zestawie zależności.
Narzędzia zakładające konkretne środowisko to druga kategoria. Część rozwiązań z ekosystemu wokół Next.js i podobnych frameworków zakłada obecność Node i jego układu katalogów, więc uruchomienie ich gdzie indziej wymaga pracy zamiast zmiany jednej komendy.
Trzecia to zespół. Środowisko, którego nikt poza autorem nie zna, jest długiem, nawet jeśli technicznie jest lepsze. Przy wyborze na projekt komercyjny warto to policzyć razem z resztą.
Osobno warto odnotować spór o znak towarowy nazwy JavaScript, który firma stojąca za tym środowiskiem prowadzi z jej właścicielem. Dla użytkownika nie ma to znaczenia praktycznego, natomiast pojawia się w materiałach na tyle często, że warto wiedzieć, czego dotyczy.
Wdrożenie i uruchamianie
Kilka rzeczy oszczędza czas przy pierwszym projekcie.
Plik konfiguracyjny środowiska trzyma listę zależności, zadania i ustawienia narzędzi w jednym miejscu. Warto go założyć nawet przy małym projekcie, bo zadania zdefiniowane raz zastępują pamiętanie długich poleceń z uprawnieniami.
Plik blokujący wersje zależności zapisuj do repozytorium. Bez niego odtworzenie tego samego zestawu na innej maszynie jest kwestią przypadku, dokładnie tak samo jak w każdym innym ekosystemie.
Uprawnienia definiuj wąsko od początku. Zaczęcie od zgody na wszystko z zamiarem zawężenia później kończy się tym, że nikt tego nie zawęża, a cały mechanizm przestaje cokolwiek dawać.
Budowanie pojedynczego pliku wykonywalnego jest tu funkcją wbudowaną i bywa niedocenianą zaletą. Narzędzie wewnętrzne rozdawane zespołowi jako jeden plik, bez wymogu instalowania czegokolwiek, rozwiązuje problem, który zwykle rozwiązuje się kontenerem.
Do wdrożenia usług sprawdzają się zarówno platformy ogólne, na przykład Railway, jak i platforma tworzona przez autorów środowiska. Wybór zależy od tego, czy potrzebujesz zwykłego kontenera, czy funkcji uruchamianych blisko użytkownika.
Typowe błędy
Pierwszy to uruchamianie ze zgodą na wszystko. Mechanizm uprawnień przestaje wtedy istnieć, a został wymieniony jako główny powód wyboru tego środowiska.
Drugi to opinia oparta na pierwszej wersji. Druga odwróciła podejście do npm, więc argumenty o braku dostępu do bibliotek są nieaktualne.
Trzeci to importowanie prosto z adresów URL w projekcie zespołowym. Bez pliku blokującego wersje odtworzenie zestawu zależności staje się loterią.
Czwarty to zakładanie, że uruchomienie TypeScriptu bez konfiguracji zastępuje sprawdzanie typów. Typy są usuwane przy uruchomieniu, więc osobny krok sprawdzający nadal jest potrzebny.
Piąty to wybór tego środowiska na duży projekt komercyjny wyłącznie z powodów technicznych. Znajomość w zespole i dojrzałość narzędzi wokół są tu czynnikami równie ważnymi.
Szósty to pominięcie sprawdzenia zależności natywnych. Zgodność jest wysoka, a te akurat są tą częścią, która potrafi zawieść, i widać to dopiero na własnym zestawie.
FAQ
Czy Deno działa z pakietami npm?
Tak, od drugiej wersji natywnie, a wsteczna zgodność z Node była celem tego wydania. Obsługiwana jest zdecydowana większość pakietów, przy czym te sięgające po rozszerzenia natywne warto sprawdzić na własnym zestawie zależności.
Czym różni się od Node.js?
Ustawieniami domyślnymi. TypeScript działa bez konfiguracji, uprawnienia są odbierane domyślnie, a formatowanie, analiza statyczna i testy przychodzą razem ze środowiskiem. Node nadrabia większym ekosystemem i szerszą znajomością w zespołach.
Czy uprawnienia rzeczywiście chronią?
Chronią przed zależnością, która sięga tam, gdzie nie powinna, o ile udzielasz ich wąsko. Zgoda na wszystko albo szerokie uprawnienie do uruchamiania procesów sprowadza ten mechanizm do zera, a to jest niestety najczęstszy sposób użycia.
Czy potrzebuję osobnego sprawdzania typów?
Tak, jeśli chcesz, żeby błędy zatrzymywały wdrożenie. Środowisko usuwa typy przy uruchomieniu, więc kod z błędem typu uruchomi się, dopóki błąd nie objawi się w czasie działania. Sprawdzanie warto dodać jako osobny krok w potoku.
Kiedy wybrać Deno zamiast Node?
Przy narzędziach wewnętrznych, skryptach automatyzujących i mniejszych usługach, gdzie oszczędność na konfiguracji jest odczuwalna od pierwszego dnia. Przy dużej aplikacji komercyjnej z długim utrzymaniem przewaga ekosystemu i znajomości w zespole zwykle przeważa.
Dokumentacja stoi na stronie projektu, a wydania w repozytorium na GitHubie.