alifeiliu

alifeiliu

哪有什么无限进步,能进一步是一步
github
x
discord server
email
strava
bilibili

This Week's Bulletin #1

As a technical professional, especially as a senior programmer, surviving in the current terrible social environment often brings about a sense of anxiety, which is caused by instability, lack of achievements, and peer pressure.

Book Review#

Recently, I have been reading the book "The Efficiency Handbook" although I don't recommend it. The content is filled with personal opinions, excessive and repetitive nonsense, boasting, and superficiality. However, there are some concepts that I find quite agreeable, such as honing one's skills. Indeed, investing in oneself, setting goals for one's life, breaking down those goals into actionable steps, and truly implementing them, just like leveling up in a game, allows oneself to continuously grow and cultivate the excellent qualities of those around them. It even enables one to surpass them and make those qualities their own, thus alleviating the aforementioned anxieties.

Work#

It has been four months since I left Bilibili and joined a large company. It feels like the growth during the probation period was the most rapid. I faced high OKRs, familiarized myself with the environment, and interacted with new colleagues. I managed to overcome that difficult period. After becoming a regular employee, it feels like all the pressure has disappeared. There are no new and exciting technologies to learn, and no complex projects to take on. It's frustrating!

However, I discovered that there are many repositories worth learning from on the company's code hosting platform. After all, they are applied in a real production environment with a large amount of UV/PV. Alright, now I have a direction. I can clone the repositories that interest me and learn independently. Not only can I freeload, but I can also learn new technologies! 😏

Slacking Off at Work#

Tailwind#

One of the business projects at the company uses Tailwind. I had heard of it before, but at the time, I thought it required memorizing a lot of class names and writing long strings of classes on elements, which was quite annoying. So I didn't delve into it. However, after joining the company, I realized that performance optimization is a common practice here (I will write a series about it later), and it is also used in business development and maintenance. Therefore, I spent a day reading the official documentation, and now I understand it better.

Advantages#

In my opinion, the obvious advantages of Tailwind are:

  • Optimized CSS: It is said that most projects generate CSS files that are less than 10KB. Traditional handcrafted CSS may contain a lot of repetitive code, but Tailwind provides better performance.
  • Semantic to Atomic: Tailwind follows a set of design specifications, allowing for fine-grained customization. Compared to inline magic values in the style attribute or inconsistent class naming conventions, Tailwind provides more constraints and better semantic meaning.
  • No separate CSS file: You don't have to worry about deleting corresponding class names when removing elements, and there are no style conflicts.
  • Development experience: You don't have to switch between CSS and HTML/components. Just add class names to elements, and it flows smoothly.

I fully accept its disadvantages compared to its advantages. Therefore, in the next new project or when optimizing existing projects, I may consider introducing Tailwind as a means to further reduce CSS file size.

tailwind-merge
Solves the problem of merging class names and correctly overrides styles.

import { twMerge } from 'tailwind-merge'

twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]')
// → 'hover:bg-dark-red p-3 bg-[#B91C1C]'

class-variance-authority
Generates different combinations of class names based on component attributes. Can be used to create custom components with Tailwind.

// components/button.ts
import { cva } from "class-variance-authority";
 
const button = cva(["font-semibold", "border", "rounded"], {
  variants: {
    intent: {
      primary: [
        "bg-blue-500",
        "text-white",
        "border-transparent",
        "hover:bg-blue-600",
      ],
      // **or**
      // primary: "bg-blue-500 text-white border-transparent hover:bg-blue-600",
      secondary: [
        "bg-white",
        "text-gray-800",
        "border-gray-400",
        "hover:bg-gray-100",
      ],
    },
    size: {
      small: ["text-sm", "py-1", "px-2"],
      medium: ["text-base", "py-2", "px-4"],
    },
  },
  compoundVariants: [
    {
      intent: "primary",
      size: "medium",
      class: "uppercase",
      // **or** if you're a React.js user, `className` may feel more consistent:
      // className: "uppercase"
    },
  ],
  defaultVariants: {
    intent: "primary",
    size: "medium",
  },
});
 
button();
// => "font-semibold border rounded bg-blue-500 text-white border-transparent hover:bg-blue-600 text-base py-2 px-4 uppercase"
 
button({ intent: "secondary", size: "small" });
// => "font-semibold border rounded bg-white text-gray-800 border-gray-400 hover:bg-gray-100 text-sm py-1 px-2"

clsx
A CSS-IN-JS library. Here is a concise introduction from its official documentation:

A tiny (239B) utility for constructing className strings conditionally.
Also serves as a faster & smaller drop-in replacement for the classnames module.

It allows for dynamically adding and removing CSS classes based on conditional values. For example:

import clsx from 'clsx';
// or
import { clsx } from 'clsx';

// Strings (variadic)
clsx('foo', true && 'bar', 'baz');
//=> 'foo bar baz'

// Objects
clsx({ foo:true, bar:false, baz:isTrue() });
//=> 'foo baz'

// Objects (variadic)
clsx({ foo:true }, { bar:false }, null, { '--foobar':'hello' });
//=> 'foo --foobar'

// Arrays
clsx(['foo', 0, false, 'bar']);
//=> 'foo bar'

// Arrays (variadic)
clsx(['foo'], ['', 0, false, 'bar'], [['baz', [['hello'], 'there']]]);
//=> 'foo bar baz hello there'

// Kitchen sink (with nesting)
clsx('foo', [1 && 'bar', { baz:false, bat:null }, ['hello', ['world']]], 'cya');
//=> 'foo bar hello world cya'

tailwindcss-animate and tailwindcss-animated
Tailwind animation plugins.

Preact#

While optimizing applications at the company, I noticed that the top 10 INP (Input Delay) values were mostly cases where the INP element was html or html>body, and the INP interaction events were pointerdown/up or keydown/up.

image

This situation always occurred when simulating CPU x4 slowdown in the local browser and was independent of internet speed. Based on my speculation, this is related to the application's adoption of an isomorphic + streaming rendering approach. The first segment of the streaming rendering allows users to see part of the page content, and at this point, users may interact with the page. Client-side interactions depend on the execution of the entry JS file, and the hydration injection is required for interactions to take effect. When clicking on a blank area, INP is recorded:

image

When any key is pressed, INP is recorded:

image

I performed a performance analysis:

image

Especially on devices with poor performance, the download of JS files is not affected, but parsing and execution may be slightly affected, resulting in a higher probability of a high Input delay. While investigating the INP issue in the company's application, I found that the inclusion of react.production.min.js and react-dom.production.min.js blocked user interactions during the initial loading phase. Therefore, I had to consider whether there were better framework options.

Fortunately, preact is said to be a drop-in replacement for react, and its production version is only 3.5KB in size. It's amazing!

image

image

image

If it can bring performance advantages, maybe it can optimize INP? I will try it when I have the opportunity.

Interesting Things#

  • Online tool for checking package size and download time: bundlephobia
  • An interesting illustrated book called "Life Montage." It depicts small things in life, healing, and empathy. At this moment, I believe that someone, somewhere in the world, is thinking the same thing as I am.
  • Blog cover images from 500px
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.