<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nik</title>
    <description>The latest articles on DEV Community by Nik (@nik_f289a9240080d43eb7ee9).</description>
    <link>https://dev.to/nik_f289a9240080d43eb7ee9</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3179713%2Fa91e2c58-0617-45f1-8c89-ab0ac76901ba.jpg</url>
      <title>DEV Community: Nik</title>
      <link>https://dev.to/nik_f289a9240080d43eb7ee9</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nik_f289a9240080d43eb7ee9"/>
    <language>en</language>
    <item>
      <title>I tried to use vis.js… then SSR and performance got in the way</title>
      <dc:creator>Nik</dc:creator>
      <pubDate>Fri, 05 Jun 2026 12:29:12 +0000</pubDate>
      <link>https://dev.to/nik_f289a9240080d43eb7ee9/i-tried-to-use-visjs-then-ssr-and-performance-got-in-the-way-1mec</link>
      <guid>https://dev.to/nik_f289a9240080d43eb7ee9/i-tried-to-use-visjs-then-ssr-and-performance-got-in-the-way-1mec</guid>
      <description>&lt;p&gt;I needed a timeline for a reporting feature.&lt;/p&gt;

&lt;p&gt;Not just something interactive in the browser, but something that could also be rendered server-side and exported (PDFs, images, etc).&lt;/p&gt;

&lt;p&gt;It also needed to show &lt;strong&gt;dependencies between items&lt;/strong&gt;, not just a flat set of events.&lt;/p&gt;

&lt;p&gt;Seemed straightforward enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  Started with vis.js
&lt;/h2&gt;

&lt;p&gt;vis.js was a pretty solid choice.&lt;/p&gt;

&lt;p&gt;It’s been around forever, lots of features, decent docs. I figured it’d cover everything.&lt;/p&gt;

&lt;p&gt;And to be fair it worked fine at first.&lt;/p&gt;

&lt;p&gt;Until the requirements stopped being “demo-sized”.&lt;/p&gt;




&lt;h2&gt;
  
  
  Requirement #1: server-side rendering
&lt;/h2&gt;

&lt;p&gt;This is where things immediately got messy.&lt;/p&gt;

&lt;p&gt;The timeline needed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;render on the server&lt;/li&gt;
&lt;li&gt;be consistent (same output every time)&lt;/li&gt;
&lt;li&gt;plug into a reporting pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;vis.js is very DOM/browser-driven, so SSR was basically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;not supported unless we also wanted to also have to deal with a headless browser&lt;/li&gt;
&lt;li&gt;possible with hacks I didn’t want to maintain long-term
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That alone was a pretty big red flag.&lt;/p&gt;




&lt;h2&gt;
  
  
  Requirement #2: dependencies between items
&lt;/h2&gt;

&lt;p&gt;This one turned out to be just as awkward.&lt;/p&gt;

&lt;p&gt;The timeline wasn’t just visualising events, it needed to show relationships:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;item A blocks item B
&lt;/li&gt;
&lt;li&gt;task C depends on task D finishing
&lt;/li&gt;
&lt;li&gt;chains of related work across time
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, that means &lt;strong&gt;links between items, not just items on a timeline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;vis.js doesn’t really handle this cleanly out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no first-class concept of dependencies
&lt;/li&gt;
&lt;li&gt;you end up hacking it together yourself
&lt;/li&gt;
&lt;li&gt;quickly gets messy when the data isn't trivial
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Then the data got bigger
&lt;/h2&gt;

&lt;p&gt;Once I started feeding in more realistic data, things slowed down fast.&lt;/p&gt;

&lt;p&gt;Nothing crazy either, just enough items to resemble a real product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scrolling started to feel heavy&lt;/li&gt;
&lt;li&gt;zooming wasn’t smooth&lt;/li&gt;
&lt;li&gt;lots of DOM nodes getting created&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add dependencies on top of that, and things got even harder to reason about.&lt;/p&gt;

&lt;p&gt;It just didn’t feel like something I’d want in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  React didn’t help much either
&lt;/h2&gt;

&lt;p&gt;Trying to wrap vis.js cleanly in React felt… off.&lt;/p&gt;

&lt;p&gt;Lots of imperative code, lifecycle juggling, things getting out of sync.&lt;/p&gt;

&lt;p&gt;It worked, but it never felt like it &lt;em&gt;fit&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  At that point it was easier to start over
&lt;/h2&gt;

&lt;p&gt;I didn’t originally plan to build a timeline library, but it got to the point where working around everything was more effort than just doing it properly.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Tempis&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://tempis.dev" rel="noopener noreferrer"&gt;https://tempis.dev&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The main decision: stop relying on the DOM
&lt;/h2&gt;

&lt;p&gt;Most of the issues came back to one thing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;too much DOM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I switched to a canvas-based approach instead.&lt;/p&gt;

&lt;p&gt;That ended up solving a lot of problems at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;far fewer rendering bottlenecks
&lt;/li&gt;
&lt;li&gt;smoother interactions
&lt;/li&gt;
&lt;li&gt;more predictable output (important for reports)
&lt;/li&gt;
&lt;li&gt;a cleaner way to render relationships between items&lt;/li&gt;
&lt;li&gt;it's super easy to render a canvas to an image &lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What it’s actually aimed at
&lt;/h2&gt;

&lt;p&gt;This isn’t really a “toy timeline” library.&lt;/p&gt;

&lt;p&gt;It’s for things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reporting views
&lt;/li&gt;
&lt;li&gt;product roadmaps
&lt;/li&gt;
&lt;li&gt;activity timelines
&lt;/li&gt;
&lt;li&gt;scheduling / Gantt-style interfaces
&lt;/li&gt;
&lt;li&gt;anything where you have &lt;em&gt;a lot&lt;/em&gt; of time-based data
&lt;/li&gt;
&lt;li&gt;and especially where items are &lt;strong&gt;connected, not just listed&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
