開源日報每天推薦一個 GitHub 優質開源項目和一篇精選英文科技或編程文章原文,堅持閱讀《開源日報》,保持每日學習的好習慣。

2024年2月1日,開源日報第1092期:
今日推薦開源項目:《brave》
今日推薦英文原文:《We Forgot Frontend Basics》


開源項目

今日推薦開源項目:《brave》傳送門:項目鏈接

推薦理由: 下一代適用於Android、Linux、MacOS和Windows的Brave瀏覽器

網站直達:brave.com


英文原文

今日推薦英文原文:We Forgot Frontend Basics

推薦理由: 作者建議回歸前端三件套基礎知識,提倡對純JavaScript的深入了解,深入了解HTML和CSS,並遵循SOLID、YAGNI和KISS等基本原則,基礎決定上層建築


We Forgot Frontend Basics

Usually, I say that it is not so bad, skillful hands can do almost everything. However, recently I have noticed some things that changed my view on the industry. It seems like in all those endless trends, paradigms, and novelty we forgot the backbone of frontend development.

In this article, I』d like to share a few code snippets from a recent project and try to explain my thoughts about them. Without any further words, let』s start!

Table Of Contents

Endless Overcomplication

Here we have the most basic Cardcomponent, which has an optional header property. If this property exists — we render it inside of wrapping div with a specific class.

const Card = ({ children, header }) => {
  return (
    <div className="card">
      {header && <div className="card__header">{header}</div>}
      {children}
    </div>
  );
};

In simple variants, everything works just fine. In that case, <Card /> the header isn』t rendered, here otherwise <Card header={"I am header"} />. Problems start to occur when the content of the header is dynamic and can return actual content or null — <Card header={<CardHeader />} />. Our condition {header && <div />} can』t detect it and will render an empty div.

One developer tried to solve that issue. He thought, 「Wait, we can check the content of the div and hide it if empty!」. That is the approximate code he wrote:

const Card = ({ children, header }) => {
  const headerRef = useRef();

  useEffect(() => {
    const hasContent = headerRef.current?.childNodes.length > 0;
    headerRef.current.style.display = hasContent ? "block" : "none";
  });

  return (
    <div className="card">
      {header && (
        <div ref={headerRef} className="card__header">
          {header}
        </div>
      )}
      {children}
    </div>
  );
};

Another guy noticed during the code review, that this code works only on the initial render. If the footer is updated asynchronously, useEffect won』t be invoked. After a long debate, developers decided to turn their attention to the MutationObserver.

During their discussions, they also asked me for advice. To be honest, it was really fun to show them my variant) It was enough just to use the usual CSS to solve that problem.

.card__header:empty {
  display: none;
}

Developers were so used to overcomplicating their tasks, that they didn』t even check the basic capabilities of CSS.

Mistakes From 1993

In my previous project, we got a side panel widget, which had to stretch to its full height, but not overlap the header and footer. The approximate formula looks like this: 100% - headerHeight - footerHeight.

The solution worked smoothly on all pages, except one. On that page, footerHeight was somehow equal to 0. The developer who got this bug, dug deeper and understood that document.querySelector('footer') returned null, but the footer was still rendered on the page. What do you think he did? Yes, MutationObserver was used again)

It looked strange to me and I decided to find an alternative solution. And I found it, I was enough just to swap a couple of lines of code…

<html>
<head></head>
<body>
  <header></header>
  <main id="root"></main>
  <script src="index.js"></script>
  <footer></footer>
</body>
</html>

Somehow <script /> ended up on the page before the footer. <script /> invokes synchronously and the footer doesn』t exist at that moment, so it is impossible to measure its height. I just swapped these lines and everything started to work as it should.

Nowadays developers highly rely on modern tooling like webpack-plugin and etc. So when it comes to writing some HTML themselves, they immediately pass. But what』s so hard about it?

The Root of All Evil

React hooks are simultaneously the best and the worst thing in React. On one hand, they add flexibility and an elegant way to handle the state. On the other hand, they dramatically increase code complexity and make it easier to make mistakes.

It doesn』t seem hard to read the documentation carefully and comprehend how to use things in the right way. However, some developers miss this obvious step and start using hooks without a complete understanding of their purpose. Especially, when it comes to optimization and notorious useMemo and useCallback. Now every developer optimizes the whole app without an explicit reason.

❗️ If you want to dig deeper into that topic, I highly recommend checking out this article about useMemo.

Let』s look at this 「crucial」 optimization together. It』s not an imaginary code I wrote specially for this article. Actually, I got this snippet from one of my projects.

const loaded = useMemo(() => {
    return submitted && !loading && !error;
  }, [submitted, error, loading]);
}

After this optimization, the app performance just 「skyrocketed」! As you can understand it is completely useless and even slightly hurts the app』s first load. To be honest, I still don』t understand the real intention of writing this.

It is always much easier to take things for granted and not to think about anything else. But isn』t that hard to do your own little research?

A Couple of Important Tips

This situation seems really sad. Developers start to forget basic technologies and lose critical thinking in all that mess of new technologies and approaches.

However, in my opinion, it』s not such a difficult issue to solve. To conclude everything above, I want to show you these straightforward points. Please, give me your feedback on them!)

  • Spend some time and understand vanilla JavaScript. Having a strong foundation makes it easier to detect the real reasons of bugs and fix them quickly
  • Learn HTML and CSS in depth. You can discover a lot of useful properties, selectors, and other stuff which can replace tons of js code. Just recall the example with the :empty selector
  • Develop your critical thinking skills. Of course, your teamlead taught you certain good practices and principles. However, you cannot blindly follow them as it will simply lead you in the wrong direction. Instead, try to understand why something is this way and not the other
  • Remember about SOLID, YAGNI, KISS, and other principles. If the simple task turns out to be a nightmare with a confusing solution — just stop and rethink it from a different angle. Probably, you went way too deep into one solution and forgot about something obvious

    下載開源日報APP:https://openingsource.org/2579/
    加入我們:https://openingsource.org/about/join/
    關注我們:https://openingsource.org/about/love/