<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/feeds/stylesheet.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	
	
	<link href="https://blog.comandeer.pl/feeds/feed.xml" rel="self" type="application/atom+xml"/>
	<link href="https://blog.comandeer.pl/" rel="alternate" type="text/html"/>
	<updated>2026-09-07T18:40:22.477Z</updated>
	<id>https://blog.comandeer.pl/feeds/feed.xml</id>
	<title type="html">Comandeerowy blog</title>
	
		<subtitle>Kolejny nudny blog kolejnego nudnego fanatyka JS-a. Nie czytać, nie warto tracić czasu.</subtitle>
	
	
		
	
	
		<entry>
			<title type="html">Pakując manatki</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/pakujac-manatki" rel="alternate" type="text/html"/>
			<published>2026-08-03T16:20:00.000Z</published>
			<updated>2026-08-03T16:20:00.000Z</updated>
			<id>https://blog.comandeer.pl/pakujac-manatki</id>
			
				<summary><![CDATA[Zaczynamy opakowywać czasomierze w pakiet npm!]]></summary>
			
			<content type="html"><![CDATA[<p><a href="https://blog.comandeer.pl/podsumowanie-2025">Tak jak obiecałem</a>, na początku tego roku – w ten piękny zimowy dzionek – zajmujemy się zrobieniem z naszych czasomierzy pełnoprawnego pakietu npm!</p>

<h2 id="erm"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#erm">Erm…</a></h2>
<p>Dzięki temu, że mamy styczeń, mamy też mnóstwo czasu na… Że co? Że jest już&nbsp;sierpień?!</p>
<figure class="figure"><a class="figure__link" href="/assets/images/pakujac-manatki/blink-meme-640w.avif"><picture><source type="image/avif" srcset="/assets/images/pakujac-manatki/blink-meme-440w.avif 440w, /assets/images/pakujac-manatki/blink-meme-640w.avif 640w" sizes="90vw"><source type="image/webp" srcset="/assets/images/pakujac-manatki/blink-meme-440w.webp 440w, /assets/images/pakujac-manatki/blink-meme-640w.webp 640w" sizes="90vw"><source type="image/jpeg" srcset="/assets/images/pakujac-manatki/blink-meme-440w.jpeg 440w, /assets/images/pakujac-manatki/blink-meme-640w.jpeg 640w" sizes="90vw"><img src="/assets/images/pakujac-manatki/blink-meme-640w.jpeg" width="640" height="394" style="aspect-ratio: 640 / 394" alt="Mężczyzna w styczniu zamyka oczy, by mrugnąć, ale gdy je otwiera, jest już sierpień." loading="lazy" decoding="async"></picture></a><figcaption class="figure__caption"><p>Ja w tym roku</p></figcaption></figure>
<p>No więc tak, projekt czasomierzy zdecydowanie zaliczył poślizg – ale hej! To raptem tylko 7 miesięcy, <a href="https://www.youtube.com/watch?v=NuAKnbIr6TE" rel="noreferrer noopener">nie ma powodów do paniki</a>. Wróćmy może do kodu…!</p>
<h2 id="tworzymy-repozytorium"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#tworzymy-repozytorium">Tworzymy repozytorium</a></h2>
<div class="note" role="note" aria-labelledby="note-73"><p class="note__label" id="note-73">Dygresja</p><div class="note__content"><p>Ten artykuł zakłada, że masz zainstalowanego <a href="https://git-scm.com/install/" rel="noreferrer noopener">gita</a> oraz <a href="https://nodejs.org/en/download" rel="noreferrer noopener">Node’a</a> z <a href="https://docs.npmjs.com/cli/v12/configuring-npm/install" rel="noreferrer noopener">npm-em</a>.</p></div></div>
<p>Jeśli spojrzymy na stronę przykładowego pakietu npm, np. <a href="https://www.npmjs.com/package/react" rel="noreferrer noopener">Reacta</a>, zauważymy, że składa się ona&nbsp;z dwóch części: dokumentacji pakietu oraz dodatkowych informacji o nim (instrukcji instalacji, liczby pobrań, itd.). Większość pakietów wśród tych informacji zawiera także linka do repozytorium, w którym znaleźć można ich kod źródłowy – tak jest też <a href="https://github.com/react/react" rel="noreferrer noopener">w przypadku Reacta</a>. Najczęściej takie repozytorium jest hostowane na <a href="https://github.com/" rel="noreferrer noopener">GitHubie</a> (GH). Na dzień dzisiejszy to największe miejsce, w którym rozwijane jest oprogramowanie open source. GitHub, jak sama nazwa wskazuje, został zbudowany wokół <a href="https://git-scm.com/" rel="noreferrer noopener">systemu kontroli wersji git</a>.</p>
<p>Z racji tego, że większość pakietów npm zaczyna się od repozytorium na GH i jest to w sumie dość&nbsp;wygodny sposób rozwijania oprogramowania open source, to nasze czasomierze również tam wylądują. W tym celu należy <a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository" rel="noreferrer noopener">stworzyć repozytorium</a>. W trakcie tworzenia GitHub zapyta nas o parę rzeczy:</p>
<ul>
<li><strong>Nazwa repozytorium</strong> – z racji tego, że projekt nazywa się <cite>czasomierze</cite>, tak też wypada nazwać nasze repozytorium. Aczkolwiek nazwa może być całkowicie dowolna.</li>
<li><strong>Opis</strong> – krótki opis zawartości repozytorium. Można go całkowicie pominąć.</li>
<li><strong>Widoczność repozytorium</strong> – publiczne repozytoria są widoczne dla wszystkich, podczas gdy prywatne tylko dla nas i osób, które zaprosimy. W przypadku czasomierzy nie ma to większego znaczenia. Ja zwykle wybieram publiczne repozytoria, bo nie widzę potrzeby chowania kodu open source.</li>
<li><strong>Szablon</strong> – pewien czas temu GitHub dodał <a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository" rel="noreferrer noopener">szablony</a>, czyli specjalny typ repozytoriów, które można wykorzystywać&nbsp;jako punkt startowy do własnych projektów. W przypadku czasomierzy szablon nie jest nam potrzebny.</li>
<li><strong>Plik <code>README</code></strong> – GitHub może stworzyć ten plik za nas.</li>
<li><strong>Plik <code>.gitignore</code></strong> – GitHub może stworzyć za nas również ten plik. Z listy wybrać można wykorzystywaną technologię, żeby był jak najlepiej dostosowany do projektu. W naszym przypadku “Node” może się dobrze sprawdzić.</li>
<li><strong>Plik <code>LICENSE</code></strong> – kolejny plik, który GitHub może wygenerować dla nas. Ja zwykle używam <a href="https://opensource.org/license/mit" rel="noreferrer noopener">licencji MIT</a>.</li>
</ul>
<div class="note" role="note" aria-labelledby="note-74"><p class="note__label" id="note-74">Dygresja</p><div class="note__content"><p>W dalszej części artykułu opisuję pokrótce te pliki.</p></div></div>
<p>Gdy już stworzymy repozytorium na GitHubie, wypada je <a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository" rel="noreferrer noopener">sklonować lokalnie</a>, by móc na nim pracować:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">Shell</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">git</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> clone</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> git@github.com:Comandeer/czasomierze.git</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><h2 id="tworzymy-szkielet"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#tworzymy-szkielet">Tworzymy szkielet</a></h2>
<p>Gdy już mamy repozytorium postawione, trzeba w nim dodać pewne podstawowe pliki.</p>
<h3 id="gitignore"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#gitignore"><code>.gitignore</code></a></h3>
<p>Zacznijmy od magicznego <a href="https://git-scm.com/docs/gitignore" rel="noreferrer noopener">pliku <code>.gitignore</code></a>. Zawiera on listę plików i folderów, które git ma ignorować. Takie pliki nie znajdą się&nbsp;w repozytorium. Zwyczajowo omija się w ten sposób np. katalog <code>node_modules</code>, zawierający zależności, oraz katalog zawierający zbudowaną/skompilowaną wersję projektu. Stąd na potrzeby naszego projektu wypada dodać następujące wpisy do pliku:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage"></span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span>dist/</span></span>
<span class="line"><span>node_modules/</span></span>
<span class="line"><span></span></span></code></pre>

			</div>
		</figure><div class="note" role="note" aria-labelledby="note-75"><p class="note__label" id="note-75">Dygresja</p><div class="note__content"><p>Jeśli plik został wygenerowany przez GitHuba, prawdopodobnie zawiera już&nbsp;wszystkie potrzebne wpisy.</p><p>Natomiast kwestię pomijania akurat zależności i zbudowanej wersji pozwolę sobie poruszyć w osobnym artykule.</p></div></div>
<h3 id="packagejson"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#packagejson"><code>package.json</code></a></h3>
<p><a href="https://docs.npmjs.com/cli/v12/configuring-npm/package-json/" rel="noreferrer noopener">Plik <code>package.json</code></a> to podstawowy plik w każdym pakiecie npm. Zawiera wszystkie najważniejsze informacje o nim, takie jak nazwa, lista zależności, skrypty itd. Nie musimy go jednak tworzyć&nbsp;ręcznie, możemy wykorzystać do tego <a href="https://docs.npmjs.com/cli/v12/commands/npm-install" rel="noreferrer noopener">komendę <code>npm init</code></a>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">Shell</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">npm</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> init</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> --y</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Komenda pyta o różne rzeczy, takie jak nazwa pakietu. Możemy to pominąc, dodając flagę <code>--y</code>. Informuje ona npm, że akceptujemy wszystkie sugerowane wartości. Dzięki temu powinniśmy dostać mniej więcej taki plik <code>package.json</code>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSON</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "name"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"czasomierze"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "version"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"1.0.0"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "description"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"A simpler and friendler timers."</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "main"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"index.js"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "scripts"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "test"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"echo </span><span style="color:#005CC5;--shiki-dark:#79B8FF">\"</span><span style="color:#032F62;--shiki-dark:#9ECBFF">Error: no test specified</span><span style="color:#005CC5;--shiki-dark:#79B8FF">\"</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> &amp;&amp; exit 1"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  },</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "repository"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "type"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"git"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "url"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"git+https://github.com/Comandeer/czasomierze.git"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  },</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "keywords"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: [],</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "author"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">""</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "license"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"ISC"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "type"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"commonjs"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "bugs"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "url"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"https://github.com/Comandeer/czasomierze/issues"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  },</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "homepage"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"https://github.com/Comandeer/czasomierze#readme"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Wprowadzimy do niego jednak kilka modyfikacji. Po pierwsze, pole <code>type</code> zmienimy z <code>commonjs</code> na <code>module</code>, a pole <code>main</code> zastąpimy <a href="https://nodejs.org/api/packages.html#exports" rel="noreferrer noopener">polem <code>exports</code></a>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSON</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "exports"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">        "."</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">            "types"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"./dist/index.d.ts"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">            "import"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"./dist/index.js"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">        }</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><div class="note" role="note" aria-labelledby="note-76"><p class="note__label" id="note-76">Dygresja</p><div class="note__content"><p>Dzięki tym zmianom informujemy npm oraz Node.js, że nasz pakiet jest w formacie ESM. Co to dokładnie oznacza, opiszę w jednych z kolejnych artykułów.</p></div></div>
<p>Dodamy też pole <code>files</code>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSON</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "files"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#032F62;--shiki-dark:#9ECBFF">    	"dist"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">    ]</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Dzięki niemu przy publikacji pakietu zostaną opublikowane tylko pliki z katalogu <code>dist</code> – a więc skompilowana wersja naszej biblioteki.</p>
<div class="note" role="note" aria-labelledby="note-77"><p class="note__label" id="note-77">Dygresja</p><div class="note__content"><p>Tak, publikacji pakietu również&nbsp;będzie poświęcony osobny artykuł.</p></div></div>
<p>A jak już mowa o skompilowanej wersji biblioteki mowa, to warto od razu <a href="https://docs.npmjs.com/cli/v12/commands/npm-install" rel="noreferrer noopener">zainstalować</a> transpiler TypeScripta:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">Shell</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">npm</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> i</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> -D</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> typescript</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Ta komenda zainstaluje najnowszą&nbsp;wersję TS-a i doda ją do zależności developerskich projektu. Potrzebujemy jeszcze skryptu, dzięki któremu zbudujemy naszą bibliotekę:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSON</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">	"scripts"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"build"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"tsc"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Dzięki temu będziemy mogli wywołać komendę <code>npm run build</code>, która stworzy z naszych plików TS pliki JS.</p>
<p>Warto także dodać autora (<code>author</code>), słowa kluczowe (<code>keywords</code>) czy opis (<code>description</code>). Osobiście zmieniam także wersję na niższą, jak <code>0.0.1</code> czy <code>0.1.0</code>. Pierwszą&nbsp;wersję&nbsp;bezpieczniej opublikować z takim <em>eksperymentalnym</em> numerem, zamiast psuć&nbsp;sobie od razu <em>poważną</em> wersję&nbsp;<code>1.0.0</code>, gdyby coś poszło nie tak.</p>
<p>Ostatecznie nasz plik <code>package.json</code> powinien wyglądać mniej więcej tak:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSON</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "name"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"czasomierze"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "version"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"0.0.1"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "description"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"A simpler and friendler timers."</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "type"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"module"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "exports"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "."</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">      "types"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"./dist/index.d.ts"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">      "import"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"./dist/index.js"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  },</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "files"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#032F62;--shiki-dark:#9ECBFF">    "dist"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  ],</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "scripts"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "build"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"tsc"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  },</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "repository"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "type"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"git"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "url"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"git+https://github.com/Comandeer/czasomierze.git"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  },</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "keywords"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#032F62;--shiki-dark:#9ECBFF">    "timers"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  ],</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "author"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"Comandeer"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "license"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"MIT"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "bugs"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "url"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"https://github.com/Comandeer/czasomierze/issues"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  },</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "homepage"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"https://github.com/Comandeer/czasomierze#readme"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">  "devDependencies"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">    "typescript"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"7.0.2"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">  }</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><h3 id="package-lockjson"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#package-lockjson"><code>package-lock.json</code></a></h3>
<p>Po instalacji TypeScriptu powinien pojawić się plik <code>package-lock.json</code>. To plik zawierający dokładne informacje o zainstalowanych zależnościach i wersjach. Na ten moment nie musimy się nim martwić, wrócimy do niego w artykule o zależnościach.</p>
<h3 id="tsconfigjson"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#tsconfigjson"><code>tsconfig.json</code></a></h3>
<p>Żeby móc transpilować naszą&nbsp;bibliotekę, przyda się&nbsp;także <a href="https://www.typescriptlang.org/tsconfig/" rel="noreferrer noopener">konfiguracja TypeScriptu</a>, którą zapiszemy w pliku <code>tsconfig.json</code>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSON</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">	"include"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#032F62;--shiki-dark:#9ECBFF">		"src/**/*"</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	],</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">	"compilerOptions"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"rootDir"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"./src"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"outDir"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"dist/"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"module"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"nodenext"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"moduleResolution"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"nodenext"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"resolveJsonModule"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"target"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">"esnext"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"declaration"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"declarationMap"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"sourceMap"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"skipLibCheck"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"verbatimModuleSyntax"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"allowImportingTsExtensions"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"rewriteRelativeImportExtensions"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"strict"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"strictNullChecks"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"exactOptionalPropertyTypes"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"noImplicitOverride"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"noUncheckedIndexedAccess"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"noFallthroughCasesInSwitch"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"noImplicitReturns"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#005CC5;--shiki-dark:#79B8FF">		"noPropertyAccessFromIndexSignature"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">: </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Nie będę wchodził w szczegóły – to zdecydowanie temat na osobny artykuł. Wypada jedynie wspomnieć, że pole <code>include</code> zawiera listę plików, które mają zostać stranspilowane, natomiast opcja <code>compilerOptions.outDir</code> – ścieżkę do katalogu, w którym mają&nbsp;być zapisane wygenerowane pliki JS.</p>
<h3 id="srcindexts"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#srcindexts"><code>src/index.ts</code></a></h3>
<p>To plik zawierający kod naszych czasomierzy! To <a href="https://blog.comandeer.pl/projektujemy-czasomierze#ca%C5%82o%C5%9B%C4%87-kodu">niemal ten sam kod</a>, co w poprzednim artykule:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">TypeScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">type</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Hours</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> `${</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }h`</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">type</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Minutes</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> `${</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }m`</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">type</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Seconds</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> `${</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }s`</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">type</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> MiliSeconds</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> `${</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }ms`</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">type</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Delay</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	|</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	|</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Exclude</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;</span></span>
<span class="line"><span style="color:#032F62;--shiki-dark:#9ECBFF">		`${</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Hours</span><span style="color:#D73A49;--shiki-dark:#F97583"> |</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> ''}${</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Minutes</span><span style="color:#D73A49;--shiki-dark:#F97583"> |</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> ''</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }${</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Seconds</span><span style="color:#D73A49;--shiki-dark:#F97583"> |</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> ''</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }${</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> MiliSeconds</span><span style="color:#D73A49;--shiki-dark:#F97583"> |</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> ''}`</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#032F62;--shiki-dark:#9ECBFF">		''</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	&gt;;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">interface</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> SetTimeoutOptions</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">	signal</span><span style="color:#D73A49;--shiki-dark:#F97583">?:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> AbortSignal</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">export</span><span style="color:#D73A49;--shiki-dark:#F97583"> async</span><span style="color:#D73A49;--shiki-dark:#F97583"> function</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> wait</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 1</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">	delay</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Delay</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	{ </span><span style="color:#E36209;--shiki-dark:#FFAB70">signal</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> }</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> SetTimeoutOptions</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {}</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Promise</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;</span><span style="color:#005CC5;--shiki-dark:#79B8FF">number</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt; {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	return</span><span style="color:#D73A49;--shiki-dark:#F97583"> new</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> Promise</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( ( </span><span style="color:#E36209;--shiki-dark:#FFAB70">resolve</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#E36209;--shiki-dark:#FFAB70">reject</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) </span><span style="color:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">		if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( signal?.aborted ) {</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">			reject</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( signal.reason );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">			return</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">		const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> delayInMs</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> convertDelayToMs</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( delay );</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">		const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> timeoutId</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> globalThis.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">setTimeout</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( () </span><span style="color:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">			resolve</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( Date.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">now</span><span style="color:#24292E;--shiki-dark:#E1E4E8">() );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		}, delayInMs );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">		if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( signal </span><span style="color:#D73A49;--shiki-dark:#F97583">!==</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> undefined</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">			signal.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">addEventListener</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'abort'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, () </span><span style="color:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">				clearTimeout</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( timeoutId );</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">				reject</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( signal.reason );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">			} );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		}</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	} );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">export</span><span style="color:#D73A49;--shiki-dark:#F97583"> async</span><span style="color:#D73A49;--shiki-dark:#F97583"> function*</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> tick</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 2</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">	tick</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Delay</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">	options</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> SetTimeoutOptions</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {}</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> AsyncIterableIterator</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;</span><span style="color:#005CC5;--shiki-dark:#79B8FF">number</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt; {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	while</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( </span><span style="color:#005CC5;--shiki-dark:#79B8FF">true</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">		yield</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> wait</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( tick, options );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">interface</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> DelayGroups</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">	hours</span><span style="color:#D73A49;--shiki-dark:#F97583">?:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Hours</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">	minutes</span><span style="color:#D73A49;--shiki-dark:#F97583">?:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Minutes</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">	seconds</span><span style="color:#D73A49;--shiki-dark:#F97583">?:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Seconds</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">	miliseconds</span><span style="color:#D73A49;--shiki-dark:#F97583">?:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> MiliSeconds</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">function</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> convertDelayToMs</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#E36209;--shiki-dark:#FFAB70">delay</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Delay</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> )</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( </span><span style="color:#D73A49;--shiki-dark:#F97583">typeof</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> delay </span><span style="color:#D73A49;--shiki-dark:#F97583">===</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> 'number'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">		return</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> delay;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> delayRegex</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> /</span><span style="color:#D73A49;--shiki-dark:#F97583">^</span><span style="color:#032F62;--shiki-dark:#DBEDFF">(?&lt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8">hours</span><span style="color:#032F62;--shiki-dark:#DBEDFF">&gt;</span><span style="color:#005CC5;--shiki-dark:#79B8FF">\d</span><span style="color:#D73A49;--shiki-dark:#F97583">+</span><span style="color:#032F62;--shiki-dark:#DBEDFF">h)</span><span style="color:#D73A49;--shiki-dark:#F97583">?</span><span style="color:#032F62;--shiki-dark:#DBEDFF">(?&lt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8">minutes</span><span style="color:#032F62;--shiki-dark:#DBEDFF">&gt;</span><span style="color:#005CC5;--shiki-dark:#79B8FF">\d</span><span style="color:#D73A49;--shiki-dark:#F97583">+</span><span style="color:#032F62;--shiki-dark:#DBEDFF">m(?!s))</span><span style="color:#D73A49;--shiki-dark:#F97583">?</span><span style="color:#032F62;--shiki-dark:#DBEDFF">(?&lt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8">seconds</span><span style="color:#032F62;--shiki-dark:#DBEDFF">&gt;</span><span style="color:#005CC5;--shiki-dark:#79B8FF">\d</span><span style="color:#D73A49;--shiki-dark:#F97583">+</span><span style="color:#032F62;--shiki-dark:#DBEDFF">s)</span><span style="color:#D73A49;--shiki-dark:#F97583">?</span><span style="color:#032F62;--shiki-dark:#DBEDFF">(?&lt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8">miliseconds</span><span style="color:#032F62;--shiki-dark:#DBEDFF">&gt;</span><span style="color:#005CC5;--shiki-dark:#79B8FF">\d</span><span style="color:#D73A49;--shiki-dark:#F97583">+</span><span style="color:#032F62;--shiki-dark:#DBEDFF">ms)</span><span style="color:#D73A49;--shiki-dark:#F97583">?$</span><span style="color:#032F62;--shiki-dark:#9ECBFF">/</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> matched</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> delay.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">match</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( delayRegex );</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	const</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> { </span><span style="color:#005CC5;--shiki-dark:#79B8FF">hours</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">minutes</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">seconds</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">miliseconds</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> } </span><span style="color:#D73A49;--shiki-dark:#F97583">=</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> matched</span><span style="color:#D73A49;--shiki-dark:#F97583">!</span><span style="color:#24292E;--shiki-dark:#E1E4E8">.groups </span><span style="color:#D73A49;--shiki-dark:#F97583">as</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> DelayGroups</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	let</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> totalDelay </span><span style="color:#D73A49;--shiki-dark:#F97583">=</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> 0</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( hours </span><span style="color:#D73A49;--shiki-dark:#F97583">!==</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> undefined</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		totalDelay </span><span style="color:#D73A49;--shiki-dark:#F97583">+=</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> removeUnit</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( hours ) </span><span style="color:#D73A49;--shiki-dark:#F97583">*</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> 3600000</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( minutes </span><span style="color:#D73A49;--shiki-dark:#F97583">!==</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> undefined</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		totalDelay </span><span style="color:#D73A49;--shiki-dark:#F97583">+=</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> removeUnit</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( minutes ) </span><span style="color:#D73A49;--shiki-dark:#F97583">*</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> 60000</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( seconds </span><span style="color:#D73A49;--shiki-dark:#F97583">!==</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> undefined</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		totalDelay </span><span style="color:#D73A49;--shiki-dark:#F97583">+=</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> removeUnit</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( seconds ) </span><span style="color:#D73A49;--shiki-dark:#F97583">*</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> 1000</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( miliseconds </span><span style="color:#D73A49;--shiki-dark:#F97583">!==</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> undefined</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		totalDelay </span><span style="color:#D73A49;--shiki-dark:#F97583">+=</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> removeUnit</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( miliseconds );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	return</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> totalDelay;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">function</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> removeUnit</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#E36209;--shiki-dark:#FFAB70">delay</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Hours</span><span style="color:#D73A49;--shiki-dark:#F97583"> |</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Minutes</span><span style="color:#D73A49;--shiki-dark:#F97583"> |</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Seconds</span><span style="color:#D73A49;--shiki-dark:#F97583"> |</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> MiliSeconds</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> )</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	return</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Number</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( delay.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">replaceAll</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> /</span><span style="color:#005CC5;--shiki-dark:#79B8FF">[a-z]</span><span style="color:#032F62;--shiki-dark:#9ECBFF">/</span><span style="color:#D73A49;--shiki-dark:#F97583">g</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#032F62;--shiki-dark:#9ECBFF">''</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Pojawiła się w nim tylko jedna, mała zmiana: funkcje <code>wait()</code> (1) i <code>tick()</code> (2) są eksportowane. Dzięki temu, gdy ktoś zainstaluje nasz pakiet, będzie mógł go użyć w swoim kodzie:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">TypeScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">import</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> { wait, tick } </span><span style="color:#D73A49;--shiki-dark:#F97583">from</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> 'czasomierze'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">await</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> wait</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'5s'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">for</span><span style="color:#D73A49;--shiki-dark:#F97583"> await</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( </span><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> _</span><span style="color:#D73A49;--shiki-dark:#F97583"> of</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> tick</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#005CC5;--shiki-dark:#79B8FF">1000</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) ) {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">    console.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">log</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'tick'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> )</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Skoro już mamy plik z kodem, to możemy przy okazji przetestować, czy nasz kod poprawnie się&nbsp;transpiluje. W tym celu wystarczy wywołać polecenie:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">Shell</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">npm</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> run</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> build</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Jeśli wszystko pójdzie dobrze, powinien pojawić się katalog <code>dist</code>, a w nim plik <code>index.js</code> z kodem JS naszej biblioteki.</p>
<h3 id="readmemd"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#readmemd"><code>README.md</code></a></h3>
<p>W tym pliku znajduje się opis projektu wraz z podstawową dokumentacją. To jego zawartość&nbsp;widać&nbsp;zarówno na npm-ie, jak i GitHubie. Dobrze więc, żeby był jak najbardziej czytelny i zawierał wszystkie potrzebne informacje. Osobiście stosuję taki szablon:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">Markdown</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold"># &lt;</span><span style="color:#22863A;--shiki-light-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold">nazwa</span><span style="color:#6F42C1;--shiki-light-font-weight:bold;--shiki-dark:#B392F0;--shiki-dark-font-weight:bold"> pakietu</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">informacyjne</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> tarcze</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">Opis</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> projektu</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> w</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> jednym</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> zdaniu</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">## Installation</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">```bash</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">npm install &lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">nazwa</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> pakietu</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">```</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">## Usage</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">Przykład</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> użycia,</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> najlepiej</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> z</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> kodem</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">Dodatkowe</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> sekcje</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> z</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> potrzebnymi</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> informacjami</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">## License</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">See [LICENSE](./LICENSE) file for details.</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Dla czasomierzy plik <code>README.md</code> może wyglądać następująco:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">Markdown</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold"># czasomierze</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">Simpler and friendler timers.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold">## Installation</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">```bash</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">npm</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> install</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> czasomierze</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">```</span></span>
<span class="line"></span>
<span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold">## Usage</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">```typescript</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">import</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> { wait, tick } </span><span style="color:#D73A49;--shiki-dark:#F97583">from</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> 'czasomierze'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">await</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> wait</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#005CC5;--shiki-dark:#79B8FF">5000</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ); </span><span style="color:#6A737D;--shiki-dark:#6A737D">// Waits for 5 seconds</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">await</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> wait</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'10m'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) </span><span style="color:#6A737D;--shiki-dark:#6A737D">// waits 10 minutes</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">for</span><span style="color:#D73A49;--shiki-dark:#F97583"> await</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( </span><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> _</span><span style="color:#D73A49;--shiki-dark:#F97583"> of</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> tick</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'1s'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) ) {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	console.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">log</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'tick'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ); </span><span style="color:#6A737D;--shiki-dark:#6A737D">// Logs in 1 second intervals</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">```</span></span>
<span class="line"></span>
<span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold">## License</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">See [</span><span style="color:#032F62;--shiki-light-text-decoration:underline;--shiki-dark:#DBEDFF;--shiki-dark-text-decoration:underline">LICENSE</span><span style="color:#24292E;--shiki-dark:#E1E4E8">](</span><span style="color:#24292E;--shiki-light-text-decoration:underline;--shiki-dark:#E1E4E8;--shiki-dark-text-decoration:underline">./LICENSE</span><span style="color:#24292E;--shiki-dark:#E1E4E8">) file for details.</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>{% note %}</p>
<p>Choć nie ma obowiązku tworzenia pliku <code>README.md</code> w języku angielskim, to jednak jest on de facto standardem w branży. Jeśli chcemy dodać także informacje w innym języku, można stworzyć dodatkowe pliki <code>README-&lt;kod języka&gt;.md</code>, np. <code>README-pl.md</code> dla języka polskiego.</p>
<p>{% endnote %}</p>
<h3 id="license"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#license"><code>LICENSE</code></a></h3>
<p>Ten plik zawiera treść licencji, na której rozprowadzamy nasze oprogramowanie. Osobiście w większości przypadków wybieram <a href="https://opensource.org/license/mit" rel="noreferrer noopener">licencję MIT</a>. Z kolei npm proponuje domyślnie <a href="https://opensource.org/license/isc" rel="noreferrer noopener">licencję ISC</a> – która jest praktycznie tożsama z MIT. Strona <a href="https://choosealicense.com/" rel="noreferrer noopener"><cite lang="en">Choose an open source license</cite></a> zawiera więcej licencji przeznaczonych dla projektów open source.</p>
<p>Licencje open source to oczywiście niejedyny możliwy wybór. Niektóre pakiety npm są na licencjach komercyjnych (wówczas najczęściej nie linkują&nbsp;też&nbsp;do repozytorium z kodem). Coraz popularniejsze robią&nbsp;się&nbsp;także licencje typu <a href="https://en.wikipedia.org/wiki/Source-available_software" rel="noreferrer noopener"><i lang="en">source-available</i></a>, które np. mogą mieć dodatkowe ograniczenia dotyczące komercyjnego wykorzystania kodu.</p>
<h3 id="contributingmd"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#contributingmd"><code>CONTRIBUTING.md</code></a></h3>
<p>Ten plik zawiera <a href="https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/setting-guidelines-for-repository-contributors" rel="noreferrer noopener">informacje dla osób, które chcą dołączyć&nbsp;do projektu</a>. Powinien wskazywać, w jaki sposób zakładać nowe <a href="https://docs.github.com/en/issues/tracking-your-work-with-issues/learning-about-issues/quickstart" rel="noreferrer noopener">issues</a>, jakie wymogi muszą spełniać <a href="https://docs.github.com/en/pull-requests/reference/pull-requests" rel="noreferrer noopener">PR-y</a>, jaki styl kodu jest używany w projekcie, itd. Jeśli nasz projekt jest małym, prywatnym projektem, to raczej można się obejść bez tego pliku. Natomiast jeśli chcemy go rozwijać na większą skalę, to taki plik warto dodać prędzej niż później.</p>
<h3 id="changelogmd"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#changelogmd"><code>CHANGELOG.md</code></a></h3>
<p>Jeśli ktoś&nbsp;chce się szybko zorientować, co zmieniło się w naszej bibliotece, najczęściej zagląda właśnie do pliku <code>CHANGELOG.md</code>. Ten plik w czytelny sposób powinien opisywać, jakie rzeczy zmieniły się w poszczególnych wersjach. Jest wiele przyjętych formatów tego pliku, ja osobiście stosuję <a href="https://keepachangelog.com/en/1.1.0/" rel="noreferrer noopener"><cite lang="en">Keep a Changelog</cite></a>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">Markdown</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold"># czasomierze Changelog</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">All notable changes to this project will be documented in this file.</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">The format is based on [</span><span style="color:#032F62;--shiki-light-text-decoration:underline;--shiki-dark:#DBEDFF;--shiki-dark-text-decoration:underline">Keep a Changelog</span><span style="color:#24292E;--shiki-dark:#E1E4E8">](</span><span style="color:#24292E;--shiki-light-text-decoration:underline;--shiki-dark:#E1E4E8;--shiki-dark-text-decoration:underline">http://keepachangelog.com/</span><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">and this project adheres to [</span><span style="color:#032F62;--shiki-light-text-decoration:underline;--shiki-dark:#DBEDFF;--shiki-dark-text-decoration:underline">Semantic Versioning</span><span style="color:#24292E;--shiki-dark:#E1E4E8">](</span><span style="color:#24292E;--shiki-light-text-decoration:underline;--shiki-dark:#E1E4E8;--shiki-dark-text-decoration:underline">http://semver.org/</span><span style="color:#24292E;--shiki-dark:#E1E4E8">).</span></span>
<span class="line"></span>
<span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold">---</span></span>
<span class="line"></span>
<span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold">## 0.1.0</span></span>
<span class="line"><span style="color:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold">### Added</span></span>
<span class="line"><span style="color:#E36209;--shiki-dark:#FFAB70">*</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> First working version, yay!</span></span>
<span class="line"></span>
<span class="line"></span></code></pre>

			</div>
		</figure><h3 id="github"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#github"><code>.github</code></a></h3>
<p>W tym katalogu znajdują się <a href="https://docs.github.com/en/communities" rel="noreferrer noopener">ustawienia <em>społecznościowe</em> GitHuba</a>, pozwalające zmienić np. <a href="https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository" rel="noreferrer noopener">szablony dla nowych issues</a> czy <a href="https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository" rel="noreferrer noopener">szablon dla nowych PR-ów</a>. Można w nim także umieścić wspomniany już plik <code>CONTRIBUTING.md</code>.</p>
<h3 id="editorconfig"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#editorconfig"><code>.editorconfig</code></a></h3>
<p>Ten plik zawiera ustawienia dla edytora kodu w formacie <a href="https://editorconfig.org/" rel="noreferrer noopener">EditorConfig</a>. Format ten jest rozpoznawany przez wiele różnych edytorów (niektóre wymagają rozszerzeń, jak np. <a href="https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig" rel="noreferrer noopener">VSC</a>). Dzięki niemu można ustawić m.in. preferowany styl nowych linii czy szerokość i styl wcięć.  Mój standardowy plik <code>.editorconfig</code> wygląda następująco:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">INI</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">root</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = true</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;--shiki-dark:#6A737D"># Unix-style newlines with a newline ending every file</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">[*]</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">end_of_line</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = lf</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">insert_final_newline</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = true</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">indent_style</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = tab</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">indent_size</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = 4</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">[*.yml]</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">indent_style</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = space</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">indent_size</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = 2</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">[package.json]</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">indent_style</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = space</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">indent_size</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> = 2</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><h3 id="nvmrc"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#nvmrc"><code>.nvmrc</code></a></h3>
<p>Jeśli mamy zainstalowaną tylko jedną wersję Node’a na komputerze, ten plik nie jest nam do niczego potrzebny. Niemniej, gdy pracuje się nad kilkoma projektami równocześnie, bardzo szybko się okazuje, że różne projekty potrzebują&nbsp;różnych wersji Node. I tutaj na pomoc przychodzą managery wersji Node’a. Osobiście stosuję <a href="https://github.com/nvm-sh/nvm" rel="noreferrer noopener">nvm</a>, stąd plik konfiguracyjny <code>.nvmrc</code>. W przypadku naszego projektu można skonfigurować nvm, żeby zawsze używał najnowszej dostępnej wersji Node’a:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage"></span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span>node</span></span>
<span class="line"><span></span></span></code></pre>

			</div>
		</figure><h3 id="gitattributes"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#gitattributes"><code>.gitattributes</code></a></h3>
<p><a href="https://git-scm.com/docs/gitattributes" rel="noreferrer noopener">Plik <code>.giattributes</code></a> ustawia atrybuty dla wybranych plików. Na ten moment nie będziemy się wgłębiać, co to dokładnie oznacza – na to przyjdzie czas w osobnym artykule. Na potrzeby naszego projektu starczy nam taki plik <code>.gitattributes</code>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage"></span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span>* text=auto</span></span>
<span class="line"><span>*.js eol=lf</span></span>
<span class="line"><span>*.ts eol=lf</span></span>
<span class="line"><span></span></span></code></pre>

			</div>
		</figure><h3 id="podsumowanie"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#podsumowanie">Podsumowanie</a></h3>
<p>Nasz szkielet powinien wyglądać mniej więcej tak:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage"></span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span>| - .github/</span></span>
<span class="line"><span>|   | - ISSUE_TEMPLATE.md</span></span>
<span class="line"><span>|   | - PULL_REQUEST_TEMPLATE.md</span></span>
<span class="line"><span>| - src/</span></span>
<span class="line"><span>|   | - index.ts</span></span>
<span class="line"><span>| - .editorconfig</span></span>
<span class="line"><span>| - .gitattributes</span></span>
<span class="line"><span>| - .gitignore</span></span>
<span class="line"><span>| - .nvmrc</span></span>
<span class="line"><span>| - CHANGELOG.md</span></span>
<span class="line"><span>| - CONTRIBUTING.md</span></span>
<span class="line"><span>| - LICENSE</span></span>
<span class="line"><span>| - package-lock.json</span></span>
<span class="line"><span>| - package.json</span></span>
<span class="line"><span>| - README.md</span></span>
<span class="line"><span>| - tsconfig.json</span></span>
<span class="line"><span></span></span></code></pre>

			</div>
		</figure><p>Możemy go teraz <a href="https://github.com/git-guides/git-commit" rel="noreferrer noopener">scomiitować</a> i <a href="https://github.com/git-guides/git-push" rel="noreferrer noopener">wypchnąć do repozytorium</a>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">Shell</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">git</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> add</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> .</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> &amp;&amp; </span><span style="color:#6F42C1;--shiki-dark:#B392F0">git</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> commit</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> -m</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> "chore: Add skeleton"</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> &amp;&amp; </span><span style="color:#6F42C1;--shiki-dark:#B392F0">git</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> push</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> origin</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> main</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><div class="note" role="note" aria-labelledby="note-78"><p class="note__label" id="note-78">Dygresja</p><div class="note__content"><p>O śmiesznym formacie commitów (<code>chore: &lt;treść&gt;</code>) porozmawiamy kiedy indziej!</p></div></div>
<p>I tym oto sposobem <a href="https://github.com/Comandeer/czasomierze" rel="noreferrer noopener">nasze repozytorium</a> zawiera działający zalążek pakietu npm!</p>
<h2 id="co-dalej"><a class="header-anchor" href="https://blog.comandeer.pl/pakujac-manatki#co-dalej">Co dalej?</a></h2>
<p>Postawiliśmy repozytorium na GitHubie i ogarnęliśmy szkielet pakietu npm. Dalszą pracę rozbijemy na zdecydowanie mniejsze etapy (totalnie nie po to, żeby łatwiej mi się pisało posty…). W następnych odcinkach przyglądniemy się bliżej niektórym plikom w repozytorium, dodamy testy i lintery, a na końcu – opublikujemy paczkę w npmie!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">🐈 mi się zepsuł</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/kot-mi-sie-zepsul" rel="alternate" type="text/html"/>
			<published>2026-07-31T15:33:00.000Z</published>
			<updated>2026-07-31T15:33:00.000Z</updated>
			<id>https://blog.comandeer.pl/kot-mi-sie-zepsul</id>
			
				<summary><![CDATA[Są takie dni, w których człowiekowi nawet kot się zepsuje.]]></summary>
			
			<content type="html"><![CDATA[<p>Jest taki upał, że nawet kot mi się zepsuł… Nie wierzycie? No to patrzcie:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#032F62;--shiki-dark:#9ECBFF">'🐈'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">.</span><span style="color:#005CC5;--shiki-dark:#79B8FF">length</span><span style="color:#6A737D;--shiki-dark:#6A737D"> // 2</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure>
<h2 id="czemu-🐈-się-psuje"><a class="header-anchor" href="https://blog.comandeer.pl/kot-mi-sie-zepsul#czemu-🐈-się-psuje">Czemu 🐈 się psuje?</a></h2>
<p>Rzućmy okiem do <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length" rel="noreferrer noopener">MDN-u</a>:</p>
<blockquote>
<p>The <strong><code>length</code></strong> data property of a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String" rel="noreferrer noopener"><code>String</code></a> value contains the length of the string in UTF-16 code units.</p>
<p>[Własność <code>length</code> ciągów tekstowych zawiera długość tego ciągu w jednostkach kodowych UTF-16.]</p>
</blockquote>
<p>No dobrze, ale co to są “jednostki kodowe” (<i lang="en">code units</i>)? Sięgnijmy raz jeszcze do <a href="https://developer.mozilla.org/en-US/docs/Glossary/Code_unit" rel="noreferrer noopener">przepastnej skarbnicy MDN-u</a>:</p>
<blockquote>
<p>A character encoding system uses one or more code units to encode a Unicode <a href="https://developer.mozilla.org/en-US/docs/Glossary/Code_point" rel="noreferrer noopener">code point</a>. […] In <a href="https://developer.mozilla.org/en-US/docs/Glossary/UTF-16" rel="noreferrer noopener">UTF-16</a>, each code point is encoded using one or two 16-bit code units.</p>
<p>[System kodowania znaków używa jednego lub więcej jednostek kodowych, by zakodować punkt kodowy. […] W UTF-16 każdy punkt kodowy jest zapisywany przy pomocy jednej lub dwóch 16-bitowych jednostek kodowych.]</p>
</blockquote>
<p>Punkty kodowe można porównać do współrzędnych znaku w wielkiej tabeli wszystkich znaków standardu Unicode. W praktyce oznacza to, że każdy znak zareprezentować można jako liczbę, np. litera <code>A</code> to <code>U+0041</code>, natomiast <code>🐈</code> to <code>U+1F408</code>.</p>
<p>Czemu jednak JS poprawnie rozpoznaje <code>A</code> jako ciąg tekstowy zawierający jeden znak, podczas gdy <code>🐈</code> jako dwa? Wynika to z ograniczenia UTF-16, a dokładniej: 16-bitowa jednostka kodowa może zakodować co najwyżej 2<sup>16</sup> (65536) znaków. Standard Unicode zawiera ich zdecydowanie więcej, więc część znaków jest kodowana przy pomocy dwóch jednostek kodowych. I do tej grupy zaliczają się także emoji. Cały problem polega na tym, że <code>String#length</code> zwraca liczbę <em>jednostek kodowych</em> w ciągu, nie – liczbę znaków. Stąd <code>🐈</code> jest zepsuty.</p>
<div class="note" role="note" aria-labelledby="note-52"><p class="note__label" id="note-52">Dygresja</p><div class="note__content"><p>Zasady działania standardu Unicode w JS-ie są mocno zawiłe, niemniej <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#utf-16_characters_unicode_code_points_and_grapheme_clusters" rel="noreferrer noopener">MDN zawiera dokładniejszy opis całego mechanizmu</a>.</p></div></div>
<h2 id="jak-naprawić-🐈"><a class="header-anchor" href="https://blog.comandeer.pl/kot-mi-sie-zepsul#jak-naprawić-🐈">Jak naprawić 🐈?</a></h2>
<p>Jeśli chcemy policzyć znaki w ciągu tekstowym, o wiele bezpieczniejszym sposobem jest wykorzystanie wbudowanego w ciągi iteratora:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">[ </span><span style="color:#D73A49;--shiki-dark:#F97583">...</span><span style="color:#032F62;--shiki-dark:#9ECBFF">'🐈'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ].</span><span style="color:#005CC5;--shiki-dark:#79B8FF">length</span><span style="color:#24292E;--shiki-dark:#E1E4E8">; </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 1</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Ale oczywiście nie może być za prosto! Istnieje jeszcze coś takiego jak <em>klastry grafemów</em> (<i lang="en">grapheme clusters</i>). W wielkim uproszczeniu: niektóre znaki mogą być tak naprawdę połączeniem wielu różnych znaków, np. <code>👨‍👦</code> to połączenie trzech znaków: <code>👨</code>, <code>‍</code> (<a href="https://en.wikipedia.org/wiki/Zero-width_joiner" rel="noreferrer noopener">łącznika o zerowej szerokości</a>) oraz <code>👦</code>. I iterator ciągu rozbije takie emoji na poszczególne znaki składowe:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">[ </span><span style="color:#D73A49;--shiki-dark:#F97583">...</span><span style="color:#032F62;--shiki-dark:#9ECBFF">'👨‍👦'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ].</span><span style="color:#005CC5;--shiki-dark:#79B8FF">length</span><span style="color:#24292E;--shiki-dark:#E1E4E8">; </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 3</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Niekoniecznie jest to pożądany rezultat. Na całe szczęście jest <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter" rel="noreferrer noopener"><code>Intl.Segmenter</code></a>!</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> segmenter</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#D73A49;--shiki-dark:#F97583"> new</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> Intl.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">Segmenter</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'pl'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, { granularity: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'grapheme'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> } ); </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">console.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">log</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( [ </span><span style="color:#D73A49;--shiki-dark:#F97583">...</span><span style="color:#24292E;--shiki-dark:#E1E4E8">segmenter.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">segment</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'👨‍👦'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) ].</span><span style="color:#005CC5;--shiki-dark:#79B8FF">length</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ); </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 2</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Najpierw tworzymy instancję&nbsp;segmentera (1). Informujemy go, że dzielony tekst będzie po polsku oraz że chcemy dzielić po grafemach. Następnie, przy pomocy <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/segment" rel="noreferrer noopener">metody <code>Intl.Segmenter#segment()</code></a>, dzielimy ciąg zawierający klaster grafemów (2). Tym razem uzyskujemy wynik <code>1</code> – jeden widoczny znak został policzony jako jeden znak.</p>
<p>I tym sposobem 🐈 został naprawiony!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Bombastyczny styl</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/bombastyczny-styl" rel="alternate" type="text/html"/>
			<published>2026-06-30T21:50:00.000Z</published>
			<updated>2026-06-30T21:50:00.000Z</updated>
			<id>https://blog.comandeer.pl/bombastyczny-styl</id>
			
				<summary><![CDATA[Czy aby na pewno promujemy odpowiednie wartośći jako brana]]></summary>
			
			<content type="html"><![CDATA[<blockquote>
<p>Ale ja nie mogę zrozumieć! Nie mogę zrozumieć, jak zachwyca, jeśli nie zachwyca.</p>
<p>– Witold Gombrowicz, <cite>Ferdydurke</cite></p>
</blockquote>
<p>Ostatnio w kilku różnych miejscach przewinąła się ta sama strona internetowa jako przykład dobrze zaprojektowanej strony – <a href="https://www.igloo.inc/" rel="noreferrer noopener">igloo.inc</a>. Swego czasu wygrała nawet <a href="https://www.awwwards.com/sites/igloo-inc" rel="noreferrer noopener">tytuł strony dnia w serwisie Awwwards</a>. I mam z tego powodu mieszane odczucia.</p>

<h2 id="estetyka-przede-wszystkim"><a class="header-anchor" href="https://blog.comandeer.pl/bombastyczny-styl#estetyka-przede-wszystkim">Estetyka przede wszystkim?</a></h2>
<p>Nie powiem, strona może zainteresować swoim wyglądem. Efekt paralaksy, animowane igloo, transformacje 3D kostek lodu, ciekawy “narracyjny” scroll… Pod względem designu dzieje się&nbsp;tu bardzo dużo interesujących rzeczy.</p>
<p>Tylko czy web design jest bardziej o designie, czy jednak bardziej o <em>webie</em>? W tym przypadku medium ma bardzo duże znaczenie i bezpośrednio wpływa na to, jakich form i środków ekspresji używać może projekt. Co więcej, web design wypadałoby rozpatrywać z perspektywy sztuki użytkowej – a więc takiej, której ostatecznym rezultatem jest przedmiot codziennego użytku, który jest przy tym estetyczny. A to oznacza, że te przedmioty muszą być <em>użyteczne</em>. Po co komu choćby szklanka bez denka? I na tym zasadza się&nbsp;cały problem z tego typu stronami: są estetyczne, często wręcz wytyczające trendy – ale trudno je uznać za użyteczne.</p>
<p>Żeby nie być gołosłownym, pozwolę sobie wskazać kilka problemów ze stroną Igloo, Inc.:</p>
<ul>
<li><strong>Strona jest całkowicie niedostępna dla czytników ekranu</strong>. Do jej stworzenia użyto <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/canvas" rel="noreferrer noopener">elementu <code>canvas</code></a>. Niemniej nie dodano treści alternatywnej. Czytnik ekranu nie ma zatem żadnej informacji o tym, co się&nbsp;dzieje na stronie. W dobie <a href="https://html-in-canvas.dev/" rel="noreferrer noopener">HTML-in-Canvas</a> to mocno słabe rozwiązanie.</li>
<li><strong>Nawigacja klawiaturą jest niemożliwa</strong>. Co prawda strzałki w górę i w dół przewijają stronę, ale nie ma żadnego sposobu, by sfocusować linki na stronie lub aktywować&nbsp;jakikolwiek element interaktywny. Razi to zwłaszcza na ekranie z linkami do mediów społecznościowych, ponieważ można pomiędzy poszczególnymi linkami przemieszczać się przy pomocy strzałek w lewo i w prawo, ale nie można ich aktywować, naciskając <kbd>Enter</kbd>.</li>
<li><strong>Wszystko się&nbsp;rusza</strong>. I ja rozumiem, że taki był zamysł, ale <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion" rel="noreferrer noopener">media query <code>prefers-reduced-motion</code></a> nie powstało bez powodu. Część osób ma <a href="https://www.a11yproject.com/posts/understanding-vestibular-disorders/" rel="noreferrer noopener">problemy z błędnikiem</a> i nie może korzystać ze stron z animacjami ruchowymi. Część osób może też&nbsp;po prostu nie lubić ruszających się&nbsp;rzeczy i fajnie byłoby to uszanować.</li>
<li><strong>Dźwięk jest automatycznie włączany</strong>. Wystarczy zacząć&nbsp;przewijać i nagle pojawia się muzyka w tle, a różne elementy reagują&nbsp;dźwiękami na choćby najechanie myszą. Nawet jeśli nie uznamy tego za błąd dostępności, to jest to skrajnie irytujące.</li>
</ul>
<p>Nie jest to oczywiście lista wszystkich problemów. Wymieniłem jedynie te widoczne na pierwszy rzut oka. Ale już dwa pierwsze z nich tak naprawdę dyskwalifikują tego typu projekt w czasach <a href="https://www.webkrytyk.pl/2025/06/23/wpadki-i-wypadki-21-europejski-akt-o-dostepnosci/" rel="noreferrer noopener">Europejskiego aktu o dostępności</a>. Wpływają&nbsp;też&nbsp;bezpośrednio na jego użyteczność. Niemniej strona na Awwards w kategorii <q>użyteczność</q> dostała ocenę 7.5/10. I to pomimo tego, że tak naprawdę jest używalna tylko przy pomocy myszy, względnie dotyku!</p>
<p>Czy jako branża naprawdę nie mamy problemu z tym, że promujemy design, który tylko wygląda, ale nie niesie ze sobą użyteczności i dostępności? Czy na pewno chcemy jako przykłady pokazywać&nbsp;strony, które wykluczają bardzo spore grono osób z możliwości interakcji z nimi? Bo jak dla mnie projekty pokroju Awwwards zdecydowanie za bardzo skupiły się na formie, zapominając o treści.</p>
<h2 id="ale-to-już-było"><a class="header-anchor" href="https://blog.comandeer.pl/bombastyczny-styl#ale-to-już-było">Ale to już było…</a></h2>
<p>A najśmieszniejsze w tym wszystkim jest to, że jestem wystarczająco stary, by pamiętać, jak to już kiedyś przerabialiśmy jako branża. Istniało coś takiego jak <a href="https://en.wikipedia.org/wiki/Adobe_Flash" rel="noreferrer noopener">Flash</a>. Był to program do animacji, później przejęty przez Adobe. Animacje w nim tworzone były zapisywane w formacie <code>.swf</code> i by je odtworzyć, potrzebny był specjalny plugin do przeglądarki, Flash Player. I tak, to był <a href="https://developer.mozilla.org/en-US/docs/Glossary/Plugin" rel="noreferrer noopener"><em>plugin</em></a>, nie <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/What_are_WebExtensions" rel="noreferrer noopener">rozszerzenie</a>. Żeby osadzić animację Flasha na stronie, używało się&nbsp;<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/embed" rel="noreferrer noopener">elementu <code>embed</code></a> – albo, jeśli chciało się&nbsp;być cool i mieć walidujący się XHTML, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/object" rel="noreferrer noopener">elementu <code>object</code></a>.</p>
<p>Lista problemów z takimi animacjami była praktycznie identyczna jak w przypadku omawianej strony. Flash był tak naprawdę monolitycznym blobem, którego często nie dało się nawet obsłużyć przy pomocy klawiatury. A do tego sam Flash znany był ze swojej zasobożerności, niestabilności i licznych problemów z bezpieczeństwem. Aż w końcu <a href="https://en.wikipedia.org/wiki/Thoughts_on_Flash" rel="noreferrer noopener">Steve Jobs wypowiedział mu wojnę</a> i zastąpił go HTML5 z <code>canvas</code>em. Flash, mimo bycia jednym z kamieni węgielnych internetowej popkultury (<a href="https://www.newgrounds.com/" rel="noreferrer noopener">Newgrounds</a>!), został wyparty przez otwarte standardy sieciowe.</p>
<p>Zatem: <a href="https://www.youtube.com/watch?v=RXM-9haRVl8" rel="noreferrer noopener">ale to już&nbsp;było</a>… i jednak wróci więcej?</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Światowy Dzień Świadomości Dostępności 2026</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/swiatowy-dzien-swiadomosci-dostepnosci-2026" rel="alternate" type="text/html"/>
			<published>2026-05-20T22:49:00.000Z</published>
			<updated>2026-05-20T22:49:00.000Z</updated>
			<id>https://blog.comandeer.pl/swiatowy-dzien-swiadomosci-dostepnosci-2026</id>
			
				<summary><![CDATA[Świętujmy razem Dzień Świadomości Dostępności 2026 🎉!]]></summary>
			
			<content type="html"><![CDATA[<p>Kolejny rok, kolejny <a href="https://accessibility.day/" rel="noreferrer noopener">Światowy Dzień Świadomości Dostępności</a> (ang. <i lang="en">Global Accessibility Awareness Day</i>, GAAD). Świętujemy go w każdy trzeci czwartek maja, by podkreślić, jak istotna w codziennym życiu jest dostępność.</p>
<p>Tradycyjnie już przygotowałem z tej okazji artykuł o dostępności. Na WebKrytyku pojawił się <a href="https://www.webkrytyk.pl/2026/05/21/wpadki-i-wypadki-23-pierwsza-zasada-uzywania-aria/" rel="noreferrer noopener">kolejny odcinek Wpadek i wypadków</a>, o pierwszej zasadzie stosowania ARIA.</p>
<p>Życzę wszystkim miłej lektury i dostępnego świętowania 🎉!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">CSS Naked Day 2026</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/css-naked-day-2026" rel="alternate" type="text/html"/>
			<published>2026-04-08T23:06:00.000Z</published>
			<updated>2026-04-08T23:06:00.000Z</updated>
			<id>https://blog.comandeer.pl/css-naked-day-2026</id>
			
				<summary><![CDATA[Świętujmy razem CSS Naked Day 2026 🎉!]]></summary>
			
			<content type="html"><![CDATA[<p>Ale ten czas leci. Mamy nowy rok a wraz z nim – nowy <a href="https://css-naked-day.org/" rel="noreferrer noopener">CSS Naked Day</a>! To ten jeden dzień w roku, w którym skupiamy się na pięknie semantycznego HTML-a zamiast na wizualiach. A żeby móc w pełni podziwiać HTML-a, CSS na ten jeden dzień znika. Przy okazji jak na dłoni widać wszystkie HTML-owe niedoróbki.</p>
<p>Miłego świętowania 🎉!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Piękno reklam</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/piekno-reklam" rel="alternate" type="text/html"/>
			<published>2026-04-01T16:39:00.000Z</published>
			<updated>2026-04-01T16:39:00.000Z</updated>
			<id>https://blog.comandeer.pl/piekno-reklam</id>
			
				<summary><![CDATA[Dodaję reklamy na bloga]]></summary>
			
			<content type="html"><![CDATA[<p>Podjąłem decyzję – na blogu pojawią się reklamy!</p>
<p><ad-></ad-></p>
<p>Postanowiłem, ze nadeszła pora, by zmonetyzować swoją wiedzę. Przez wszystkie te lata dzieliłem się nią za darmo, ale być może w końcu nadszedł czas, by to zmienić.</p>
<p><ad-></ad-></p>
<p>Zadbałem o to, by reklamy nie były zbyt agresywne. Dzięki temu są dopasowane do treści i nie przeszkadzają za bardzo przy zapoznawaniu się z nią.</p>
<p><ad-></ad-></p>
<p><ad-></ad-></p>
<p>Również bloki kodu doczekały się własnych reklam:</p>
<code-ad>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">TypeScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isNumber</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> (</span><span style="color:#E36209;--shiki-dark:#FFAB70">value</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> unknown</span><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#E36209;--shiki-dark:#FFAB70"> value</span><span style="color:#D73A49;--shiki-dark:#F97583"> is</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span><span style="color:#D73A49;--shiki-dark:#F97583"> =&gt;</span><span style="color:#D73A49;--shiki-dark:#F97583"> typeof</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> value </span><span style="color:#D73A49;--shiki-dark:#F97583">===</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> 'number'</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isEven</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> (</span><span style="color:#E36209;--shiki-dark:#FFAB70">value</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> unknown</span><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> boolean</span><span style="color:#D73A49;--shiki-dark:#F97583"> =&gt;</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isNumber</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(value) </span><span style="color:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> value </span><span style="color:#D73A49;--shiki-dark:#F97583">%</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> 2</span><span style="color:#D73A49;--shiki-dark:#F97583"> ===</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> 0</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isOdd</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> (</span><span style="color:#E36209;--shiki-dark:#FFAB70">value</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> unknown</span><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> boolean</span><span style="color:#D73A49;--shiki-dark:#F97583"> =&gt;</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isNumber</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(value) </span><span style="color:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="color:#D73A49;--shiki-dark:#F97583"> !</span><span style="color:#6F42C1;--shiki-dark:#B392F0">isEven</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(value)</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure></code-ad>
<p>Mam nadzieję, że ta mała, nieinwazyjna zmiana się spodoba!</p>
<p><ad-></ad-></p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Piękno prezentacji</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/piekno-prezentacji" rel="alternate" type="text/html"/>
			<published>2026-03-21T21:53:00.000Z</published>
			<updated>2026-03-21T21:53:00.000Z</updated>
			<id>https://blog.comandeer.pl/piekno-prezentacji</id>
			
				<summary><![CDATA[Opublikowałem swoją prezentację o inkluzywnym designie z Warsaw IT Days]]></summary>
			
			<content type="html"><![CDATA[<p>19 marca miałem okazję poopowiadać o respektowaniu preferencji osoby odwiedzającej stronę&nbsp;WWW na  <a href="https://warszawskiedniinformatyki.pl/" rel="noreferrer noopener">Warsaw IT Days</a>. Jeśli ktoś chcialby sobie przypomnieć moją <a href="https://blog.comandeer.pl/assets/piekno-prezentacji/wid-2026.pdf"><em>jakże piękną i wspaniałą</em> prezentację</a>, to od teraz jest dostępna na tym blogu.</p>
<p>Dzięki za dołączenie online, żeby posłuchać!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Warsaw IT Days 2026 – kod rabatowy</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/wdi-2026-kod-rabatowy" rel="alternate" type="text/html"/>
			<published>2026-03-09T21:38:00.000Z</published>
			<updated>2026-03-09T21:38:00.000Z</updated>
			<id>https://blog.comandeer.pl/wdi-2026-kod-rabatowy</id>
			
				<summary><![CDATA[Zniżka na Warsaw IT Days 2026 tylko dla osób czytających mojego bloga!]]></summary>
			
			<content type="html"><![CDATA[<p>Już wkrótce kolejna edycja <a href="https://warszawskiedniinformatyki.pl/" rel="noreferrer noopener">Warsaw IT Days</a> – 19 marca widzimy się online, a 20 marca kolejne prelekcje odbędą się na PGE Narodowym w Warszawie. Oprócz mojego wystąpienia będzie można posłuchać ponad 300 innych na 25 ścieżkach tematycznych.</p>
<p>Dla osób czytających mojego bloga mam kod rabatowy, dzięki któremu można kupić bilety w pakietach Standard i Exec o 20% taniej. Kod rabatowy to: <strong>WID26SP20</strong>. Można go użyć w trakcie <a href="https://warszawskiedniinformatyki.pl/registration.html" rel="noreferrer noopener">kupowania biletu na oficjalnej stronie wydarzenia</a>.</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Piękno CSS-a</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/piekno-cssa" rel="alternate" type="text/html"/>
			<published>2026-03-05T21:57:00.000Z</published>
			<updated>2026-03-05T21:57:00.000Z</updated>
			<id>https://blog.comandeer.pl/piekno-cssa</id>
			
				<summary><![CDATA[Opublikowałem swoją prezentację o CSS-ie z OLX Frontend Masterclass]]></summary>
			
			<content type="html"><![CDATA[<p>3 marca miałem okazję wygłosić prelekcję na wydarzeniu <a href="https://evenea.pl/pl/wydarzenie/masterclassfrontend" rel="noreferrer noopener">OLX Frontend Masterclass</a> w Poznaniu. Opowiadałem tam o nowych ficzerach w CSS-ie. <em>Przepiękne</em> demo z tej prezentacji <a href="https://github.com/Comandeer/cssdemo" rel="noreferrer noopener">wrzuciłem już na GitHuba</a>. Z kolei <a href="https://www.youtube.com/watch?v=Mcqm15d-qmI" rel="noreferrer noopener">zapis streama z wydarzenia</a> jest dostępny na YouTube.</p>
<p>Dzięki za wpadnięcie, żeby posłuchać, i dzięki za ciekawe dyskusje w trakcie networkingu!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Prelekcjowy marzec</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/prelekcjowy-marzec" rel="alternate" type="text/html"/>
			<published>2026-02-20T21:29:00.000Z</published>
			<updated>2026-02-20T21:29:00.000Z</updated>
			<id>https://blog.comandeer.pl/prelekcjowy-marzec</id>
			
				<summary><![CDATA[W marcu 2026 będzie mnie można usłyszeć na aż dwóch wydarzeniach: OLX Masterclass Frontend oraz Warsaw IT Days!]]></summary>
			
			<content type="html"><![CDATA[<p>Marzec zapowiada się niezwykle pracowicie, bo wygłoszę w nim aż dwie prelekcje – i to na dwa zupełnie różne tematy!</p>
<h2 id="olx-masterclass-frontend"><a class="header-anchor" href="https://blog.comandeer.pl/prelekcjowy-marzec#olx-masterclass-frontend">OLX Masterclass Frontend</a></h2>
<p><strong>3 marca 2026 o godzinie 18:00</strong> rozpocznie się <a href="https://evenea.pl/pl/wydarzenie/masterclassfrontend" rel="noreferrer noopener">OLX Masterclass Frontend</a>. Można w nim uczestniczyć zarówno fizycznie, w <a href="https://maps.app.goo.gl/A6K6svPFJfkEbTD67" rel="noreferrer noopener">poznańskim biurze OLX</a>, jak i <a href="https://docs.google.com/forms/d/e/1FAIpQLSeAFoynaDeryxixlrYik4RJScBwKjh9ybqe5-GL6xrxrfXPIQ/viewform" rel="noreferrer noopener">dołączyć online</a>. Wstęp na wydarzenie jest darmowy. Usłyszeć&nbsp;będzie można trzy prelekcje o tematyce webdevowej. Ja opowiadać będę o zmianach, jakie zaszły w nowoczesnym CSS-ie – w tym zagnieżdżaniu, warstwach czy regule <code>@scope</code> – oraz o tym, jak mogą one wpłynąć na to, jak piszemy i zarządzamy stylami. Dla transparentności: za tę prelekcję <strong>pobieram wynagrodzenie</strong>. Po wszystkim będzie można się napić kawy i pogadać.</p>
<h2 id="warsaw-it-days-2026"><a class="header-anchor" href="https://blog.comandeer.pl/prelekcjowy-marzec#warsaw-it-days-2026">Warsaw IT Days 2026</a></h2>
<p>Z kolei <strong>19 marca 2026</strong> (online) i <strong>20 marca 2026</strong> (na <a href="https://maps.app.goo.gl/5UnHbp2A3MkXbmMZ9" rel="noreferrer noopener">PGE Narodowym w Warszawie</a>) odbywa się kolejna edycja <a href="https://warszawskiedniinformatyki.pl/" rel="noreferrer noopener">Warsaw IT Days</a>. Można posłuchać ponad 300 prelekcji na 25 różnych ścieżkach tematycznych.</p>
<p><picture><source type="image/avif" srcset="/assets/images/prelekcyjny-marzec/wdi-440w.avif 440w, /assets/images/prelekcyjny-marzec/wdi-880w.avif 880w, /assets/images/prelekcyjny-marzec/wdi-1024w.avif 1024w" sizes="90vw"><source type="image/webp" srcset="/assets/images/prelekcyjny-marzec/wdi-440w.webp 440w, /assets/images/prelekcyjny-marzec/wdi-880w.webp 880w, /assets/images/prelekcyjny-marzec/wdi-1024w.webp 1024w" sizes="90vw"><source type="image/png" srcset="/assets/images/prelekcyjny-marzec/wdi-440w.png 440w, /assets/images/prelekcyjny-marzec/wdi-880w.png 880w, /assets/images/prelekcyjny-marzec/wdi-1024w.png 1024w" sizes="90vw"><img src="/assets/images/prelekcyjny-marzec/wdi-1024w.png" width="1024" height="1024" style="aspect-ratio: 1024 / 1024" alt="" loading="lazy" decoding="async"></picture></p>
<p>Moje wystąpienie, <cite lang="en">Giving control back to the user</cite>, będzie transmitowane online <strong>19 marca 2026 o 14:35</strong>. Będę mówił o inkluzywnym designie, a dokładniej – o respektowaniu preferencji osób korzystających z naszej strony WWW. <a href="https://warszawskiedniinformatyki.pl/registration.html" rel="noreferrer noopener">Bilety można kupić&nbsp;na stronie wydarzenia</a>.</p>
<p>Obydwa wystąpienia będą w całości po angielsku. Serdecznie zapraszam!</p>
]]></content>
		</entry>
	
</feed>
