DEV Community

Cover image for Scaling Frontend Applications - Coding Guidelines
Wale Ayandiran
Wale Ayandiran

Posted on

Scaling Frontend Applications - Coding Guidelines

Structuring your frontend application can become tricky as your product and codebase grows. In this post, I will be sharing what I have found to a working solution for almost any kind of Frontend project size. This guideline is strongly inspired by a pattern termed as the duck pattern.

The entire idea of ducks is to group seemingly related files together in a way that makes it modular, modification easier, scalable, and easy to deconstruct whenever a need arises and move technologies around like state libraries etc.

Ducks are extroverted, gregarious animals who feel most at minimal fuss when they're in groups.
Duck pattern at its core is about colocating small files that work together as a unit to make working with them a breeze. Lets see guideline below;

File and Folder Convention

Using the feature pattern to colocate feature related files rather than by functions, lets take a look at a login example

Feature-first ✅

Login/
  Login.tsx
  index.ts
  store/
    reducers.ts
    actions.ts
Enter fullscreen mode Exit fullscreen mode

"Feature-first" refers to naming your top-level folders after the primary feature your app contains, Login in this case.

Because each new feature comes with its own folder, this technique scales considerably better.

You can have files that aren't associated with any functionality and call them common/shared/core e.t.c. because you want to reuse code across several functionalities in your product.


Function-first ❌

Components/
  Login.tsx
  Signup.tsx
Containers/
  Login.tsx
store/
  reducers.ts
  actions.ts
Enter fullscreen mode Exit fullscreen mode

"Function-first" refers to naming your top-level folders after the purpose of the files they contain.
So far, you've got containers, components, actions, reducers, and so on.

This isn't going to scale at all.
Files are added to the same directories as your programme evolves and additional features are added.

The issue also involves tying the folders together.
A single flow in your programme will almost certainly necessitate editing files from all directories.

Using the "Feature-first" approach, we can generate a general Project struture like so;

src/
  pages/ ---> Contains top level files rendering as a page
    login {feature-folder}/ ---> Would contains components, api|hooks|actions files & folders related to login pages, if these components are going to be reused elsewhere aside login, move it into the core/components directory.
  core/ ---> Globally shared, reusable, components and files JSX related.
    components/ ---> Globally Shared React components, mostly dumb/presentational components
      {ComponentName}/
        ComponentName.tsx ---> Using named exports e.g `export const ComponentName = () => {}` Always keep this file as simple as possible
        Styles.tsx ---> A case for using styledComponents, all created elements will be stored here, exported using named exports
        index.ts ---> exports { ComponentName } from './Componentname'
        utils.ts ---> Optional when you need to move some functions out of the component file to keep things clean.
  utils/ ---> JS files that are globally needed, helper functions, etc.
Enter fullscreen mode Exit fullscreen mode

Components

Your Frontend Components will most likely be grouped into 2 kinds, presentational and connected components.

Worthy to Remember

  • Endeavor to use functional components all through because, why not 🤷🏾? it saves you from dealing with class components and its numerous lifecycle methods.
  • Have an index file that exports all components from a feature folder, helps to organize your imports and exports.

Presentational Components

  • Have no dependencies on the rest of the application.
  • Values and callbacks are passed into these via props.

Example:

ComponentName/
  ComponentName.tsx ---> Using named exports e.g `export const ComponentName = () => {}` Always keep this file as simple as possible
  Styles.tsx ---> A case for using styledComponents, all created elements will be stored here, exported using named exports
  index.ts ---> exports { ComponentName } from './Componentname'
  utils.ts ---> Optional when you need to move some functions out of the component file to keep things clean.
Enter fullscreen mode Exit fullscreen mode
export const PresentationComponent = ({ prop1, props2 ...propN }) => (
  <div>Show something</div>
);
Enter fullscreen mode Exit fullscreen mode

Connected Components

  • are responsible for retrieving data.
  • are aware of the store and be connected to it.
  • provide data to other components.
  • are responsible for dispatching actions.
  • grab data from store and then passes that data down to its children as props.

Example:

ComponentName/
  ComponentName.tsx ---> Using named exports e.g `export const ComponentName = () => {}` Always keep this file as simple as possible
  Styles.jsx ---> A case for styledComponents, all created elements will be stored here, exported using named exports
  actions/ ---> handles all Async events, and certain Events that needs to be seperated from the components.
    store/ reducers/ etc
    api|hooks/
  index.js ---> exports { ComponentName } from './Componentname'
  utils.js ---> Optional when you need to move some functions out of the component file to keep things clean.
Enter fullscreen mode Exit fullscreen mode

Styling Components

Because I've been a making a case for using styled components, we will like to keep these clean and away from jsx logic. All created styled components will be inside an Styles.js file inside the component folder.

Example:

// Styles.js
import styled from "styled-components";

export const Header = styled("div")`
  display: flex;
  flex-direction: column;
  width: 500px;
  height: 200px;
`;

export const Footer = styled("div")`
  display: flex;
  flex-direction: column;
  width: 500px;
  height: 200px;
`;
export const LeftMenu = styled("div")`
  display: flex;
  flex-direction: column;
  width: 500px;
  height: 200px;
`;
Enter fullscreen mode Exit fullscreen mode

Interacting with Backend

All backend related actions should be in the actions folder within each components directory. see Connected Components above.

State sharing

There's a couple of options for this and I see most teams now are leaning towards React Context for React applications,
other worthy mentions include:
Redux, VueX, Mobx.

Same philosophy applies regardless of the state library employed.

Actions/
  reducers/
Enter fullscreen mode Exit fullscreen mode

This writeup is highly opinionated on my experience but a lot of teams both small and large have similar approach to handling their frontend applications.

Let me know if you find this useful or have questions or share how you've been able to structure your frontend applications at work.

Photo by Simone Hutsch on Unsplash

Top comments (0)