<?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>Forem: David Sancho</title>
    <description>The latest articles on Forem by David Sancho (@davesnx).</description>
    <link>https://forem.com/davesnx</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%2F2610%2F1e7c4110-c1a4-426c-88a4-697fb64d5ecb.jpg</url>
      <title>Forem: David Sancho</title>
      <link>https://forem.com/davesnx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/davesnx"/>
    <language>en</language>
    <item>
      <title>Don't use Tailwind for your Design System</title>
      <dc:creator>David Sancho</dc:creator>
      <pubDate>Sat, 06 Mar 2021 15:37:19 +0000</pubDate>
      <link>https://forem.com/davesnx/don-t-use-tailwind-for-your-design-system-3074</link>
      <guid>https://forem.com/davesnx/don-t-use-tailwind-for-your-design-system-3074</guid>
      <description>&lt;p&gt;Don't use Tailwind for your Design System or your "UI Framework" or component system, call it whatever you prefer. What I meant is Tailwind isn't component-driven, which they claim to be, and you might struggle making a Design system with it.&lt;/p&gt;

&lt;p&gt;Recently I read a lot of opinions about Tailwind (&lt;a href="https://mxstbr.com/thoughts/tailwind"&gt;mxstbr's thoughts&lt;/a&gt;, &lt;a href="https://dev.to/jaredcwhite/why-tailwind-isn-t-for-me-5c90"&gt;jaredcwhite's opinion&lt;/a&gt;, &lt;a href="https://thoughtbot.com/blog/tailwind-versus-bem"&gt;Tailwind versus BEM&lt;/a&gt;) and nevertheless I agree with most of the points there I got a different perspective.&lt;/p&gt;

&lt;p&gt;I will try to explain which are the drawbacks to make a Design system in Tailwind, focusing in the technical part of the components. Here I'm assuming that the reader is familiar with Design systems. Otherwise, can read more about in &lt;a href="https://www.invisionapp.com/inside-design/guide-to-design-systems/"&gt;here&lt;/a&gt; or &lt;a href="https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A little bit about my experience
&lt;/h3&gt;

&lt;p&gt;Currently I'm working at Draftbit, and our frontend is build on top of ReasonReact uses Tailwind, it's about ~500 components and the main page, called the &lt;code&gt;builder&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ok7-o2Ux--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/7ae490f2229bfbc7ed4e39baf34fe00feda2d8fd/76a6e/static/ca7f5881d29cb6d489393a6cd8546c3a/27b8e/draftbit-builder.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ok7-o2Ux--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/7ae490f2229bfbc7ed4e39baf34fe00feda2d8fd/76a6e/static/ca7f5881d29cb6d489393a6cd8546c3a/27b8e/draftbit-builder.png" alt="screenshot-draftbit-builder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have a design system on top of Tailwind (we might Open Source it at some point) and I contributed in a few Design Systems in my career, I even write my own.&lt;/p&gt;

&lt;p&gt;I'm obsessed with the conjunction of design with functional programming and how those enable writing modular UIs.&lt;/p&gt;

&lt;p&gt;But now, let's talk about Tailwind.&lt;/p&gt;

&lt;h3&gt;
  
  
  First, the good parts
&lt;/h3&gt;

&lt;p&gt;The reason why I think Tailwind is amazing have nothing to do with their utility classes. Those utility classes have been around the Frontend community for a long time - &lt;a href="http://tachyons.io/"&gt;tachyons&lt;/a&gt; has been created around 2016. Even some people found them pleasant to use I personally prefer to write directly CSS.&lt;/p&gt;

&lt;p&gt;The reasons why I think Tailwind shines are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Theme with strong defaults, beautiful and scalar.&lt;/strong&gt; The config generates all the values needed to produce a scaled system based on all those tokens. For example, spacing. The defaultConfig will generate spacing based on a scale from 0 to 96 that goes from 0px until 24rems. &lt;a href="https://github.com/tailwindlabs/tailwindcss/blob/master/stubs/defaultConfig.stub.js#L7"&gt;defaultConfig&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extendability,&lt;/strong&gt; being able to extend those values in the config brings the possibility to represent any design and being propagated to the right CSS properties. Ex, spacing would generate the values for margin, padding, width, min-height, min-height, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's just CSS.&lt;/strong&gt; It's not an abstraction, or coupled to any framework. ****Anyone can use it with minimal setup: all IDE would have support for it, all frontend framework can use it, there's ton of build tools to optimise their performance and long etcetera.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How is used in React
&lt;/h3&gt;

&lt;p&gt;I use the example of React since I'm familiar with it, but I believe everything in this post applies to other frontend libs.&lt;/p&gt;

&lt;p&gt;React uses JSX via Babel or any transpiler to transform JSX  to function calls, and some props/attributes renames on the process, such as &lt;code&gt;classNames&lt;/code&gt; to &lt;code&gt;class&lt;/code&gt;(since it's a reserved keyword in JavaScript).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;className&lt;/code&gt; is used to apply CSS classes to React Elements, which at the end will be DOM Elements.&lt;/p&gt;

&lt;p&gt;This is the defacto method to use Tailwind with React, you will often will see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex md:block w-32 h-full"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's wrong with className
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8PBXNm6q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/6732581c4c8101c449210f56ee56c839ee3be194/398b3/static/c0715a28bb712705b589d263cfb673c5/27b8e/classnames.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8PBXNm6q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/6732581c4c8101c449210f56ee56c839ee3be194/398b3/static/c0715a28bb712705b589d263cfb673c5/27b8e/classnames.png" alt="Editor-with-classNames"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hard &lt;strong&gt;to maintain&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It's error prone to remove one of the &lt;code&gt;classNames&lt;/code&gt; from the list, is a similar situation when you want to remove an unused CSS class in an &lt;a href="https://css-tricks.com/oh-no-stylesheet-grows-grows-grows-append-stylesheet-problem"&gt;append only stylesheet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Aside from hard to remove, it's hard to change. Adding those classes might seem simple and fast while creating those components, but it will slow you down when modify or refactor them.&lt;/p&gt;

&lt;h3&gt;
  
  
  It is optimised for writing, but not for reading
&lt;/h3&gt;

&lt;p&gt;When reading JSX, I feel confortable to imagine a 1-to-1 match with the UI. I can easily navigate thought the component tree and map with the reality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6-dJpP2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/e8b59e62ef09799a052c3344983200e1cb428ddb/edb8f/static/69c0f1240097b9e2d13446315d556487/49e4f/jsx-ui.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6-dJpP2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/e8b59e62ef09799a052c3344983200e1cb428ddb/edb8f/static/69c0f1240097b9e2d13446315d556487/49e4f/jsx-ui.jpg" alt="screenshot-jsx-sketch-UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even that this snapshot of code-UI is doable in Tailwind, at some level of those components you will find a layer with a bunch of &lt;code&gt;classNames&lt;/code&gt; that you need to parse in your head in order to imagine the UI.&lt;/p&gt;

&lt;p&gt;There's a famous quote floating around...&lt;br&gt;
&lt;strong&gt;"Best code isn't optimised to be written, instead, it's optimised to be read"&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fail at dynamic styling
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Dynamic Styling&lt;/strong&gt;: Style your components with a global theme or based on runtime states.&lt;/p&gt;

&lt;p&gt;Having a component API coherent, versatile and scoped is relatively hard by itself. Doing so, requires a good understanding of the problems that the component is trying to solve. Using Tailwind it's very tempting to use the same utility classes on that API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There's a definite disconnect between a CSS API and a component API. For a design system, I care more about getting the component one right - &lt;a href="https://twitter.com/sarah_federman"&gt;@sarah_federman&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, having a &lt;strong&gt;&lt;code&gt;&amp;lt;Link /&amp;gt;&lt;/code&gt;&lt;/strong&gt; component with &lt;code&gt;color="text-mono-100"&lt;/code&gt;. At the beginning it would make sense since &lt;code&gt;text-mono-100&lt;/code&gt; represents the desired color. Maybe later, appears a need to style the link with a different color on hover. You would add another prop called &lt;code&gt;hoverColor="text-mono-200"&lt;/code&gt; and call it a day.&lt;/p&gt;

&lt;p&gt;The fact that &lt;code&gt;color&lt;/code&gt; is represented in another format it's a nightmare, often UIs derive styles from props. In the example above, you could have a color be their hexadecimal representation &lt;code&gt;color="#b54c4c"&lt;/code&gt; and derive the &lt;code&gt;hoverColor&lt;/code&gt; with a library.&lt;/p&gt;

&lt;p&gt;The Tailwind language is nice to avoid typing CSS but isn't made for component APIs that use any sort of dynamic theme, making impossible (or very hard) to accomplish generative UI.&lt;/p&gt;

&lt;p&gt;As an example &lt;a href="https://hihayk.github.io/shaper/#system-ui,%20sans-serif/1.4/0.8/2.28/0.23/1/0.5/137/43/30/5/0.49/2/false"&gt;https://hihayk.github.io/shaper&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nb_W4cOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/b6e6c3eb30215173c13a956b7d21d1902101479f/ee8ad/static/a3d2375d5bcdb38a96d594bbf5a7fd8d/27b8e/shaper.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nb_W4cOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/b6e6c3eb30215173c13a956b7d21d1902101479f/ee8ad/static/a3d2375d5bcdb38a96d594bbf5a7fd8d/27b8e/shaper.png" alt="Shaper-by-hayk"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Breaks style encapsulation
&lt;/h3&gt;

&lt;p&gt;I consider harmful allowing &lt;code&gt;className&lt;/code&gt; as a prop on the component's API. This is often made to have flexibility from the outside to enable any sort of customisation to your component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex text-mono-100 p-4 &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a trap, designing a closed API for those customisations would battle-test your component and force you to decide on an API that have some boundaries, which is the initial goal of making a component.&lt;/p&gt;

&lt;p&gt;Tailwind doesn't have any opinion on this, but it's very tempting to allow any sort of className from the outside in your &lt;code&gt;classNames&lt;/code&gt;, given that you need customisation from the outside.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stack: Example of variants
&lt;/h3&gt;

&lt;p&gt;There're a &lt;a href="https://seek-oss.github.io/braid-design-system/foundations/layout#stack"&gt;lot&lt;/a&gt; &lt;a href="https://polaris.shopify.com/components/structure/stack"&gt;of&lt;/a&gt; &lt;a href="https://chakra-ui.com/docs/layout/stack"&gt;implementations&lt;/a&gt; &lt;a href="https://www.framer.com/api/stack/"&gt;of&lt;/a&gt; &lt;a href="https://v2.grommet.io/stack"&gt;Stack&lt;/a&gt;. That's a screenshot of &lt;a href="https://taco-davesnx.vercel.app/?path=/story/distribute--stack"&gt;mine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt; places a list of elements on the Y axis, one on top of the other. Adds consistent spacing between and moves them horizontally or vertically. It's an abstraction on top of &lt;strong&gt;&lt;code&gt;flexbox&lt;/code&gt;&lt;/strong&gt;, but limited. Those constraints are defined mostly by the designer, having a Component that enforces the number of variants it's generally a good think.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5SIy_kIB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/e64a4dacd359e9fd904cf7b9db4be62381b03b47/5df0d/static/d1cc0c33ebee0d35b2a8e84fb2deee8d/27b8e/stack.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5SIy_kIB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/e64a4dacd359e9fd904cf7b9db4be62381b03b47/5df0d/static/d1cc0c33ebee0d35b2a8e84fb2deee8d/27b8e/stack.png" alt="Stack-documentation-taco"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Composing at the wrong layer
&lt;/h3&gt;

&lt;p&gt;The key feature of &lt;strong&gt;React&lt;/strong&gt; is composition of components. Composition here means the possibility to plug those components like a lego which enables create more complex components based on more simple ones.&lt;/p&gt;

&lt;p&gt;Composition is a concept that more or less you might feel familiar with it, which applies to many areas of Software development.&lt;/p&gt;

&lt;p&gt;I see those &lt;strong&gt;"Components"&lt;/strong&gt; are a set of rules that React forces on top of just functions. The rules are simple and allow the React library to perform many benefits that we take for granted. Those rules, are better explained by &lt;em&gt;Dan Abramov&lt;/em&gt; in one of his posts, &lt;a href="https://overreacted.io/writing-resilient-components/#writing-resilient-components"&gt;Writing resilent components&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As I mentioned before, appending strings to style your component feels like a step backwards. Composing components that are made to solve one thing, It's the pattern that I trend to prefer.&lt;/p&gt;

&lt;p&gt;The composition of components allows React components, to benefit from&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Declarative representation of the UI&lt;/strong&gt;. Create complex pieces of UI based on smaller ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decoupled&lt;/strong&gt;: Isolate UI problems into black boxes that doesn't know anything about it's context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variants&lt;/strong&gt; Implement variants of the same component, without he need to re-implement different versions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example of component composition over Tailwind
&lt;/h3&gt;

&lt;p&gt;Re-implementation of Charkra's UI &lt;a href="https://chakra-ui.com/docs/layout/box"&gt;Box component&lt;/a&gt; into a pseudo design-system and Tailwind.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fgJfxFIf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/06427c472b1dc27ac89cf31c85092569df2bfc5a/255a0/static/39767e5642088e180493ec63d90ac9f4/27b8e/card.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fgJfxFIf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://d33wubrfki0l68.cloudfront.net/06427c472b1dc27ac89cf31c85092569df2bfc5a/255a0/static/39767e5642088e180493ec63d90ac9f4/27b8e/card.png" alt="Card-from-CharkaUI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can see the different approaches to the same UI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"320px"&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Stack&lt;/span&gt; &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"md"&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://bit.ly/2k1H1t6"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt; &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Badge&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#702459"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Plus&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Badge&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Spacer&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;
          &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm"&lt;/span&gt;
          &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt;
          &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#702459"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          VERIFIED &lt;span class="ni"&gt;&amp;amp;bull;&lt;/span&gt; CAPE TOWN
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Spacer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"xl"&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"semibold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Modern, Chic Penthouse with Mountain, City &lt;span class="err"&gt;&amp;amp;&lt;/span&gt; Sea Views
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;$119/night&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt; &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;MdStar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#ED8936"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm"&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;4.84&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; (190)
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"p-5 w-32 rounded"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rounded w-full"&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://bit.ly/2k1H1t6"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-row mt-2"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rounded py-2 px-4 bg-mono-400"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-mono-100"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Plus&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-sm font-bold text-pale-100"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        VERIFIED &lt;span class="ni"&gt;&amp;amp;bull;&lt;/span&gt; CAPE TOWN
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-semibold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Modern, Chic Penthouse with Mountain, City &lt;span class="err"&gt;&amp;amp;&lt;/span&gt; Sea Views
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-semibold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;$119/night&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-row items-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;MdStar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#ED8936"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-sm"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"font-bold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;4.84&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        (190)
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A mention to &lt;code&gt;@apply&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;@apply&lt;/code&gt;&lt;/strong&gt; is the directive that Tailwind recommend to extract repeated utility patterns. I don't want to get into muchs details about it, but it does fail at the same problems as traditional CSS. Using apply it feel like just writting plain CSS, which in some of the cases it's amazing, but for a larger app it's a drawback.&lt;/p&gt;

&lt;h3&gt;
  
  
  When I would use Tailwind again then?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Document-like websites&lt;/strong&gt;, styling content that is structured as a big chunk. Using &lt;a href="https://blog.tailwindcss.com/tailwindcss-typography"&gt;Tailwind Typography&lt;/a&gt; it does come with good defaults for raw content like a blog or a newsletter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prototyping&lt;/strong&gt;, creating a UI that visually doesn't need to be high quality or needs  a unique style.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What should I use instead of Tailwind for my design system?
&lt;/h3&gt;

&lt;p&gt;Not all the teams can have the possibility to invest time on building tooling and systems to give super-powers to the rest of the engineering team. In fact, create a Design system it's a full-time job.&lt;/p&gt;

&lt;p&gt;But, there's a bunch of people who spend a lot of time thinking about those problems and tried to create a few abstractions that you could benefit from.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://theme-ui.com/"&gt;https://theme-ui.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rebassjs.org/"&gt;https://rebassjs.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stitches.dev/"&gt;https://stitches.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://radix-ui.com/primitives/docs/overview/introduction"&gt;https://radix-ui.com&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you still like what Tailwind offers, I recommend a similar approach that we do at &lt;strong&gt;Draftbit&lt;/strong&gt;. Create a tiny layer on top of it: Treat all the Tailwind tokens as code and maintain Tailwind scoped inside those components. Abstract those utility components that you found repeated in your code into a more strict version, and minimise Tailwind for your app.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I try to do it
&lt;/h3&gt;

&lt;p&gt;Mentioned before that I made my own Design system, which is a set of components that only cares about layout disposition, doesn't contain any opinions about cosmetics and allows to compose those elegantly. It's called &lt;strong&gt;taco&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's currently still a work in progress, since there's a lot of patterns that aren't solved yet. But I have been using them for all my projects.&lt;br&gt;
Even that is public, isn't for consumption. I didn't write all of this for a plot-twist to sell my library, but you can use it as an example for inspiration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://taco.davesnx.vercel.app/"&gt;Storybook&lt;/a&gt; and repository &lt;a href="https://github.com/davesnx/taco"&gt;https://github.com/davesnx/taco&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this post doesn't get in the wrong form, any tool is perfect and using those to solve problems is part of who we are.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>query-json: A story of cross-compilation with Reason</title>
      <dc:creator>David Sancho</dc:creator>
      <pubDate>Mon, 12 Oct 2020 17:49:06 +0000</pubDate>
      <link>https://forem.com/davesnx/query-json-a-story-of-cross-compilation-with-reason-2c3p</link>
      <guid>https://forem.com/davesnx/query-json-a-story-of-cross-compilation-with-reason-2c3p</guid>
      <description>&lt;h1&gt;
  
  
  What's query-json
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/davesnx/query-json"&gt;query-json&lt;/a&gt; is a faster and simpler re-implementation of &lt;a href="https://github.com/stedolan/jq/wiki/jq-Language-Description"&gt;jq's language&lt;/a&gt; in &lt;a href="https://reasonml.github.io"&gt;Reason&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's a CLI to run small programs against JSON, the same idea as &lt;a href="https://www.linode.com/docs/tools-reference/tools/manipulate-text-from-the-command-line-with-sed/"&gt;sed&lt;/a&gt; but for JSON files. As a web engineer is an essential tool while developing APIs.&lt;/p&gt;

&lt;p&gt;Started with the goal to create something useful and learn during the process. Was very interested in learning about how to write parsers and compilers using the OCaml stack: &lt;a href="https://opam.ocaml.org/packages/menhir"&gt;menhir&lt;/a&gt; and &lt;a href="https://github.com/ocaml-community/sedlex"&gt;sedlex&lt;/a&gt;, compile it to any architecture and try to compile it to JavaScript.&lt;/p&gt;

&lt;p&gt;This post explains the project, how it was made and which decisions were followed and some reflections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why learning parsers/compilers
&lt;/h2&gt;

&lt;p&gt;I had a little idea about the theory, but very vague and useless and was the righ time to learn more since I created &lt;a href="https://github.com/davesnx/styled-ppx"&gt;styled-ppx&lt;/a&gt; which is a&lt;br&gt;
&lt;strong&gt;ppx&lt;/strong&gt; (&lt;strong&gt;P&lt;/strong&gt;re*&lt;em&gt;P&lt;/em&gt;&lt;em&gt;rocessor E&lt;/em&gt;&lt;em&gt;x&lt;/em&gt;*tension) that allows CSS-in-Reason/OCaml. Needs to parse the CSS and have a backend that compiles to &lt;a href="https://github.com/ahrefs/bs-emotion"&gt;bs-emotion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I asked for some help to &lt;a href="https://www.twitch.tv/eduardorfs"&gt;@EduardoRFS&lt;/a&gt; about writing a CSS Parser that supports the entire &lt;a href="https://www.w3.org/TR/2001/WD-css3-roadmap-20010523/"&gt;CSS3 specification&lt;/a&gt; which I will want to understand, improve and maintain over time.&lt;/p&gt;
&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;query-json &lt;span class="s2"&gt;".store.books | filter(.price &amp;gt; 10)"&lt;/span&gt; stores.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This reads &lt;code&gt;stores.json&lt;/code&gt; and access to &lt;code&gt;"store"&lt;/code&gt; field, access to &lt;code&gt;"books"&lt;/code&gt; field (since it's an array) it will run a filter on each item and filter each item by it's &lt;code&gt;"price"&lt;/code&gt; that's larger than 10 and finally, print the resultant list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"War and Peace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Leo Tolstoy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lolita"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Vladimir Nabokov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;13.0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first argument is called &lt;code&gt;query&lt;/code&gt; and it's a jq expression. The second one is called &lt;code&gt;json&lt;/code&gt; or &lt;code&gt;payload&lt;/code&gt;, and it's a valid JSON file.&lt;/p&gt;

&lt;p&gt;The semantics of jq consist of a set of piped operations, where each output is connected to an input where the first input it's the JSON itself. Some pseudo-code to illustate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ /* json */ } | filter | transform | count
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to transform the &lt;code&gt;query&lt;/code&gt; to a set of operations that run against a JSON, we will divide the problem into 3 steps: &lt;strong&gt;parse&lt;/strong&gt;, &lt;strong&gt;compile&lt;/strong&gt; and &lt;strong&gt;run&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parsing
&lt;/h3&gt;

&lt;p&gt;Responsible for transforming a string into an &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;AST&lt;/a&gt;(Abstract Syntax Tree) and provide a good error message when the input is malformed.&lt;/p&gt;

&lt;p&gt;One of the beauties of &lt;code&gt;jq&lt;/code&gt; is that all the expressions are piped by default, so &lt;code&gt;.store | .books&lt;/code&gt; is equivalent to &lt;code&gt;.store.books&lt;/code&gt;. I designed the &lt;em&gt;AST&lt;/em&gt; to represent the pipe structure in its nature. If you want to know more about jq's language, check their &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's dive into an example. When the parser recieves &lt;code&gt;.store.books&lt;/code&gt; will return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pipe(
    Key("store"),
    Key("books")
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All the operations are transformed into these constructors from above (&lt;code&gt;Pipe&lt;/code&gt;, &lt;code&gt;Key&lt;/code&gt;). Those constructors are called Variants.&lt;/p&gt;

&lt;p&gt;Variants models values that may assume one of many known variations. This feature is similar to &lt;code&gt;enums&lt;/code&gt; in other languages, but each variant may optionally contain data that is carried inside. Variants belong to a large group of types called &lt;a href="https://en.wikipedia.org/wiki/Algebraic_data_type"&gt;&lt;em&gt;ADTs&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The entire &lt;code&gt;query-json&lt;/code&gt; program representation it's one big recursive Variant.&lt;/p&gt;

&lt;p&gt;Following with a more complex example, let's parse &lt;code&gt;.store.books | filter(.price &amp;gt; 10)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pipe(
    Pipe(
        Key("store"),
        Key("books")
    ),
    Filter(
        Pipe(
            Key("price"),
            Literal(Number(10.))
        )
    )
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can see more examples in the &lt;a href="https://github.com/davesnx/query-json/blob/master/test/ParseTest.re"&gt;parsing tests&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Compiling
&lt;/h3&gt;

&lt;p&gt;The compilation step recieves the &lt;em&gt;AST&lt;/em&gt; expression and transforms it to code. It's a big recursive &lt;a href="https://reasonml.github.io/docs/en/pattern-matching"&gt;pattern match&lt;/a&gt;, which is another great feature of Reason and looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let rec compile = (expression, json) =&amp;gt; {
  switch (expression) {
  | Empty =&amp;gt; empty
  | Keys =&amp;gt; keys(json)
  | Key(key, opt) =&amp;gt; member(key, opt, json)
  | Index(idx) =&amp;gt; index(idx, json)
  | Head =&amp;gt; head(json)
  | Tail =&amp;gt; tail(json)
  | Length =&amp;gt; length(json)
  /* [...] */
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;On the left side are defined all the possible &lt;code&gt;Variants&lt;/code&gt; and on the right side the operations. Those operations transforms the JSON. Here is where &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;index&lt;/code&gt;, etc... are implemented.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running
&lt;/h3&gt;

&lt;p&gt;The easier part, the compile step give us back a curried function that expects a json as the only argument, we just apply the function to this JSON and print the result.&lt;/p&gt;

&lt;p&gt;This example only describes the happy path, in reality, the parsing and compilation steps return a &lt;code&gt;Result&lt;/code&gt; type which allows handling errors more composable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Distribution
&lt;/h1&gt;

&lt;p&gt;Now we already covered how it works internally and a little overview of the architecture. Now let's dive on how developers can use it in their machines.&lt;/p&gt;

&lt;h3&gt;
  
  
  But first, let's recap on what's what.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/OCaml"&gt;OCaml&lt;/a&gt; is a programing language from the family of ML ("Meta Language") and is best known for their static type system and type-inference.&lt;br&gt;
OCaml allows to compile to binary code which are often compared to C/C++ performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bucklescript.netlify.app"&gt;BuckleScript&lt;/a&gt; is a compiler (a fork of the OCaml compiler) that outputs JavaScript code, instead of binary. BuckleScript supports OCaml syntax and Reason syntax.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://reasonml.github.io"&gt;Reason&lt;/a&gt; is a language that can be compiled with the OCaml compiler or BuckleScript.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to cross-compilation to binary
&lt;/h2&gt;

&lt;p&gt;All of the build process and their tests runs on our CI in Github Actions, which allows running Mac, Windows and Linux images. Each build compiles with the OCaml compiler to each architecture.&lt;/p&gt;

&lt;p&gt;Once the build and test succeeds it pushes the binary into Github Releases and npm registry.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to compile to the Web
&lt;/h2&gt;

&lt;p&gt;The compilation to JavaScript is the sweet section of this blog post since we are using OCaml (under the hood while writing Reason), and it allows us to compile directly to JavaScript using &lt;a href="https://github.com/ocsigen/js_of_ocaml"&gt;js_of_ocaml&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;js_of_ocaml is a compiler that can be plugged to the OCaml's one and It makes it possible to run pure OCaml programs into JavaScript.&lt;br&gt;
As you can see, query-json uses menhir, sedlex and &lt;a href="https://github.com/ocaml-community/yojson"&gt;yojson&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to use it in &lt;a href="http://esy.sh"&gt;esy&lt;/a&gt;, the package manager, I only needed to add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;esy add js_of_ocaml
esy add js_of_ocaml-compiler
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and modify it's &lt;a href="https://dune.build"&gt;dune&lt;/a&gt; file, the build system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;executable&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;modes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;libraries&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;console.lib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;yojson&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;js_of_ocaml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After running the build, it generates a bundle.js!&lt;/p&gt;

&lt;h2&gt;
  
  
  Made query-json's playground
&lt;/h2&gt;

&lt;p&gt;After having a JavaScript artefact I was able to run it as a playground in the browser. To teach people how to use it without the binary install or to test new versions on each pull request, well, the possibilities of the web are endless!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6-WMd_OW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r4hsw8spupu2eac7v75q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6-WMd_OW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r4hsw8spupu2eac7v75q.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I build a website using Reason and BuckleScript which uses query-json JavaScript's artefact to run it, you can try it yourself here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://query-json.netlify.app"&gt;https://query-json.netlify.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The query-json computation runs synchronous since it's able to run on each key-stroke. Comparing this playground with &lt;a href="https://jqplay.org/"&gt;jqplay.org&lt;/a&gt; that needs to hit a backend and respond with the result.&lt;/p&gt;

&lt;p&gt;Having a playground as a serverless frontend app It's a massive improvement over backend-dependant ones. Actually, most of the REPL's from Reason, OCaml, Flow, ReScript uses js_of_ocaml.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;p&gt;This allows any OCaml backend being able to run in a browser without much hassle, sharing code between backend and frontend has been a dream for a lot of Engineering teams.&lt;/p&gt;

&lt;p&gt;But not only share logic matters, here's a list of other upsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Portability&lt;/strong&gt;, moving code from server to client or viceversa, sharing marshal/unmarshal code, easier contract testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Familiarity&lt;/strong&gt;: Writing the same patterns would benefit new comers that need to learn less platform-specific rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage of OCaml's ecosystem&lt;/strong&gt;: Access to many libraries and ppxs and latest ocaml's features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features that weren't possible&lt;/strong&gt;: Some apps might benefit from Server-side rendering, others might benefit from moving stuff to offline, and many app-specific designs that are unblocked by this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Challenges
&lt;/h3&gt;

&lt;p&gt;This solution has downsides as well, js_of_ocaml isn't the tool that solves all of your problems, actually, there's no such tool.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bundlesize
&lt;/h4&gt;

&lt;p&gt;It's quite big compared to regular JavaScript applications.&lt;/p&gt;

&lt;p&gt;The entire playground is about 660kb. Includes the Monaco Editor (~356kb) and the rest is query-json and js_of_ocaml runtime (300kb).&lt;/p&gt;

&lt;p&gt;js_of_ocaml wasn't created with the same mentality as most Frontend developers solve their problems today and was born 10 years ago to run some OCaml into a browser.&lt;/p&gt;

&lt;h4&gt;
  
  
  Documentation
&lt;/h4&gt;

&lt;p&gt;One of my biggest complains about the OCaml community is the lack of quality documentation.&lt;/p&gt;

&lt;p&gt;Coming from the JavaScript community (which have more than 9 million devs) there's plenty of tutorials, examples, manuals, many StackOverflow resolved questions and this culture of the copy-paste driven development.&lt;/p&gt;

&lt;p&gt;That gives all sort of problems, but lowers the barrier to the language and the usage of many dependencies for new comers or not so passionate FP developers.&lt;/p&gt;

&lt;p&gt;It's a non-sense compare OCaml and JavaScript, but one of the biggest missing pieces is good documentation at all levels.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bridge between BuckleScript/Reason and js_of_ocaml
&lt;/h4&gt;

&lt;p&gt;Js_of_ocaml lacks some of the basics to enable compatibility with JavaScript codebases, modern build systems such as webpack and many bindings to other libraries. So to build the online playground, I used BuckleScript for the UI and js_of_ocaml for the query-json browser build, and this required having to make them communicate to each other.&lt;/p&gt;

&lt;p&gt;This isn't particular to js_of_ocaml, is more related to the mix of js_of_ocaml and BuckleScript. In order to run the js_of_ocaml artefact into the BuckleScript/Reason codebase, I needed to write bindings for it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[@bs.module "../../_build/default/js/Js.bc.js"]
external queryJson: (string, string) =&amp;gt; result(string, string) = "run";
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using the &lt;a href="https://caml.inria.fr/pub/docs/manual-ocaml/libref/Result.html"&gt;Result from OCaml&lt;/a&gt; in the query-json's JavaScript entry-point and the &lt;a href="https://rescript-lang.org/docs/manual/latest/api/belt/result"&gt;Result from BuckleScript&lt;/a&gt; in the Reason code I needed to write an unsafe bridge which transforms OCaml result to the internal representation of BuckleScript variant.&lt;/p&gt;

&lt;p&gt;There're probably better ways of achieving it since I made the implementation very unsafe &lt;a href="https://github.com/davesnx/query-json/blob/master/js/Js.re"&gt;davesnx/query-json/js/Js.re&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  It's a tradeoff, as always...
&lt;/h3&gt;

&lt;p&gt;You can't really compare BuckleScript/rescript with js_of_ocaml, since both tools try to solve the same problem in a very different fashion.&lt;/p&gt;

&lt;p&gt;If you are writing an OCaml backend and your team is familiar with it. Your project would benefit from sharing code, don't require a hard need on a lower bundlesize and want to carry all OCaml dependencies, ppx and patterns, js_of_ocaml it's the best option.&lt;/p&gt;

&lt;p&gt;Since most modern build tools such as &lt;a href="https://webpack.js.org/"&gt;Webpack&lt;/a&gt; or &lt;a href="https://rollupjs.org"&gt;Rollup&lt;/a&gt; allows to lazy import chunks of your app, you might find no-issue with the big bundle, since most shared logic doesn't require to be present during load-time.&lt;/p&gt;

&lt;p&gt;You won't have the facility to write frontend code with React, but I'm sure it will change soon since there's a current implementation of React in jsso &lt;a href="https://github.com/jchavarri/jsoo-react"&gt;jsoo-react&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For now, writing a website in ReasonReact and BuckleScript it's the most robust experience. You can find a lot of bindings to JavaScript libraries, there's a lot of usage in production, plenty of examples.&lt;/p&gt;

&lt;p&gt;I truly believe that &lt;a href="https://rescript-lang.org"&gt;ReScript&lt;/a&gt; it's such a great project to target JavaScript developers that found TypeScript slow and liar or Flow abandoned. It improves the status quo for many issues regarding the Reason Community and keeps delivering in a fast pace the best tooling.&lt;/p&gt;

&lt;p&gt;It makes me very sad that ReScript will diverge at some point from the OCaml ecosystem and won't spend time to build a cross-platform language with the advantatges of cross-compilation and future features from OCaml.&lt;/p&gt;

&lt;h1&gt;
  
  
  Future
&lt;/h1&gt;

&lt;p&gt;The future of query-json is to provide a better experience in running operations on top of JSON.&lt;/p&gt;

&lt;p&gt;Providing better error messages and better performance has been the goal.&lt;/p&gt;

&lt;p&gt;Currently jq has an issue, it's very powerful but confusing. The amount of questions of StackOverflow proves that there's a lot of problems without a solution on the language/compiler.&lt;/p&gt;

&lt;p&gt;The other mission of query-json is to push performance forward, now we are implementing most of the missing functionality since I first release it and next is to explore performance optimizations, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replacing menhir with a written parser/lexer&lt;/li&gt;
&lt;li&gt;Using OCaml multicore&lt;/li&gt;
&lt;li&gt;Partial JSON parsing, only parse the needed parts of a json based on the user's query&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final
&lt;/h2&gt;

&lt;p&gt;Hope you liked the project and the story, let me know if you are interested in those topics I'm always happy to chat and help. I answer to all the DMs on &lt;a href="https://twitter.com/davesnx"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See you next time 👋&lt;/p&gt;

&lt;p&gt;Thanks everyone how reviewed this blog post, &lt;a href="http://javierchavarri.com/"&gt;Javi&lt;/a&gt;, &lt;a href="https://twitter.com/epallerols"&gt;Enric&lt;/a&gt; and &lt;a href="http://gerard.sh/"&gt;Gerard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>json</category>
      <category>reason</category>
      <category>ocaml</category>
      <category>jsoo</category>
    </item>
  </channel>
</rss>
