Making Iran's biggest tech media website

2023-02-11

Zoomit (the parent company of Zoomit, Zoomg, Kojaro, and Pedal) is Iran's largest technology media group, receiving over 10 million monthly visits and millions of followers on various social media platforms(Instagram, Telegram, Twitter). We decided to rewrite the organization to achieve a unified design and ease the future development and maintainability.

zoomit landing

Zoomit has been around for a long time, and I've been reading articles on the website since elementary school. It has always been community-driven, and since it's one of my favorite websites, I want to pay tribute and contribute in any way I can.

zoomit web archive
from top-left to bottom-right. zoomit landing in Nov 13 2010, Jan 12 2017, Jan 20 2020 and current version in Jan 30 2023.
💡

These are my troughs and experiences. I'm not talking on behalf of Zoomit or the team. Also, this article only covers the client side of things.

Complexity is the heart of software

WYSIHTWYT(What you see is harder than what you think. fake acronym of course). At the surface level, we are making a Content Management System(CMS) but there is a lot to it. 500+ screens are no joke. It's a massive project and needed solid building blocks to ease the development and maintenance. Let's take a look at some of our challenges and how we solve them.

Everything is dynamic

Let's discuss the business aspect for a moment. Zoomit org requires a blend of a CMS and a website generator. The website pages are segmented into various positions, and the admin can select different modules for each position.

the team

Modules are the data mapping from different subdomains and chips are the filters of it. Consider these subdomains: article, comment, authors. each of them has it owns modules which determine the position and number of item. Chips are the filter. for example article from a week ago sort by number of comments in mobile category.

the team

As you can see article module

the team

Take a look at this screen only. It's the templates of related-article block

// block types
type RelatedArticleType = {
  data: {
    id: string,
    title: string,
    lead: string,
    author: AuthorType,
    coverImage: CoverImageType,
    mainCategoryId: string,
    readingTime: number,
    slug: string,
    publishedDate: string,
    link: LinkType,
    ...
  },
  template: "id-1" | "id-2" | "id-3" | ...,
  ...
};
 
// renderer
switch(block.template) {
    case "id-1":
        const RelatedArticleID1  = dynamic(() => import('./path'));
        return <RelatedArticleID1 {...data} />
    case "id-2":
        const RelatedArticleID2  = dynamic(() => import('./path'));
        return <RelatedArticleID2 {...data} />
}

For a single Block, there is 10+ possible designs. We have 20+ block and 10+ modules. do the math yourself.

Writing great end-to-end type safe(from editorial to website) renderer with dynamic loading is the key to succeed this scenario.

Editorial AKA admin panel

With over 50 writer and chief editor. Editorial it self contain a lot pages including modules and chips, articles, comments advertisement, media and user management. It's takes multiple posts to talk about each of them. For now let's only talk about article and it's editor

Block Editor and migration

Ok

the team

SEO and marketing

It's tricky. So many stuff to consider. What the hell is canonical. Seo schema!? yeah yeah GA inside GTM got it. Important to

We eventually build a library to map different types of seo schema. Maybe publish it in future

Here's a list to check:

  • title and description
  • robots.txt(fun fact we have humans.txt too. check out ours zoomit.ir/humans.txt)
  • Site Maps look for ours
  • SEO Schema
  • Canonical
  • NO BROKEN LINK

The stack

TypeScript, Nx, React, Next.js, Styled-Components, TanStack Query(can't believe he made us do that), zustand, Storybook, Cypress, Jest(I hate you), Framer Motion, React Aria, dnd-kit, lexical, dayjs, immer, ...

Ok probably many familiar names. Let's forget the obvious ones(yeah I need to defend TypeScript in 2023) and talk about controversial/cool kids.

Nx

Nx is fantastic. I'm recommending Nx for multiple years now and adopting it really pays off. Nx is simply the savior for project maintainers. JavaScript is not stable. tools coming and going very fast(yes Jest time to go. I can't bother configuring you anymore).

Styled-Components

Yeah I know. I'm css-in-js person and I have to defend it. I like the clean looking jsx and flexible and dynamic

zustand and immer

State management was hard and tedious and zustand created. Ok zustand isn't a new thing anymore(and I'm sad. no more gate keeping). I think 99% of projects will be fine with zustand and react-query. give immer a try. It makes mutating a breeze.

Headless ui

You should almost always build on top of headless ui. It was one of my bad calls to write out own primitives and we end up switching to React Aria. React Aria is nice but the documentation isn't. Reading through their source code, I learned a lot about focus management. I prefer the Radix's model. Radix helps me style and animate elements better and a good fit with css-in-js.

// not so great DX of React Aria
const { someProps, otherProps, moreProps } = useHook();
 
return (
  <button {...someProps} {...otherProps} {...moreProps}>
    click me
  </button>
);
the team
From left to right: Armin Shokati, Ehsan JafariMoghadam, Me, Reza Sobhgol