<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Vojtech Rinik on Medium]]></title>
        <description><![CDATA[Stories by Vojtech Rinik on Medium]]></description>
        <link>https://medium.com/@vojto?source=rss-5a63352826d8------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*rFEUacYPUpehnmyrv1ZO2Q.jpeg</url>
            <title>Stories by Vojtech Rinik on Medium</title>
            <link>https://medium.com/@vojto?source=rss-5a63352826d8------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 03 Aug 2026 14:23:50 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@vojto/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[How to install Python under Rosetta 2]]></title>
            <link>https://medium.com/thinknum/how-to-install-python-under-rosetta-2-f98c0865e012?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/f98c0865e012</guid>
            <category><![CDATA[apple-silicon]]></category>
            <category><![CDATA[rosetta]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Fri, 24 Sep 2021 08:54:31 GMT</pubDate>
            <atom:updated>2021-09-24T08:54:31.950Z</atom:updated>
            <content:encoded><![CDATA[<p>Running frontend written in TypeScript is easy and can be done under M1. With Python backends it’s a bit more complicated: There are pip dependencies that just won’t work under M1.</p><p>The solution is just to run your entire pipeline under Rosetta. (Ideal solution is to get everything on latest versions which support M1, but this is just not realistic with most projects.)</p><h4>Copy the Terminal app</h4><p>Copy and paste the Terminal (or in my case iTerm app — reason why I use this is support for split windows) and rename one to Rosetta. Press cmd-I and make sure “Open using Rosetta” is checked.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/273/1*Y7BKi0fp0GoIoMza185niw.png" /></figure><h4>Add current architecture to your $PROMPT</h4><p>You can always print the current architecture using <strong><em>uname -m</em></strong> command. Since I’m switching around a lot, I wanna know which one is running:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/408/1*48YOG-7GDHHRioofIWS4_w.png" /></figure><p>I edited theme in my oh-my-zsh installation by editing file ~/.oh-my-zsh/themes/robbyrussell.zsh-theme (theme I&#39;m using).</p><p>This is the updated version:</p><pre>declare -A archs<br>archs=(<br>    [&quot;arm64&quot;]=&quot;$bg_bold[yellow]%}%{$fg_bold[black]%}m1%{$reset_color%}&quot;<br>    [&quot;x86_64&quot;]=&quot;$bg_bold[red]%}%{$fg_bold[black]%}x86%{$reset_color%}&quot;<br>)<br>arch=$(uname -m)<br>label=$archs[$arch]<br><br>PROMPT=&quot;%{$label %(?:%{$fg_bold[green]%}➜ :%{$fg_bold[red]%}➜ )&quot;<br>PROMPT+=&#39; %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)&#39;<br><br>ZSH_THEME_GIT_PROMPT_PREFIX=&quot;%{$fg_bold[blue]%}(%{$fg[red]%}&quot;<br>ZSH_THEME_GIT_PROMPT_SUFFIX=&quot;%{$reset_color%} &quot;<br>ZSH_THEME_GIT_PROMPT_DIRTY=&quot;%{$fg[blue]%}) %{$fg[yellow]%}✗&quot;<br>ZSH_THEME_GIT_PROMPT_CLEAN=&quot;%{$fg[blue]%})&quot;</pre><p>Using red box to indicate I’m on older system, and yellow to show I’m up to date.</p><h4>Install separate copy of Homebrew</h4><p>I’m assuming you already installed Homebrew under M1. Make sure you have by running this command:</p><pre>m1 ➜  ~ which brew<br>/opt/homebrew/bin/brew</pre><p>We’re going to add another installation and put it in /usr/local.</p><p>Open your Rosetta terminal and install Homebrew. (Just follow the instructions on the website.) It will automatically create a binary in /usr/local/bin/brew.</p><p>After you installed it, your brew command still points to your M1 installation. So let&#39;s open .zshrc and add an alias:</p><pre>alias brow=&#39;/usr/local/bin/brew&#39;</pre><p>I saw the idea of using brow on some other blog (can&#39;t remember where) and I thought that was pretty neat. Basically, you&#39;ll run brew for M1 commands and you&#39;ll run brow for Rosetta commands.</p><h4>Install dependencies using `brow`</h4><p>Now install whatever dependencies you’ll need for Python and its packages. For me this was:</p><pre>brow install zlib<br>brow install openssl<br>brow install pcre</pre><h4>Install Python under Rosetta using pipenv</h4><p>In your project directory, create a Pipfile:</p><pre>[[source]]<br>name = &quot;pypi&quot;<br>url = &quot;https://pypi.org/simple&quot;<br>verify_ssl = true<br>[requires]<br>python_version = &quot;3.7&quot;</pre><p>I use version 3.7 here, because such version doesn’t exist on my system yet, so I know it will be installed using pyenv.</p><p>Whatever you do, make sure Pipenv doesn’t reuse existing version of Python that was installed under M1. Python has to be installed under Rosetta.</p><h4>Activate Python and install requirements</h4><p>Run pipenv shell and then start installing:</p><pre>pip install -r requirements.txt</pre><p>Another alternative is that your Pipfile already contains your requirements, in which case they would be installed in the previous step.</p><p>If you encounter any problems with missing libraries (such as zlib), relink them using brow link zlib and make sure to run those export commands that brew spits at the end, for example:</p><pre>For compilers to find zlib you may need to set:<br>  export LDFLAGS=&quot;-L/usr/local/opt/zlib/lib&quot;<br>  export CPPFLAGS=&quot;-I/usr/local/opt/zlib/include&quot;<br><br>For pkg-config to find zlib you may need to set:<br>  export PKG_CONFIG_PATH=&quot;/usr/local/opt/zlib/lib/pkgconfig&quot;</pre><p>(For zlib try exporting this too: CFLAGS=&#39;-I/usr/local/opt/zlib/include -L/usr/local/opt/zlib/lib&#39;)</p><h4>This should work!</h4><p>Now you have two Homebrew installations and two version of each Homebrew package — one compiled under M1, and one compiled under Rosetta.</p><p>There might be some issues when switching between the environments, but I’m assuming you’ll be running your backend under Rosetta, so it shouldn’t be a problem.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f98c0865e012" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thinknum/how-to-install-python-under-rosetta-2-f98c0865e012">How to install Python under Rosetta 2</a> was originally published in <a href="https://medium.com/thinknum">Thinknum</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing Graph UI]]></title>
            <link>https://medium.com/thinknum/introducing-graph-ui-9026b29e4ae2?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/9026b29e4ae2</guid>
            <category><![CDATA[amazon-neptune]]></category>
            <category><![CDATA[graph-database]]></category>
            <category><![CDATA[janusgraph]]></category>
            <category><![CDATA[neo4j]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Tue, 25 Aug 2020 13:43:48 GMT</pubDate>
            <atom:updated>2020-08-26T08:33:07.984Z</atom:updated>
            <content:encoded><![CDATA[<h3>Change your Graph Database into a No-Code Tool</h3><p>Here at Thinknum, we store an increasing amount of data in graph databases.</p><p>Using graphs allows us to derive some unique insights, by following a path of relationships and collecting information along the way.</p><p>The industry has two popular languages: Cypher, with its declarative SQL-like notation, and Gremlin with its imperative style. Using these languages is a powerful way to answer any query you may think of.</p><p>Graph databases are growing in popularity, as more organizations find that they are the right tool to work with their data.</p><p>As more users are exposed to these technologies, there is a growing need to access them in a user-friendly way, and we felt that too.</p><p>However, when we set out to find an easy to use, web-based, Tableau-style UI to work with these databases, we returned empty handed. Every program is still centered around writing queries by hand, and then inspecting the results using some kind of visualization.</p><p>That’s still very far from what we needed and imagined. We wanted to build a query, and work with the results; See them as a graph, but also turn them into a chart if we wanted.</p><p>Over the last year or so, a part of our team set out to fix this problem. We decided to build a UI for graph databases that would act as a “data lab” (a term we’ve used since the birth of Thinknum.)</p><p>And so today we’re officially announcing <a href="https://graphui.dev/">Graph UI</a>. It is a feature-rich UI to work with your graph database.</p><p>You can build your query visually by defining a series of steps to take through your database. For example, you may want to start with movies, follow all the directors, and end up in their hometowns.</p><p>Along the way, you can collect data that might be useful in the final report. For example, you may want to see how many Oscar movies each hometown produced. You can have endless use cases.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Nnsq2aHoCYWt7d0o" /></figure><p>And now, you can ask these questions without writing any code, just by using the drag-and-drop interface in Graph UI.</p><p>Once you’ve collected your data, you can turn to the analysis portion, which works the same as any relational tool. You can display your results as a table, and from there, you can turn it into various charts.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*a5jHOWzrdCFoind6" /></figure><p>There’s a lot more to Graph UI, and you can learn all about it over <a href="https://graphui.dev/">here</a>. If Graph UI seems like a great fit for your needs, feel free to sign up for the waitlist. You can email us directly with any questions!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9026b29e4ae2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thinknum/introducing-graph-ui-9026b29e4ae2">Introducing Graph UI</a> was originally published in <a href="https://medium.com/thinknum">Thinknum</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mac apps are dead]]></title>
            <link>https://medium.com/@vojto/mac-apps-are-dead-5f192524f88b?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/5f192524f88b</guid>
            <category><![CDATA[mac]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Mon, 22 Jun 2020 19:11:43 GMT</pubDate>
            <atom:updated>2020-06-22T19:14:30.908Z</atom:updated>
            <content:encoded><![CDATA[<p>After watching WWDC 2020 keynote, I’m really sad.</p><h3></h3><p></p><p>I always had a passion for “Mac applications”. Perfect integration with the system, beautiful design, great ease of use…</p><p>My favorite example has always been <a href="https://culturedcode.com/things/">Things</a>. It’s a joy to use. This idea is dead after today.</p><p>Because us, macOS developers, we’ll have to compete with the shit that is iOS apps running on Mac. We’ve seen Catalyst. Not even Apple can ship a nice Catalyst app.</p><p>And it’ll be so easy to run your iOS app on the Mac that no one will bother crafting beautiful, native macOS experience.</p><p>So… Crappy day for macOS developers.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5f192524f88b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to get into flow when doing taxes]]></title>
            <link>https://medium.com/@vojto/how-to-get-into-flow-when-doing-taxes-79844514de7?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/79844514de7</guid>
            <category><![CDATA[flow]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[pomodoro-technique]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Tue, 05 May 2020 18:28:58 GMT</pubDate>
            <atom:updated>2020-05-05T18:28:58.055Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I9tD_Wb81fnVLiyRyNuuhw.jpeg" /></figure><p>From <a href="https://superorganizers.substack.com/p/stop-trying-to-make-hard-work-easy">Stop Trying to Make Hard Work Easy</a> with Nir Eyal:</p><blockquote>It’s the same deal with flow. You’ve heard, I’m sure all of the research on flow, and it’s actually not very good advice for most people. Because again, it makes you think you can make anything effortless. You know, professional basketball players are in flow.<strong> But how do you get into flow when you’re doing your taxes?</strong></blockquote><blockquote>Same with writing. I’ve written two books, and hundreds of articles. Writing is never easy. It’s boring. It’s frustrating. It’s difficult. It’s anxiety producing.</blockquote><p>You don’t. If you’re doing taxes, you don’t get into flow.</p><p>Some days there’s just no flow, and we need to accept that. Stop looking for the easy way out. Work is hard sometimes.</p><p>The key is to still push yourself through the boring tasks. Train yourself to concentrate even through the difficult.</p><p>The <strong>Pomodoro technique</strong> helps a lot. Do the hard thing for 25 minutes, then you get to take a break.</p><p>My typical coding workflow is to use <a href="https://tomato2.app">Tomato 2</a> to work for at least 25 minutes. (The app won’t interrupt me once the time is up.) If it’s going well, I’ll continue and find myself working for an hour. But if it’s really difficult, I’ll just take a break, then repeat.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=79844514de7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Writing high performance React-Pixi code]]></title>
            <link>https://medium.com/thinknum/writing-high-performance-react-pixi-code-c8c75414020b?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/c8c75414020b</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[pixijs]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Thu, 05 Mar 2020 14:07:54 GMT</pubDate>
            <atom:updated>2020-03-05T14:07:54.915Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wPyvsZNNJ_y3dDwKkzQ62w.png" /><figcaption>Graph rendered with Pixi.js and React-Pixi</figcaption></figure><p>At <a href="https://kgbase.com/">KgBase</a>, we recently rewrote our graph UI to use WebGL instead of SVG. Our goal was to:</p><ol><li>Improve performance and allow 1,000s of nodes to be rendered</li><li>Keep using React, if possible. We want to quickly iterate on new features, and React lets you prototype faster.</li></ol><p>A very common tool for rendering WebGL content is <a href="https://www.pixijs.com/">Pixi.js</a>. It’s typically used for making simple games, but it works very well for our use case.</p><p>If you want to integrate Pixi.js with React, you’ll need to use <a href="https://reactpixi.org/">React Pixi</a>, (or react-pixi-fiber, but I’ll get to that later.)</p><p>In its initial version, our rendering code was this simple:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/350e891e87b49b4ef362b5a44a4bd0d6/href">https://medium.com/media/350e891e87b49b4ef362b5a44a4bd0d6/href</a></iframe><p>You can just take all the nodes, and for each render your own NodeView component that takes care of rendering a single node:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d889318a503dac449d9387e03f504c21/href">https://medium.com/media/d889318a503dac449d9387e03f504c21/href</a></iframe><p>Now notice the Circle component. This is not part of react-pixi. We&#39;re importing that from our own ./Primitivesfolder.</p><p>React Pixi shows you how to build your own components like above right on their <a href="https://reactpixi.org/">landing page</a>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/af8312e9007f32c41ec8dadf06359d56/href">https://medium.com/media/af8312e9007f32c41ec8dadf06359d56/href</a></iframe><p><strong>Notice anything wrong with that code?</strong></p><p>I didn’t either, until we got into a specific situation:</p><p>When you click on a node, we want to highlight it. We do it by setting alpha of clicked node to 1.0, while decreasing alpha of all other nodes to 0.2 or so.</p><p>With the implementation above, each change in alpha will call applyProps, which will re-draw the entire shape. So we call this snippet 1,000 times each time user clicks a node:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ae1805b0b71483cba00993dbe08693b2/href">https://medium.com/media/ae1805b0b71483cba00993dbe08693b2/href</a></iframe><p>If we just want to change the alpha, this is all we have to do:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5130d80de97a2acc08295f1e0e6feb52/href">https://medium.com/media/5130d80de97a2acc08295f1e0e6feb52/href</a></iframe><p>So the proper way to implement your custom Rectangle/Circle component would be like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9c75bf608d381d20030c73d0162e2853/href">https://medium.com/media/9c75bf608d381d20030c73d0162e2853/href</a></iframe><p>The important part is to make sure that there is no unnecessary re-drawing of your component. Whenever you see code like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7e886a1f14ad1aec0e72f1856c7ad01e/href">https://medium.com/media/7e886a1f14ad1aec0e72f1856c7ad01e/href</a></iframe><p>You should refactor it: Always compare your props to oldProps, and only re-render if something changed.</p><p><strong>Interesting fact:</strong> Default implementation of Text in react-pixi will also update the component each time, even if nothing changed. Default implementation looks something like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7f648fa6fbc44aa965441e412dc54694/href">https://medium.com/media/7f648fa6fbc44aa965441e412dc54694/href</a></iframe><p>The action of setting new text value (instance.text = text) is an expensive operation! It will cause your Pixi instance to be re-rendered. Instead, always check if re-render is necessary.</p><p>To fix this, you’ll need to create your own component, called for example FastText:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e2d8b81914bd5196fa3cdef3a23ca91a/href">https://medium.com/media/e2d8b81914bd5196fa3cdef3a23ca91a/href</a></iframe><p>And now rerendering will only happen if text was really changed.</p><p>There are a lot more performance questions to consider when dealing with Pixi and WebGL. What I described above is a good first step to writing performant code. Always be careful for what happens in applyProps. It should never be creating new Graphics objects, and it should not even be changing properties needlessly. It should always be comparing current and old properties before changing anything.</p><p>Like I said, this is a good first step. We’ve been able to render up to 5,000–10,000 nodes fairly effortlessly with this approach. There’s more to be done for higher FPS and more nodes, but that’s a topic for another blog post.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c8c75414020b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thinknum/writing-high-performance-react-pixi-code-c8c75414020b">Writing high performance React-Pixi code</a> was originally published in <a href="https://medium.com/thinknum">Thinknum</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Common pitfalls: Creating a custom NPM package with React and TypeScript]]></title>
            <link>https://medium.com/thinknum/common-pitfalls-creating-a-custom-npm-package-with-react-and-typescript-730d56e4131a?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/730d56e4131a</guid>
            <category><![CDATA[rollup]]></category>
            <category><![CDATA[webpack]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Tue, 03 Mar 2020 14:41:25 GMT</pubDate>
            <atom:updated>2020-03-03T14:41:25.960Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This article is written by </em><a href="https://twitter.com/_vojto"><em>Vojtech Rinik</em></a><em>, lead frontend engineer at </em><a href="https://thinknum.com/"><em>Thinknum</em></a><em>. We started using React in 2014, and currently it powers most of our UI. We’re at version 16.8 now, enjoying the latest features in this recent release. </em><a href="https://careers.smartrecruiters.com/thinknum"><em>If you’re in NYC and enjoy writing React code, check out our open positions.</em></a></p><p>I recently decided to create a private NPM package for some of the UI we use in our apps. The goal was simple. I wanted to install and start using the package with one line of code: yarn add rainbow-buttons. (&quot;Rainbow&quot; buttons being an example.)</p><p>I had some clear requirements for this package:</p><ul><li>It should be written in TypeScript, like the rest of our codebase</li><li>It should contain its type declarations, so that we wouldn’t have to install separate package from @types/rainbow-buttons.</li><li>It should contain React components. We’ll want to do &lt;RainbowButton&gt;Hello!&lt;/RainbowButton&gt;.</li><li>It should contain it’s own CSS styles written in Sass. Those should be imported automatically when I run import {RainbowButton} from &quot;rainbow-buttons&quot;.</li></ul><p>Unfortunately, it wasn’t straightforward at all. I came across quite a few problems. In this blog post, I’d like to go through these problems, explain what caused them and how to address them.</p><h3>Pitfall 1: Don’t forget to use <a href="https://stackoverflow.com/a/34645112">peer dependencies</a></h3><p>At my first attempt, I added all of package’s dependencies into its regular, production dependencies list. This was a bad idea of course.</p><p>What happened was that my React dependency, for example, was installed by my package, but also by the host project. So now I had two instances of React, possibly at two different versions.</p><p>This is kinda obvious now, but that’s why NPM/Yarn has the concept of <strong>peer dependencies</strong>. Your package will specify which dependencies it needs, and the host project is responsible for installing them.</p><figure><img alt="Some of peer dependencies are set to “*”, any version, and some are locked at a particular version.c" src="https://cdn-images-1.medium.com/max/412/1*-cOlwMZj6avCrZyXnpc2fQ.png" /><figcaption>Some of peer dependencies are set to “*”, any version, and some are locked at a particular version.c</figcaption></figure><h3>Pitfall 2: Don’t use <a href="https://webpack.js.org/">WebPack</a>, use <a href="https://rollupjs.org/guide/en">Rollup</a></h3><p>I was seeing a lot of errors when just trying to build the package with WebPack. One of the problems was with peer dependencies. They were defined in peerDependencies section of package.json, but as soon as I removed the actual files from node_modules/, the build broke. So to fix that issue, I had to add them also to devDependencies, because Yarn won&#39;t install peer dependencies on regular yarn install, only dev and prod dependencies.</p><p>My package.json was quickly becoming a mess. I had to keep @types packages in dev dependencies, and regular packages in both dev and peer dependencies. Go figure.</p><p>There were more strange errors which I still don’t know how to resolve. Most likely version mismatches.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/608/1*d4T_AnHmiaB2242FxDHwPw.png" /></figure><p>But somehow, everything works fine once I switched to <a href="https://rollupjs.org/guide/en">Rollup</a>. If you haven’t used it yet, it’s an alternative packaging tool which is primarily used in libraries. It’s used by React, D3.js, and many more popular open-source packages. There is a great <a href="https://medium.com/webpack/webpack-and-rollup-the-same-but-different-a41ad427058c">article explaining the main differences</a>, and a <a href="https://hackernoon.com/building-and-publishing-a-module-with-typescript-and-rollup-js-faa778c85396">great article explaining how to use it with TypeScript</a>.</p><p>I ended up with fairly simple config file:</p><pre>import typescript from &#39;rollup-plugin-typescript2&#39;;<br>import pkg from &#39;./package.json&#39;;<br>import postcss from &#39;rollup-plugin-postcss&#39;;</pre><pre>export default {<br>  input: &#39;src/index.ts&#39;,<br>  output: [<br>    {<br>      file: pkg.main,<br>      format: &#39;cjs&#39;,<br>    },<br>    {<br>      file: pkg.module,<br>      format: &#39;es&#39;,<br>    },<br>  ],<br>  external: [<br>    ...Object.keys(pkg.dependencies || {}),<br>    ...Object.keys(pkg.peerDependencies || {}),<br>  ],<br>plugins: [<br>    typescript({<br>      typescript: require(&#39;typescript&#39;),<br>    }),<br>    postcss({<br>      modules: true,<br>      namedExports: true<br>    })<br>  ],<br>}</pre><p>The ES module makes sense when you pair it with module config in your package.json:</p><pre>&quot;main&quot;: &quot;dist/index.js&quot;,<br>&quot;module&quot;: &quot;dist/index.es.js&quot;,<br>&quot;types&quot;: &quot;dist/index.d.ts&quot;,</pre><p>You can see a few more nifty things going on in that config file:</p><ul><li>It’s automatically defining all peer dependencies AND dependencies as external. The resulting package should only contain the package files.</li><li>It’s taking care of CSS compilation including generating modules to be used as import * as styles from &quot;./styles.scss&quot;</li></ul><p>But here’s the important thing: <strong>Rollup doesn’t need your peer dependencies to be actually installed in node_modules/</strong>. It just needs your @types/* packages, which are installed as dev dependencies, so they would be present in node_modules/ at all times.</p><p>It allowed me to clean up my package.json with double dev and peer entries for my peer dependencies. The package.json file can now be this simple:</p><pre>&quot;devDependencies&quot;: {<br>  &quot;<a href="http://twitter.com/types/react">@types/react</a>&quot;: &quot;16.4.6&quot;,<br>  &quot;<a href="http://twitter.com/types/react-dom">@types/react-dom</a>&quot;: &quot;16.8.3&quot;,<br>  // ...<br>},<br>&quot;peerDependencies&quot;: {<br>  &quot;react&quot;: &quot;*&quot;,<br>  &quot;react-dom&quot;: &quot;*&quot;,<br>  // ...<br>}</pre><h3>Pitfall 3: Avoid symlinks, don’t use yarn link</h3><p>Our package relies on types packages for some 3rd party libraries, such as @types/react or @types/recompose. These are defined as dev dependencies in package.json.</p><p>With this setup, compiling the main project would return a bunch of Duplicate identifier errors all over the place:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/602/1*vIe1Iodb1pGJT-iB_7tZ5A.png" /></figure><p>After some Googling, I figured out the problem is with TypeScript compiler. These type definitions now exist in project’s node_modules, but also in package’s node_modules. Somehow, <strong>TypeScript is not able to deduplicate these type definitions when symlinking is used.</strong> And yarn link relies on symlinking.</p><p>This can be resolved with some <a href="https://blog.rytmis.net/2018/04/27/typescript-duplicate-identifiers-when-using-npm-link/">smart configuration</a> in your main project, but my favorite solution is to use <a href="https://github.com/whitecolor/yalc">yalc</a>. It’s a simple tool that simulates publishing to NPM by actually copying the files.</p><p>The usage is simple:</p><pre># In your package:<br>yalc publish</pre><pre># In your main project:<br>yalc add rainbow-buttons</pre><pre># In your package, after a rebuild:<br>yalc push</pre><p>The last command is the most interesting: When you run yalc push, it will go to each project where it&#39;s used, and automatically copy the newest files over.</p><p>So I end up running this each time I change any code in my package:</p><pre>yarn build &amp;&amp; yalc push</pre><p>You can read more about the issue in this <a href="https://medium.com/@mtfranchetto/the-solution-for-a-working-npm-yarn-link-ddcb4f3c785e">blog post</a>.</p><h3>Conclusion &amp; source code</h3><p>That’s it, a summary of some real-world problems you can come across when developing a non-trivial TypeScript package for React.</p><p>If you’re interested in source code of this particular package, we’ve actually published it as open-source library called <a href="https://github.com/thinknum/react-tour">react-tour</a>. Feel free to work through the configuration files if anything’s not making sense.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=730d56e4131a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thinknum/common-pitfalls-creating-a-custom-npm-package-with-react-and-typescript-730d56e4131a">Common pitfalls: Creating a custom NPM package with React and TypeScript</a> was originally published in <a href="https://medium.com/thinknum">Thinknum</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[If you can’t concentrate]]></title>
            <link>https://medium.com/@vojto/if-you-cant-concentrate-110158674f52?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/110158674f52</guid>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[focus]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Thu, 27 Feb 2020 07:05:22 GMT</pubDate>
            <atom:updated>2020-02-27T07:05:22.837Z</atom:updated>
            <content:encoded><![CDATA[<p>Take a walk outside for 20 minutes. Leave the phone in the office.</p><p>During these 20 minutes, only think about the problem you’re working on. Nothing else.</p><p>Try to visualize how you’re gonna work on it when you’re back. Try to picture the solution. Try to envision the steps you’ll take.</p><p>Then go back and get started. Stay as focused as you were during your walk.</p><p>This works like magic.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=110158674f52" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Book tip for “The Martian” fans]]></title>
            <link>https://medium.com/@vojto/book-tip-for-the-martian-fans-c985233fa4f4?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/c985233fa4f4</guid>
            <category><![CDATA[founders]]></category>
            <category><![CDATA[books]]></category>
            <category><![CDATA[startup]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Sat, 15 Feb 2020 16:52:09 GMT</pubDate>
            <atom:updated>2020-02-15T16:56:43.242Z</atom:updated>
            <content:encoded><![CDATA[<p>When I ask my programmer friends for a book tip, The Martian by Andy Weir keeps coming up. No wonder. I think it appeals to engineers in general. Guy’s faced with a big technical problem, and needs to come up with a solution, quick. If he can’t, he runs out of food.</p><p>What I really liked about The Martian, is that it’s taking place in the near-future. No crazy aliens, no jumping between galaxies. The storyline could be the reality in a decade or so. The book was also technically very sound, another reason why we all liked it so much.</p><p>Getting to the point now. I started reading <a href="https://www.amazon.com/Winter-World-Long-Book-ebook/dp/B07N32K12H?tag=vojto-20">Winter World</a>, a book by A.G. Riddle. <strong>It reminds me so much of the Martian! </strong>I’ll try to describe it without any spoilers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/318/1*jCiGUlwbB_-R66POdnv5HA.jpeg" /></figure><p>The story is set in near future. The Earth is cooling down significantly, and no one knows why. Until they find a possibly alien object in space, which also destroys the ISS, right after being discovered.</p><p>Our protagonists, James and Emma (and a team of scientists) go on a space mission to investigate these artifacts. The trip takes 4 months, and they spend it building drones. Then they finally find something unexpected… And you’ll have to find out yourself what happens next.</p><p>I’m sharing this as a book tip, because I think it would have the same appeal to tech people, as Martian had.</p><p>It’s the same concept. Skilled engineer/scientist has a mission to figure out something technical, and they have to do in on a deadline, or face dire consequences.</p><p>The story is a little more detached from reality (aliens), but we don’t really meet them (thus far — I’ve only ready about 1/3 of the first book), so there’s an air of mystery.</p><p>I’m not sure about the technical details, but I have no complaints — no obvious flaws. Their “space drones” sound pretty convincing. You’ll also find similar conversations about NASA and space travel in general, as in The Martian.</p><p>So all in, it’s a great space book to relax with. It will definitely go on my list of what I call “mild sci-fi books”.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c985233fa4f4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Apple cares about devs, it turns out]]></title>
            <link>https://medium.com/@vojto/apple-cares-about-devs-it-turns-out-4504f823c43c?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/4504f823c43c</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[indie]]></category>
            <category><![CDATA[app-store]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Fri, 07 Feb 2020 18:41:30 GMT</pubDate>
            <atom:updated>2020-02-07T18:41:30.197Z</atom:updated>
            <content:encoded><![CDATA[<p>So a few days ago, <a href="https://medium.com/@vojto/app-store-rejected-my-simple-appfigures-client-5948136c6f0?source=your_stories_page---------------------------">I tried submitting a very simple app, and it got rejected</a>. I thought it was pretty unfair, so I asked around on Twitter. Most people agreed with me. A lot of people suggested I should skip App Store altogether.</p><h3>A digression: Why I need App Store</h3><p>Here’s why I need App Store: I need a reliable updates system. My first iteration has minimal set of features. I’m planning to improve it soon. And then again, and again. But I need reliable updates to do that.</p><p>I could use Sparkle, but if I can have this feature for free, I’ll take it. I would rather spend my time building features, instead of implementing Sparkle.</p><p>Another reason for App Store: It’s part of my idea validation. The app is called “Median for Appfigures”. I’m deliberately optimizing for “appfigures” keyword, because it will answer an important question: <strong>Is anybody searching for Appfigures app on the App Store? </strong>If not, I may as well move on the another idea.</p><p>(My ultimate plan is to support more data services, so that you could have all this “data at your fingertips”, but that’s for later.)</p><h3>My expectations were low</h3><p>Right after the rejection, I submitted an appeal. I didn’t expect much. I heard the stories. Once your app gets rejected, there’s nothing you can do, I thought. Especially if you’re small and irrelevant.</p><p>So I Tweeted about it, and I received a lot of responses. Most of them were supportive. A lot of them suggested that I should skip App Store. However, <strong>the best advice was to try and work with Apple</strong>. I honestly didn’t think that would help. But it did.</p><p>To my surprise, I got a reply to my appeal. (At this point, I wasn’t expecting one.) Just two days later I received a response, which basically said <strong>“Yup, we checked again, you’re fine, actually.”</strong></p><p>Unbelievable, I thought. The best part? This heart warming message at the end: <strong>“Thank you for your commitment to Mac app development.” </strong>I’ll be much more patient in the future, now that I’ve seen a positive side of App Store.</p><h3>Thanks, everyone!</h3><p>Thanks to everyone who replied and retweeted my little frustrated Tweet. It’s really good to be around this community of iOS devs — big or small, doesn’t matter. Thank you!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4504f823c43c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[App Store — rejected my simple Appfigures client]]></title>
            <link>https://medium.com/@vojto/app-store-rejected-my-simple-appfigures-client-5948136c6f0?source=rss-5a63352826d8------2</link>
            <guid isPermaLink="false">https://medium.com/p/5948136c6f0</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[indie]]></category>
            <dc:creator><![CDATA[Vojtech Rinik]]></dc:creator>
            <pubDate>Wed, 05 Feb 2020 18:53:27 GMT</pubDate>
            <atom:updated>2020-02-07T18:46:12.582Z</atom:updated>
            <content:encoded><![CDATA[<h3>App Store — rejected my simple Appfigures client</h3><p><em>Edit: 2 days later, the appeal worked. </em><a href="https://medium.com/@vojto/apple-cares-about-devs-it-turns-out-4504f823c43c"><em>More here.</em></a></p><p>I’ve always wanted to build a desktop app that would let me access my most important data quickly. Like those old dashboard widgets used to.</p><p>I finally got around to it, and started with Appfigures, my favorite service to track App Store sales. I wanted to ship something to users, so I built my first iteration in 26 days of weekends and evenings:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n0J0OzSGSjwHJx4SxoWqug.png" /></figure><p>Sometimes I just have a quick question for my data, and this lets me get an answer in the matter of seconds. It’s very limited now, but I have a lot of ideas for improvement. (I’ve tried building this idea <a href="https://median.tech">before</a>. That failed, and I keep coming back to it.)</p><p>Unfortunately, App Store Review team didn’t agree:</p><blockquote><strong>We noticed that your app offers a subscription with a mechanism other than the in-app purchase API.</strong></blockquote><p>Can anyone explain to me, how did they let the official Appfigures app into the App Store? It’s the same thing, and I’m pretty sure they don’t have IAPs. It’s just a dumb viewer of the data.</p><p><strong>There are countless apps that use 3rd party data, even if a subscription is needed. This doesn’t make any sense.</strong></p><p>Worst part — there’s nothing I can do. I have no idea how to fix this, except for finding a brand new project to work on.</p><p>Is there anyone who has experience with a situation like this? I would appreciate a ton any tip how to proceed. Please let me know in the comments, on <a href="https://twitter.com/_vojto">Twitter</a> or via email. (vojto at rinik dot net)</p><p>I’m not a big company, I’m not a big name, and it seems Apple couldn’t care less about people like me. But every success story started like this. I wish Apple would help us, instead of sabotaging all good efforts.</p><p>If you’re iOS developer, please feel free to <a href="https://twitter.com/_vojto/status/1225131206959910912">Tweet this</a>. I’m too irrelevant for anybody to notice, but with your help, there’s a chance…</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5948136c6f0" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>