/emah-dev

Official emah website

Primary LanguageTypeScript

emah

The official emah website built in Next.js and Typescript with TailwindCSS for styling and R3F for 3D graphics.

Technologies

Configuration

Using NextJS ESLint with StandardJS, is necessary the following configuration for eslintrc file to ensure ESLint works propertly with React components:

"extends": [
  "next/core-web-vitals",
  "./node_modules/standard/eslintrc.json"
]

Folder Structure

I'm using the src folder for keep code at a different level than configurations and miscellaneous files.

This is the structure I use for my Next.js projects:

Onion-shape structure

We can express the above image with the following structure:

- src
  - app
  - core
  - components (domain)
  - pages
    - api

App

Contains code that is being used by the special pages/_app.tsx Next.js file, like:

  • Components
  • The store of the global state
  • Business logic
  • And more...

We could develop our folder structure in this way:

- src
  - app
    - layout
    - store
    - ...

Core

This layer is used to place all unrelated to our domain

The core and the domain of a project, in my view, should be kept well separate.

Hard rule: the core layer can never import anything from the domain layer.

If something within the core layer needs something from the domain, it probably does not belong to the core layer.

For example:

  • The database connector functions
  • The utils for authentification
  • The email provider
  • And more...

The core layer provides the domain with the necessary tools for the application to work, for example, authenticating, querying the DB, or sending emails. But does not know how the consumer uses these tools.

We could develop our folder structure in this way:

- src
  - core
    - database
      - connector.ts
      - ...
    - auth
      - auth.ts
    - ...

Domain

The business domain is the area of control or a sphere of knowledge, such as, the group of entities, relationships, and behaviors of the business model, implemented as code.

We can express the domain layer with the following structure:

- src
  - components
Components

The components that make up our app pages.

The business-logic side keep a lot of things, such as queries, or functions that mutate data, are all at the same folder that components and they can be reusable across components.

  • Custom hooks
  • Configurations
  • Queries
  • And all utilities related to the domain

We could develop our folder structure in this way:

- src
  - components
    - input
      - CallToAction
        - index.tsx
        - hooks
        - utils
        - queries
    - navigation
      - Navbar
        - index.tsx
        - hooks
        - config
    - sections
      - Hero.tsx

Pages

Next.js's router is file-system based, the folder pages is a Next-specific directory to place our API.

We could develop our folder structure in this way:

- src
  - pages
    - api
      - Search
        - [keyword].ts
      - products
        - [id].tsx

Imports between Layers

Something important to clarify is the rules I have around importing between layers.

Typically, an inner layer cannot import from an outer layer, that means that core cannot import from the domain layer, and the latter cannot import from pages.

Wrong

Onion-shape structure flow wrong

Ok

Onion-shape structure flow ok

This rule can ensure your core is decoupled from the domain to avoid cyclical dependencies and keep your architecture untangled.

Linting import paths with EsLint

We can ensure that we're using the rules above correctly when importing files in our application.

EsLint can help us by adding the following configuration, can automatically warn you that you're importing from the wrong paths:

"rules": {
  "import/no-restricted-paths": [
    "error",
    {
      "zones": [
        {
          "target": "./src/core",
          "from": "./src/components"
        },
        {
          "target": "./src/core",
          "from": "./src/pages"
        },
        {
          "target": "./src/components",
          "from": "./src/pages"
        },
        {
          "target": "./src/core",
          "from": "./src/app"
        },
        {
          "target": "./src/components",
          "from": "./src/app"
        }
      ]
    }
  ]
}
  • Queries## Getting started

I recommend use pnpm because it hold all the packages at a global (centralized) store and use them if needed by other projects too by creating hard links to it.

  1. Clone the project
$ git clone https://github.com/saufth/emah.git/
  1. Install the dependencies:
$ pnpm install (recommended)
# or
$ yarn
# or
$ npm install
  1. Run the development server
pnpm dev (recommended)
# or
yarn dev
# or
npm run dev

Open http://localhost:3000/ with your browser to see the result.

Credits

Licence

Copyright © 2022 emah. All rights reserved.