开源日报每天推荐一个 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/