tag:blog.namangoel.com,2014:/feedNaman Goel2023-10-02T20:39:16-07:00Naman Goelhttp://blog.namangoel.comnaman34@gmail.comSvbtle.comtag:blog.namangoel.com,2014:Post/let-the-people-use-their-tools2023-10-02T20:39:16-07:002023-10-02T20:39:16-07:00The Imperfect Solution<p>I saw this article by Jeff Sandberg railing against Tailwind. I’m no fan of Tailwind myself, but the article reeked of elitism and gatekeeping. I don’t think Jeff (or anyone else railing against Tailwind) is doing this on purpose, so I will try to counter with my own arguments:</p>
<blockquote class="short">
<p>developers are throwing away decades of carefully wrought systems for a bit of perceived convenience. </p>
</blockquote>
<p>The words “perceived convenience” implies that Tailwind doesn’t bring any actual convenience, but this is measurably false. For all its faults, Tailwind does many developers faster and provides <em>actual</em> convenience.</p>
<blockquote>
<p>Tools such as Tailwind CSS seem to be spreading like wildfire, with very few people ever willing to acknowledge the regression they bring to our field.</p>
</blockquote>
<p>I would argue that Tailwind isn’t causing a “regression” here. Developers have <em>long</em> had trouble understanding how CSS works. Pick any time since the birth of CSS and you will see developers hating on CSS because they don’t understand it. Websites have been bogged down by huge, complicated CSS for decades. Tailwind gives such developers a way to write mediocre styles instead of catastrophically bad styles.</p>
<blockquote class="short">
<p>The problem I have with tailwind is that it reduces your HTML to a gigantic pile of near-gibberish CSS classes. </p>
</blockquote>
<p>This is a fair critique but also irrelevant. We always say that UX is more important than DX. And so if a tool like Tailwind lets developers ship fast, minimal CSS at the cost of messy HTML, it’s a worthy tradeoff. Could you do better? Probably. But most developers, who have always struggled with CSS selectors would probably end up doing much worse!</p>
<blockquote class="short">
<p>Tooling is utterly broken by tailwind</p>
</blockquote>
<p>Tooling can be fixed. We can build dev-tools extensions and if atomic styles becomes successful enough, browsers will probably adapt.</p>
<blockquote class="short">
<p>… a bunch of problems with Tailwind enumerated</p>
</blockquote>
<p>I actually don’t have a problem with any of this. I agree that Tailwind is a leaky abstraction with many issues.</p>
<blockquote class="short">
<p>What’s the alternative? Scoped CSS and component based design.</p>
</blockquote>
<p>Scoped CSS helps with correctness, but it doesn’t help with performance. Scoped styles means that every component needs to ship its own styles. So, as the number of components you write grows, the amount of styles grow too. There is little to no style re-use.</p>
<p>Then there’s the fact that, today, scoped styles are either possible using Shadow DOM, or using other tooling. Both those solutions have their own problems, but I would argue that Shadow DOM has way <em>more</em> problems than a long list of classNames in HTML.</p>
<p>Atomic styles already solve all of these problems and there are ways to generate atomic styles that aren’t leaky like Tailwind. PandaCSS and Tamagui are two such examples. (Soon there will be StyleX)</p>
<blockquote>
<p>The CSS tailwind generates might not be bloated, but repeating the gigantic strings of classes all over your codebase certainly adds to the size of the final HTML output.</p>
</blockquote>
<p>When it comes to performance, this is right tradeoff to make. HTML is the cheapest bytes you can ship to a browser. The alternative is to have bigger CSS files which you’re then forced to lazy-load. Every time you load CSS on a page, the browser has to invalidate <em>all</em> styles. Loading more HTML on a page without a change to the CSS is much faster.</p>
<h2 id="tailwind-isn39t-the-only-way-to-write-atomic_2">Tailwind isn’t the only way to write Atomic Styles <a class="head_anchor" href="#tailwind-isn39t-the-only-way-to-write-atomic_2">#</a>
</h2>
<p>The core of my problem with the article is that it conflates Tailwind with Atomic Styles. Tailwind has many problems but it has become popular for a reason. Developers find Tailwind simpler and easier because it frees them from having to carefully manage the issues of specificity and selectors and choosing colours. Tailwind is <em>convenient</em>.</p>
<p>Tailwind is also <em>fast</em> because it uses Atomic Styles.</p>
<p>Perhaps in the future, when declarative shadow DOM is commonplace and loading unique CSS for every component stops being a bottleneck, scoped styles will make more sense. But until then, the only thing better than Tailwind is a better way to generate Atomic Styles.</p>
tag:blog.namangoel.com,2014:Post/swift-is-the-more-convenient-rust2023-10-02T20:34:00-07:002023-10-02T20:34:00-07:00Swift is a more convenient Rust<p>I’ve been learning Rust lately. </p>
<p>Rust is one of the most loved languages out there, is fast, and has an amazing community. Rust invented the concept of ownership as a solution memory management issues without resorting to something slower like Garbage Collection or Reference Counting. But, when you don’t need to be quite as low level, it gives you utilities such as <code class="prettyprint">Rc</code>, <code class="prettyprint">Arc</code> and <code class="prettyprint">Cow</code> to do reference counting and “clone-on-right” in your code. And, when you need to go lower-level still, you can use the <code class="prettyprint">unsafe</code> system and access raw C pointers.</p>
<p>Rust also has a bunch of awesome features from functional languages like tagged enums, match expressions, first class functions and a powerful type system with generics.</p>
<p>Rust has an LLVM-based compiler which lets it compile to native code and WASM.</p>
<p>I’ve also been doing a bit of Swift programming for a couple of years now. And the more I learn Rust, the more I see a reflection of Swift. (I know that Swift stole a lot of ideas from Rust, I’m talking about my own perspective here).</p>
<p>Swift, too, has awesome features from functional languages like tagged enums, match expressions and first-class functions. It too has a very powerful type system with generics.</p>
<p>Swift too gives you complete type-safety without a garbage collector. By default, everything is a value type with “copy-on-write” semantics. But when you need extra speed you can opt into an ownership system and “move” values to avoid copying. And if you need to go even lower level, you can use the unsafe system and access raw C pointers.</p>
<p>Swift has an LLVM-based compiler which lets it compile to native code and WASM.</p>
<h2 id="deja-vu_2">Deja Vu? <a class="head_anchor" href="#deja-vu_2">#</a>
</h2>
<p>You’re probably feeling like you just read the same paragraphs twice. This is no accident. Swift is extremely similar to Rust and has most of the same feature-set. But there is a very big difference is <em>perspective</em>. If you consider the default memory model, this will start to make a lot of sense.</p>
<h2 id="rust-is-bottomup-swift-is-topdown_2">Rust is bottom-up, Swift is top-down. <a class="head_anchor" href="#rust-is-bottomup-swift-is-topdown_2">#</a>
</h2>
<p>Rust is a low-level systems language at heart, but it gives you the tools to go higher level. Swift starts at a high level and gives you the ability to go low-level.</p>
<p>The most obvious example of this is the memory management model. Swift use value-types by default with <code class="prettyprint">copy-on-write</code> semantics. This is the equivalent of using <code class="prettyprint">Cow<></code> for all your values in Rust. But defaults matter. Rust makes it easy to use “moved” and “borrowed” values but requires extra ceremony to use <code class="prettyprint">Cow<></code> values as you need to “unwrap” them <code class="prettyprint">.as_mutable()</code> to actually use the value within. Swift makes these Copy-on-Write values easy to use and instead requires extra ceremony to use borrowing and moving instead. Rust is faster by default, Swift is simpler and easier by default.</p>
<h2 id="swift-takes-rust39s-ideas-and-hides-them-in-c_2">Swift takes Rust’s ideas and hides them in C-like syntax. <a class="head_anchor" href="#swift-takes-rust39s-ideas-and-hides-them-in-c_2">#</a>
</h2>
<p>Swift’s syntax is a masterclass in taking awesome functional language concepts and hiding them in C-like syntax to trick the developers into accepting them.</p>
<p>Consider <code class="prettyprint">match</code> statements. This is what a match statement looks like in Rust:</p>
<pre><code class="prettyprint lang-rust">enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
</code></pre>
<p>Here’s how that same code would be written in Swift:</p>
<pre><code class="prettyprint lang-swift">enum Coin {
case penny
case nickel
case dime
case quarter
}
func valueInCents(coin: Coin) -> Int {
switch coin {
case .penny: 1
case .nickel: 5
case .dime: 10
case .quarter: 25
}
}
</code></pre>
<p>Swift doesn’t have a <code class="prettyprint">match</code> statement or expression. It has a <code class="prettyprint">switch</code> statement that developers are already familiar with. Except this <code class="prettyprint">switch</code> statement is actually not a <code class="prettyprint">switch</code> statement at all. It’s an expression. It doesn’t “fallthrough”. It does pattern matching. It’s just a <code class="prettyprint">match</code> expression with a different name and syntax.</p>
<p>In fact, Swift treats <code class="prettyprint">enums</code> as more than <em>just</em> types and lets you put methods directly on it:</p>
<pre><code class="prettyprint lang-swift">enum Coin {
case penny
case nickel
case dime
case quarter
func valueInCents() -> Int {
switch self {
case .penny: 1
case .nickel: 5
case .dime: 10
case .quarter: 25
}
}
}
</code></pre>
<h3 id="optional-types_3">Optional Types <a class="head_anchor" href="#optional-types_3">#</a>
</h3>
<p>Rust doesn’t have <code class="prettyprint">null</code>, but it does have <code class="prettyprint">None</code>. Swift has a <code class="prettyprint">nil</code>, but it’s really just a <code class="prettyprint">None</code> in hiding. Instead of an <code class="prettyprint">Option<T></code>, Swift let’s you use <code class="prettyprint">T?</code>, but the compiler still forces you to check that the value is not <code class="prettyprint">nil</code> before you can use it.</p>
<p>You get the same safety with more convenience since you can do this in Swift with an optional type:</p>
<pre><code class="prettyprint lang-swift">let val: T?
if let val {
// val is now of type `T`.
}
</code></pre>
<p>Also, you’re not forced to wrap every value with a <code class="prettyprint">Some(val)</code> before returning it. The Swift compiler takes care of that for you. A <code class="prettyprint">T</code> will transparently be converted into a <code class="prettyprint">T?</code> when needed.</p>
<h3 id="error-handling_3">Error Handling <a class="head_anchor" href="#error-handling_3">#</a>
</h3>
<p>Rust doesn’t have <code class="prettyprint">try-catch</code>. Instead it has a <code class="prettyprint">Result</code> type which contains the success and error types.</p>
<p>Swift doesn’t have a <code class="prettyprint">try-catch</code> either, but it does have <code class="prettyprint">do-catch</code> and you have to use <code class="prettyprint">try</code> before calling a function that could throw. Again, this is just deception for those developers coming from C-like languages. Swift’s error handling works exactly like Rust’s behind the scenes, but it is hidden in a clever, familiar syntax. </p>
<pre><code class="prettyprint lang-swift">func usesErrorThrowingFunction() throws {
let x = try thisFnCanThrow()
}
func handlesErrors() {
do {
let x = try thisFnCanThrow()
} catch err {
// handle the `err` here.
}
}
</code></pre>
<p>This is very similar to how Rust let’s you use <code class="prettyprint">?</code> at the end of statements to automatically forward errors, but you don’t have to wrap your success values in <code class="prettyprint">Ok()</code>.</p>
<h2 id="rust39s-compiler-catches-problems-swift39s-co_2">Rust’s compiler catches problems. Swift’s compiler solves some of them <a class="head_anchor" href="#rust39s-compiler-catches-problems-swift39s-co_2">#</a>
</h2>
<p>There are many common problems that Rust’s compiler will catch at compile time and even suggest solutions for you. The example that portrays this well is self-referencing enums.</p>
<p>Consider an enum that represents a tree. Since, it is a recursive type, Rust will force you to use something like <code class="prettyprint">Box<></code> for referencing a type within itself.</p>
<pre><code class="prettyprint lang-rust">enum TreeNode<T> {
Leaf(T),
Branch(Vec<Box<TreeNode<T>>>),
}
</code></pre>
<p>(You could also us <code class="prettyprint">Box<Vec<TreeNode<T>>></code> instead)</p>
<p>This makes the problem explicit and forces you to deal with it directly. Swift is a little more, <em>automatic</em>.</p>
<pre><code class="prettyprint lang-swift">indirect enum TreeNode<T> {
case leaf(T)
case branch([TreeNode<T>])
}
</code></pre>
<p><strong>Note</strong>: that you still have to annotate this <code class="prettyprint">enum</code> with the <code class="prettyprint">indirect</code> keyword to indicate that it is recursive. But once you’ve done that, Swift’s compiler takes care of the rest. You don’t have to think about <code class="prettyprint">Box<></code> or <code class="prettyprint">Rc<></code>. The values just work normally.</p>
<h2 id="swift-is-less-quotpurequot_2">Swift is less “pure” <a class="head_anchor" href="#swift-is-less-quotpurequot_2">#</a>
</h2>
<p>Swift was designed to replace Objective-C and needed to be able to interface with existing code. So, it has made a lot of pragmatic choices that makes it a much less “pure” and “minimalist” language. Swift is a pretty big language compared to Rust and has many more features built-in. However, Swift is designed with “progressive disclosure” in mind which means that just as soon as you think you’ve learned the language a little more of the iceberg pops out of the water.</p>
<p>Here are just <em>some</em> of the language features:</p>
<ul>
<li>Classes / Inhertence</li>
<li>async-await</li>
<li>async-sequences</li>
<li>actors</li>
<li>getters and setters</li>
<li>lazy properties</li>
<li>property wrappers</li>
<li>Result Builders (for building tree-like structures. e.g. HTML / SwiftUI)</li>
</ul>
<h2 id="convenience-has-its-costs_2">Convenience has its costs <a class="head_anchor" href="#convenience-has-its-costs_2">#</a>
</h2>
<p>Swift is a far easier language to get started and productive with. The syntax is more familiar and a lot more is done for you automatically. But this really just makes Swift a higher-level language and it comes with the same tradeoffs.</p>
<p>By default, a Rust program is much faster than a Swift program. This is because Rust is fast by default, and <em>lets</em> you be slow, while Swift is easy by default and <em>lets</em> you be fast.</p>
<p>Based on this, I would say both languages have their uses. Rust is better for systems and embedded programming. It’s better for writing compilers and browser engines (Servo) and it’s better for writing entire operating systems.</p>
<p>Swift is better for writing UI and servers and some parts of compilers and operating systems. Over time I expect to see the overlap get bigger.</p>
tag:blog.namangoel.com,2014:Post/shadow-dom-considered-harmful2023-08-27T19:42:53-07:002023-08-27T19:42:53-07:00Shadow DOM considered harmful<p>I was going to write an article about how Shadow DOM has been a horrible idea and here comes Manuel Matuzovic with <a href="https://www.matuzo.at/blog/2023/pros-and-cons-of-shadow-dom/">an article</a> that lays out exactly what’s wrong with it.</p>
<p>The article is balanced and well considered, so I’m going to feel free to be more unhinged and not mince my words when I say that Shadow DOM has been actively harmful to the web.</p>
<p>Let’s consider the 3 “pros” mentioned by Manuel.</p>
<ul>
<li>Style Encapsulation</li>
<li>DOM Encapsulation</li>
<li>Slots</li>
</ul>
<h2 id="style-encapsulation_2">Style Encapsulation <a class="head_anchor" href="#style-encapsulation_2">#</a>
</h2>
<p>This is arguably the most useful part of Shadow DOM today and it is already not what most developers wanted when they asked for “scoped CSS”.</p>
<p>Usually, we want global styles to apply to our components. What we don’t want is styles that are only meant for our components from leaking <em>out</em>. </p>
<p>CSS will soon add <a href="https://www.bram.us/2023/08/22/a-quick-introduction-to-css-scope/">true scoped selectors</a> to CSS which is what we have wanted this whole time.</p>
<p>All the work and heavy-handed promoting of web components and shadow DOM meant that work on the truly useful scoped CSS was de-prioritised. Shadow DOM has been harmful to the web and held us back.</p>
<p>(Btw, <code class="prettyprint">all: initial</code> already exists in CSS if we want to avoid inheriting global styles.)</p>
<h2 id="dom-encapsulation_2">DOM Encapsulation <a class="head_anchor" href="#dom-encapsulation_2">#</a>
</h2>
<p>I remember when the <code class="prettyprint"><video></code> element and other html 5 elements were introduced people complained about how hard it was to style the various elements within.<br>
Developers hated how these new HTML elements would hide what they actually rendered. (Let’s not even start talking about <code class="prettyprint"><select></code>)<br>
We had to add a bunch of pseudo elements just to be able to style <em>buttons</em> within a video element.</p>
<p>The solution offered by web components? Let’s make <em>all</em> components hide their HTML. Now we need to manually expose those part using <code class="prettyprint">::part</code> selectors. We are forced to write lots and lots of duplicate CSS just to be able to style the paragraphs tags in shadow DOM trees of different custom elements.</p>
<p>Oh, and yeah it also break DOM traversal and events.</p>
<p>There are use cases when we need true encapsulation. We already had <code class="prettyprint"><iframe></code> (or <code class="prettyprint"><object></code>?) for those use cases. All we needed was a way to set <code class="prettyprint">size=auto</code>. Again this is something that finally being discussed again after many years. The flawed and complicated solution of shadow DOM meant work on better solutions was de-prioritised.</p>
<h2 id="slots_2">Slots <a class="head_anchor" href="#slots_2">#</a>
</h2>
<p>Slots are a nice feature for web components and there are ways to achieve them without the need for shadow DOM at all.</p>
<p>All we need is a way to pass HTML to a component in a way that puts the component in control of how to render it. There are many ways to do so. The simplest solution is probably to use <code class="prettyprint"><template></code> tags which can be read by the custom elements without rendering anything by default.</p>
<h2 id="opportunity-cost_2">Opportunity Cost <a class="head_anchor" href="#opportunity-cost_2">#</a>
</h2>
<p>People often wonder why developers using JS-frameworks are so angry about web components.</p>
<p>Apart from all the gaslighting by the DevRel team at Google, it’s how all these deeply flawed APIs were rammed down our throats at the cost of thing we were asking for.</p>
<p>Web component apologists will often point to their usage in large projects as some kind of evidence of their success. Of course we’re forced to use what the platform actually gives us. If ShadowDOM is the only way to get scoped styles, what other choice do we have?<br>
We use all the terrible old APIs built into DOM too. That doesn’t mean they’re good APIs. It’s just what we’re stuck with since we don’t remove APIs and break the web.</p>
<p>Web Components are a good idea. Adding new browser APIs for encapsulation is a good idea. But Shadow DOM and Google’s tone deaf, non-collaborative approach to shoving half-baked idea into the spec has forever ruined our chances of having better solutions instead and held back better idea from coming to fruition. (Many from within Google itself).</p>
tag:blog.namangoel.com,2014:Post/what-do-web-components-do2023-08-17T20:52:05-07:002023-08-17T20:52:05-07:00What do Web Components do?<p>A trend I have seen recently is that people are making some extremely flawed arguments against React. And then, these same people hype up web components and their only argument is favour of Web Components is that “it’s the platform”, as if implying that Web Components can somehow replace React or a similar UI framework.</p>
<p>One day I’m going to write a longer post taking apart some of the most flawed arguments, but first, I wanted to learn about Web Components themselves. What can they actually do?</p>
<h1 id="what-are-web-components_1">What are Web Components? <a class="head_anchor" href="#what-are-web-components_1">#</a>
</h1>
<p>Web Components is a term used to describe three new features available in the web platform:</p>
<ol>
<li>Custom Elements</li>
<li>Shadow DOM</li>
<li>Template Element</li>
</ol>
<h2 id="custom-elements_2">Custom Elements <a class="head_anchor" href="#custom-elements_2">#</a>
</h2>
<p>Custom Elements are elements with a hyphen in their name which can be defined as subclasses of HTMLElement in Javascript, but what makes them useful over using simple HTML elements?</p>
<p>After a lot of research, I think the answer comes down to the fact that they provide the ability to react to the following events:</p>
<ol>
<li>An element being “mounted”</li>
<li>An element being “unmounted”</li>
<li>An element getting new attributes and/or children</li>
</ol>
<p>Essentially, custom elements give you web-native equivalents of <code class="prettyprint">componentDidMount</code>, <code class="prettyprint">componentWillUnmount</code> and <code class="prettyprint">componentWillReceiveProps</code>.</p>
<p>These are all great features, but I don’t think they should be limited to “custom elements”. Sadly, the only way to listen to the same events for “regular” HTML elements is to MutationObserver which isn’t the best when it comes to performance.</p>
<h2 id="shadow-dom_2">Shadow DOM <a class="head_anchor" href="#shadow-dom_2">#</a>
</h2>
<p>Shadow DOM create a kind of black box inside a custom element. But from all I can find, the only real benefit of using Shadow DOM is to get style encapsulation, i.e. scoped styles. </p>
<p>Scoped styles seem more useful than they actually are. In most cases you want to share styles across your entire web app rather creating little silos and duplicating the same styles over and over again. Instead they should only be used for special use-cases such as rendering user-styles in a way that won’t accidentally leak out to the page itself.</p>
<h2 id="template-element_2">Template Element <a class="head_anchor" href="#template-element_2">#</a>
</h2>
<p>The template element seems the least useful part of web components, but also the most inoffensive. It’s just a new HTML tag that doesn’t render anything. There might be some performance ramifications to using Template elements rather than strings, but it doesn’t make much of a difference either way.</p>
<p>The main benefit of the template at this point is to enable server-side rendering for Shadow DOM.</p>
<h2 id="web-components-the-good-parts_2">Web Components the Good Parts? <a class="head_anchor" href="#web-components-the-good-parts_2">#</a>
</h2>
<p>New information may change my mind, but I’m this 🤏 close to writing a “Shadow DOM Considered Harmful” article! Custom Elements are great! They give you some nice events to handle UI updates manually. And there’s not much to say about Template elements at all.</p>
<p>But Shadow DOM just makes everything worse for no good reason. Scoped styling leads to inefficient duplication. Event handling and external styling becomes needless complicated. Server side rendering is literally impossible outside of Chrome. The only benefit? You can be sloppy with your CSS. We have many tools available to help with CSS. We don’t need Shadow DOM most of the time.</p>
<p>I hate to sound so lame (because the Sith are generally cooler than the Jedi), but in this case, it’s better on the light-side of the force.</p>
<h2 id="are-web-components-inherently-better_2">Are Web Components inherently Better? <a class="head_anchor" href="#are-web-components-inherently-better_2">#</a>
</h2>
<p>Web Components let you react to updates, but they don’t have anything to help you actually update the content within your components. You would usually still need a library or framework to do that for you.</p>
<p>So Web Components are some new primitives that can help you build a framework, they can’t replace frameworks entirely.</p>
<p>The frameworks that build on top of Web Components are using the “DOM” events provided by CustomElements to handle updates. Other frameworks, just use function calls. Using DOM events (which are events that call JS functions), signals (which are just JS functions) and Virtual DOM (which are just JS objects) are all part of “the platform”.</p>
<p>Web Components are just a newer part of the platform so they’re worse on older browsers where you still need polyfills.</p>
<p>The only real benefit Web Components provide is that they make it easy to use directly from HTML. But it’s fairly simple to provide that capability for components built with any framework. You need a very <em>light</em> web component wrapper around it. And, yes, this is possible with <em>all</em> popular frameworks, even React.</p>
<h2 id="are-web-components-inherently-faster_2">Are Web Components inherently faster? <a class="head_anchor" href="#are-web-components-inherently-faster_2">#</a>
</h2>
<p>No. If you look at the benchmark, Solid and Svelte are both usually faster than the fastest Web Component based framework Lit. Further, to get an apples to apples comparison, you can see that LitHTML without Web Components are actually slightly faster than LitHTML with Web Components. (Side note: Lit HTML is a very cool on it’s own!) The web component part of Lit should really be an optional piece that only makes sense when packaging up components to be used in mostly static HTML pages.</p>
<h2 id="are-web-component-quotframeworkagnosticquot_2">Are Web Component “framework-agnostic”? <a class="head_anchor" href="#are-web-component-quotframeworkagnosticquot_2">#</a>
</h2>
<p>Not really. If you think about it, components built in <em>all</em> frameworks can be used within a different framework. I’ve used React within Angular and Angular within React. D3, ThreeJS and ChartJS have all been used within React. You can render Solid within React and React within Solid. There’s nothing really stopping you from mixing and matching frameworks. </p>
<p>You usually need some glue code, but that can be abstracted into a library. Web components do give you a unified API for that glue code, but that’s about where the benefits end. The real reason people avoid mixing frameworks is to avoid the overhead of multiple framework runtimes.</p>
<p>So what <em>really</em> makes a component is if it’s lightweight. This means that Svelte and Solid are good options as they have fairly small runtimes. When it comes to Web Components, it really depends on the framework used to implement them. Something like Lit is fairly lightweight and is a good candidate. But this is not about Web Components, but the frameworks used.</p>
<h2 id="can-web-components-be-used-to-build-a-good-fr_2">Can Web Components be used to build a good framework? <a class="head_anchor" href="#can-web-components-be-used-to-build-a-good-fr_2">#</a>
</h2>
<p>Yes! There’s nothing inherently wrong with custom elements. Using the light DOM, SSR is fairly easy and a framework can be fairly lightweight by leveraging the built-in events. At the same time, there are some significant trade-offs that come from using the DOM instead of javascript. DOM attributes can only be strings, and “children” can only be DOM nodes. Web Components actually makes it <em>harder</em> to pass objects, arrays and functions in components.</p>
<p>This leads to framework design with less power and expressiveness, which are a good fit for light weight use-cases. It’s all about trade-offs and how well the technology suits certain needs.</p>
<h2 id="we-need-more-nuance_2">We need more nuance <a class="head_anchor" href="#we-need-more-nuance_2">#</a>
</h2>
<p>The discourse in the Javascript community is down in the dumps. It’s just fanboys and flamewars on all sides. React, Preact, Solid, Svelte, Qwik, Lit, Astro, are all doing very interesting things. But they all make different trade-offs. Some are clearly better for smaller apps as they have smaller runtimes. Some, like React, only have features that only make sense for huge apps, (like concurrent rendering).</p>
tag:blog.namangoel.com,2014:Post/revisiting-features-css-needs-from-20202023-08-17T19:57:58-07:002023-08-17T19:57:58-07:00Revisiting "Features CSS Needs" from 2020<p>Back in 2020, I wrote an article titled “<a href="http://blog.namangoel.com/features-we-actually-need-in-css">Features CSS Needs</a>”</p>
<p>I wanted to revisit it since so much of it has already come true, and to update my list for 2023.</p>
<h2 id="a-more-powerful-code-classprettyprintcalccode_2">A More Powerful <code class="prettyprint">calc</code> <a class="head_anchor" href="#a-more-powerful-code-classprettyprintcalccode_2">#</a>
</h2>
<p>Support for dividing units has been part of the official specification for years now, yet no browser has implemented it.</p>
<p><code class="prettyprint">calc(100% / 100px)</code> still doesn’t work. This is unfortunate as this simple enhancement would make CSS so much more powerful without the need to use much more verbose concepts such as Container Queries</p>
<h2 id="more-css-functions-code-classprettyprintfloor_2">More CSS functions — <code class="prettyprint">floor</code>, <code class="prettyprint">ceil</code> and <code class="prettyprint">round</code> <a class="head_anchor" href="#more-css-functions-code-classprettyprintfloor_2">#</a>
</h2>
<p>The <code class="prettyprint">round</code> function is a reality and supported in Firefox today! Better yet, it lets you do <code class="prettyprint">floor</code> and <code class="prettyprint">ceil</code> as well!</p>
<h2 id="logical-operations-in-code-classprettyprintca_2">Logical Operations in <code class="prettyprint">calc</code> <a class="head_anchor" href="#logical-operations-in-code-classprettyprintca_2">#</a>
</h2>
<p>There’s some discussions about this, but nothing yet. At least we’re getting “Container Style” queries which handle many of the use-cases</p>
<h2 id="scrolltimeline_2">ScrollTimeline <a class="head_anchor" href="#scrolltimeline_2">#</a>
</h2>
<p>ScrollTimeline, (<code class="prettyprint">animation-timeline</code>) is real and in Chromium today. Firefox has it behind a flag. This is going to be a huge improvement to the state of animations on the web and I can wait for it to be implemented across all three browsers!</p>
<h2 id="directionaldocking_2">Directional-Docking <a class="head_anchor" href="#directionaldocking_2">#</a>
</h2>
<p>Actually, ScrollTimelines already enable this!</p>
<h2 id="hover-and-swipe-timelines_2">Hover and Swipe Timelines <a class="head_anchor" href="#hover-and-swipe-timelines_2">#</a>
</h2>
<p>I still think that these would be nice to have. However, ScrollTimelines solve a large subset of problems itself, and I’m happy to wait a few more years before even asking for this again.</p>
<h2 id="container-queries_2">Container Queries!! <a class="head_anchor" href="#container-queries_2">#</a>
</h2>
<p>This wasn’t even on my wishlist anymore. I had given up. But somehow, like a phoenix rising from the ashes, Container Queries appeared out of nowhere and are already implemented cross-browser.</p>
<p>Container (Style) queries aren’t as well supported, but let’s be honest, size queries is what we really wanted anyway!</p>
<h2 id="code-classprettyprinthascode_2">
<code class="prettyprint">:has()</code> <a class="head_anchor" href="#code-classprettyprinthascode_2">#</a>
</h2>
<p>This again, came out of nowhere and is almost supported cross-browser (still behind a flag in Firefox for now). This also has huge ramifications for reducing the amount of JS needed for styling puposes.</p>
<h2 id="view-transitions_2">View Transitions <a class="head_anchor" href="#view-transitions_2">#</a>
</h2>
<p>Jake Archibald has done it again! View Transitions are god-tier API for the web and the entire web-community is literally foaming at the mouth looking at all the cool demos built with it.</p>
<h2 id="what-do-i-even-ask-for-anymore_2">What do I even ask for anymore!? <a class="head_anchor" href="#what-do-i-even-ask-for-anymore_2">#</a>
</h2>
<p>I literally have nothing more to ask of CSS anymore. Sure, there’s little things we could come up with if we really thought about it, but there so much awesome stuff that has landed in CSS in recent years that I just want cross-browser support for it all. The main three things that needs support ASAP are:</p>
<ul>
<li>View Transitions</li>
<li>Scroll/Animation Timelines</li>
<li>Container (Style) Queries</li>
</ul>
<p>The rest can wait.</p>
<h1 id="what-a-great-time-for-the-web_1">What a great time for the web! <a class="head_anchor" href="#what-a-great-time-for-the-web_1">#</a>
</h1>tag:blog.namangoel.com,2014:Post/the-complicated-but-powerful-state-of-object-types-in-flow2023-08-17T19:40:44-07:002023-08-17T19:40:44-07:00Using Flow instead of Typescript in 2023<p>Any mention of using Flow in the year 2023 causes strange reactions for web developers everywhere. Why would you do that!?</p>
<p>The tradeoffs won’t make sense for everyone, but there are actually some very compelling reasons to choose Flow instead of Typescript.</p>
<p>Let’s start with the things that Typescript is undeniably better at.</p>
<h2 id="typescript-has-emmuchem-better-availability-o_2">Typescript has <em>much</em> better availability of type definitions <a class="head_anchor" href="#typescript-has-emmuchem-better-availability-o_2">#</a>
</h2>
<p>If you look at NPM download metrics alone, Typescript is about 80x more popular than Flow. This comes with some serious benefits. Typescript is ubiquitous and virtually every module on NPM has typescript type definitions available.</p>
<p>If you’re using a type-system to improve your developer experience and get better auto-complete, Typescript is clearly the right choice.</p>
<p>That said, it’s becoming easier than ever to convert Typescript definitions to Flow. Flow supports mostly the same syntax now. You simply have to convert some <code class="prettyprint">extends</code> to <code class="prettyprint">:</code> and mark somethings as “$ReadOnly` explicitly to get the correct "variance” behaviour.</p>
<h2 id="typescript-also-has-better-editor-support_2">Typescript also has better editor support <a class="head_anchor" href="#typescript-also-has-better-editor-support_2">#</a>
</h2>
<p>If you use anything other VSCode, chances are that Typescript likely has good support and Flow support is an afterthought if there is any kind of support at all.</p>
<p><a href="https://zed.dev">Zed</a> is a new code editor generating a lot of buzz. It has Typescript support built-in, but since there are no third-party extensions yet, there’s no Flow integration at all.</p>
<p><a href="https://nova.app">Nova</a> is an editor for macOS by Panic that is a lot like VS Code but made a fully native app with great design. It has a great first-party Typescript extension. There <em>is</em> a Flow extension available, but it only shows type errors after you save a file, and it doesn’t give you any auto-complete at all.</p>
<h2 id="typescript39s-template-string-literal-types-a_2">Typescript’s template string literal types are handy <a class="head_anchor" href="#typescript39s-template-string-literal-types-a_2">#</a>
</h2>
<p>Typescript has a lot of very interesting features and to many people, it may seem like Flow is missing out. However, Flow has actually adopted most of the powerful features from Typescript, often with the exact same syntax. In recent versions, Flow has added support for “Mapped Types”, “Conditional Types” and “Type Guards”.</p>
<h2 id="flow-gives-you-much-more-type-safety_2">Flow gives you much more type safety <a class="head_anchor" href="#flow-gives-you-much-more-type-safety_2">#</a>
</h2>
<p>If your goal is to prevent runtime exceptions, Flow protects you <em>much</em> better than Typescript does. Even if we consider Typescript in “strict” mode, it is easy to trick Typescript a lot of the times. The most obvious example of “unsoundness” (the type-system letting you do incorrect stuff) in Typescript is “variance”.</p>
<p>What is variance? Let’s look at a simple example:</p>
<pre><code class="prettyprint lang-ts">class Animal { ... }
class Dog extends Animal { ... }
class Cat extends Animal { ... }
const dogs: Array<Dog> = [new Dog(), new Dog(), new Dog()];
const animals: Array<Animal> = dogs;
</code></pre>
<p>Do you see the mistake there? Most people don’t, and nor does Typescript. The mistake here is that an <code class="prettyprint">Array<Dog></code> <em>is NOT</em> an <code class="prettyprint">Array<Animal></code>. But, you would say, every <code class="prettyprint">Dog</code> <em>is</em> and <code class="prettyprint">Animal</code>. That’s true. But an <code class="prettyprint">Array<Dog></code> <em>is NOT</em> an <code class="prettyprint">Array<Animal></code>, because Arrays are mutable.</p>
<p>Let me show you <em>why</em> it is an error:</p>
<pre><code class="prettyprint lang-ts">animals.push(new Cat());
dogs.forEach(dog => dog.bark());
</code></pre>
<blockquote class="short">
<p>TypeError: dog.bark is not a function. (In ‘dog.bark()’, ‘dog.bark’ is undefined)</p>
</blockquote>
<p>Uh oh, you accidentally put a cat in your list of dogs, and Typescript just let you. Flow would’ve caught the error and saved you from a potential runtime exception.</p>
<p>Let’s see the two ways you <em>can</em> do what you want in Flow:</p>
<pre><code class="prettyprint">const readOnlyAnimals: $ReadOnlyArray<Animal> = dogs;
// It's safe if you promise not to mutate this list.
const animals: Array<Animal> = [...dogs];
// It's safe if you make a copy of the array.
</code></pre>
<p>Typescript treats all such types of types as “co-variant”. This works work collections such as arrays and objects as long as you don’t do any mutation. Depending on the type of code you write, this is OK, but problems start to arise as Typescript, by default, also treats types that should be “contra-variant” (types flow in the opposite direction as that of the types contained) as “co-variant”. The most common example of this is refs in React. Typescript will actively guide you to do the wrong thing in such cases.</p>
<p>Do you want a type-system to save you from common mistakes, or do you want a type-system that makes the same common mistakes as you so it doesn’t “annoy” you?</p>
<h2 id="flow-has-emmuchem-better-object-types_2">Flow has <em>much</em> better object types <a class="head_anchor" href="#flow-has-emmuchem-better-object-types_2">#</a>
</h2>
<p>Typescript’s object types are surprisingly bad. Typescript lacks any concept of “Exact Object Types” that have been available in Flow for years now. An <a href="https://github.com/microsoft/TypeScript/issues/12936">issue on Typescript’s repo</a> has been open for 7 years now, and people just want a way to define object types that disallow extra properties. No luck!</p>
<p>Want an object type where you want a specific key to have one value but any other key to be a different value?</p>
<pre><code class="prettyprint lang-ts">type Data = {
id: number,
[key: string]: string,
};
</code></pre>
<p>Again, Typescript won’t let you do this. People come up with creative workarounds to make this work. Badly. Flow just handles it like a champ!</p>
<p>Further, Typescript expects you to use <code class="prettyprint">&</code> to combine object types together, which means if your keys collide you get strange results. Flow lets you use Object Spread syntax instead!</p>
<pre><code class="prettyprint">type CombinedObject = {...ObjType1, ...ObjType2};
</code></pre>
<p>Once you get used to this, Typescript’s handling of Object types feel archaic by comparison.</p>
<h2 id="typescript-just-gives-up-sometimes_2">Typescript just gives up sometimes <a class="head_anchor" href="#typescript-just-gives-up-sometimes_2">#</a>
</h2>
<p>There are many situations, where you can lie to Typescript, and it will just let you. </p>
<pre><code class="prettyprint lang-ts">function isNumber(x: unknown): x is number {
return typeof x === 'string';
}
</code></pre>
<p>Typescript will just let you do this. Once you say the return type is <code class="prettyprint">x is number</code>, Typescript just trusts you implicitly. Flow will double-check.</p>
<p>You can also often just use <code class="prettyprint">x as Y</code> somewhere and even if that’s not the case, Typescript will just let you do that.</p>
<p>Again, Typescript is not built to be safe, it’s built to be helpful. Flow is built to catch mistakes.</p>
<h2 id="flow39s-tooling-is-starting-to-get-better_2">Flow’s tooling is starting to get better <a class="head_anchor" href="#flow39s-tooling-is-starting-to-get-better_2">#</a>
</h2>
<p>For the longest time, tooling to generate Flow type definitions from source code was abysmal. This is starting to change. The <code class="prettyprint">flow-api-translator</code> package will let you extract types from your Flow-typed code and publish <code class="prettyprint">.js.flow</code> alongside your <code class="prettyprint">.js</code> file for NPM package. It even supports generating <code class="prettyprint">.d.ts</code> files as well out of the box. This is a different way to ship types in your NPM package, but it works just as well as the usual process of bundling all types for your package into a single file, and generally is more flexible when you want to let users use files <em>within</em> your package.</p>
<p>Now, <code class="prettyprint">flow-api-translator</code> is quite new and far from perfect, but it’s improving fast!</p>
<h2 id="it-might-be-time-try-flow-once-again_2">It might be time try Flow once again <a class="head_anchor" href="#it-might-be-time-try-flow-once-again_2">#</a>
</h2>
<p>Now, using Flow is near as nice an “experience” as using Typescript. You need to do more work up-front to get all the type definitions. Editors don’t work as well. The tooling isn’t as good.</p>
<p>But if you want a solid type-system that actually catches your mistakes and prevents <em>most</em> runtime exceptions, Flow is a great choice that gets you very far without having to switch languages to something like <code class="prettyprint">Elm</code> or <code class="prettyprint">ReScript</code>.</p>
tag:blog.namangoel.com,2014:Post/features-we-actually-need-in-css2020-02-20T00:07:03-08:002020-02-20T00:07:03-08:00Features CSS Needs<p>While the work on Houdini continues, I think it makes sense to prioritise a few simple features that would make life much easier for developers trying to build the most common things we need on the web.</p>
<p>I have carefully chosen the following features to fulfil two requirements:</p>
<ol>
<li>They enable new functionality that was previously impossible or very difficult without Javascript.</li>
<li>They should be modest enough to be able to implemented in browsers.</li>
</ol>
<p>Recent features such as <code class="prettyprint">scroll-snap-type</code>, <code class="prettyprint">position: sticky</code> and <code class="prettyprint">backdrop-filter</code> are examples of simple capabilities that have greatly expanded the capabilities and quality of what we can build on the web.</p>
<h2 id="a-more-powerful-code-classprettyprintcalccode_2">A More Powerful <code class="prettyprint">calc</code> <a class="head_anchor" href="#a-more-powerful-code-classprettyprintcalccode_2">#</a>
</h2>
<p><strong>tldr;</strong> allow multiplication and division of mixed units</p>
<p>The calc function is a game changer. The function was introduced years ago and it enables us to achieve layout that most of think needs features like container queries, which, to put it bluntly, are not possible because they introduce cyclical dependencies in the layout engine.</p>
<p><code class="prettyprint">calc</code> steps around the problem of cyclical dependencies as it inherently causes the child to be dependent on the parent dimensions, just like percentages have done since CSS started.</p>
<p>However, there is a strange limitation in the specification of <code class="prettyprint">calc</code> that has outlived its usefulness:</p>
<blockquote>
<p>At <code class="prettyprint">*</code>, check that at least one side is <code class="prettyprint"><number></code>. If both sides are <code class="prettyprint"><integer></code>, resolve to <code class="prettyprint"><integer></code>. Otherwise, resolve to the type of the other side.</p>
<p>At <code class="prettyprint">/</code>, check that the right side is <code class="prettyprint"><number></code>. If the left side is <code class="prettyprint"><integer></code>, resolve to <code class="prettyprint"><number></code>. Otherwise, resolve to the type of the left side.</p>
</blockquote>
<p>What this means is that when you multiply or divide within a <code class="prettyprint">calc</code> expression, only one of the two sides can contain a unit. The reason given for this limitation is the complexity of “unit algebra”. I think CSS authors who want to use complex mathematical expressions should be trusted to get their “unit algebra” right.</p>
<p>I should be allowed to write this:<br>
<code class="prettyprint">calc((100% / 100px) * 90px)</code>.</p>
<p>This may seem like a strange ask, but it would make more sense with the next feature request.</p>
<h2 id="more-css-functions-code-classprettyprintfloor_2">More CSS functions — <code class="prettyprint">floor</code>, <code class="prettyprint">ceil</code> and <code class="prettyprint">round</code> <a class="head_anchor" href="#more-css-functions-code-classprettyprintfloor_2">#</a>
</h2>
<p><code class="prettyprint">calc</code> kind of opened the floodgates to functions in CSS values. Recently we got powerful new functionality with the introduction of <code class="prettyprint">min</code>, <code class="prettyprint">max</code> and <code class="prettyprint">clamp</code> functions. It’s time to add functions to get CSS counterparts to <code class="prettyprint">Math.floor</code>, <code class="prettyprint">Math.ceil</code> and <code class="prettyprint">Math.round</code>.</p>
<p>This would allow us to round our transforms to the nearest pixel value to avoid blurry text, but it would also allow us to do powerful layout without being forced into using grid or flexbox layout.</p>
<p>Consider, again, the example from above.<br>
<code class="prettyprint">calc((100% / 100px) * 90px)</code> can simply be written as <code class="prettyprint">90%</code> which is pretty useless. However, with functions like <code class="prettyprint">floor</code> we could do this:</p>
<p><code class="prettyprint">width: calc(100% / floor(100% / 100px))</code></p>
<p>This lets us calculate how many 100px wide elements can fit in a given container and divide the width equally among that many elements. Of course we can do similar things today with flexbox and grid layout. But those layout systems don’t always fit correctly. If you don’t have enough child elements your child elements will become too wide to fill the row. Or if you have a horizontally scrolling element, they’ll squish to less that 100px wide.</p>
<p>That simple calculation above would give us capabilities that are currently impossible in CSS. Further, since it’s just an extension of <code class="prettyprint">calc</code> there should be cyclical dependencies and should actually be implementable.</p>
<h2 id="logical-operations-in-code-classprettyprintca_2">Logical Operations in <code class="prettyprint">calc</code> <a class="head_anchor" href="#logical-operations-in-code-classprettyprintca_2">#</a>
</h2>
<p>While we are making <code class="prettyprint">calc</code> more powerful why not add logical operations such as <code class="prettyprint"><</code>, <code class="prettyprint">></code>, and <code class="prettyprint">==</code> and add a ternary statement? Image:</p>
<p><code class="prettyprint">width: calc(100% > 500px ? 50% : 100%)</code></p>
<p>Wouldn’t this solve most of what we want from container queries?<br>
But again, I don’t think this breaks any cyclical dependency rules of CSS.</p>
<h2 id="scrolltimeline_2">ScrollTimeline <a class="head_anchor" href="#scrolltimeline_2">#</a>
</h2>
<p>A recent article talked about a feature like this being <a href="https://developers.google.com/web/updates/2018/10/animation-worklet#hooking_into_the_space-time_continuum_scrolltimeline">considered for Houdini</a>.</p>
<p>This is a great idea. However, it’s a terrible idea to wait around for something so ambitious and dependent on Javascript as AnimationWorklet to get this feature.</p>
<p>How about a new CSS property that gives us most of what we need today:</p>
<p>Consider this:</p>
<pre><code class="prettyprint lang-css">animation-name: my-keyframe-animation;
/* the animation progress is synced to document scrolling */
animation-timeline: scroll-timeline-y(:root);
/*
the animation progress is synced to the horizontal scrolling of the
element with the id element-id.
*/
animation-timeline: scroll-timeline-x(#element-id);
</code></pre>
<p>Almost all of our scroll-based animations could be solved in one fell swoop. Define a <code class="prettyprint">@keyframe</code> animation, but set its progression based on the scrolling of an element instead of time. The scroll value would be converted to a percentage based on the <code class="prettyprint">scrollTop / scrollHeight</code> so there would be no need to do any pixel math.</p>
<p>This seems like something that should be much easier to implement than ScrollTimeline for AnimationWorklet as it is smaller is scope, doesn’t have to deal with running javascript, a worklet, or stateful code. Rolling this out would also provide additional context for implementing AnimationWorklet.</p>
<p>(A small detail to note that might need additional thought — What happens if the scroll height of the container changes, but the user didn’t scroll. The percentage scrolled would change. In such a case, I would suggest that the animation-timeline should jump to the new percentage scrolled value even if that means a jerky animation change)</p>
<h2 id="hover-and-swipe-timelines_2">Hover and Swipe Timelines <a class="head_anchor" href="#hover-and-swipe-timelines_2">#</a>
</h2>
<p>If we add support for ScrollTimelines to CSS, it would make sense to add other timelines as well. Namely Hover and Swipe. These would depend on mouse position on an element or touch gestures.</p>
<pre><code class="prettyprint lang-css">animation-timeline: hover-timeline-x(#element-id);
</code></pre>
<p>Here the timeline would progress from 0% when the pointer is hovering on left of edge of a the element to 100% when the pointer is hovering on the right edge of the element.</p>
<p>There are more open questions for something like this as you would need to decide what would happen before you start hovering on the given element after you stop hovering on it. We could decide to have a <code class="prettyprint">animation-timeline-initial-value</code> property. (Or we could just default to 0). And we could keep the last valid value we did have on blur.</p>
<p>Whatever we decide for those cases would probably not be a problem as we have the ability to customise the behaviour with the <code class="prettyprint">:hover</code> pseudo-selector.</p>
<p>Similarly, we can imagine something like: </p>
<pre><code class="prettyprint lang-css">animation-timeline: touch-timeline-y(#element-id);
</code></pre>
<p>This would work the same way as the <code class="prettyprint">hover-timeline-(x | y)</code> but for swiping with touchscreens instead. You may have your own ideas for more timelines which we can add over time.</p>
<p>Over time, we can come up with new types of timelines and ways to transform the timelines (clamp the values etc).</p>
<p>Some ideas for additional timelines that should be implemented after ScrollTimeline, HoverTimeline and TouchTimeline:</p>
<ul>
<li>VideoTimeline (for animations that should play in sync with video playback)</li>
<li>AudioTimeline (similarly for audio playback)</li>
<li>PressureTimeline (for pressure sensitive touchscreens and styluses)</li>
<li>AngleTimeline (for devices with accelerometers) along x, y or z axis</li>
<li>GyroTimeline (for synching with gyroscope movement)</li>
<li>PinchZoomTimeline</li>
<li>AmbientLightTimeline</li>
<li>Various Face Tracking Timeline
<ul>
<li>percentage mouth opened</li>
<li>percentage eyes opened</li>
<li>eye angle</li>
<li>etc.</li>
</ul>
</li>
</ul>
<p>An advantage of this API in addition to enabling better animations on the web is that this could be a new way to provide a limited version of APIs to the web that would otherwise raise privacy concerns. In the case of face-tracking for example, you would be able to sync an animation to a particular feature, but you won’t be able to query it directly.</p>
<h2 id="directionaldocking_2">Directional-Docking <a class="head_anchor" href="#directionaldocking_2">#</a>
</h2>
<p>One under-appreciated feature introduced in the last few years is <code class="prettyprint">position: sticky</code>. It makes many common use-cases simpler. It’s time to add it’s logical successor with <code class="prettyprint">position: directionally-sticky</code> (name TBD).</p>
<p>This would work similarly to position sticky. Except it would scroll along with the scroll container every time the scroll direction changes until it hits it’s given limit with the <code class="prettyprint">top</code> or <code class="prettyprint">bottom</code> value.</p>
<p>Look at this video from <a href="https://developers.google.com/web/updates/2018/10/animation-worklet">Google’s blog about Animation Worklet</a> again:</p>
<div style="width:100%;max-width:360px;margin:10px auto;">
<video src="https://storage.googleapis.com/webfundamentals-assets/animation-worklet/hidey_x264.mp4"></video>
</div>
<p>[right click to enable controls on the video above]</p>
<p>So essentially, it would scroll along with the scroll container but get stuck when it starts to leave the given interval between the <code class="prettyprint">top</code> and <code class="prettyprint">bottom</code> values.</p>
<p>The styles for the header in the video above could look like this:</p>
<pre><code class="prettyprint lang-css">height: 60px;
position: directionally-sticky;
top: 0;
bottom: calc(100vh - 60);
</code></pre>
<h2 id="conclusion_2">Conclusion <a class="head_anchor" href="#conclusion_2">#</a>
</h2>
<p>These are some of the CSS features that would make my life building websites easier and enable some truly new capabilities that are currently not possible on the web or have significant performance costs.</p>
<p>If you agree with me, please share this post to get it more visibility. If you have ideas of your own, please tweet at me and we can advocate for features we really want.</p>
tag:blog.namangoel.com,2014:Post/flow-for-typescript-developers2016-07-21T12:49:02-07:002016-07-21T12:49:02-07:00Flow Compared To Typescript<p><strong>Disclaimers</strong>:</p>
<ul>
<li>I’m not trying to start a flame-war. Both Typescript and Flow are great.</li>
<li>I’m not a Typescript expert so feel free to correct me on Twitter (@naman34)</li>
<li>I’m assuming Typescript >2.0 which includes non-nullable types (because nullbale-types === ?)</li>
</ul>
<p>If you haven’t noticed, there are two popular ways of adding types to your Javascript code — Microsoft’s Typescript and Facebook’s Flow.</p>
<p>Both are extremely powerful, gradual, structural, type-systems. They also, look very similar, with almost the same syntax. <strong>Almost</strong>.</p>
<p>Often developers jumping from one system to the other get frustrated that all the things they learnt no longer work in the same way. And they assume that the features aren’t supported. And so, they do what any modern JS developer would do and vent on Twitter.</p>
<p>But wait, didn’t I just tell you that <strong>both</strong> type-systems are powerful. Everything you did in one type-systems can <em>probably</em> be achieved in the other.</p>
<p>So, this is an ongoing, incomplete comparison of some of the differences between Flow and Typescript</p>
<h2 id="interfaces-vs-object-types_2">Interfaces vs Object Types <a class="head_anchor" href="#interfaces-vs-object-types_2">#</a>
</h2>
<p>It is common in Typescript to use <code class="prettyprint">interface</code> to declare the type of an object.</p>
<pre><code class="prettyprint">interface MyObj {
a: number;
b: string;
}
</code></pre>
<p>In Flow you’re more likely to do something like this:</p>
<pre><code class="prettyprint">type MyObj = {
a: number;
b: string;
}
</code></pre>
<p>But wait, did you know that that both those examples are valid in both Flow and Typescript??<br>
<img src="http://media.galaxant.com/000/187/612/ce9c949d6c73dbfb889f6036bac022ddgif" alt="Mind-Blown"></p>
<p>You see, flow supports <code class="prettyprint">interface</code> and Typescript supports object types. So, it’s usually a matter of culture.</p>
<h2 id="class_2">class <a class="head_anchor" href="#class_2">#</a>
</h2>
<p>Both flow and typescript support adding types to a class</p>
<pre><code class="prettyprint">class X {
a: number;
b: string;
}
</code></pre>
<p>However, there is one big difference. Flow doesn’t support <code class="prettyprint">implementing</code> Interfaces.</p>
<p>So, this code while valid in typescript isn’t valid in Flow:</p>
<pre><code class="prettyprint">interface AData {
a: number;
getA(): number;
setA(val: number): void;
}
class AB implements AData {
a: number = 0;
getA(): number {
return this.a
}
setA(v: number) {
this.a = v
}
}
</code></pre>
<p>Now in typescript any object created by instantiating the class <code class="prettyprint">AB</code> will also be of type <code class="prettyprint">AData</code>. (Java 101).</p>
<p>In Flow, you can’t actually use the <code class="prettyprint">implements</code> keyword. So how do you do the same thing with Flow? You remove the words <code class="prettyprint">implements AData</code> and you’re done.</p>
<p>You see, since the class has the same structure as the interface defined before, you can use an object of its type whenever the interface type is expected.</p>
<p>You do lose the ability to type-check your class definition as you type it, but you’ll catch the same mistakes when you actually use it.</p>
<p>That said, if you’re just declaring types, flow lets you use a different keyword <code class="prettyprint">mixins</code> to share common code. You can read about it <a href="https://flowtype.org/docs/declarations.html#mixins">here</a></p>
<h3 id="publicprivate-etc-etc_3">public/private etc etc. <a class="head_anchor" href="#publicprivate-etc-etc_3">#</a>
</h3>
<p>Flow also doesn’t support any of the other extensions to class syntax that come with Typescript. You see Typescript often claims to be JS with types, but it also brings all these other syntax extensions that have basically nothing to do with JS but look familiar to Java and C# developers. So, you get things like the <code class="prettyprint">public</code> and <code class="prettyprint">private</code> keywords. I already mentioned <code class="prettyprint">implements</code></p>
<p>Flow skips all these syntax extensions and only supports features in ES6 and many proposals supported by ES7. A simple rule is that if Babel supports a feature, Flow probably supports it too.</p>
<h2 id="compilation_2">Compilation <a class="head_anchor" href="#compilation_2">#</a>
</h2>
<p>Flow is not a compiler, Typescript is. You will usually use Typescript instead of Babel. You will usually use Flow alongside Babel. Again, Flow is much more literally just Javascript with types. Flow understands many of the new, fancy ES6+ features, but all it does is check your code like a super-smart linter. You still rely on Babel to convert your code down to ES5, and also remove your types. Typescript pretty much does it all.</p>
<p>On the other hand, both Flow and Typescript kind of support type-checking without any type annotations at all. Typescript understands JSDoc annotations and do its best with just those types.</p>
<p>Flow, has a special <code class="prettyprint">flotate</code> syntax that lets you write ALL your annotation in inline comments, and skip the compilation step entirely. Learning this syntax is easy. Whenever you’re about to write an inline annotation, you can just wrap that in a comment.</p>
<pre><code class="prettyprint">var a: number = 1
// becomes
var a/*: number */ = 1
</code></pre>
<p>And any other multi-line type definitions etc, can be wrapped in: <code class="prettyprint">/*:: ... */</code></p>
<pre><code class="prettyprint">/*::
type MyObj = {
a: string,
b: number
}
*/
</code></pre>
<h2 id="enums_2">Enums <a class="head_anchor" href="#enums_2">#</a>
</h2>
<p>Typescript supports enums, Flow doesn’t. Flow just supports enum types.</p>
<p>Typescript:</p>
<pre><code class="prettyprint">enum States {
ON,
OFF,
QUANTUM
}
</code></pre>
<p>Flow:</p>
<pre><code class="prettyprint">type States
= 'ON'
| 'OFF'
| 'QUANTUM'
</code></pre>
<p>Actually, the enum type is supported by Typescript as well. From what I gather, the only point of an <code class="prettyprint">enum</code> is to let you define descriptive variable names while using small numbers. So, in the first example, <code class="prettyprint">States</code> is just a collection of <code class="prettyprint">0</code>, <code class="prettyprint">1</code> and <code class="prettyprint">2</code>, but you get to use names that actually mean something.</p>
<p>Again, Flow skips this, because it doesn’t add features to the language, just types. However, you can achieve something similar with Flow with a little more typing.</p>
<pre><code class="prettyprint">const ON = 0
const OFF = 1
const QUANTUM = 2
type States = 0 | 1 | 2
</code></pre>
<p>It’s a little more code, but it does exactly the same thing as a Typescript <code class="prettyprint">enum</code></p>
<h2 id="magic-types_2">Magic Types <a class="head_anchor" href="#magic-types_2">#</a>
</h2>
<p>By now, you’re probably thinking “Typescript is great, who needs Flow, Bleh!”. Let me even the odds. In this section that should probably be called, ‘Getting derailed while comparing type systems and deep-diving into a little-known feature instead’</p>
<p>Flow has a few <em>Magic Types</em> that make it possible to write much more accurate types.</p>
<h3 id="keys_3">$Keys <a class="head_anchor" href="#keys_3">#</a>
</h3>
<p>It’s a magic type that takes an object type and gives you an enum of all the keynames.</p>
<p>Let’s consider a Record type. A function that takes an object, and then returns an object with getters for all the values. Consider it a simple way to make objects immutable.</p>
<pre><code class="prettyprint">function makeRecord(obj) {
return {
get(key) {
return obj[key]
}
}
}
</code></pre>
<p>With Typescript you’d probably type it like so:</p>
<pre><code class="prettyprint">function makeRecord(obj: Object) {
return {
get(key: string): any {
return obj[key]
}
}
}
</code></pre>
<p>But you see how yo basically lost all type information with the <code class="prettyprint">get</code> method.</p>
<p>You can do slightly better with Flow.</p>
<pre><code class="prettyprint">function makeRecord<T: Object>(obj: T) {
return {
get(key: $Keys<T>): any {
return obj[key]
}
}
}
</code></pre>
<p>Now, flow will complain if you use a string that didn’t exist in the original object.</p>
<p>The value type is still essentially lost, but that’s something that might be fixed soon. The Typescript team on Twitter suggested that they will add the functionality soon too.</p>
<h3 id="diff_3">$Diff <a class="head_anchor" href="#diff_3">#</a>
</h3>
<p>This is a magic type that was basically added for React, but it can be used for other purposes as well.</p>
<p>In basic terms, it’s object subtraction.</p>
<pre><code class="prettyprint">type A = {
a: number,
b: string
}
type B = {
b: string
}
type C = $Diff<A, B>
// {a: number, b?: string}
</code></pre>
<p>It’s used to to create the prop-contract for React components by doing <code class="prettyprint">$Diff<Props, DefaultProps></code>.</p>
<p>The Typescript type-definition just skips <code class="prettyprint">defaultProp</code> entirely as it can’t be supported.</p>
<p>This magic type is also extremely useful for defining the types for <code class="prettyprint">Higher-Order-Components</code> in React, but that is a complex topic probably left for another post.</p>
<h3 id="inferrable-types_3">Inferrable Types <a class="head_anchor" href="#inferrable-types_3">#</a>
</h3>
<p>This is not a Magic Type per-say, but it makes it possible to write magic types. In flow you can use the <code class="prettyprint">*</code> character to tell Flow that it should try to infer the type on its own, and it can be extremely smart.</p>
<p>Here’s an example of using <code class="prettyprint">*</code> to write your own magic type. This code is a little far-fetched and you won’t usually need to write it. But when you do need it, nothing else will do.</p>
<pre><code class="prettyprint">type $Function1<A, B> = (arg: A) => B;
type _Function1Value<A, B, F: $Function1<A, B>> = B; // eslint-disable-line
type $Function1Value<F: $Function1<*, *>, A> = _Function1Value<A, *, F>;
</code></pre>
<p>// This is a type that takes a function that takes one argument, the type of the argument and gives you the return type. This is useful when dealing with function overloads.</p>
<h2 id="typecasting_2">TypeCasting <a class="head_anchor" href="#typecasting_2">#</a>
</h2>
<p>This is just a simple syntax difference. When you deal with types, every now and then you need to override the type system and tell it what the type of something is.</p>
<p>In Typescript you do it like this.</p>
<pre><code class="prettyprint">(<TypeName> variableName)
// OR
(variableName as TypeName)
</code></pre>
<p>[you’ll need to use the second syntax if you plan on using JSX]</p>
<p>In Flow, you do it like this:</p>
<pre><code class="prettyprint">(variableName: TypeName)
</code></pre>
<h2 id="library-type-definitions-and-tooling_2">Library Type Definitions and Tooling <a class="head_anchor" href="#library-type-definitions-and-tooling_2">#</a>
</h2>
<p>There’s no simpler way to say this. Typescript is a more mature tool and you’ll find better IDE integrations and more types for libraries.</p>
<p>However, Flow is pretty good with it’s IDE features too. In the department Library definitions, however, Flow has a long way to catch up.</p>
<h2 id="conclusion_2">Conclusion <a class="head_anchor" href="#conclusion_2">#</a>
</h2>
<p>I’ve probably missed a lot of stuff. But I think I covered the basics. Let me know if I got anything wrong, or missed something important. Any general feedback is also welcome. (@naman34)</p>
<p>There are a few concepts I skipped on purpose, such as <code class="prettyprint">co-variance</code> vs <code class="prettyprint">contra-variance</code>. This is because I’m not sure about all the details about that. I just know Flow and Typescript have different strategies for dealing with sub-types.</p>
tag:blog.namangoel.com,2014:Post/swift-4-wishlist2016-05-18T19:53:25-07:002016-05-18T19:53:25-07:00Swift Today, Swift Tomorrow<p>I’m primarily a Javascript developer. I’ve written servers in Node.js for years, made small and big front-end apps, (mostly in React.js, of course) and written plugins for Atom and Visual Studio Code.</p>
<p>Yet, even after living and breathing Javascript for years now, I’ve never been quite content. I’ve always wanted something a little more <code class="prettyprint">functional</code>. Javascript (I’m talking ES6) does great in many respects. It has first-class functions, tail call optimization. But it still lacks immutable data structures or a powerful type system. I’ve tried to fix these problems. I end up using Immutable.js for most of my projects, and I don’t write Javascript without <a href="http://flowtype.org/">flow</a> anymore. Immutable is great, and flow is constantly getting better.</p>
<p>Yet, I like languages and I learn languages. I spent time learning the basics of Haskell and Elm. I can read OCaml. I’ve tried to get comfortable reading lisp (read Clojure). On the other hand, I’ve worked with Java, learnt some Scala and I play around with Swift on a regular basis.</p>
<p>Now, most ‘functional’ developers would talk about languages like Elm, Haskell, OCaml, Clojure, F# or, recently, Elixir. These are all great languages, and I would recommend learning at least 2 of them. But I like to bring Swift to this discussion. ‘Pure’ functional languages are great for building resilient programs, the learning curve remains steep. And the fact remains that developers coming from languages like Java, C++ et al have an extremely hard time adapting.</p>
<p>Swift seemed like the perfect language for such a use case. It has a strong static type system. It’s fast. And it covertly brings many functional concepts to a language that looks object-oriented on the surface. While, like Javascript, I would say it has <code class="prettyprint">good</code> parts, by which I mean functional parts. Classes in Swift remain a necessary evil to make it backwards compatible with Objective C.</p>
<p>That said, here are some of the highlights of Swift for me:</p>
<ul>
<li>First Class Functions</li>
<li>Non-Nullable Types and Optionals</li>
<li>Great C-like Syntax</li>
<li>Structs that behave just like records in Functional Languages.</li>
<li>Local Mutability, but the benefits of Immutability by copy-or-write/pass-by-value</li>
<li>The Swift Package Manager seems promising.</li>
</ul>
<p>Overall Swift seems great, but I think it could be improved a lot. Swift 3 is just around the corner, but it’s mostly a stability release, so here’s my wish list for Swift 4:</p>
<h2 id="1-bring-back-the-currying-syntax_2">1. Bring back the currying syntax. <a class="head_anchor" href="#1-bring-back-the-currying-syntax_2">#</a>
</h2>
<p>The Currying Syntax was the best idea I had seen to bring a syntax that works well for currying in a C-like language.</p>
<pre><code class="prettyprint">func add(a: Int)(_ b: Int) -> Int {
return a + b
}
add(1)(2)
</code></pre>
<p>I would almost say that all functions should be written like this. There should be <em>no</em> functions with multiple arguments. Yet, somehow, Apple and the community decided to remove this syntax from the language in Swift 3.0.<br>
I’m not holding my breath, but I would love to get this feature back.</p>
<h2 id="2-generic-type-aliases_2">2. Generic type aliases <a class="head_anchor" href="#2-generic-type-aliases_2">#</a>
</h2>
<p>Swift has a simple keyword for declaring types:</p>
<pre><code class="prettyprint">typealias Model = Int
</code></pre>
<p>Now this is well and good, but it would be great to get a way to declare generic types.</p>
<p>For example, you can easily write generic functions.</p>
<pre><code class="prettyprint">func maybe<T>(a: T)-> T? {
if (arc4random_uniform(10) > 5) {
return a
} else {
return nil
}
}
func identity<T>(a: T)-> T? {
return a
}
</code></pre>
<p>This is great. <code class="prettyprint">identity</code> and <code class="prettyprint">maybe</code> both have the same type. One of them will always return the value, while the other one will return it about half the time. Plus, the compiler will help us avoid any null-pointers.</p>
<p>But it’s impossible to give this type of functions a name. While I can do this:</p>
<pre><code class="prettyprint">func filterUsing<T>(arr: [T], _ fn: (T) -> T?) -> [T] {
return arr.filter({ x in
if fn(x) != nil {
return true
} else {
return false
}
})
}
</code></pre>
<p>This is illegal in Swift:</p>
<pre><code class="prettyprint">typealias Maybe<T> = (T) -> T?
func filterUsing<T>(arr: [T], _ fn: Maybe<T>) -> [T] {
return arr.filter({ x in
if fn(x) != nil {
return true
} else {
return false
}
})
}
</code></pre>
<p>This may not be a great example, but writing long type signatures over and over can get annoying, and being able to give it a name would be a big improvement. Further, since this feature would have no runtime cost so it will make developers faster without a penalty.</p>
<h2 id="3-union-types_2">3. Union Types <a class="head_anchor" href="#3-union-types_2">#</a>
</h2>
<p>This is something I learnt to love after using Flow, and playing with languages like Elm, Haskell, OCaml, Purescript.</p>
<p>In Swift, you can already do some workarounds to have union types using Enums and Structs, it’s often noisy.</p>
<pre><code class="prettyprint">enum IntOrString {
case Num(Int)
case Str(String)
}
func add(a: IntOrString, b: IntOrString) -> String {
switch (a, b) {
case (.Str(let sa), .Str(let sb)):
return sa + sb
case (.Str(let sa), .Num(let sb)):
return sa + String(sb)
case (.Num(let sb), .Str(let sa)):
return sa + String(sb)
case (.Num(let sb), .Num(let sa)):
return String(sa) + String(sb)
}
}
</code></pre>
<p>Wouldn’t it be much better to just be able to to this:</p>
<pre><code class="prettyprint">func add(a: Int | String, b: Int | String) -> String {
return String(a) + String(b)
}
</code></pre>
<p>This is common pattern in all the functional languages and even the type systems for Javascript like Flow and Typescript.</p>
<p>Further, there shouldn’t be a run-time cost to this either as Swift clearly already has a union type built-in: <code class="prettyprint">Optional</code>.</p>
tag:blog.namangoel.com,2014:Post/a-reintroduction-to-gulp2016-05-18T19:52:53-07:002016-05-18T19:52:53-07:00A Re-Introduction to Gulp<p>Forget everything you know about Gulp. Welcome to Gulp 4.</p>
<p>If you’re a front-end developer you surely have a build process in place. You maybe using Grunt, Gulp, Broccoli, NPM scripts etc. If everything works for you and you understand everything in your build process, you should stop reading now and focus your energy elsewhere.</p>
<p>If, however, you’re confused or just want to learn a little more about Gulp hang around.</p>
<h2 id="using-multiple-files-to-organize-tasks_2">Using Multiple Files to Organize Tasks. <a class="head_anchor" href="#using-multiple-files-to-organize-tasks_2">#</a>
</h2>
<p>If you currently break your <code class="prettyprint">gulpfile</code> into multiple files, you probably make a folder called <code class="prettyprint">gulp</code> and using something like <code class="prettyprint">require-dir</code> to import it all.</p>
<p>While this works for now, it has the effect of making your build process harder to read.</p>
<p>Instead, keep things more explicit. This happens in two steps.</p>
<p>Firstly, start writing you gulp tasks as simple functions and attach them to gulp.task separately.</p>
<p>So, instead of writing this:</p>
<pre><code class="prettyprint">gulp.task('taskName', function(){
// task here
})
</code></pre>
<p>Do this:</p>
<pre><code class="prettyprint">function taskName(){
// task here
}
gulp.task('taskName', taskName)
</code></pre>
<p>Now, just export functions in the files in your gulp folder. Import them and register them in your gulpfile manually. This makes things more explicit, and you get all your tasks in one place again.</p>
<p>Plus, with Gulp 4, you will be able to get rid of the <code class="prettyprint">gulp.task</code> business altogether. Soon you’ll be able to just export functions in your <code class="prettyprint">gulpfile</code>.</p>
<pre><code class="prettyprint">export function taskName(){
// task here
}
</code></pre>
<p>This also means you task functions are all more re-usable by default.</p>
<h2 id="use-es6_2">Use ES6. <a class="head_anchor" href="#use-es6_2">#</a>
</h2>
<p>Using ES6 in your <code class="prettyprint">gulpfile</code> has been possible for a while.</p>
<ul>
<li>Step 1: <code class="prettyprint">npm install --save-dev babel babel-preset-es2015</code>
</li>
<li>Step 2: Create a <code class="prettyprint">.babelrc</code> file:
<code class="prettyprint">
{
"presets": ["es2015"]
}
</code>
</li>
<li>Step 3: Rename <code class="prettyprint">gulpfile.js</code> to <code class="prettyprint">gulpfile.babel.js</code>
</li>
</ul>
<h2 id="use-libraries-when-needed_2">Use Libraries when needed <a class="head_anchor" href="#use-libraries-when-needed_2">#</a>
</h2>
<p>Gulp has always been quite fast because it used Node Streams and did things in parallel. However, Node streams have a low-level API and can be slightly hard to deal with.</p>
<p>Instead, consider using a library like Highland.js or RxJS (with rx-node) to make your life simpler when writing complex logic in your gulp tasks.</p>
<h2 id="don39t-overrely-on-gulp-dependencies_2">Don’t over-rely on gulp dependencies. <a class="head_anchor" href="#don39t-overrely-on-gulp-dependencies_2">#</a>
</h2>
<p>Gulp has a simple way to define the dependencies you want to run before the current one.</p>
<pre><code class="prettyprint">gulp.task('taskName', ['dependency1', 'dependency2'], function(){...})
</code></pre>
<p>This is nice and simple</p>