21 Frontend Engineering Tips ️💡 — This Quarter I Learned(1Q 2024)

365kim
6 min readMar 29, 2024

--

Photo by Unseen Studio on Unsplash

In the dynamic world of web development, the first quarter of 2024 has been a journey filled with learning and growth. Here’s a glimpse into the insights and lessons I’ve gathered:

TypeScript/JavaScript

1. TypeScript 5.4 brings NoInfer utility type

TypeScript 5.4, released on March 6, 2024, added the NoInfer utility type. NoInfer restricts additional type inference within a given type, ensuring stricter type checks.

Before TypeScript 5.4, certain type checks would pass unexpectedly.

createStreetLight(["red", "yellow", "green"], "blue"); // Passed 🤔


function createStreetLight<C extends string>(colors: C[], defaultColor?: C) {
// ...
}

With NoInfer, TypeScript now correctly identifies type mismatches, enhancing code reliability.

createStreetLight(["red", "yellow", "green"], "blue"); 
~~~~~~
// Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'.


function createStreetLight<C extends string>(colors: C[], defaultColor?: NoInfer<C>) {
// ...
}

2. On MacOS, keyup event does not fire when the meta key is down

A peculiar behavior where if the meta key is pressed, other keys won’t trigger keyup events unless the meta key is released first. (So, it’s like keyupWhenMetaKeyIsNotPressedOnMacOS.)

3. break statement can also be used with label statement

It’s possible to use the break statement within label statements, expanding its utility beyond loops and switch cases.

outerBlock: {
innerBlock: {
console.log("1");
break outerBlock; // breaks out of both innerBlock and outerBlock
console.log(":-("); // skipped
}
console.log("2"); // skipped
}

4. valueMissing property becomes true only when…

The valueMissing property in the ValidityState interface becomes true only under specific conditions:

  • when an element has the required attribute set
  • and lacks a value.

If the required attribute is not present, the valueMissing property will not be affected and remains false.

React

5. React.useTransition facilitates smooth transitions

React.useTransition is ideal for managing transitions and animations in your app, ensuring maintain a fluid user experience.

export default function TabButton({ children, onClick }) {
const [isPending, startTransition] = useTransition();

const handleClick = () => {
startTransition(() => {
onClick();
});
}

if (isPending) {
return <div className="pending">{children}</div>;
}
return (
<button onClick={handleClick}>
{children}
</button>
);
}

6. React.useDeferredValue ensures responsiveness.

React.useDeferredValue is best used for deferring updates to non-urgent UI elements.

For example, the following code ensures deprioritizing re-rendering the SlowList and so preventing keystrokes from being blocked.

import { useState, useDeferredValue } from 'react';
import SlowList from './SlowList.js';

export default function App() {
const [text, setText] = useState('');
const deferredText = useDeferredValue(text);

return (
<>
<input value={text} onChange={e => setText(e.target.value)} />
<SlowList text={deferredText} />
</>
);
}

HTML/CSS

7. strong, em, mark, and b — Frequently confused HTML tags.

Selecting the correct tag is essential for semantic accuracy and accessibility.

  • Use <strong> for indicating importance(e.g. seriousness or urgency)
  • Use <em> to emphasize text
  • <mark> should be used to highlight text that is relevant in a particular context
  • Only use <b> when other tags are not appropriate

Remember that styling for bold text should be done using CSS

8. How to fix layout shifts with bold text on focus

To avoid layout shifts when the text becomes bold on focus, use a ::before pseudo-element with font-weight: bold.

Cross-Browsers

9. A button element is not focusable in Safari

Unlike most browsers, Safari does not give focus to a button element upon clicking, which is a deliberate design choice.

in Chrome
in Safari

10. Hard Refresh is different from Standard Refresh in that…

Unlike a standard refresh, which relies on the browser cache, a hard refresh ignores the browser cache and requests all resources directly from the server again.

For Chrome, the keyboard shortcut to initiate the hard refresh is cmd + shift + R (cmd + option + R for Safari)

Cross-Environment

11. How to deal with ‘document is not defined’ error

This error typically occurs when code intended for a browser environment is executed elsewhere, like in server-side rendering or during automated testing in non-browser environments. (I encounted this error in CI environment.)

To handle this error, you can add a guard statement:

const isOnBrowser = typeof document !== 'undefined'

if (!isOnBrowser) {
return;
}

// Do something

12. ‘__dirname is not defined’ error in ES Modules

Unlike CommonJS environment, __dirname is not defined under ES6 environment. Therefore, accessing __dirname in the ES Module environment will introduce '__dirname is not defined' error. (I encountered this error while porting code directly from a .cjs file to a .mjs )

To solve this, you can recreate __dirname:

import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

Git

13. — no-verify flag can be a lifesaver

--no-verify flag is useful for bypassing pre-commit hooks during urgent commits, though it should be used judiciously.

14. Who is initial committer in this repository

To discover who made the first commit in a repository, use the command git log | tail.

Package Manager

15. keep depencencies up-to-date with npm-check-updates'

npm-check-updates simplifies the process of keeping your project's dependencies current. It compares the versions in your package.json against the latest ones available in the npm registry. The --interactive flag (or -i for short) allows you to selectively update dependencies.

npm i -g npm-check-updates
ncu --interactive

For a simpler check, use npm outdated command. It provides a concise list of updates to consider.

16. ~, ^ — package.json version notation

The symbols ~ and ^ in package.json have always been a bit confusing to me, despite reading about them several times.

Here’s a clearer breakdown of what these version notations mean:

  • The tilde ~ prefix in ~version is approximately equivalent to the specified version, allowing for patch-level changes. For instance, if the version is specified as ~1.2.3 and you run npm install, updates to versions like 1.2.4 or 1.2.30 are permitted, but an update to 1.3.0 is not.
  • The caret ^ allows updates that do not modify the left-most non-zero element. So, if you start with ^1.2.3 and run npm install, you could get any version up to 1.3.0 but not 2.0.0. This is because changes up to the minor version are considered backward-compatible.

When the major version is 0, indicating early development stages, the ^ behaves differently! Even with ^, only patch-level changes are allowed, acknowledging that minor version changes might introduce breaking changes commonly in these early versions.

Network

17. Understanding Quality Values in comma-separated lists

Quality values, or “q-values,” enable the prioritization of preferences within HTTP headers, such as Accept-Language. They follow a ";q=" suffix with a numeric value ranging from 0 to 1 to denote priority:

Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5

Higher q-values indicate higher priority, with a default of 1 when unspecified.

18. bodyUsed Property of response object

The bodyUsed property of the Response object indicates whether the body has been read or not. It changes to true only after methods like response.json(), response.text(), or response.blob() are called to read the response body.

19. Status code - 503 Service

It’s a temporary state indicating the server is currently unable to process requests. This could be due to the server being overloaded or down for maintenance.

AWS

20. AWS Lightsail vs AWS EC2

Deciding between AWS Lightsail and AWS EC2 should be based on the specific needs of your project.

AWS Lightsail is designed for simplicity and affordability, making it perfect for smaller projects.

  • Offers a predictable, fixed pricing model
  • Simplifies setup and management(although it may lack some advanced features)
  • Is sufficient for standard web hosting needs. (This is why I chose this for a personal project.)

AWS EC2, conversely, offers more flexibility and scalability for complex architectures.

  • Adopts a pay-as-you-go pricing model.
  • Suits intricate applications demanding customized configurations.
  • Excels in hosting complex applications with its adaptable and scalable environment.

UX

21. Punctuation in UI

In UX writing, omitting periods(.) in single sentences can enhance readability and scanning.

I believe small insights can also build big value. Ready to move onward to more discoveries. 🛳

--

--

365kim

Web Front-End Developer who believes Every Day Counts!