As a technical professional, especially as a senior programmer, surviving in the current terrible social environment always brings 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, as it contains personal opinions, repetitive and irrelevant content, and boasts without grounding, there are still some concepts that I find acceptable, such as honing practical skills. Indeed, investing in oneself, setting goals for one's life, breaking them down 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 the people around them, even surpassing them, making them one's own strengths, and thus alleviating the aforementioned anxieties.
Work#
It has been four months since I left Bilibili and joined a big company. It feels like the growth during the probation period is the most rapid. I have overcome the challenges of high OKRs, familiarizing myself with the environment, and interacting with new colleagues. 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 found that there are many repositories worth learning on the company's code hosting platform. After all, they are applied in production environments with a large number of UV/PV. Alright, now I have a direction. I can clone the repositories I'm interested in and learn independently. Not only can I benefit from them, but I can also learn new technologies! 😏
Slacking Off at Work#
Tailwind#
One of the business projects in the company uses Tailwind. I had heard of it before, but at that 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 have a clear understanding.
Advantages#
In my opinion, the obvious advantages of Tailwind are:
- Optimized CSS: It is said that the CSS generated by most projects will not exceed 10KB. Traditional handcrafted CSS may contain a lot of repetitive code, while 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 semantics. - 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 back and forth between CSS and HTML/components. Just add class names to elements and you're good to go.
I fully accept its disadvantages compared to its advantages. Therefore, in the next new project or when optimizing existing projects, I might consider using Tailwind's atomic approach to further reduce CSS file size.
Related Libraries#
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 official description:
A tiny (239B) utility for constructing className strings conditionally.
Also serves as a faster & smaller drop-in replacement for the classnames module.
It dynamically adds or removes 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 the company's applications, I found that most of the cases where the INP (Input Delay) value exceeded 200 were related to the html
or html>body
elements, and the INP interaction events were pointerdown/up
or keydown/up
.
This issue always occurred when simulating CPU x4 slowdown
in the local browser and was independent of network speed. Based on my speculation, it is related to the application's adoption of an isomorphic + streaming rendering approach. The first chunk of the stream 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:
When any key is pressed, INP is recorded:
I ran a performance test:
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 high Input delay
. When investigating the INP issue in the company's applications, I found that the inclusion of react.production.min.js
and react-dom.production.min.js
blocks user interactions during the initial loading phase. Therefore, I have to consider whether there are better options for framework selection.
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!
If it can bring performance advantages, can it 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," which depicts small things in life, healing, and empathy. At this moment, what I think in my world must have been thought by someone else at some point.
- Blog cover images taken from 500px