<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>nodets.com articles</title>
<subtitle>Articles by Yamin</subtitle>
<link href="https://nodets.com/articles/feed.xml" rel="self" type="application/atom+xml"/>
<link href="https://nodets.com/articles/" rel="alternate" type="text/html"/>
<id>https://nodets.com/articles/</id>
<updated>2026-10-26T00:00:00.000Z</updated>
<author><name>Yamin</name><uri>https://nodets.com/about/</uri></author>
<entry>
<title>How nodets.com is built</title>
<link href="https://nodets.com/articles/how-this-site-is-built/" rel="alternate" type="text/html"/>
<id>https://nodets.com/articles/how-this-site-is-built/</id>
<published>2026-10-26T00:00:00.000Z</published>
<updated>2026-10-26T00:00:00.000Z</updated>
<summary>A static site generator, zero JavaScript and one rule: every change is a new build. Notes on how this site stays fast.</summary>
<category term="meta"/><category term="static-sites"/><category term="performance"/>
<content type="html">&lt;p&gt;This site is a small Node.js program that turns markdown into plain HTML. There is no framework, no client-side rendering and no JavaScript shipped to your browser.&lt;/p&gt;
&lt;h2 id=&quot;one-rule-every-change-is-a-new-build&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#one-rule-every-change-is-a-new-build&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;#&lt;/a&gt;One rule: every change is a new build&lt;/h2&gt;
&lt;p&gt;Nothing on the live site is assembled at request time. A page changes only when I run a build and deploy the result:&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;code-lang&quot;&gt;sh&lt;/span&gt;&lt;pre class=&quot;shiki shiki-themes github-light-high-contrast github-dark-high-contrast&quot; style=&quot;--shiki-light:#0e1116;--shiki-dark:#f0f3f6;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0a0c10&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#702C00;--shiki-dark:#FFB757&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032563;--shiki-dark:#ADDCFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032563;--shiki-dark:#ADDCFF&quot;&gt; deploy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That command fetches the documentation of each project from its GitHub repository, renders every page to HTML with the CSS inlined, compresses it, and syncs the result to the web server. Articles like this one work the same way: a markdown file in the repository becomes a finished HTML page at build time.&lt;/p&gt;
&lt;h2 id=&quot;why-prebuilt-html&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#why-prebuilt-html&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;#&lt;/a&gt;Why prebuilt HTML&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Speed.&lt;/strong&gt; The server only sends files that already exist. Each page is also precompressed, so nginx never compresses anything on the fly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nothing to break.&lt;/strong&gt; No database, no runtime, no scripts to fail. If the file exists, the page works.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy to check.&lt;/strong&gt; Syntax highlighting happens at build time, so code blocks cost zero bytes of JavaScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-it-costs&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#what-it-costs&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;#&lt;/a&gt;What it costs&lt;/h2&gt;
&lt;p&gt;The price is that a typo fix needs a rebuild. For a site like this, that is a good trade: a build takes seconds, and the result is the same for every visitor.&lt;/p&gt;
</content>
</entry>
<entry>
<title>Why I made jalali_date</title>
<link href="https://nodets.com/articles/why-i-made-jalali-date/" rel="alternate" type="text/html"/>
<id>https://nodets.com/articles/why-i-made-jalali-date/</id>
<published>2026-10-26T00:00:00.000Z</published>
<updated>2026-10-26T00:00:00.000Z</updated>
<summary>The history of jalali_date, a Persian calendar package for Dart: the first version in 2018, a conversion bug I had to own, and the rewrite in 2026.</summary>
<category term="dart"/><category term="flutter"/><category term="jalali"/><category term="open-source"/>
<content type="html">&lt;p&gt;In 2018 I was writing Dart and needed Jalali dates. That is most of the story.&lt;/p&gt;
&lt;p&gt;The Jalali calendar, also called Persian, Shamsi or Solar Hijri, is the official calendar of Iran and Afghanistan. If you build anything for people in Iran, every date on the screen is in it. The week starts on Saturday and Friday is the day off. The year begins at Nowruz, around 21 March. I was working in Tehran at the time, and showing a Gregorian date and hoping nobody minded was not an option.&lt;/p&gt;
&lt;p&gt;So I wrote a small package. The repository, &lt;a href=&quot;https://github.com/YaminT/Dart-Persian-Date&quot; rel=&quot;noopener&quot;&gt;Dart-Persian-Date&lt;/a&gt;, went up on 10 July 2018. Version 0.0.1 did one thing: it took a Gregorian date and gave back a Jalali one. The next day I added the time to &lt;code&gt;toString&lt;/code&gt;. I did not plan beyond that.&lt;/p&gt;
&lt;p&gt;In April 2019 I fixed a few things &lt;code&gt;dart pub&lt;/code&gt; complained about, and in May I added a homepage URL. By then it was on &lt;a href=&quot;https://pub.dev/packages/jalali_date&quot; rel=&quot;noopener&quot;&gt;pub.dev&lt;/a&gt; as &lt;code&gt;jalali_date&lt;/code&gt;. In July 2020 I added options to show or hide the hour, minute and second, and fixed the length of minutes and seconds in the output.&lt;/p&gt;
&lt;p&gt;Then nothing for about six years. I moved to Germany at some point in that time, and the package sat untouched.&lt;/p&gt;
&lt;h2 id=&quot;coming-back&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#coming-back&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;#&lt;/a&gt;Coming back&lt;/h2&gt;
&lt;p&gt;This month I opened it again. The first job was housekeeping: move to Dart 3 and null safety, and drop the Flutter dependency so it is pure Dart and runs anywhere Dart runs.&lt;/p&gt;
&lt;p&gt;Then I found the real problem. The Gregorian-to-Jalali conversion I wrote in 2018 was wrong for some years. Century years, and years that fall across a Jalali leap cycle. That is my mistake, and it had been in the package the whole time. If you used it and a date near one of those boundaries looked off, that was the package, not you.&lt;/p&gt;
&lt;p&gt;I did not try to patch it. I replaced the algorithm with a port of &lt;a href=&quot;https://github.com/jalaali/jalaali-js&quot; rel=&quot;noopener&quot;&gt;jalaali-js&lt;/a&gt; and stopped trying to be clever about calendar arithmetic.&lt;/p&gt;
&lt;p&gt;That became 1.0.0. With the conversion fixed it made sense to add the other direction, Jalali to Gregorian, plus validation that throws an &lt;code&gt;ArgumentError&lt;/code&gt; on a bad date, leap years and month lengths, Persian month and weekday names, a &lt;code&gt;format(pattern)&lt;/code&gt; method and a padded &lt;code&gt;toString&lt;/code&gt;. 1.0.0 has breaking changes. They are listed on the &lt;a href=&quot;https://nodets.com/jalali/migration/&quot;&gt;migration page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;1.1.0 came after that: date arithmetic, comparisons, weeks that start on Saturday, parsing with either Persian or Arabic-Indic digits, output in Persian digits, &lt;code&gt;DateTime.toPersianDate()&lt;/code&gt;, JSON, Dari month names for Afghanistan, and ranges and bounds so you can build a date picker on top of it.&lt;/p&gt;
&lt;p&gt;I also merged a pull request from &lt;a href=&quot;https://github.com/AliRn76&quot; rel=&quot;noopener&quot;&gt;AliRn76&lt;/a&gt; that zero-pads the time parts and respects the show flags. Thank you for that.&lt;/p&gt;
&lt;h2 id=&quot;where-it-stands&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;#where-it-stands&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;#&lt;/a&gt;Where it stands&lt;/h2&gt;
&lt;p&gt;The docs are at &lt;a href=&quot;https://nodets.com/jalali/&quot;&gt;nodets.com/jalali&lt;/a&gt;. The source is on &lt;a href=&quot;https://github.com/YaminT/Dart-Persian-Date&quot; rel=&quot;noopener&quot;&gt;GitHub&lt;/a&gt; under Apache-2.0, and the package is on &lt;a href=&quot;https://pub.dev/packages/jalali_date&quot; rel=&quot;noopener&quot;&gt;pub.dev&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you use it and a date comes out wrong, &lt;a href=&quot;https://github.com/YaminT/Dart-Persian-Date/issues&quot; rel=&quot;noopener&quot;&gt;open an issue&lt;/a&gt;. I have been wrong about this once already.&lt;/p&gt;
</content>
</entry>
</feed>
